diff --git a/build_test.go b/build_test.go index 0342a7f..719317a 100644 --- a/build_test.go +++ b/build_test.go @@ -85,7 +85,7 @@ func TestBuildBadCommand(t *testing.T) { wantErr := os.ErrNotExist breakNixCommand(t) if err := nix.Build( - nix.New(t.Context(), nil, nil, nil), + nix.New(t.Context(), nil, nil, nil, nil), nil, ); !errors.Is(err, wantErr) { t.Errorf("Build: error = %v, want %v", err, wantErr) diff --git a/cmd/nix-tool/main.go b/cmd/nix-tool/main.go index 1e2ca7e..8141178 100644 --- a/cmd/nix-tool/main.go +++ b/cmd/nix-tool/main.go @@ -45,11 +45,14 @@ func main() { } } - var extraArgs []string + var ( + store nix.Store + extraArgs []string + ) flagStore = strings.TrimSpace(flagStore) if flagStore != string(os.PathSeparator) { + store = nix.Local(flagStore) extraArgs = append(extraArgs, - "--store", flagStore, // do not use any binary cache nix.FlagOption, nix.OptionBuildUseSubstitutes, nix.ValueFalse, nix.FlagOption, nix.OptionSubstituters, "", @@ -62,7 +65,7 @@ func main() { if flagVerbose { stderr = os.Stderr } - ctx = nix.New(nixCtx, extraArgs, os.Stdout, stderr) + ctx = nix.New(nixCtx, store, extraArgs, os.Stdout, stderr) return nil }). @@ -111,7 +114,7 @@ func main() { } log.Println("copying to binary cache...") - if err := nix.Copy(ctx, flagCacheKeyPath, &nix.BinaryCache{ + if err := nix.Copy(ctx, &nix.BinaryCache{ Compression: flagCacheComp, ParallelCompression: flagCachePComp, Bucket: flagCacheBucket, @@ -119,6 +122,7 @@ func main() { Region: flagCacheRegion, Scheme: flagCacheScheme, CredentialsPath: flagCacheCredPath, + KeyPath: flagCacheKeyPath, }, slices.Values(collective)); err != nil { return commandHandlerError(fmt.Sprintf("cannot copy: %v", err)) } diff --git a/exec.go b/exec.go index 65b27de..b089737 100644 --- a/exec.go +++ b/exec.go @@ -19,6 +19,7 @@ var Nix = "nix" type nix struct { name string + store Store ctx context.Context extra []string @@ -40,12 +41,17 @@ A non-nil stderr implies verbose. Streams will not be connected for commands outputting JSON. */ -func New(ctx context.Context, extraArgs []string, stdout, stderr io.Writer) Context { +func New(ctx context.Context, store Store, extraArgs []string, stdout, stderr io.Writer) Context { + extra := []string{ExtraExperimentalFeatures, ExperimentalFeaturesFlakes} + if store != nil { + extra = append(extraArgs, FlagStore, store.String()) + } return &nix{ - name: Nix, - ctx: ctx, + name: Nix, + store: store, + ctx: ctx, // since flakes are supposedly experimental - extra: append(extraArgs, ExtraExperimentalFeatures, ExperimentalFeaturesFlakes), + extra: append(extraArgs, extra...), stdout: stdout, stderr: stderr, @@ -56,6 +62,9 @@ func (n *nix) Nix(ctx context.Context, arg ...string) *exec.Cmd { cmd := exec.CommandContext(ctx, n.name, append(n.extra, arg...)...) cmd.Cancel = func() error { return cmd.Process.Signal(os.Interrupt) } cmd.WaitDelay = defaultWaitDelay + if n.store != nil { + cmd.Env = append(cmd.Env, n.store.Environ()...) + } return cmd } diff --git a/exec_stub_test.go b/exec_stub_test.go index 73bea86..bbf552b 100644 --- a/exec_stub_test.go +++ b/exec_stub_test.go @@ -54,7 +54,7 @@ func stubNixCommand(t *testing.T) { // newStubContext creates a context for use with the nix command stub. func newStubContext(ctx context.Context, extraArgs []string, stdout, stderr io.Writer) nix.Context { - return nix.New(ctx, append(stubExtraArgs, extraArgs...), stdout, stderr) + return nix.New(ctx, nil, append(stubExtraArgs, extraArgs...), stdout, stderr) } type stubContextCommand struct { diff --git a/exec_test.go b/exec_test.go index 642bdab..a4ead44 100644 --- a/exec_test.go +++ b/exec_test.go @@ -13,8 +13,36 @@ import ( ) func TestNixWriteStdin(t *testing.T) { + t.Run("store", func(t *testing.T) { + ctx := nix.New(t.Context(), &nix.BinaryCache{ + Compression: "none", + ParallelCompression: false, + Bucket: "example", + Endpoint: "s3.example.org", + Region: "us-east-1", + Scheme: "http", + CredentialsPath: "/dev/null", + KeyPath: nonexistent, + }, nil, nil, nil) + cmd := ctx.Nix(t.Context(), nix.FlagVersion) + + wantArgs := []string{ + nix.Nix, + nix.FlagStore, + "s3://example?compression=none¶llel-compression=false®ion=us-east-1&scheme=http&endpoint=s3.example.org&secret-key=/proc/nonexistent", + nix.FlagVersion} + if !slices.Equal(cmd.Args, wantArgs) { + t.Errorf("Args = %#v, want %#v", cmd.Args, wantArgs) + } + + wantEnv := []string{nix.EnvAwsSharedCredentialsFile + "=/dev/null"} + if !slices.Equal(cmd.Env, wantEnv) { + t.Errorf("Env = %#v, want %#v", cmd.Env, wantEnv) + } + }) + t.Run("already set", func(t *testing.T) { - ctx := nix.New(t.Context(), nil, os.Stdout, os.Stderr) + ctx := nix.New(t.Context(), nil, nil, os.Stdout, os.Stderr) cmd := exec.CommandContext(t.Context(), nonexistent) cmd.Stdin = os.Stdin if _, err := ctx.WriteStdin(cmd, nil, nil); err == nil { diff --git a/format.go b/format.go index a821dff..ac2bfe5 100644 --- a/format.go +++ b/format.go @@ -80,6 +80,9 @@ const ( // FlagVersion show version information. FlagVersion = "--version" + // FlagStore is a loosely documented flag for specifying the store url to operate on. + FlagStore = "--store" + // FlagKeepGoing keep going in case of failed builds, to the greatest extent possible. // That is, if building an input of some derivation fails, Nix will still build the other inputs, // but not the derivation itself. diff --git a/instantiated_test.go b/instantiated_test.go index 1a5c397..f34ac30 100644 --- a/instantiated_test.go +++ b/instantiated_test.go @@ -107,7 +107,7 @@ func TestInstantiatedEvaluatorBadCommand(t *testing.T) { breakNixCommand(t) if _, err := nix.EvalInstantiated( - nix.New(t.Context(), nil, os.Stdout, os.Stderr), + nix.New(t.Context(), nil, nil, os.Stdout, os.Stderr), "", ); !errors.Is(err, wantErr) { t.Errorf("EvalInstantiated: error = %v, want %v", err, wantErr)