cmd/nixbuild: implement cache command

The tool this entire library is created for.
This commit is contained in:
Ophestra 2025-07-20 01:33:10 +09:00
parent 149b9c6a2a
commit 270298c73d
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
3 changed files with 122 additions and 26 deletions

View File

@ -5,7 +5,7 @@ import (
"os"
"strings"
"git.gensokyo.uk/yonah/nixbuild"
"gensokyo.uk/nix"
)
func formatInstallable(name string, installable *string, flagNixOS bool, args []string) error {
@ -21,16 +21,32 @@ func formatInstallable(name string, installable *string, flagNixOS bool, args []
fields := strings.SplitN(*installable, "#", 2)
switch len(fields) {
case 2:
*installable = nixbuild.NixOSInstallable(fields[0], fields[1])
*installable = nix.InstallableNixOS(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)
*installable = nix.InstallableNixOS(fields[0], hostname)
return nil
default:
return commandHandlerError("unexpected installable")
}
}
func replaceFromEnviron(v map[string]*string) error {
for key, p := range v {
if *p != "env" {
continue
}
if s, ok := os.LookupEnv(key); !ok {
return commandHandlerError(key + " not set")
} else {
*p = s
}
}
return nil
}

View File

@ -47,6 +47,68 @@ func main() {
Flag(&flagVerbose, "v", command.BoolFlag(false), "Connect nix stderr").
Flag(&flagJSON, "json", command.BoolFlag(false), "Serialise output in JSON when applicable")
// this is most likely what you are here for
var (
flagCacheKeyPath string
flagCacheComp string
flagCachePComp bool
flagCacheBucket string
flagCacheEndpoint string
flagCacheRegion string
flagCacheScheme string
flagCacheCredPath string
)
c.NewCommand("cache", "Build an installable and upload it to a binary cache", func(args []string) error {
if err := replaceFromEnviron(map[string]*string{
"NIX_TOOL_CACHE_KEY": &flagCacheKeyPath,
"NIX_TOOL_CACHE_COMPRESSION": &flagCacheComp,
"NIX_TOOL_CACHE_BUCKET": &flagCacheBucket,
"NIX_TOOL_CACHE_ENDPOINT": &flagCacheEndpoint,
"NIX_TOOL_CACHE_REGION": &flagCacheRegion,
"NIX_TOOL_CACHE_SCHEME": &flagCacheScheme,
"NIX_TOOL_CACHE_CRED": &flagCacheCredPath,
}); err != nil {
return err
}
var (
installable string
collective []string
)
if err := buildAndResolve(ctx, "cache", &installable, &collective, flagNixOS, args); err != nil {
return err
}
log.Println("signing collected paths")
if err := nix.Sign(ctx, flagCacheKeyPath, slices.Values(collective)); err != nil {
return commandHandlerError(fmt.Sprintf("cannot sign: %v", err))
}
log.Println("copying to binary cache")
if err := nix.Copy(ctx, flagCacheKeyPath, &nix.BinaryCache{
Compression: flagCacheComp,
ParallelCompression: flagCachePComp,
Bucket: flagCacheBucket,
Endpoint: flagCacheEndpoint,
Region: flagCacheRegion,
Scheme: flagCacheScheme,
CredentialsPath: flagCacheCredPath,
}, slices.Values(collective)); err != nil {
return commandHandlerError(fmt.Sprintf("cannot copy: %v", err))
}
return nil
}).
Flag(&flagCacheKeyPath, "secret-key", command.StringFlag("env"), "Path to the secret key used to sign the binary cache").
Flag(&flagCacheComp, "compression", command.StringFlag("zstd"), "Name of the compression algorithm to use").
Flag(&flagCachePComp, "parallel-compression", command.BoolFlag(true), "Whether parallel compression is enabled").
Flag(&flagCacheBucket, "bucket", command.StringFlag("env"), "S3 bucket name").
Flag(&flagCacheEndpoint, "endpoint", command.StringFlag("env"), "S3 endpoint").
Flag(&flagCacheRegion, "region", command.StringFlag("env"), "S3 region").
Flag(&flagCacheScheme, "scheme", command.StringFlag("https"), "S3 scheme").
Flag(&flagCacheCredPath, "credentials-path", command.StringFlag("env"), "Path to the s3 shared credentials file")
c.Command("show", command.UsageInternal, func(args []string) error {
if len(args) < 1 {
return commandHandlerError("show requires at least 1 argument")
@ -90,32 +152,14 @@ func main() {
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 {
var (
installable string
collective []string
)
if err := buildAndResolve(ctx, "resolve", &installable, &collective, flagNixOS, args); err != nil {
return err
}
log.Printf("evaluating %s", installable)
var installables []string
if v, err := nix.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 := nix.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 := nix.DerivationShow(ctx, slices.Values(installables)); err != nil {
return commandHandlerError(fmt.Sprintf("cannot show: %v", err))
} else {
collective = nix.CollectFromDerivations(derivations)
}
f, err := os.Create(resolveFlagOut)
if err != nil {
return commandHandlerError(fmt.Sprintf("cannot create store paths file: %v", err))

36
cmd/nixbuild/resolve.go Normal file
View File

@ -0,0 +1,36 @@
package main
import (
"fmt"
"log"
"slices"
"gensokyo.uk/nix"
)
func buildAndResolve(ctx nix.Context, name string, installable *string, collective *[]string, flagNixOS bool, args []string) error {
if err := formatInstallable(name, installable, flagNixOS, args); err != nil {
return err
}
log.Printf("evaluating %s", *installable)
var installables []string
if v, err := nix.EvalInstantiated(ctx, *installable); err != nil {
return commandHandlerError(fmt.Sprintf("cannot evaluate: %v", err))
} else {
installables = v
}
log.Println("building instantiated derivations")
if err := nix.Build(ctx, slices.Values(installables)); err != nil {
return commandHandlerError(fmt.Sprintf("cannot build: %v", err))
}
log.Println("collecting store paths")
if derivations, err := nix.DerivationShow(ctx, slices.Values(installables)); err != nil {
return commandHandlerError(fmt.Sprintf("cannot get derivations: %v", err))
} else {
*collective = nix.CollectFromDerivations(derivations)
return nil
}
}