fix(codeaf): build furrow from source and hand it over in CODEAF_FURROW
CI / check (push) Has been cancelled
CI / check (push) Has been cancelled
The package used to fetch the Agent-Field/furrow release asset and stage it for go:embed, which is what `make build` does. Those bytes are a stock glibc build that no Nix phase ever touched, so the copy codeaf writes out to ~/.codeaf/bin/furrow-0.1.0 cannot start here: NixOS answers "Could not start dynamically linked executable" and names stub-ld. Every furrow verb the package offers was dead with it. Staging a rebuilt furrow was not an option. Upstream's fetcher hashes what it stages against internal/furrowbin/pin.json and refuses anything else, and patching the downloaded asset changes its hash. So this stages nothing, and ./furrow.nix builds the pinned version from source instead. The wrapped codeaf passes it through CODEAF_FURROW, which internal/furrow reads before it looks at the embedded copy, so the go binary carries no furrow at all (63 MB, was 67 MB) and nothing unpatched is written to the state root. furrow is Rust, not Go, and rusqlite bundles sqlite, hence the build time. Its test suite wants a filesystem that supports user.* xattrs; the sandbox /tmp is tmpfs and answers EOPNOTSUPP, which takes out the fixture of all 54 cli tests at tests/cli.rs:48 and one lib test with it. The unit tests run, minus that one. Verified with nix build .#codeaf: `codeaf --version` reports 0.7.1, the wrapper sets CODEAF_FURROW to the store furrow, that furrow prints `furrow 0.1.0` against store glibc, and it sits in the codeaf output's references so a gc cannot pull it out from under the wrapper. Not verified on darwin, no builder. Refs nix-overlay-bju
This commit is contained in:
@@ -2,4 +2,8 @@
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
pkgs.callPackage ./package.nix { }
|
||||
pkgs.callPackage ./package.nix {
|
||||
# Not a package of its own: codeaf is the only consumer, and codeaf is the one
|
||||
# that knows which furrow version it pinned. See ./furrow.nix.
|
||||
furrow = pkgs.callPackage ./furrow.nix { };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
lib,
|
||||
rustPlatform,
|
||||
fetchFromGitHub,
|
||||
}:
|
||||
|
||||
# furrow is the copy-on-write workspace snapper codeaf drives. codeaf ships a
|
||||
# copy of it inside the go binary: the release asset from GitHub, glibc-dynamic
|
||||
# and untouched by anything in this build, so the file codeaf writes out to
|
||||
# ~/.codeaf/bin/furrow-<version> cannot start here — NixOS answers "Could not
|
||||
# start dynamically linked executable" and names stub-ld. Building furrow here
|
||||
# instead gives the same version as an ordinary Nix binary, and codeaf is told
|
||||
# to use it through CODEAF_FURROW, which internal/furrow reads before it ever
|
||||
# looks at the embedded copy. See ./package.nix.
|
||||
#
|
||||
# The version here has to be the one codeaf pinned in
|
||||
# internal/furrowbin/pin.json: the decoders in codeaf were written for that
|
||||
# furrow. Bump the two together.
|
||||
rustPlatform.buildRustPackage rec {
|
||||
pname = "furrow";
|
||||
version = "0.1.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "Agent-Field";
|
||||
repo = "furrow";
|
||||
rev = "v${version}";
|
||||
hash = "sha256-xknfvnBDFxDYeBE1yAjXl1Fx3VDHrNSUhXEWQO3PK6s=";
|
||||
};
|
||||
|
||||
cargoHash = "sha256-FGtrKtWFPcT3R8nF5OQFlmIiKSuZ8aiHfj76bBvga5A=";
|
||||
|
||||
# Only the unit tests run here. Every cli integration test builds a fixture
|
||||
# whose first step is `xattr::set(…, "user.furrow-test", …)`, and the sandbox
|
||||
# /tmp is a tmpfs that answers EOPNOTSUPP for user.* xattrs, so all 54 of them
|
||||
# die in setup — same reason forks_files_links_modes_and_xattrs is skipped, in
|
||||
# the one lib test that touches an xattr. Upstream's CI runs the whole suite on
|
||||
# a filesystem that supports them.
|
||||
cargoTestFlags = [ "--lib" ];
|
||||
checkFlags = [
|
||||
"--skip"
|
||||
"forks_files_links_modes_and_xattrs"
|
||||
];
|
||||
|
||||
meta = with lib; {
|
||||
description = "Local-first working-state snapshots for agentic development";
|
||||
homepage = "https://github.com/Agent-Field/furrow";
|
||||
changelog = "https://github.com/Agent-Field/furrow/releases/tag/v${version}";
|
||||
license = licenses.asl20;
|
||||
# Thirteen source files use std::os::unix with no windows guards, so the
|
||||
# upstream release has no windows asset either.
|
||||
platforms = platforms.unix;
|
||||
mainProgram = "furrow";
|
||||
};
|
||||
}
|
||||
+33
-57
@@ -2,55 +2,24 @@
|
||||
lib,
|
||||
buildGoModule,
|
||||
fetchFromGitHub,
|
||||
fetchurl,
|
||||
stdenv,
|
||||
makeWrapper,
|
||||
furrow,
|
||||
}:
|
||||
|
||||
# Every codeaf ships a furrow inside it: internal/furrowbin embeds a pinned
|
||||
# Agent-Field/furrow release, and `make build` stages it with
|
||||
# `fetch -from <file>` instead of downloading, which is the road this build
|
||||
# takes. The fetcher re-checks the sha256 named in internal/furrowbin/pin.json,
|
||||
# so the hashes below are a second copy of a pin already in the source. Without
|
||||
# a staged furrow codeaf still builds, and looks for the binary on PATH instead.
|
||||
let
|
||||
furrow = (
|
||||
{
|
||||
x86_64-linux = {
|
||||
goos = "linux";
|
||||
goarch = "amd64";
|
||||
source = fetchurl {
|
||||
url = "https://github.com/Agent-Field/furrow/releases/download/v0.1.0/furrow-linux-amd64";
|
||||
hash = "sha256-x/h+3m81Kq0F066kJRfqychmCa3rYlGHKGQRSSZj4rQ=";
|
||||
};
|
||||
};
|
||||
aarch64-linux = {
|
||||
goos = "linux";
|
||||
goarch = "arm64";
|
||||
source = fetchurl {
|
||||
url = "https://github.com/Agent-Field/furrow/releases/download/v0.1.0/furrow-linux-arm64";
|
||||
hash = "sha256-ifE9UG8vf1TSyJIMU7V4TwsBiK5w91jpErcb/v3x0dY=";
|
||||
};
|
||||
};
|
||||
x86_64-darwin = {
|
||||
goos = "darwin";
|
||||
goarch = "amd64";
|
||||
source = fetchurl {
|
||||
url = "https://github.com/Agent-Field/furrow/releases/download/v0.1.0/furrow-darwin-amd64";
|
||||
hash = "sha256-B5mP5JoqoZ9O0IdVud6mWkiwjR/WgLWFKMVbNXnLaFI=";
|
||||
};
|
||||
};
|
||||
aarch64-darwin = {
|
||||
goos = "darwin";
|
||||
goarch = "arm64";
|
||||
source = fetchurl {
|
||||
url = "https://github.com/Agent-Field/furrow/releases/download/v0.1.0/furrow-darwin-arm64";
|
||||
hash = "sha256-EJN1Fmnla1dqK2WPvZxFKcqvNWfqoJyfduDV2wL4+hY=";
|
||||
};
|
||||
};
|
||||
}
|
||||
.${stdenv.hostPlatform.system} or null
|
||||
);
|
||||
in
|
||||
# codeaf carries a furrow inside itself: internal/furrowbin embeds whatever is
|
||||
# staged in internal/furrowbin/cache and, on first use, writes it out to
|
||||
# ~/.codeaf/bin/furrow-<version>. Upstream stages the GitHub release asset there,
|
||||
# whose bytes are someone else's glibc-dynamic build that no Nix phase ever
|
||||
# touched, so the file that lands in the state root cannot start here. Staging a
|
||||
# rebuilt furrow is not an option either: upstream's fetcher re-checks the sha256
|
||||
# named in internal/furrowbin/pin.json and would refuse one. So this build stages
|
||||
# nothing, and hands over ./furrow.nix through CODEAF_FURROW instead, which
|
||||
# internal/furrow reads before it looks at the embedded copy at all. Nothing of
|
||||
# furrow's ends up in the codeaf binary; without that variable codeaf looks for
|
||||
# furrow on PATH, the way a plain `go build` does.
|
||||
#
|
||||
# A codeaf run without this wrapper is not the same program: it has no furrow
|
||||
# unless one is on PATH.
|
||||
buildGoModule rec {
|
||||
pname = "codeaf";
|
||||
version = "0.7.1";
|
||||
@@ -66,6 +35,8 @@ buildGoModule rec {
|
||||
|
||||
env.CGO_ENABLED = 0;
|
||||
|
||||
nativeBuildInputs = [ makeWrapper ];
|
||||
|
||||
# The shipped binary carries the packed manual rather than the raw Markdown.
|
||||
tags = [ "codeaf_packed_manual" ];
|
||||
|
||||
@@ -75,20 +46,22 @@ buildGoModule rec {
|
||||
# and timing assumptions; it is not buildGoModule-shaped.
|
||||
doCheck = false;
|
||||
|
||||
# `make build` runs two host-side steps before compiling. Both are built for
|
||||
# the build machine even when codeaf targets another platform, hence the
|
||||
# unset GOOS/GOARCH; the fetcher is told the target platform by hand. The
|
||||
# vendoring derivation runs preBuild too, before vendor/ exists, and these two
|
||||
# need the vendored dependencies, so they wait for it.
|
||||
# `make build` runs a host-side step before compiling: packing the manual into
|
||||
# what the codeaf_packed_manual tag embeds. It is built for the build machine
|
||||
# even when codeaf targets another platform, hence the unset GOOS/GOARCH. The
|
||||
# vendoring derivation runs preBuild too, before vendor/ exists, and this step
|
||||
# needs the vendored dependencies, so it waits for it. Upstream's other step,
|
||||
# staging the furrow release, is deliberately not run: see ./furrow.nix.
|
||||
preBuild = ''
|
||||
if [ -d vendor ]; then
|
||||
env -u GOOS -u GOARCH go generate ./internal/manual
|
||||
${lib.optionalString (furrow != null)
|
||||
"env -u GOOS -u GOARCH go run ./internal/furrowbin/cmd/fetch -goos=${furrow.goos} -goarch=${furrow.goarch} -from ${furrow.source}"
|
||||
}
|
||||
fi
|
||||
'';
|
||||
|
||||
postInstall = ''
|
||||
wrapProgram $out/bin/codeaf --set CODEAF_FURROW ${furrow}/bin/furrow
|
||||
'';
|
||||
|
||||
ldflags = [
|
||||
"-s"
|
||||
"-w"
|
||||
@@ -97,11 +70,14 @@ buildGoModule rec {
|
||||
];
|
||||
|
||||
passthru = {
|
||||
inherit furrow;
|
||||
category = "AI Coding Agents";
|
||||
updateScript = [
|
||||
"nix-update"
|
||||
"--flake"
|
||||
".#codeaf"
|
||||
# furrow.nix is not a flake output, so nix-update never touches it: bump it
|
||||
# by hand alongside the version codeaf pins in internal/furrowbin/pin.json.
|
||||
];
|
||||
};
|
||||
|
||||
@@ -110,8 +86,8 @@ buildGoModule rec {
|
||||
homepage = "https://github.com/Agent-Field/CodeAF";
|
||||
changelog = "https://github.com/Agent-Field/CodeAF/blob/v${version}/CHANGELOG.md";
|
||||
license = licenses.asl20;
|
||||
# Not fromSource all the way down: the binary embeds the prebuilt furrow
|
||||
# release named in internal/furrowbin/pin.json.
|
||||
# Runs the furrow built from source by ./furrow.nix, not the release asset
|
||||
# upstream would have embedded.
|
||||
mainProgram = "codeaf";
|
||||
platforms = platforms.linux ++ platforms.darwin;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user