nishikaze 0.2.0

Zephyr build system companion.
Documentation
# Nishikaze - The West Wind
[![crates.io](https://img.shields.io/crates/v/nishikaze.svg)](https://crates.io/crates/nishikaze)
[![docs.rs](https://img.shields.io/docsrs/nishikaze)](https://docs.rs/nishikaze)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
[![pipeline](https://gitlab.com/byacrates/nishikaze/badges/master/pipeline.svg)](https://gitlab.com/byacrates/nishikaze/-/commits/master)
[![codecov](https://codecov.io/gl/byacrates/nishikaze/graph/badge.svg?token=NB4LAR3GVO)](https://codecov.io/gl/byacrates/nishikaze)


A CLI companion that orchestrates the whole lifecycle of Zephyr-based projects
using a declarative config.

## Index

<!-- toc -->

- [Why?]#why
- [Features]#features
- [Installation]#installation
- [Usage]#usage
- [Kaze config]#kaze-config
  * [File discovery]#file-discovery
  * [Configuration layers and precedence]#configuration-layers-and-precedence
  * [Top-level schema overview]#top-level-schema-overview
  * [Logging]#logging
  * [`[project]`]#project
  * [`[profile.]`]#profile
  * [Profile selection rules]#profile-selection-rules
  * [`[zephyr]`]#zephyr
  * [`[build]`]#build
  * [Build output layout]#build-output-layout
  * [`[project.args]` and per-profile args]#projectargs-and-per-profile-args
  * [Arg merge order]#arg-merge-order
  * [Minimal examples]#minimal-examples
    + [1) Simple project (profile-less)]#1-simple-project-profile-less
    + [2) Project with profiles]#2-project-with-profiles
- [Similar projects]#similar-projects
- [License]#license
- [Contribution]#contribution
- [Development]#development

<!-- tocstop -->

## Why?

Because Zephyr's `west` sucks, that's why. Even though at first glance this meta
tool looks exactly like west, you have the option to configure your project
declaratively. I admit, when building a simple Zephyr app, you can just use pure
CMake + ninja/make and configure everything in CMake. However, when building a
multi-image app using sysbuild (e.g. updatehub OTA + mcuboot + app image) then
you're stuck with passing a mile of args into west as you cannot configure it
declaratively and cannot externally modify mcuboot's CMake config.

## Features

1. Manage the whole lifecycle of a Zephyr app - config, build, flash, sim runs
2. Supports both simple Zephyr apps and multi-image apps with sysbuild
3. Automatic Zephyr workspace detection
4. Declarative config through `kaze.toml` @ project root
5. Automatic project dir navigation (can be run from both project root or build dir)
6. Automatically detects `sysbuild` projects and adjusts the build accordingly
7. Supports multiple build profiles (can build multiple binaries for a specific app, useful for simulations or multiple board targets)

## Installation

Install using cargo:
```bash
cargo install nishikaze
```

## Usage

```bash
Usage: kaze [OPTIONS] <COMMAND>

Commands:
  init      Initializes project with kaze.toml
  boards    Lists available boards
  runners   Lists available runners
  profiles  Lists profiles configured in kaze.toml
  clean     Cleans build dir
  conf      Configure project
  build     Build binary
  run       Run simulation
  flash     Flash binary
  help      Print this message or the help of the given subcommand(s)

Options:
  -c, --clean              Pre-clean the active build dir
  -a, --all                Run command for all configured profiles (overrides --profile/default)
  -p, --profile <PROFILE>  Select project profile defined in kaze.toml
  -b, --board <BOARD>      Zephyr OS board/target
  -r, --runner <RUNNER>    Zephyr OS runner
      --project <PROJECT>  Explicit project root
  -v, --verbose...         Verbosity (repeatable)
  -d, --dry-run            Dry run
  -h, --help               Print help
  -V, --version            Print version
```

Verbosity levels:
- `-v` (1): quiet β€” no kaze logs, no command output
- default / `-vv` (2): normal β€” kaze logs only; command output only on error
- `-vvv`+ (3+): verbose β€” kaze logs + command output always

## Kaze config

> πŸ”” **Note:** Under construction. This doc section contains some features that are not yet implemented.

`kaze.toml` is a declarative config located at the **project root**.

### File discovery

`kaze` locates the project by:
1) if `--project <path>` is given, use it
2) else traverse upward from `cwd` until `kaze.toml` is found
3) if run from a build directory, traverse upward to find the owning project root

### Configuration layers and precedence

Resolved configuration is produced by merging layers in this order:

1) **Defaults**
2) **Project config**: `<project>/kaze.toml`
3) **CLI flags** (`--profile`, `--board`, `--runner`, etc.)

Within the project config:
- global values apply first
- active profile values override global values
- CLI overrides override both

### Top-level schema overview

Recommended top-level tables:

- `[project]` β€” defaults and profile selection
- `[zephyr]` β€” workspace and base paths
- `[build]` β€” build directory rules

### Logging

Kaze emits user-facing logs prefixed with `kaze:` and uses colored logs if colour output is supported by the terminal.

Verbosity levels:
- `-v` (1): quiet β€” no kaze logs, no command output
- default / `-vv` (2): normal β€” kaze logs only; command output only on error
- `-vvv`+ (3+): verbose β€” kaze logs + command output always

Environment variables:
- `KAZE_TESTING=1` suppresses logs (useful for tests).
- `KAZE_LOGS=1` re-enables logs during tests.

### `[project]`

| Key | Type | Default | Summary |
|---|---|---:|---|
| `board` | string | *(none)* | Default Zephyr board |
| `runner` | string | *(none)* | Default Zephyr runner |
| `default_profile` | string | *(none)* | Default profile name |
| `name` | string | *(optional)* | Display name for the project (optional) |

### `[profile.<name>]`

Each profile is a partial override of the global project config.

| Key | Type | Summary |
|---|---|---|
| `board` | string | Profile board |
| `runner` | string | Profile runner |
| `args` | table | Per-phase args for the profile |

Example:
```toml
[profile.sim]
board = "native_sim"

[profile.prod]
board = "nucleo_f767zi"
runner = "openocd"
```

### Profile selection rules

When profiles are defined:
1) if `--all` set β†’ all profiles selected
2) else if `--profile` set β†’ that profile selected
3) else if `default_profile` set β†’ selected
4) else β†’ first profile in config file order (or lexicographic if order isn’t preserved)

When profiles are not defined:
- profile selection is ignored and build is profile-less.

### `[zephyr]`

| Key | Type | Default | Summary |
|---|---|---:|---|
| `workspace` | string | auto-detect | Zephyr workspace root |
| `base` | string | `${zephyr_ws}/zephyr` | Zephyr base directory |

Auto-detection order (when not set):
1) `ZEPHYR_BASE` environment variable
2) find `.west/` by traversing upward; if found, treat its parent as workspace
3) (optional) fallback helpers can be added later

### `[build]`

| Key | Type | Default | Summary |
|---|---|---:|---|
| `root` | string | `"build"` | Root build output directory |
| `layout` | string enum | `"auto"` | Build layout mode: `auto`, `profiles`, `single` |
| `link_compile_commands` | bool | `true` | When profiles enabled, create root `build/compile_commands.json` symlink |

### Build output layout

- Profile-less mode: `./<build.root>/`
- Profiles mode: `./<build.root>/<profile>/`

If profiles mode and `link_compile_commands=true`:
- `./<build.root>/compile_commands.json` is a symlink to the selected default/first profile’s `compile_commands.json`
Linking is skipped when profiles are not configured or when `link_compile_commands=false`.

### `[project.args]` and per-profile args

Args are configurable for phases:

- `conf` (CMake configure)
- `build` (Ninja)
- `flash` (west flash / runner invocation)
- `run` (simulator binary or fallback command)

Value forms:
- string β†’ treated as a single argument string (split behavior is implementation-defined; recommended to use arrays)
- array of strings β†’ preferred, exact args list

Example:
```toml
[project.args]
conf  = ["-DHG_TEST=ON"]
build = ["-j", "0"]
flash = ["--hex-file", "path/to/other.hex"]
run   = ["-flash_mount=seed/sd"]

[profile.sim.args]
run = ["-flash=seed/flash.bin", "-wait_uart"]
```

### Arg merge order

For a given phase:
1) global `[project.args.<phase>]`
2) profile `[profile.<name>.args.<phase>]`
3) CLI passthrough args after `--`

Note: Top-level `[args]` is no longer supported. Move global args under `[project.args]`.

### Minimal examples

#### 1) Simple project (profile-less)
```toml
[project]
board = "nucleo_f767zi"
runner = "openocd"
```

#### 2) Project with profiles
```toml
[project]
runner = "openocd"
default_profile = "sim"

[profile.sim]
board = "native_sim"

[profile.prod]
board = "nucleo_f767zi"
```

## Similar projects
- [Zync]https://gitlab.com/byarocks/zync

## License

This project is licensed under either of:
* Apache License, Version 2.0, ([LICENSE-APACHE] or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT] or http://opensource.org/licenses/MIT)

## Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you shall be dual licensed under the Apache-2.0 and
MIT license, without any additional terms or conditions.

[LICENSE-APACHE]: ./LICENSE-APACHE
[LICENSE-MIT]: ./LICENSE-MIT

## Development

Only requires `just` to bootstrap all tools and configuration.
```bash
cargo install just
just init # setup repo, install hooks and all required tools
```

To run:
```bash
just run
```

To test:
```bash
just test
```

Before committing work:
```bash
just pre-commit
```

To see all available commands:
```bash
just list
```