[M5+] flake codegen + SPEC §7/§10 amendment for per-dep nixpkgs pins
This commit is contained in:
60
SPEC.md
60
SPEC.md
@@ -277,21 +277,34 @@ Stubs in v0.1 — accepted but only print a deprecation-style message: `cargoxx
|
||||
|
||||
## 7. Generated `flake.nix`
|
||||
|
||||
cargoxx generates exactly this template. Fields in `<<...>>` are substituted from the manifest.
|
||||
The shared `nixpkgs` input always tracks `nixos-unstable` and provides the
|
||||
toolchain (clang, cmake, ninja, libc++). Each *pinned* manifest dep
|
||||
(`<pkg>@<concrete-version>`) gets its own additional `nixpkgs_<...>`
|
||||
input pointing at a specific commit; the dep is built from that
|
||||
flake's `pkgs` set instead of the shared one. Wildcard deps stay on
|
||||
the shared `nixpkgs`.
|
||||
|
||||
```nix
|
||||
{
|
||||
description = "<<package.name>>";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/<<resolved-rev>>";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
# one line per pinned dep, in manifest order:
|
||||
nixpkgs_<<sanitized_dep_a>>.url = "github:NixOS/nixpkgs/<<rev_a>>";
|
||||
nixpkgs_<<sanitized_dep_b>>.url = "github:NixOS/nixpkgs/<<rev_b>>";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
outputs = { self, nixpkgs, nixpkgs_<<sanitized_dep_a>>,
|
||||
nixpkgs_<<sanitized_dep_b>>, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
pkgs_nixpkgs_<<sanitized_dep_a>> =
|
||||
import nixpkgs_<<sanitized_dep_a>> { inherit system; };
|
||||
pkgs_nixpkgs_<<sanitized_dep_b>> =
|
||||
import nixpkgs_<<sanitized_dep_b>> { inherit system; };
|
||||
llvmPkgs = pkgs.llvmPackages;
|
||||
in {
|
||||
devShell = llvmPkgs.libcxxStdenv.mkDerivation {
|
||||
@@ -302,6 +315,12 @@ cargoxx generates exactly this template. Fields in `<<...>>` are substituted fro
|
||||
pkgs.cmake
|
||||
pkgs.clang-tools
|
||||
];
|
||||
buildInputs = [
|
||||
# pinned dep: from the per-dep nixpkgs set
|
||||
pkgs_nixpkgs_<<sanitized_dep_a>>.<<dep_a_attr>>
|
||||
# wildcard / unpinned dep: from the shared `pkgs`
|
||||
pkgs.<<dep_c_attr>>
|
||||
];
|
||||
env.NIX_CFLAGS_COMPILE = toString [
|
||||
"-stdlib=libc++"
|
||||
"-Wno-unused-command-line-argument"
|
||||
@@ -316,9 +335,21 @@ cargoxx generates exactly this template. Fields in `<<...>>` are substituted fro
|
||||
}
|
||||
```
|
||||
|
||||
`<<resolved-rev>>` is the Nixpkgs commit hash from `Cargoxx.lock`. The toolchain (`clang_21`, `cmake`, `ninja`) is fixed in v0.1 — Clang because module support is most mature there.
|
||||
`<<sanitized_dep>>` is `<dep-name>_<dep-version>` with every char
|
||||
outside `[a-zA-Z0-9_]` replaced by `_`. The same identifier is reused
|
||||
in three places: the input attribute, the outputs lambda parameter,
|
||||
and the `pkgs_...` `let` binding — keeping it a valid Nix identifier
|
||||
in all three contexts.
|
||||
|
||||
Regeneration is idempotent: cargoxx writes the file only if its content would change. This avoids spurious `flake.lock` updates.
|
||||
`<<rev_a>>` etc. come from `Cargoxx.lock`'s per-dep `nixpkgs_rev`
|
||||
field. Wildcard pins (`pkg = "*"`) leave the field null and emit no
|
||||
extra input.
|
||||
|
||||
The toolchain (`clang_21`, `cmake`, `ninja`) is fixed in v0.1 — Clang
|
||||
because module support is most mature there.
|
||||
|
||||
Regeneration is idempotent: cargoxx writes the file only if its
|
||||
content would change. This avoids spurious `flake.lock` updates.
|
||||
|
||||
---
|
||||
|
||||
@@ -515,17 +546,20 @@ Each successful step writes the result to the user overlay before returning.
|
||||
|
||||
## 10. Version resolution algorithm
|
||||
|
||||
`resolve_version(package, version_spec) -> (version, nixpkgs_rev)`:
|
||||
cargoxx pins **per dep**: each `<pkg>@<concrete-version>` resolves to
|
||||
its own nixpkgs revision and lands as a separate flake input. The
|
||||
shared `nixpkgs` input always tracks `nixos-unstable` and provides
|
||||
the toolchain.
|
||||
|
||||
1. If `Cargoxx.lock` already pins this package and the spec is satisfied, return the lockfile entry.
|
||||
2. Query nixhub.io: `https://www.nixhub.io/packages/<package>?_data=routes%2F_nixhub.packages.%24pkg._index`. Parse JSON for available versions and their commits.
|
||||
3. If nixhub.io is unreachable, fall back to lazamar: `https://lazamar.co.uk/nix-versions/?package=<package>&channel=nixpkgs-unstable`. Parse HTML (well-formed table).
|
||||
4. If both fail, fall back to a local Nixpkgs git clone at `~/.cache/cargoxx/nixpkgs/`. Run `git log --all -S 'version = "<version>"' -- pkgs/`.
|
||||
5. Filter the candidate list by the version spec, choose the highest match, return `(version, rev)`.
|
||||
`resolve_version(package, version) -> nixpkgs_rev`:
|
||||
|
||||
For the *whole-project* resolution (multiple deps), cargoxx picks one revision: the latest revision that contains acceptable versions of every dependency. This is brute-force in v0.1: for each candidate revision (newest first, capped at 50 attempts), check whether all deps resolve. Take the first hit.
|
||||
1. **Primary — devbox API.** `GET https://search.devbox.sh/v1/resolve?name=<package>&version=<version>`. The JSON response contains `commit_hash`. Same Jetify backend that powers nixhub.io, but the API is documented and returns the commit directly. (See `devbox/internal/searcher/client.go`.) 10-second timeout.
|
||||
2. **Fallback — local nixpkgs git clone.** Lazy clone of `https://github.com/NixOS/nixpkgs.git` at `~/.cache/cargoxx/nixpkgs/` (or `$XDG_CACHE_HOME/cargoxx/nixpkgs/`). On a miss, run `git -C <repo> log --all -S 'version = "<version>"' --pretty='%H %ct' -- pkgs/` and pick the youngest matching commit.
|
||||
3. If both fail, return `ResolutionVersionNotFound`.
|
||||
|
||||
If no revision satisfies all constraints simultaneously, fail with a list of conflicting deps. The user resolves manually by relaxing version specs.
|
||||
When `cargoxx add <pkg>@<ver>` succeeds, the rev is written to `Cargoxx.lock` next to the dep entry (`nixpkgs_rev`). `cargoxx build` then merges the lockfile rather than overwriting it — pins survive arbitrary rebuilds. Wildcard pins (`<pkg>` with no `@<ver>`, or `<pkg>@*`) skip resolution entirely; the dep tracks the shared `nixos-unstable` input.
|
||||
|
||||
There is no whole-project rev solver. Two pinned deps may pull from different nixpkgs commits, with the ABI-mismatch risk that implies (different glibc / libc++ majors). cargoxx accepts that trade-off in exchange for fine-grained control; a future `cargoxx update` may surface compatibility warnings.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user