This is primarily for chroot stores. This might not be useful however since chroot store breaks builds.
87 lines
1.9 KiB
Go
87 lines
1.9 KiB
Go
package nix
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"iter"
|
|
"os"
|
|
"os/exec"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
defaultWaitDelay = 30 * time.Second
|
|
)
|
|
|
|
// Nix is the name of the nix program.
|
|
var Nix = "nix"
|
|
|
|
type nix struct {
|
|
name string
|
|
store Store
|
|
ctx context.Context
|
|
extra []string
|
|
|
|
stdout, stderr io.Writer
|
|
}
|
|
|
|
func (n *nix) Unwrap() context.Context { return n.ctx }
|
|
func (n *nix) Streams() (stdout, stderr io.Writer) { return n.stdout, n.stderr }
|
|
|
|
const (
|
|
ExtraExperimentalFeatures = "--extra-experimental-features"
|
|
ExperimentalFeaturesFlakes = "nix-command flakes"
|
|
)
|
|
|
|
/*
|
|
New returns a new [Context].
|
|
|
|
A non-nil stderr implies verbose.
|
|
|
|
Streams will not be connected for commands outputting JSON.
|
|
*/
|
|
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, extra...),
|
|
|
|
stdout: stdout,
|
|
stderr: stderr,
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
func (n *nix) WriteStdin(cmd *exec.Cmd, installables iter.Seq[string], f func() error) (int, error) {
|
|
w, err := cmd.StdinPipe()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if err = cmd.Start(); err != nil {
|
|
return 0, err
|
|
}
|
|
count, writeErr := WriteStdin(w, installables)
|
|
closeErr := w.Close()
|
|
var fErr error
|
|
if f != nil && writeErr == nil && closeErr == nil {
|
|
fErr = f()
|
|
}
|
|
return count, errors.Join(writeErr, closeErr, fErr, cmd.Wait())
|
|
}
|