exec: append custom store

This is primarily for chroot stores. This might not be useful however since chroot store breaks builds.
This commit is contained in:
Ophestra 2025-07-23 12:09:32 +09:00
parent b6961508e8
commit 4d9d4bcef2
Signed by: cat
SSH Key Fingerprint: SHA256:wr6yH7sDDbUFi81k/GsIGwpM3O2QrwqYlLF26CcJa4w
7 changed files with 56 additions and 12 deletions

View File

@ -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)

View File

@ -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))
}

13
exec.go
View File

@ -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,
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
}

View File

@ -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 {

View File

@ -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&parallel-compression=false&region=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 {

View File

@ -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.

View File

@ -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)