diff --git a/.gitignore b/.gitignore index 47c5249..7d63985 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.so *.dylib *.pkg +/nixbuild # Test binary, built with `go test -c` *.test diff --git a/cmd/nixbuild/main.go b/cmd/nixbuild/main.go new file mode 100644 index 0000000..f903f4e --- /dev/null +++ b/cmd/nixbuild/main.go @@ -0,0 +1,93 @@ +package main + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "log" + "os" + "os/signal" + "strings" + "syscall" + + "git.gensokyo.uk/yonah/nixbuild" + "hakurei.app/command" +) + +type commandHandlerError string + +func (c commandHandlerError) Error() string { return string(c) } + +func main() { + var ( + flagNixOS bool + flagVerbose bool + flagJSON bool + ) + c := command.New(os.Stderr, log.Printf, "nixbuild", func(args []string) error { + log.SetFlags(0) + log.SetPrefix("nixbuild: ") + nixbuild.Stdout = os.Stdout + if flagVerbose { + nixbuild.Stderr = os.Stderr + } + return nil + }). + Flag(&flagNixOS, "nixos", command.BoolFlag(false), "Interpret input as NixOS flake installable"). + Flag(&flagVerbose, "v", command.BoolFlag(false), "Connect nix stderr"). + Flag(&flagJSON, "json", command.BoolFlag(false), "Serialise output in JSON when applicable") + + c.Command("instantiated", "Evaluate an installable and output all derivations it instantiated", func(args []string) error { + if len(args) != 1 { + return commandHandlerError("instantiated requires exactly 1 argument") + } + + 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") + } + } + + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer stop() + + if v, err := nixbuild.EvalInstantiated(ctx, installable); err != nil { + return commandHandlerError(fmt.Sprintf("cannot evaluate for instantiated derivations: %v", err)) + } else if flagJSON { + if err = json.NewEncoder(os.Stdout).Encode(v); err != nil { + return commandHandlerError(fmt.Sprintf("cannot serialise JSON: %v", err)) + } + return nil + } else { + for _, drv := range v { + if strings.HasSuffix(drv, ".drv") { + fmt.Println(drv + "^*") + } else { + fmt.Println(drv) + } + } + return nil + } + }) + + c.MustParse(os.Args[1:], func(err error) { + var ce commandHandlerError + if errors.As(err, &ce) { + log.Fatal(ce.Error()) + return + } + log.Fatalf("cannot parse command: %v", err) + }) +} diff --git a/go.mod b/go.mod index 8871f9a..30916db 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module git.gensokyo.uk/yonah/nixbuild go 1.24.4 + +require hakurei.app v0.1.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..d65731b --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +hakurei.app v0.1.1 h1:b1ooWWIdvvBRj0BCOmK2wLfVs3nvYbxEHtQX5DP6bos= +hakurei.app v0.1.1/go.mod h1:bWcF0vCO+ZOtZ2zK7L3e08sNb0kIkv1CBcdWTZtu1Gs=