From eb471ed99efce61d217ea40d9579c4562e2c1181 Mon Sep 17 00:00:00 2001 From: Lucas Date: Mon, 2 Feb 2026 15:17:54 +0100 Subject: [PATCH 1/2] fix: new derivation output in nix 2.33 --- internal/executor/nix_flake.go | 5 +++++ internal/executor/utils.go | 12 +++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/internal/executor/nix_flake.go b/internal/executor/nix_flake.go index 782a36a..01a5e35 100644 --- a/internal/executor/nix_flake.go +++ b/internal/executor/nix_flake.go @@ -75,6 +75,11 @@ type Derivation struct { Outputs Output `json:"outputs"` } +type DerivationOutput struct { + Version int `json:"version"` + Derivations map[string]Derivation `json:"derivations"` +} + type Show struct { NixosConfigurations map[string]struct{} `json:"nixosConfigurations"` DarwinConfigurations map[string]struct{} `json:"darwinConfigurations"` diff --git a/internal/executor/utils.go b/internal/executor/utils.go index 3d060db..b003b94 100644 --- a/internal/executor/utils.go +++ b/internal/executor/utils.go @@ -131,10 +131,16 @@ func showDerivationWithFlake(ctx context.Context, flakeUrl, hostname, systemAttr } var output map[string]Derivation - err = json.Unmarshal(stdout.Bytes(), &output) - if err != nil { - return + var wrapper DerivationOutput + if err := json.Unmarshal(stdout.Bytes(), &wrapper); err == nil && wrapper.Derivations != nil { + output = wrapper.Derivations + } else { + // fallback to legacy format (Nix < 2.33) + if err := json.Unmarshal(stdout.Bytes(), &output); err != nil { + return "", "", fmt.Errorf("failed to unmarshal JSON in both formats: %w", err) + } } + keys := make([]string, 0, len(output)) for key := range output { keys = append(keys, key) From 31a44814424b0128aaebfc540da402f1a5aacdc0 Mon Sep 17 00:00:00 2001 From: Antoine Eiche Date: Thu, 5 Feb 2026 07:40:01 +0100 Subject: [PATCH 2/2] Add a derivation format test --- internal/executor/utils.go | 38 ++++++++++-------- internal/executor/utils_test.go | 71 +++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 17 deletions(-) diff --git a/internal/executor/utils.go b/internal/executor/utils.go index b003b94..993bcc3 100644 --- a/internal/executor/utils.go +++ b/internal/executor/utils.go @@ -115,28 +115,15 @@ func showDerivationWithNix(ctx context.Context, directory, systemAttr string) (d return } -func showDerivationWithFlake(ctx context.Context, flakeUrl, hostname, systemAttr string) (drvPath string, outPath string, err error) { - installable := fmt.Sprintf("%s#%s.\"%s\".config.system.build.toplevel", flakeUrl, systemAttr, hostname) - args := []string{ - "derivation", - "show", - installable, - "-L", - "--show-trace", - } - var stdout bytes.Buffer - err = runNixFlakeCommand(ctx, args, &stdout, os.Stderr) - if err != nil { - return - } - +func parseDerivationWithFlake(buf bytes.Buffer) (drvPath string, outPath string, err error) { var output map[string]Derivation var wrapper DerivationOutput - if err := json.Unmarshal(stdout.Bytes(), &wrapper); err == nil && wrapper.Derivations != nil { + if err := json.Unmarshal(buf.Bytes(), &wrapper); err == nil && wrapper.Derivations != nil { output = wrapper.Derivations } else { // fallback to legacy format (Nix < 2.33) - if err := json.Unmarshal(stdout.Bytes(), &output); err != nil { + // TODO: we should use the derivation format version + if err := json.Unmarshal(buf.Bytes(), &output); err != nil { return "", "", fmt.Errorf("failed to unmarshal JSON in both formats: %w", err) } } @@ -162,6 +149,23 @@ func showDerivationWithFlake(ctx context.Context, flakeUrl, hostname, systemAttr return } +func showDerivationWithFlake(ctx context.Context, flakeUrl, hostname, systemAttr string) (drvPath string, outPath string, err error) { + installable := fmt.Sprintf("%s#%s.\"%s\".config.system.build.toplevel", flakeUrl, systemAttr, hostname) + args := []string{ + "derivation", + "show", + installable, + "-L", + "--show-trace", + } + var stdout bytes.Buffer + err = runNixFlakeCommand(ctx, args, &stdout, os.Stderr) + if err != nil { + return + } + return parseDerivationWithFlake(stdout) +} + func buildWithFlake(ctx context.Context, drvPath string) (err error) { args := []string{ "build", diff --git a/internal/executor/utils_test.go b/internal/executor/utils_test.go index 40114f4..0ba8820 100644 --- a/internal/executor/utils_test.go +++ b/internal/executor/utils_test.go @@ -1,12 +1,83 @@ package executor import ( + "bytes" "context" "testing" "github.com/stretchr/testify/assert" ) +const drv_nix_2_33 string = `{ + "derivations": { + "6bidfy5ckghrp1mra47i1b9j5whld606-nixos-system-bucatini-26.05.20260121.88d3861.drv": { + "args": [], + "builder": "/nix/store/lw117lsr8d585xs63kx5k233impyrq7q-bash-5.3p3/bin/bash", + "env": {}, + "inputs": { + "drvs": { + "37j2jc708n38xfvhx1wffm0pbrixnnr3-initrd-linux-hardened-6.12.66.drv": { + "dynamicOutputs": {}, + "outputs": ["out"] + } + }, + "srcs": [ + "l622p70vy8k5sh7y5wizi5f2mic6ynpg-source-stdenv.sh" + ] + }, + "name": "nixos-system-bucatini-26.05.20260121.88d3861", + "outputs": { + "out": { + "path": "ysdrf7krk4q64sgd1q7z3b42l3plpgw8-nixos-system-bucatini-26.05.20260121.88d3861" + } + }, + "system": "x86_64-linux", + "version": 4 + } + }, + "version": 4 +} +` + +const drv_nix_2_31 string = `{ + "/nix/store/plbm2vvs61q9868g8wh3m191dslvpgwi-nixos-system-tilia-25.11.20260122.078d69f.drv": { + "args": [], + "builder": "/nix/store/j8645yndikbrvn292zgvyv64xrrmwdcb-bash-5.3p3/bin/bash", + "env": {}, + "inputDrvs": { + "/nix/store/05hi8vkdi5d9q4rdgpnnimp3x5s3ja50-make-shell-wrapper-hook.drv": { + "dynamicOutputs": {}, + "outputs": [ + "out" + ] + } + }, + "inputSrcs": [], + "name": "nixos-system-tilia-25.11.20260122.078d69f", + "outputs": { + "out": { + "path": "/nix/store/wc14lijvyzacwf6by6dfj4hq1qx8s745-nixos-system-tilia-25.11.20260122.078d69f" + } + }, + "system": "x86_64-linux" + } +} +` + +func TestParseDerivationWithFlake(t *testing.T) { + var buf = bytes.NewBufferString(drv_nix_2_33) + drvPath, outPath, err := parseDerivationWithFlake(*buf) + assert.Equal(t, "/nix/store/6bidfy5ckghrp1mra47i1b9j5whld606-nixos-system-bucatini-26.05.20260121.88d3861.drv", drvPath) + assert.Equal(t, "/nix/store/ysdrf7krk4q64sgd1q7z3b42l3plpgw8-nixos-system-bucatini-26.05.20260121.88d3861", outPath) + assert.Nil(t, err) + + buf = bytes.NewBufferString(drv_nix_2_31) + drvPath, outPath, err = parseDerivationWithFlake(*buf) + assert.Equal(t, "/nix/store/plbm2vvs61q9868g8wh3m191dslvpgwi-nixos-system-tilia-25.11.20260122.078d69f.drv", drvPath) + assert.Equal(t, "/nix/store/wc14lijvyzacwf6by6dfj4hq1qx8s745-nixos-system-tilia-25.11.20260122.078d69f", outPath) + assert.Nil(t, err) +} + func TestGetExpectedMachineId(t *testing.T) { tests := []struct { name string