From fdf97861a44a9405cbfe2406f0565182af51a8c4 Mon Sep 17 00:00:00 2001 From: Amadey Vorontsov Date: Sun, 17 May 2026 12:29:30 +0000 Subject: [PATCH] [M7] flake: distribution bundles + non-NixOS wrapper --- CHANGELOG.md | 37 ++++++++++ flake.lock | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++- flake.nix | 74 ++++++++++++++++++- 3 files changed, 311 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6b5e07..a5ad18e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -398,3 +398,40 @@ All notable changes to cargoxx will be documented in this file. - Fix: `-Wparentheses` warning in `looks_like_missing_attribute` (`src/resolver/nixpkgs_probe.cpp:34`) — explicitly parenthesize the `&&` clause inside `||`. +- M7 `cargoxx-bin` wraps the binary with `makeWrapper` to lock its + runtime CLI dependencies — `nix`, `cmake`, `ninja`, `curl`, `git` + — onto `PATH`. Previously cargoxx silently relied on the user's + ambient PATH, so it broke whenever invoked outside a `nix develop` + shell. The wrapped binary works under `env -i` with a minimal PATH. +- M7 the wrapper also `--set-default`s `NIX_CONFIG` to + `experimental-features = nix-command flakes` and + `build-users-group =`. Without this, the bundled `pkgs.nix` + defaults to the multi-user daemon model and fails on non-NixOS + hosts (`error: the group 'nixbld' specified in 'build-users-group' + does not exist`). `--set-default` lets a user with a properly- + configured nix daemon override by exporting `NIX_CONFIG=...` + before invoking cargoxx. Verified end-to-end in `archlinux:latest` + via `docker run`: install the `.pkg.tar.zst`, `cargoxx new demo && + cargoxx add fmt` runs the resolver chain through verify-link + cmake/ninja and writes the dep without error. +- M7 packaging functions exposed as a stable `to*` library and as + ready-to-build flake packages, mirroring the + `github:NixOS/bundlers` naming. Available as both + `packages.` (for `nix build .#`) and + `lib.to` (for downstream flakes to package their own + derivations): + - `toAppImage` / `packages.appimage` — Linux AppImage (~207 MB) + - `toDockerImage` / `packages.dockerImage` — `docker load`-able + tar.gz (~213 MB) + - `toDEB` / `packages.deb` — Debian `.deb` (~211 MB) + - `toRPM` / `packages.rpm` — Red Hat `.rpm` (~212 MB) + - `toArchPkg` / `packages.archpkg` — Arch `.pkg.tar.zst` + (~196 MB), implemented locally because no NixOS bundler exists. + Builds a closure via `pkgs.closureInfo`, lays it under + `/nix/store`, drops a `/usr/bin/` symlink, writes + `.PKGINFO` from `drv.pname`/`drv.version`/`drv.meta`, and packs + with `bsdtar --zstd`. Generic — works for any derivation with + a `bin/` and the usual `pname`/`version` attrs. + Added `inputs.bundlers.url = "github:NixOS/bundlers"` (with + `inputs.nixpkgs.follows = "nixpkgs"`) to keep the closure aligned + with the project's pinned nixpkgs. diff --git a/flake.lock b/flake.lock index ae76b78..e2b7e7c 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,44 @@ { "nodes": { + "bundlers": { + "inputs": { + "nix-appimage": "nix-appimage", + "nix-bundle": "nix-bundle", + "nix-utils": "nix-utils", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1777842037, + "narHash": "sha256-E6kwkFsKnU5k/QAX1aNOPfh69G6Im8/EwdRcZR4J0QE=", + "owner": "NixOS", + "repo": "bundlers", + "rev": "7bb70086c2dad3eecae4805f4d758c80e3cba960", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "bundlers", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1733328505, + "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { "inputs": { "systems": "systems" @@ -18,7 +57,119 @@ "type": "github" } }, + "flake-utils_2": { + "locked": { + "lastModified": 1623875721, + "narHash": "sha256-A8BU7bjS5GirpAUv4QA+QnJ4CceLHkcXdRp4xITDB0s=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "f7e004a55b120c02ecb6219596820fcd32ca8772", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_3": { + "inputs": { + "systems": "systems_3" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nix-appimage": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "nixpkgs": [ + "bundlers", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1757920913, + "narHash": "sha256-jd0QwCVz4O1sHHkeaZILD/7D6oyalceEJ4EFnWCgm0k=", + "owner": "ralismark", + "repo": "nix-appimage", + "rev": "7946addbc0d97e358a6d7aefe5e82310f0fe6b18", + "type": "github" + }, + "original": { + "owner": "ralismark", + "repo": "nix-appimage", + "type": "github" + } + }, + "nix-bundle": { + "inputs": { + "nixpkgs": [ + "bundlers", + "nixpkgs" + ], + "utils": "utils" + }, + "locked": { + "lastModified": 1756736056, + "narHash": "sha256-8YFhvulVX3iS4TYnKisA9zSImJeFN21G75HOUUFjzuE=", + "owner": "nix-community", + "repo": "nix-bundle", + "rev": "eff01593f62794d458ec714090091419194ab64d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-bundle", + "type": "github" + } + }, + "nix-utils": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1744222205, + "narHash": "sha256-di1eNHQdpvvyXv6i7Z+S79KF7cQyhTs7AdFHp7q1e3Q=", + "owner": "juliosueiras-nix", + "repo": "nix-utils", + "rev": "53282197ad090c8cf47c96e99bf6c6c3b2cdc7c0", + "type": "github" + }, + "original": { + "owner": "juliosueiras-nix", + "repo": "nix-utils", + "type": "github" + } + }, "nixpkgs": { + "locked": { + "lastModified": 1629252929, + "narHash": "sha256-Aj20gmGBs8TG7pyaQqgbsqAQ6cB+TVuL18Pk3DPBxcQ=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "3788c68def67ca7949e0864c27638d484389363d", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { "locked": { "lastModified": 1777954456, "narHash": "sha256-hGdgeU2Nk87RAuZyYjyDjFL6LK7dAZN5RE9+hrDTkDU=", @@ -36,8 +187,9 @@ }, "root": { "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" + "bundlers": "bundlers", + "flake-utils": "flake-utils_3", + "nixpkgs": "nixpkgs_2" } }, "systems": { @@ -54,6 +206,54 @@ "repo": "default", "type": "github" } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "utils": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 2551fe1..09ec7a4 100644 --- a/flake.nix +++ b/flake.nix @@ -4,18 +4,39 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; + bundlers.url = "github:NixOS/bundlers"; + bundlers.inputs.nixpkgs.follows = "nixpkgs"; }; - outputs = { self, nixpkgs, flake-utils }: + outputs = { self, nixpkgs, flake-utils, bundlers }: flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs { inherit system; }; + # exec::run shells out to these at runtime; wrap the binary so + # they're reachable even outside a nix develop shell. + cargoxxRuntimePath = pkgs.lib.makeBinPath [ + pkgs.nix + pkgs.cmake + pkgs.ninja + pkgs.curl + pkgs.git + ]; + + # Defaults applied to the bundled `nix` so it works on hosts + # that don't already have nix set up (Arch/Debian/Fedora users + # who install our .pkg.tar.zst / .deb / .rpm). Multi-user mode + # would expect a `nixbld` group and a running daemon + cargoxxNixConfig = '' + experimental-features = nix-command flakes + build-users-group = + ''; + cargoxx-bin = pkgs.gcc15Stdenv.mkDerivation { pname = "cargoxx"; version = "0.1.0"; src = ./.; - nativeBuildInputs = [ pkgs.cmake pkgs.ninja ]; + nativeBuildInputs = [ pkgs.cmake pkgs.ninja pkgs.makeWrapper ]; buildInputs = [ pkgs.sqlite pkgs.reproc pkgs.catch2_3 ]; configurePhase = '' cmake -S build -B build/release -G Ninja \ @@ -27,6 +48,9 @@ installPhase = '' mkdir -p $out/bin cp build/release/cargoxx $out/bin/ + wrapProgram $out/bin/cargoxx \ + --prefix PATH : ${cargoxxRuntimePath} \ + --set-default NIX_CONFIG ${pkgs.lib.escapeShellArg cargoxxNixConfig} ''; hardeningDisable = [ "all" ]; }; @@ -103,8 +127,54 @@ ''; hardeningDisable = [ "all" ]; }; + bundlers-sys = bundlers.bundlers.${system}; + + # Arch's pacman expects a tar.zst archive containing a + # `.PKGINFO` metadata file plus the file tree rooted at /. + # We ship the entire closure under /nix/store; /usr/bin/cargoxx + # is a symlink to the in-store wrapper. + toArchPkg = drv: + let + pname = drv.pname or drv.name; + version = drv.version or "0"; + mainProgram = drv.meta.mainProgram or pname; + in pkgs.runCommand "${pname}-${version}-1-x86_64.pkg.tar.zst" { + nativeBuildInputs = [ pkgs.libarchive pkgs.coreutils ]; + closureInfo = pkgs.closureInfo { rootPaths = [ drv ]; }; + } '' + stage=$(mktemp -d) + mkdir -p $stage/nix/store $stage/usr/bin + for p in $(cat $closureInfo/store-paths); do + cp -a "$p" $stage/nix/store/ + done + ln -s ${drv}/bin/${mainProgram} $stage/usr/bin/${mainProgram} + installed_size=$(du -sk $stage | cut -f1) + cat > $stage/.PKGINFO < drv`. + # Mirror the `to*` naming used by github:NixOS/bundlers. + lib.toAppImage = bundlers-sys.toAppImage; + lib.toDockerImage = bundlers-sys.toDockerImage; + lib.toDEB = bundlers-sys.toDEB; + lib.toRPM = bundlers-sys.toRPM; + lib.toArchPkg = toArchPkg; lib.buildCppPackage = buildCppPackage; devShells.default = pkgs.gcc15Stdenv.mkDerivation { name = "cargoxx-dev";