diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f7171a2..89a425e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,17 +63,20 @@ lock. `std::mutex`, `std::atomic`, `std::condition_variable` — use them correctly or don't use them at all. If you don't know what `memory_order` means, stay out of the scheduler. -### 6. Tests are shell scripts. For now. +### 6. Tests are shell scripts. -Integration tests live in `test.sh` and `test-init-switch.sh`. They -exercise the CLI. If you add a subcommand, add a test. C++ unit tests -are welcome — set up Google Test or Catch2 in CMake and we'll merge it. +Integration tests live in three suites. If you add a subcommand, add a test. ```sh -./test.sh # 31 tests, must pass -./test-init-switch.sh # 23 tests, must pass +./test.sh # 30 tests — DSL parsing, config, services, init systems +./test-init-switch.sh # 23 tests — init-switching, rebuild impact, bootloaders +./test-full.sh # 85 tests — CLI, all keywords, repos, add/remove, + # resolver conflicts, deptrees, build, env ops, + # index generation, --root, imports, doctor, and more ``` +All three must pass. CI enforces this on every push to `main`. + ### 7. Backward compatibility is mandatory The `.kap` DSL is the contract. You can add keywords. You cannot remove @@ -85,29 +88,32 @@ change means someone's `config.kap` stops parsing, it doesn't ship. ### Pick something Good first issues: -- Adding a 6th init system backend -- Adding a 3rd bootloader backend -- C++ unit test framework setup -- Shell completion scripts +- Adding a 6th init system backend (we have 5: systemd, openrc, s6, runit, dinit) +- Adding a 3rd bootloader backend (we have 2: grub, limine) +- Improving the `kappa doctor` diagnostics for package recipes +- Adding `--features` / `--config` flags to `kappa add` +- Shell completion scripts (bash, zsh, fish) Ambitious issues: - Binary package support (pre-built caches) - Remote build farm (distcc-style) -- Signed package verification +- Signed package verification with index signing - Filesystem overlay activation (like Nix profiles) +- Transitive dependency resolution (auto-including deps not in config) ### Send a PR 1. Fork the repo 2. Create a branch: `feat/my-thing` or `fix/my-bug` 3. Write code that follows the rules above -4. Run `./test.sh && ./test-init-switch.sh` — both must pass +4. Run `./test.sh && ./test-init-switch.sh && ./test-full.sh` — all three must pass 5. Open a PR against `main` ### PR requirements -- Build must pass: `cmake --build build` with zero warnings -- Tests must pass: both shell test suites +- Build must pass: `cmake --build build` with zero warnings on Clang 17+ +- Tests must pass: all three shell test suites +- Follow the conventions in [STYLEGUIDE.md](STYLEGUIDE.md) - No commented-out code. No dead code. No TODO without a date. - Commit messages in imperative: `Add runit backend` not `Added runit backend` diff --git a/README.md b/README.md index 6bb2724..614c9a0 100644 --- a/README.md +++ b/README.md @@ -72,16 +72,45 @@ kappa rebuild config.kap # boot.init = "openrc" — only 5 packages actually r simultaneously, eight jobs each. The scheduler uses depth-based priority grouping so leaf dependencies unblock as much work as possible first. -- **Package recipe caching.** Declare `remotes = ["https://repo.example.com/"]` - in your config. Kappa fetches `.kap` files on demand, caches them, and only - re-fetches when the remote version is newer. +- **Package recipe caching with indexed repos.** Declare named repos with + channels and mirrors in your config. Kappa fetches `index.kap` from each + repo, caches it, and only re-fetches when the remote changes. Package recipes + are resolved from the index — fast, offline-tolerant, and mirror-aware. + +```kap +repos { + kappa-os { + url = "https://packages.kappa-os.org/" + channels = ["stable"] + mirrors = [ + "https://cdn.kappa-os.org/", + "https://eu.kappa-os.org/", + ] + } +} +``` + +`remotes = [...]` still works. Repos are tried first, then legacy remotes. - **Source tarball caching.** Downloaded once, stored at `$KAPPA_ROOT/cache/` (default: `/usr/local/kappa/cache/`). Rebuilds don't touch the network unless versions change. +- **Env operators.** Three ways to set build environment variables: + `=` (hard set), `+=` (append with space), `?=` (soft set — only if not + already defined). System-level env propagates to all packages. + +```kap +env { + CFLAGS = "-O2 -march=native" # overwrite + CFLAGS += "-pipe" # append → "-O2 -march=native -pipe" + CFLAGS ?= "-g" # soft — only if not set +} +``` + - **Conflicts.** `systemd` declares `conflicts = ["eudev", "elogind"]`. The - resolver catches mutual incompatibility before a build starts. + resolver catches mutual incompatibility before a build starts — and now + actually reports it, rather than silently ignoring it. - **Init-agnostic system config.** `groups { wheel { gid = 998 } }` — kappa creates the groups. `system { hostname = "mybox" }` — kappa writes @@ -113,41 +142,53 @@ kappa rebuild config.kap # boot.init = "openrc" — only 5 packages actually r cmake -B build -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ cmake --build build -# Write a config -cat > system.kap << 'EOF' -system { hostname = "kappa.local" } -packages { nginx {} } -services { nginx { enable = true } } -boot { - kernel = "linux"; init = "s6"; root = "/dev/sda1"; bootloader = "limine" -} -users { root { shell = "/bin/zsh" } } -remotes = ["https://packages.kappa-os.org/stable/"] -EOF +# Add packages to your system config +build/kappa add make +build/kappa add nginx ">=1.24" +build/kappa add zlib -# Parse it -build/kappa parse-config system.kap +# Rebuild — kappa fetches recipes, resolves deps, builds everything +build/kappa rebuild $KAPPA_ROOT/system/config.kap -# Rebuild -build/kappa rebuild system.kap +# Remove packages +build/kappa remove zlib ``` +No config files to write by hand. `kappa add` writes the `packages {}` block +for you. `kappa rebuild` handles the rest. + ### Subcommands | Command | What it does | |---------|-------------| -| `parse-package ` | Validate a `.kap` package definition | -| `parse-config ` | Validate a system configuration | -| `validate ` | Validate any kappa file | -| `format ` | Pretty-print to canonical style | -| `doctor ` | Check for issues and warnings | -| `resolve ` | Compute a build plan | +| `add [version]` | Add a package to system config | +| `remove ` | Remove a package from system config | +| `build ` | Build a single package from its `.kap` definition | +| `rebuild ` | Diff config against installed state, rebuild changed | +| `resolve ` | Compute a build plan (shows order, deps, conflicts) | +| `doctor ` | Check a file for issues and warnings | | `fetch ` | Download and verify source tarballs | | `fetch-package ` | Fetch a package recipe from remotes | -| `build ` | Build a single package | -| `rebuild ` | Diff config against installed state, rebuild changed | +| `format ` | Pretty-print to canonical style | +| `index ` | Build an `index.kap` from `.kap` files in a directory | | `list` | Show installed packages | +| `parse-config ` | Validate a system configuration | +| `parse-package ` | Validate a `.kap` package definition | | `rollback` | Show available generations | +| `validate ` | Validate any kappa file (package, config, or index) | + +### Repo maintenance + +```sh +# Generate an index from a directory of .kap files +kappa index ./packages/ +# → packages/index.kap + +# Host the directory behind any HTTP server. That's your repo. +``` + +The index is a tiny text file listing every package and version. +Clients fetch it once, cache it, and check for updates via HTTP headers. ### License @@ -156,4 +197,7 @@ BSD 2-Clause. Do whatever you want. Just don't sue us. ### Contributing See [CONTRIBUTING.md](CONTRIBUTING.md). We're opinionated but we merge good -code. +code. See [STYLEGUIDE.md](STYLEGUIDE.md) for code conventions. + +Tests: 138 integration tests across three suites. CI runs on Arch Linux. +Everything passes or nothing merges.