komorebi-e2e-macos builds the test window and the agent for macOS in a derivation of its own, on the
dependency artifacts of the macOS build, so that fullBuild (what users get) does not change. The
e2e-macos app, on aarch64-darwin, runs the scenarios of the shared core against the golden Tart image
with this checkout's daemon, as e2e-windows does for Windows: tart comes from nixpkgs, where its
licence makes it unfree, so only it is allowed, here. KOMOREBI_E2E_BINS runs another build, and
KOMOREBI_E2E_TART another tart.
The check that runs the Python of the e2e guests that needs no guest (windows-e2e-tests, on
Linux) now also runs platforms/tart_macos/tests: the ignore rules, which windows count as hidden,
the paths a scenario may ask for, and that every scenario the macOS runner names exists in the core.
Move the macOS agent into komorebi-e2e-agent as macos.rs, answering the protocol of protocol.rs
with its own verbs (os_windows, displays, activate, minimize, close, move; a window is found by
its title), and remove the separate komorebi-macos-e2e crate that had copied the protocol. There
is one binary name and one port on every platform, so the host has one client and one description
of the protocol.
AppKit is for the main thread, so the macOS agent serves one connection at a time on it, where
the Windows one serves each on a thread. A spawned program on macOS gets a standard input that
stays open, as the test window leaves when its input closes. The crate is built for macOS and
Windows now and stubbed on Linux, as komorebi-testwin is.
An AppKit window of a regular application, so that the daemon sees it as it sees any program: the
same options and standard input commands as the Win32 one (title, colour, size, minimum size,
fixed, late rename, fullscreen as a borderless window over its display, report with the frame in
points from the top left of the main display, close, exit). The main thread runs the event loop
in short turns and takes the lines the input thread queued; the program leaves when its window is
closed. A window class has no meaning on macOS, so --class is accepted and ignored.
The macOS source set now builds the crate; Linux still stubs it.
The Windows guest has komorebi-e2e-agent; this is its macOS counterpart, speaking the same
protocol (one JSON line per request, raw bytes after it for put_file and get_file) so that the
host client is the same. Beyond exec, spawn and file transfer it answers with the windows the
accessibility API gives (title, frame, focus, minimized) and the displays with their work areas,
and it can activate, minimize, close and move a window.
It has to be started by a program that holds the Accessibility and Screen Recording grants, so
that the daemon it spawns is attributed to that program.
nix flake check --no-build failed in the nix-eval job on the runner with "path ...-Cargo.lock is not
valid": crane's vendorCargoDeps runs pathExists on the lock at evaluation time, and `repoFile` is a
store path that builtins.path makes during evaluation. Nix 2.35 with an empty store, as on a fresh
runner, does not have it yet under --no-build; Lix, and a store that had seen the file, do.
The parsed lock now comes from the flake source (cargoLockParsed in nix/lib.nix), and the Windows guest
reads tools/test-partition.json the same way. The derivations are unchanged (same drv paths), so no
cache key moves. Reproduced and fixed with upstream Nix and an empty store:
nix shell nixpkgs#nixVersions.latest -c nix flake check --no-build --all-systems --store <empty dir>
devShells.hygiene is the toolchain with the nightly rustfmt, cargo-deny, shellcheck, actionlint, jq,
ripgrep and git, without the Windows SDK, the VM tooling and the rest of the full shell, so that the
first stage sets up in seconds and a local `nix develop .#hygiene` runs what CI runs.
The workspace members, the path dependencies, the include_str! and test
fixture paths, the recorder's indexed source keys, and the Nix source
filter and path literals follow the new layout. Cargo.lock is unchanged.
nix/nixgen has the package and the clippy and nextest checks (in the default check sets), from a
"nixgen" platform of nix/workspace-src.nix that is the tool alone; it is a stub in every other
platform's source, so an edit of it rebuilds none of theirs.
nix/recorder holds the native packages and checks of macOS and Linux (the recorder and the
sources it indexes are the "recorder" platform of nix/workspace-src.nix), the Windows
build has it as one of its members, and the dev shell gets ffmpeg, resvg and GStreamer. The
flake inputs komorebi-mac and komorebi-windows are gone: the sources are in the tree.
The Windows crates' unit tests could only run in the (future) hosted Windows
CI. They run in the existing Windows e2e guest: nix run .#windows-nextest
boots the golden image like a scenario (restoring a saved state when
KOMOREBI_E2E_STATE is set), uploads the test executables that the check
windows-nextest-build cross-compiled, runs every test in a process of its own
(nextest.exe is not needed: komorebi's tests share global state, so one
process per test is what nextest does too) and prints a line per executable
and the failures, with OUT/cargo-tests.json for every result.
The driver e2e/platforms/qemu_windows/cargo_tests.py already existed and was
wired to nothing; it now takes the check output (tests.tsv) as well as cargo
messages, creates the saved state itself, prints the panic message of a
failure, and uploads the data files the tests read. Those are found by the
CARGO_MANIFEST_DIR baked into the executables, a path of the Nix build, so
the check also keeps schemas/ and the tests' fixtures and the driver puts them
at that path under C:. Without them 20 tests failed for the missing files.
docs/dev/build-and-test.md and docs/dev/flake-checks.md describe the check,
the app and the neutral crates in linux-nextest.
Verified: nix run .#windows-nextest on the golden image g8 (scale 1.5, state
~/e2e-w0/state-nextest): 964 tests in 37 executables, 964 passed, 0 failed,
202 s with the state restored (first run 163 s more to save the state).
One run only; not soaked. No e2e scenario, the golden image or the existing
e2e-windows behaviour changed.
The tests of the Windows crates cannot run on a Linux builder, and the old
windows-nextest (crane cargoNextest with doCheck = false) ran none. This
check does the part a builder can do: cross-compile every test executable of
the Windows workspace (cargo test --workspace --release --no-run, target
x86_64-pc-windows-msvc through the xwin toolchain) and keep them with a
tests.tsv that lists them (48 executables), so that they are proved to
compile and link, and so that the next revision can run them in the guest.
The stub members of the Windows source (Linux and macOS packages) are
excluded: objc2 does not build for Windows. The check is in the set
windows-test.
Verified: nix build .#checks.x86_64-linux.windows-nextest-build; the output
holds tests/*.exe and tests.tsv. Not run: the executables (see the next
revision).
linux-nextest ran only the tests of the Linux packages (-p komorebi -p
komorebi-linux ...). The tests of komorebi-layouts, komorebi-scrolling,
komorebi-themes and the shared crates/* (backend, collections, config, core,
protocol, settings, transport, komorebic-core) ran in no nix check. They are
platform neutral, so the check now names them too (explicit -p list: with
--workspace the feature unification of komorebi-daemon breaks windows-future
on Linux), and runs with --no-fail-fast so one run lists every failure.
Two of those tests read files that the Linux source did not have: the
schemas of every platform (komorebi-config schemas test) and the macOS CLI
pages (komorebic-core docs_cli), so nix/workspace-src.nix keeps schemas/ and
docs/macos/cli/ in the Linux source.
Verified: nix build .#checks.x86_64-linux.linux-nextest, 1532 tests run, 1532
passed (9.1 s of test time).
The macos-nextest check was built with doCheck = false like the Windows one, so crane printed
'doCheck is not set, nextest tests will not run' and the check ran no test. It now uses
doCheck = true, as linux-nextest does, so the macOS unit tests run in the nix sandbox of a
darwin machine (the owner asked: can nextest run on a Mac with nix-darwin; if so, keep it).
Verified on the Mac Mini (aarch64-darwin, nix, no komorebi daemon started):
nix build .#checks.aarch64-darwin.macos-nextest exits 0 in about 1 minute with the cached
dependencies; nextest reports 'Summary 383 tests run: 383 passed, 1 skipped'. This is the
komorebi-macos library's tests; the cargo test run of the other packages (753 tests in all) was
done outside nix earlier. Not run: the other macOS checks again after this change (it only
touches this one check's arguments).
docs/dev/flake-checks.md records why the evaluation of the checks needed more than
the host has (about 0.55 GB per VM suite and 0.4 GB per NixOS system of the module
check, nothing shared), the sets and what is in each, how they are exposed
(checkSets, checkMembers, defaultCheckSets in nix/checks.nix), the alternatives
rejected, what was measured with the sets (nix flake check --no-build 4.54 GB / 33 s
on one system, 6.55 GB / 40 s --all-systems; each set alone from 0.2 GB for the cheap
ones to 11.6 GB for linux-nixos-eval), and why windows-nextest and macos-nextest ran
no test.
build-and-test.md gets the commands for one set, the default and one member and
loses windows-nextest; flake.md, docs/linux/CONTRIBUTING.md, docs/linux/dev/vm-tests.md,
the comment of nix/linux/tests/vm/default.nix and the CI step of CUTOVER-PLAN.md name
the new places (checkSets, checkMembers, legacyPackages.<system>.vm.NAME) instead of the
placeholder heavyChecks and checks.<system>.vm-NAME. Not run: the docs build.
overlays.linux and overlays.forVmTests (which applies the first as well) ran
mkPkgs, a new `import nixpkgs` with the rust overlay, and the whole crane
mkKomorebiPackages once for every NixOS system an evaluation instantiated: every
node of every VM suite and every module scenario, twice each. lib.mkPkgs now
hands out one instance per system and the linux module builds the packages of
each Linux system once (buildFor).
The derivations are the same (drvPath of linux-clippy, vm-kwin and linux-run-kde
equal to those before). Measured on a scratch copy of the same change: the
stand-alone expression of 4 suites 2.15 -> 1.50 GB, 8 real suites 5.18 -> 4.79 GB,
linux-nixos-module-eval 10.3 -> 8.5 GB, plasma guests 9.0 -> 8.7 GB. It does not
make the heavy sets cheap: see docs/dev/flake-checks.md.
The Windows crates are built with doCheck = false (individualCrateArgs of
nix/windows/build.nix) and the tests of a Windows program cannot run on a Linux
builder, so crane's cargoNextest derivation only ran `cargo nextest --version`:
a check named nextest that ran nothing. It is removed from the checks (22 names
left on x86_64-linux) and the windows-test set has the e2e Python tests only.
windows-clippy (--all-targets) still compiles the tests; the Windows CI runs
them (`cargo test`, .github/workflows/windows.yaml). The name is dropped from
docs/dev/flake.md and build-and-test.md, with a comment where it was.
macos-nextest has the same shape (doCheck = false in nix/macos/build.nix): it is
left as it is, since the Intel/Apple names stay stable until the Mac run decides.
checks.<system> is now the members of the sets named in one list,
defaultCheckSets in nix/checks.nix (fmt, deny, windows-lint, windows-test,
linux-lint, linux-test, linux-options, macos-lint, macos-test, macos-options),
instead of "every set but the heavy ones", so choosing what `nix flake check`
runs is a one-line edit. The heavy sets (linux-demo, linux-nixos-eval, vm-fast,
vm-slow) stay reachable as `nix build .#checkSets.<set>` and their members as
.#checkMembers.<set>.<name>. Two sets are added to checkSets: cheap (what
checks has, one derivation) and all (every check).
The members of checks are the same as before this revision on every system
(x86_64-linux: 23 names).
Every platform module now defines its checks as allChecks.<name> and the new
nix/checks.nix says which set each is in (fmt, deny, windows-lint, windows-test,
linux-lint, linux-test, linux-options, macos-lint, macos-test, macos-options,
linux-demo, linux-nixos-eval, vm-fast, vm-slow; the vm tiers come from the
suites). A check in no set, or in two, fails the evaluation. checks.<system>
holds the members of the sets that are not heavy, the same split flake-one made
(vm-*, the Plasma guests, the module scenarios and run-kde left out), and the
placeholder legacyPackages.<system>.heavyChecks is gone: every set is one
linkFarm derivation, legacyPackages.<system>.checkSets.<set>, and its members
are legacyPackages.<system>.checkMembers.<set>.<name>. legacyPackages.<system>.vm
is unchanged.
The linux module is mostly reindented (the split wrapper is gone); no check
changed. Verified: see the revision that composes the sets.
treefmt and pre-commit, which the treefmt-nix and git-hooks-nix modules add to checks themselves, are allChecks of nix/common.nix now (those modules' own entries are switched off, treefmt.flakeCheck and pre-commit.check.enable), so that they are members of the set fmt.
One flake.nix and one flake.lock replace the root flake that re-exported two nested flakes.
The inputs are one nixpkgs (the revision the KDE flake was locked to, f05535a0: the VM suites
run against its Plasma and KWin 6.8.2), one crane, rust-overlay (19ecdd08, rustc 1.99.1),
flake-parts, treefmt-nix and git-hooks-nix, all the KDE flake revisions, plus asc. A second
nixpkgs, nixpkgs-x86_64-darwin (16c7794d, the macOS flake pin), serves the x86_64-darwin
outputs only: evaluating that system with the unified pin throws (nixpkgs 26.11 dropped it).
Layout: nix/common.nix (systems, pkgs, treefmt, pre-commit, dev shells default and native,
default overlay), nix/lib.nix, nix/workspace-src.nix (one source per platform from the one Cargo
workspace: the platform members, its files of the shared crates told apart by name, the data
files, and stubs for the other members, which cargo needs), nix/{windows,linux,macos}/
{build,flake-module}.nix. The dependency derivations use a manifests-only dummy source, a plain
path, so crane reads nothing built at evaluation and the Darwin outputs evaluate on Linux.
Names: unprefixed outputs are the native build (Linux: KDE; Darwin: macOS); Windows cross
outputs are windows-*; checks are windows-*, linux-*, macos-* and vm-NAME; table in docs/dev/flake.md
(next revision). One deny.toml, one format-all and one version (workspace) are used by all.
PLACEHOLDER for the agent that owns the check sets: the checks that evaluate a NixOS system
or a VM (vm-*, linux-nixos-module-eval, linux-plasma-guests-eval, linux-run-kde*) are
legacyPackages.<system>.heavyChecks.<name>, not checks, because evaluating them needs more
memory than nix flake check --all-systems can use. The Plasma guests got a stub root file system
and boot loader (mkDefault, replaced by their vmVariant) so that nix flake check can evaluate
their toplevel.
Verified: nix flake check --no-build --all-systems passes (42 s, rc 0); nix flake check
--no-build passes. Not verified: any build (next revisions record them).
The pure moves put the KDE and macOS nix files under nix/linux and nix/macos but left the
relative paths they read: the JSON schema (now schemas/linux and schemas/macos), the example
configurations and key binding samples (docs/linux, docs/macos), the key binding fixtures
(komorebi-hotkeys at the top level), the wsl2 probe script (scripts/linux). Each path now
names the file in the final directory, one more directory up because the files are one level
deeper.
Not touched: flake.nix and the nested flakes (next revisions), which still name the old paths.
Verified: not verified (nothing evaluates until the flake is rewritten; the new flake checks
these paths).
komorebi-for-kde/nix/ -> nix/linux/
komorebi-for-mac/nix/ -> nix/macos/
The nix expressions of the platforms (modules, option files, VM test suites, kwin effects,
the darwin module) sit next to the existing nix/workspace-src.nix. Renames only (252
files); the flakes that import them are replaced by one root flake later in this stack, so
nix does not evaluate at this revision.
The three flakes now build from the one root Cargo workspace (previous revision, which must land with
this one). nix/workspace-src.nix assembles each platform's source: the files it needs (its crates, the
root crates they depend on, the root Cargo.toml and Cargo.lock) plus a stub (the member's own
manifest, an empty lib.rs, a main that does nothing) for every other member, because cargo has to load
the whole workspace but must not depend on the other platforms' code. The KDE and macOS flakes pass
-p <their packages> (cargoExtraArgs), no longer cd into a subdirectory workspace, use the root
Cargo.lock/Cargo.toml (vendored from the filtered source, so crane does not read the stubbed one),
and run cargo deny with --workspace --exclude <the other platforms' packages> and their own
deny.toml; the root flake excludes the KDE and macOS packages from deny and builds default-members.
komorebic/applications.json is added to the macOS source filter (it is embedded by include_str!).
The KDE/macOS deny.toml clarify entries and root deny.toml follow the package renames (squashed into
the rename revisions).
Evaluation (nix eval drvPath, no build): Windows clippy, deny, fmt, nextest, toml-fmt; kfde clippy,
doc, deny, fmt, toml-fmt, nextest, schema-fresh; kfde-komorebi, kfde-komorebic, komorebic. Cache
isolation measured by evaluation: an edit of crates/komorebi-bar-core or komorebi/src changes the
Windows drvs and leaves the kfde clippy and nextest drvs unchanged; an edit of komorebi-for-kde changes
kfde and leaves Windows unchanged; an edit of komorebi-for-mac changes neither. tools/kde-closure-check
ok (rewritten for the merged workspace), root-crates.json unchanged.
KNOWN LIMITS: (1) the stubbed source is a derivation that crane reads at evaluation (readDir in
mkDummySrc), so evaluating or building another system's attributes needs a builder for that system:
`nix flake show --all-systems` and drvPath of aarch64-darwin attributes now fail on a Linux host (the
fast-check nix step evaluates the current system only). (2) cargo deny, fmt and taplo behaviour in the
merged workspace is unverified: not built. (3) the version placeholder warning of crane for the
virtual root manifest (cosmetic).
Needs from the coordinator (idle host, heavy gates): nix build -L .#checks.x86_64-linux.komorebi-workspace-clippy
(the root deps derivation is a new one because of the lock), .#checks.x86_64-linux.komorebi-workspace-deny,
-fmt, -nextest, -toml-fmt; the same for kfde-komorebi-workspace-{clippy,deny,fmt,nextest,toml-fmt,doc},
kfde-schema-fresh, .#packages.x86_64-linux.kfde-komorebic and kfde-komorebi; then one KDE VM fast run
(the KDE package derivation changed); on a Mac or a darwin builder: .#packages.aarch64-darwin.kfm-komorebic,
kfm-komorebi, kfm-komorebi-bar and the kfm checks. Not run by me: any of these.
A flake that builds the recorder for macOS and cross-compiles it for Windows
from a Mac (xwin for the SDK, LLVM for the toolchain), with a dev shell for
each, and `nix flake check` running clippy for both targets, rustfmt, taplo,
cargo-deny and the tests.
The sources of komorebi for Mac and komorebi for Windows are flake inputs,
pinned in `flake.lock`: the recorder indexes them so that a line of komorebi's
log can be traced to the statement that wrote it, and the dev shells and every
derivation export where they are.