# BreezeCLI `breeze`: a global command line tool for projects built on the breeze SDK (the CMake template in `breeze/`). It is written with [CLIForge](source/CLIForge) and is itself a breeze project: build it with `breeze/scripts/build.sh` (or, once you have a `breeze`, `breeze build`). Three things, kept apart on purpose: | | What it is | Where it lives | Versioned by | |---|---|---|---| | **CLI** | this program; one per machine, any number of versions installed | `~/.breeze/cli//` | its own version (`breeze cli version`) | | **SDK** | the template: `breeze/`, replaced as a whole on an update | in each project | `breeze/VERSION` (`breeze sdk version`) | | **Tools** | extensions a project installs from a repository | `/.breeze/tools//` | the tool's tags | The CLI is global and the SDK is per project, so one CLI works on projects that are on different SDK versions, and on the layouts before `breeze/` existed (see [Older SDKs](#older-sdks)). ## Commands Run `breeze --help`, or `breeze --help`, for the exact options. The commands inside a project find it by walking up from the current directory. ### Projects and modules ``` breeze project new [--id] [--sdk] a new project (no demo code, one executable module to start from) breeze project version|name|id [--set] the project's version, name (CMake project()) and id breeze add exec|obj|test|example [--id] [--deps ...] breeze add lib (--static|--shared) [--id] [--deps ...] breeze delete [--yes] refuses while another module depends on it breeze rename [--name] [--id] renames the directory and/or id, fixing the DEPENDS that name it breeze ls [--filter] [--exec] [--obj] [--lib] [--test] [--example] [--shared] [--static] breeze deps of [--recursive] what it depends on breeze deps on [--recursive] what depends on it ``` Modules are read from, and written as, the `add_*_module(...)` calls in each `CMakeLists.txt`; the CLI changes only what it must (a rename touches the id, the directories and the DEPENDS entries, nothing else in the files). Ids default to `` plus `_exe`, `_lib`, `_obj`, `_test` or `_example`; `--deps` takes modules (by id or directory) or any other CMake target (`fmt::fmt`). ### Building and running ``` breeze setup [--required|--all] breeze build [-P platform] [-A arch] [-C compiler] [-M mode] [-j jobs] [-p preset] [--cargs ...] [--bargs ...] [--no-configure] breeze install [the same, and --no-build] breeze run [id] [-p/-P/-A/-C/-M ...] [-x arguments ...] breeze docs breeze clean [--no-build] [--docs] breeze defaults build platform|arch|compiler|preset|mode [--set ] breeze defaults run [--set ] ``` These drive the SDK's own scripts (`breeze/scripts/*.sh`, `.bat` on Windows), so the environment they set up (the pinned Ninja, the MSVC environment) is the one used. A platform, architecture and compiler name a preset (`-P linux -A x64 -C gcc` is `linux-x64-gcc`, ignoring case and punctuation: `ClangCl` finds `clang-cl`); whatever is missing comes from the project's defaults, then this machine. `--set none` clears a default. Defaults are kept in `.breeze/defaults.json`, meant to be committed. `--cargs` and `--bargs` take everything up to the next option, dashes included: `breeze build --cargs -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON -j 8`. `--bargs` (and `--no-configure`) run `cmake --build` on the directory the scripts configured, which the SDK's scripts have no way to do; so there must be a configured build first, and on Windows these two are not supported yet (the MSVC environment comes from the scripts). `-j` reaches the build through `CMAKE_BUILD_PARALLEL_LEVEL`. `run` with no id runs `breeze defaults run`, or the project's only executable. `-M` is accepted for `run` and ignored: the SDK keeps one build directory per preset. ### The CLI itself ``` breeze cli version | ls breeze cli install | pick | uninstall ``` Versions live in `~/.breeze/cli//` (`$BREEZE_HOME` moves `~/.breeze`); `cli/current` names the picked one. Every other command first hands itself over to the picked version, so whichever `breeze` your shell finds is the picked one, and `cli ...` commands always run in the version you started. Put `~/.breeze/bin` on `PATH`: the first `cli install` puts a copy of `breeze` there. Installing this program's own version needs nothing else: ``` ./breeze cli install $(./breeze cli version) ``` Other versions come from the **CLI source**: `breeze config cli-source --set `, expected to hold `/breeze--[.exe]` (platform `linux`, `macos`, `windows`; arch `x64`, `arm64`, `arm32`, `x86`). A URL is downloaded with `curl`. What is installed must run and say it is that version, or nothing is kept. ### SDK versions ``` breeze sdk version | update | upgrade | migrate ``` An SDK version is a snapshot of the whole template: `breeze/` (the SDK proper) plus the files a project starts from. Versions come from the **SDK source**: `breeze config sdk-source --set `. A repository's tags are the versions (`v1.2.0` or `1.2.0`); a directory has one subdirectory per version (`1.0.0/`, `1.1.0/`). The version of an SDK is the one line in `breeze/VERSION`, which the repository's tag should match. * `update` looks at the source and says what is there, and whether this project is behind. * `upgrade` moves to the newest version with the same major version. * `migrate ` moves to exactly that version, any way, across majors; `latest` is the newest release. Moving replaces `breeze/` (the old one is kept in `.breeze/backup/`), adds to `project/Configuration.cmake` any setting the new SDK has and the project's file lacks, and says which dot files (`.clang-format`, ...) now differ from the SDK's. Nothing else of the project is touched. ### Tools ``` breeze tool install | uninstall | update | upgrade | migrate | ls breeze tool ``` A tool is a git repository (or, while it is being written, a directory) with a `breeze-tool.json` at its root: ```json { "id": "resembed", "version": "1.0.0", "description": "Embeds resources", "entry": "bin/resembed.sh" } ``` `entry` may be `{ "posix": "...", "windows": "..." }`. Installed, it is copied into `.breeze/tools//` and recorded in `.breeze/tools.json` (commit both); `breeze tool ...` then runs the entry with those arguments, in the project's directory, with `BREEZE_PROJECT_ROOT`, `BREEZE_SDK_DIR`, `BREEZE_SDK_VERSION`, `BREEZE_TOOL_ID`, `BREEZE_TOOL_DIR`, `BREEZE_CLI`, `BREEZE_HOME` and `BREEZE_EDITOR` set. Everything after the id belongs to the tool, `--help` included, and its exit code is the CLI's. So `breeze tool san asan enable ` is whatever the `san` tool does with `asan enable `. `install`, `uninstall`, `update`, `upgrade`, `migrate` and `ls` can't be tool ids. ### Configuration ``` breeze config editor [--set] the editor tools open files with (BREEZE_EDITOR in their environment) breeze config sdk-source [--set] where SDK versions come from breeze config cli-source [--set] where CLI versions come from ``` Kept in `~/.breeze/config.json`; `BREEZE_EDITOR`, `BREEZE_SDK_SOURCE` and `BREEZE_CLI_SOURCE` in the environment win. `--set none` clears one. ## Older SDKs The CLI asks each project's SDK where things are instead of assuming: * **breeze/ layout** (with or without `breeze/VERSION`): everything above. * **The flat layout** (`scripts/`, `cmake/`, `Configuration.cmake` at the root): `ls`, `deps`, `add`, `rename`, `delete`, `project name|version|id`, `build`, `run`, `install`, `clean` work through that layout's scripts and presets; what an old SDK lacks is said when asked for (`add obj` on an SDK without objects modules; a preset on one without presets). `breeze sdk migrate ` moves a flat project to the `breeze/` layout: the old `CMakeLists.txt`, `Configuration.cmake`, `cmake/`, `scripts/` and `.githooks/` go to `.breeze/backup/`, and the project's name, version, description, languages, C++ standard and any setting it had changed go into `project/Configuration.cmake`. The project's own `README.md`, sources and dot files stay. ## Building and testing ``` breeze/scripts/build.sh --preset linux-x64-gcc --cargs -DBUILD_TESTS=ON out/build/linux-x64-gcc/bin/tests/core_tests # unit tests tests/e2e.sh # drives the built program through every command group ``` `tests/e2e.sh` needs cmake, a compiler and git, and no network: it builds its own SDK source, tool and releases in a temporary directory. Layout: `source/CLIForge` (the command line library), `source/BreezeCore` (everything the commands do; unit tested), `source/Breeze` (the `breeze` executable: command registration only), `source/tests/CoreTests`. nlohmann/json is used for the files the CLI keeps: an installed 3.11 or newer is found, else the release is fetched (pinned by hash) when you configure. ## Notes on CLIForge CLIForge is used as it came, with these changes to `source/CLIForge`, to be taken back into the library: * `CliError::kind()` returned `kind()` (endless recursion); it now returns `m_kind`. * `#pragma once` removed from the four `.cpp` files (a compiler warning each). Things to know when writing commands with it: an action's return value is ignored (so `Commands.cpp` leaves exit codes in `breeze::cli::exitCode()` for `main()`); an exception that is not a `CliError` leaves `Engine::run`; a token starting with `-` is always read as an option (which is why `main()` rewrites the values of `--cargs`, `--bargs` and `-x` to the `--cargs=-DX=1` form, see `breeze/Arguments.hpp`); parameters are required, so `run [id]` is two commands. ## Status Built and tested on Linux with gcc and clang (x64) and gcc for arm64 (run under qemu): the unit tests and the 94 checks of `tests/e2e.sh` pass. Downloading a CLI release over HTTP was tried against a local web server with `curl`; git sources were tried with local repositories only. MinGW compiles the Windows code (process creation, `cmd.exe` scripts, paths) but nothing has been run on Windows, and nothing has been built on macOS.