From d4572eb50f9d7f03fe623d716f74d2692764e195 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Tue, 15 Jul 2025 04:44:55 +0900 Subject: [PATCH] cmd/nixbuild: implement dependency resolver This replaces the bash implementation of this hack. --- cmd/nixbuild/format.go | 36 ++++++++++++++++++++ cmd/nixbuild/main.go | 76 +++++++++++++++++++++++++++--------------- 2 files changed, 86 insertions(+), 26 deletions(-) create mode 100644 cmd/nixbuild/format.go diff --git a/cmd/nixbuild/format.go b/cmd/nixbuild/format.go new file mode 100644 index 0000000..19697f2 --- /dev/null +++ b/cmd/nixbuild/format.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + "os" + "strings" + + "git.gensokyo.uk/yonah/nixbuild" +) + +func formatInstallable(name string, installable *string, flagNixOS bool, args []string) error { + if len(args) != 1 { + return commandHandlerError(name + " requires exactly 1 argument") + } + + *installable = args[0] + if !flagNixOS { + return nil + } + + fields := strings.SplitN(*installable, "#", 2) + switch len(fields) { + case 2: + *installable = nixbuild.NixOSInstallable(fields[0], fields[1]) + return nil + case 1: + hostname, err := os.Hostname() + if err != nil { + return commandHandlerError(fmt.Sprintf("cannot get hostname: %v", err)) + } + *installable = nixbuild.NixOSInstallable(fields[0], hostname) + return nil + default: + return commandHandlerError("unexpected installable") + } +} diff --git a/cmd/nixbuild/main.go b/cmd/nixbuild/main.go index 947f8da..58e0c29 100644 --- a/cmd/nixbuild/main.go +++ b/cmd/nixbuild/main.go @@ -9,7 +9,6 @@ import ( "os" "os/signal" "slices" - "strings" "syscall" "git.gensokyo.uk/yonah/nixbuild" @@ -44,7 +43,7 @@ func main() { c.Command("show", command.UsageInternal, func(args []string) error { if len(args) < 1 { - return commandHandlerError("usage requires at least 1 argument") + return commandHandlerError("show requires at least 1 argument") } if drv, err := nixbuild.DerivationShow(ctx, slices.Values(args)); err != nil { @@ -66,26 +65,57 @@ func main() { return nil }) - c.Command("instantiated", "Evaluate an installable and output all derivations instantiated during evaluation", func(args []string) error { - if len(args) != 1 { - return commandHandlerError("instantiated requires exactly 1 argument") + var ( + resolveFlagOut string + ) + c.Command("resolve", "Resolve possible build-time dependencies", func(args []string) error { + var installable string + if err := formatInstallable("resolve", &installable, flagNixOS, args); err != nil { + return err } - installable := args[0] - if flagNixOS { - fields := strings.SplitN(installable, "#", 2) - switch len(fields) { - case 2: - installable = nixbuild.NixOSInstallable(fields[0], fields[1]) - case 1: - hostname, err := os.Hostname() - if err != nil { - return commandHandlerError(fmt.Sprintf("cannot get hostname: %v", err)) - } - installable = nixbuild.NixOSInstallable(fields[0], hostname) - default: - return commandHandlerError("unexpected installable") + log.Printf("evaluating %s", installable) + var installables []string + if v, err := nixbuild.EvalInstantiated(ctx, installable); err != nil { + return commandHandlerError(fmt.Sprintf("cannot evaluate for instantiated derivations: %v", err)) + } else { + installables = v + } + + log.Println("building instantiated derivations") + if err := nixbuild.Build(ctx, slices.Values(installables)); err != nil { + return commandHandlerError(fmt.Sprintf("cannot build: %v", err)) + } + + var collective []string + log.Println("collecting store paths") + if derivations, err := nixbuild.DerivationShow(ctx, slices.Values(installables)); err != nil { + return commandHandlerError(fmt.Sprintf("cannot show: %v", err)) + } else { + collective = nixbuild.CollectFromDerivations(derivations) + } + + f, err := os.Create(resolveFlagOut) + if err != nil { + return commandHandlerError(fmt.Sprintf("cannot create store paths file: %v", err)) + } + if flagJSON { + if err = json.NewEncoder(f).Encode(collective); err != nil { + return commandHandlerError(fmt.Sprintf("cannot serialise JSON: %v", err)) } + } else { + if _, err = nixbuild.WriteStdin(f, slices.Values(collective)); err != nil { + return commandHandlerError(fmt.Sprintf("cannot write store path list: %v", err)) + } + } + return nil + }). + Flag(&resolveFlagOut, "o", command.StringFlag("store-paths"), "Path to write collected store paths") + + c.Command("instantiated", "Evaluate an installable and output all derivations instantiated during evaluation", func(args []string) error { + var installable string + if err := formatInstallable("instantiated", &installable, flagNixOS, args); err != nil { + return err } if v, err := nixbuild.EvalInstantiated(ctx, installable); err != nil { @@ -96,13 +126,7 @@ func main() { } return nil } else { - for _, drv := range v { - if strings.HasSuffix(drv, ".drv") { - fmt.Println(drv + "^*") - } else { - fmt.Println(drv) - } - } + _, _ = nixbuild.WriteStdin(os.Stdout, slices.Values(v)) return nil } })