diff --git a/bob/bobfile/bobfile.go b/bob/bobfile/bobfile.go index b6454621..d4e0a000 100644 --- a/bob/bobfile/bobfile.go +++ b/bob/bobfile/bobfile.go @@ -65,8 +65,14 @@ type Bobfile struct { // RTasks run tasks RTasks bobrun.RunMap `yaml:"run"` + // Dependencies are nix packages used on a global scope. + // Mutually exclusive with Shell. ??Overwrites task based dependencies.?? Dependencies []string `yaml:"dependencies"` + // Shell specifies a shell.nix file as usually used by nix-shell. + // This is mutualy exclusive with Dependencies. + Shell string `yaml:"shell"` + // Nixpkgs specifies an optional nixpkgs source. Nixpkgs string `yaml:"nixpkgs"` diff --git a/bob/build.go b/bob/build.go index 54089abd..fffa75d5 100644 --- a/bob/build.go +++ b/bob/build.go @@ -48,7 +48,7 @@ func (b *B) Build(ctx context.Context, taskName string) (err error) { } // AggregateWithNixDeps does aggregation together with evaluating nix dependecies. -// Nic dependencies are altering a tasks input hash. +// Nix dependencies are altering a tasks input hash. // Use this function for building `bob inspect` cmds. func (b *B) AggregateWithNixDeps(taskName string) (aggregate *bobfile.Bobfile, err error) { defer errz.Recover(&err) diff --git a/bob/nix-builder/nix_builder.go b/bob/nix-builder/nix_builder.go index 1ce21ddc..3f52222b 100644 --- a/bob/nix-builder/nix_builder.go +++ b/bob/nix-builder/nix_builder.go @@ -2,8 +2,11 @@ package nixbuilder import ( "fmt" + "os" + "github.com/benchkram/bob/pkg/boblog" "github.com/benchkram/bob/pkg/envutil" + "github.com/benchkram/bob/pkg/file" "github.com/benchkram/errz" "github.com/benchkram/bob/bob/bobfile" @@ -88,6 +91,28 @@ func (n *NB) BuildNixDependencies(ag *bobfile.Bobfile, buildTasksInPipeline, run return usererror.Wrap(fmt.Errorf("nix is not installed on your system. Get it from %s", nix.DownloadURl())) } + if ag.Shell != "" { + boblog.Log.Info(fmt.Sprintf("using shell file %s, ignoring dependencies", ag.Shell)) + // hash shell file + if !file.Exists(ag.Shell) { + return usererror.Wrap(fmt.Errorf("shell file %s does not exist", ag.Shell)) + } + + nixShellEnv, err := nix.NixShell(ag.Shell) + errz.Fatal(err) + + f, err := os.ReadFile(ag.Shell) + errz.Fatal(err) + hash := envutil.Hash(string(f)) + n.envStore[envutil.Hash(hash)] = nixShellEnv + for _, name := range buildTasksInPipeline { + t := ag.BTasks[name] + t.SetEnvID(envutil.Hash(hash)) + ag.BTasks[name] = t + } + return nil + } + // Resolve nix storePaths from dependencies // and rewrite the affected tasks. for _, name := range buildTasksInPipeline { @@ -153,7 +178,6 @@ func (n *NB) BuildEnvironment(deps []nix.Dependency, nixpkgs string) (_ []string return nix.BuildEnvironment(deps, nixpkgs, n.cache, n.shellCache) } -// Clean removes all cached nix dependencies func (n *NB) Clean() (err error) { return n.cache.Clean() } diff --git a/pkg/nix/nix.go b/pkg/nix/nix.go index 34c260e6..6565a852 100644 --- a/pkg/nix/nix.go +++ b/pkg/nix/nix.go @@ -336,3 +336,43 @@ func HashDependencies(deps []Dependency) (_ string, err error) { } return string(h.Sum()), nil } + +// NixShell returns the environment of a nix-shell command +func NixShell(path string) ([]string, error) { + + args := []string{} + for _, envKey := range global.EnvWhitelist { + if _, exists := os.LookupEnv(envKey); exists { + args = append(args, []string{"--keep", envKey}...) + } + } + args = append(args, []string{"--pure", "--command", "env"}...) + args = append(args, path) + cmd := exec.Command("nix-shell", args...) + + var out bytes.Buffer + var errBuf bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = &errBuf + + env := strings.Split(out.String(), "\n") + err := cmd.Run() + if err != nil { + return nil, prepareRunError(err, cmd.String(), errBuf) + } + + // if NIX_SSL_CERT_FILE && SSL_CERT_FILE are set to /no-cert-file.crt unset them + var clearedEnv []string + for _, e := range env { + pair := strings.SplitN(e, "=", 2) + if pair[0] == "NIX_SSL_CERT_FILE" && pair[1] == "/no-cert-file.crt" { + continue + } + if pair[0] == "SSL_CERT_FILE" && pair[1] == "/no-cert-file.crt" { + continue + } + clearedEnv = append(clearedEnv, e) + } + + return clearedEnv, nil +}