feat(go): Add environment configuration for package set sources
Adds environment variables with which users can configure the package set source to use. Not setting a source lets Nix default to a recent NixOS channel (currently nixos-19.03).
This commit is contained in:
parent
2db92243e7
commit
3bc04530a7
1 changed files with 74 additions and 11 deletions
|
@ -46,12 +46,65 @@ import (
|
||||||
"cloud.google.com/go/storage"
|
"cloud.google.com/go/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// pkgSource represents the source from which the Nix package set used
|
||||||
|
// by Nixery is imported. Users configure the source by setting one of
|
||||||
|
// the supported environment variables.
|
||||||
|
type pkgSource struct {
|
||||||
|
srcType string
|
||||||
|
args string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the package source into the representation required by Nix.
|
||||||
|
func (p *pkgSource) renderSource(tag string) string {
|
||||||
|
// The 'git' source requires a tag to be present.
|
||||||
|
if p.srcType == "git" {
|
||||||
|
if tag == "latest" || tag == "" {
|
||||||
|
tag = "master"
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("git!%s!%s", p.args, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s!%s", p.srcType, p.args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve a package source from the environment. If no source is
|
||||||
|
// specified, the Nix code will default to a recent NixOS channel.
|
||||||
|
func pkgSourceFromEnv() *pkgSource {
|
||||||
|
if channel := os.Getenv("NIXERY_CHANNEL"); channel != "" {
|
||||||
|
log.Printf("Using Nix package set from Nix channel %q\n", channel)
|
||||||
|
return &pkgSource{
|
||||||
|
srcType: "nixpkgs",
|
||||||
|
args: channel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if git := os.Getenv("NIXERY_PKGS_REPO"); git != "" {
|
||||||
|
log.Printf("Using Nix package set from git repository at %q\n", git)
|
||||||
|
return &pkgSource{
|
||||||
|
srcType: "git",
|
||||||
|
args: git,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if path := os.Getenv("NIXERY_PKGS_PATH"); path != "" {
|
||||||
|
log.Printf("Using Nix package set from path %q\n", path)
|
||||||
|
return &pkgSource{
|
||||||
|
srcType: "path",
|
||||||
|
args: path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// config holds the Nixery configuration options.
|
// config holds the Nixery configuration options.
|
||||||
type config struct {
|
type config struct {
|
||||||
bucket string // GCS bucket to cache & serve layers
|
bucket string // GCS bucket to cache & serve layers
|
||||||
builder string // Nix derivation for building images
|
builder string // Nix derivation for building images
|
||||||
web string // Static files to serve over HTTP
|
web string // Static files to serve over HTTP
|
||||||
port string // Port on which to launch HTTP server
|
port string // Port on which to launch HTTP server
|
||||||
|
pkgs *pkgSource // Source for Nix package set
|
||||||
}
|
}
|
||||||
|
|
||||||
// ManifestMediaType is the Content-Type used for the manifest itself. This
|
// ManifestMediaType is the Content-Type used for the manifest itself. This
|
||||||
|
@ -67,6 +120,9 @@ type image struct {
|
||||||
// Name of the container image.
|
// Name of the container image.
|
||||||
name string
|
name string
|
||||||
|
|
||||||
|
// Tag requested (only relevant for package sets from git repositories)
|
||||||
|
tag string
|
||||||
|
|
||||||
// Names of packages to include in the image. These must correspond
|
// Names of packages to include in the image. These must correspond
|
||||||
// directly to top-level names of Nix packages in the nixpkgs tree.
|
// directly to top-level names of Nix packages in the nixpkgs tree.
|
||||||
packages []string
|
packages []string
|
||||||
|
@ -94,10 +150,11 @@ type BuildResult struct {
|
||||||
//
|
//
|
||||||
// It will expand convenience names under the hood (see the `convenienceNames`
|
// It will expand convenience names under the hood (see the `convenienceNames`
|
||||||
// function below).
|
// function below).
|
||||||
func imageFromName(name string) image {
|
func imageFromName(name string, tag string) image {
|
||||||
packages := strings.Split(name, "/")
|
packages := strings.Split(name, "/")
|
||||||
return image{
|
return image{
|
||||||
name: name,
|
name: name,
|
||||||
|
tag: tag,
|
||||||
packages: convenienceNames(packages),
|
packages: convenienceNames(packages),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,13 +189,17 @@ func buildImage(ctx *context.Context, cfg *config, image *image, bucket *storage
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command(
|
args := []string{
|
||||||
"nix-build",
|
|
||||||
"--no-out-link",
|
"--no-out-link",
|
||||||
"--show-trace",
|
"--show-trace",
|
||||||
"--argstr", "name", image.name,
|
"--argstr", "name", image.name,
|
||||||
"--argstr", "packages", string(packages), cfg.builder,
|
"--argstr", "packages", string(packages), cfg.builder,
|
||||||
)
|
}
|
||||||
|
|
||||||
|
if cfg.pkgs != nil {
|
||||||
|
args = append(args, "--argstr", "pkgSource", cfg.pkgs.renderSource(image.tag))
|
||||||
|
}
|
||||||
|
cmd := exec.Command("nix-build", args...)
|
||||||
|
|
||||||
outpipe, err := cmd.StdoutPipe()
|
outpipe, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -270,7 +331,7 @@ func prepareBucket(ctx *context.Context, cfg *config) *storage.BucketHandle {
|
||||||
// routes required for serving images, since pushing and other such
|
// routes required for serving images, since pushing and other such
|
||||||
// functionality is not available.
|
// functionality is not available.
|
||||||
var (
|
var (
|
||||||
manifestRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/manifests/(\w+)$`)
|
manifestRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/manifests/([\w|\-|\.|\_]+)$`)
|
||||||
layerRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/blobs/sha256:(\w+)$`)
|
layerRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/blobs/sha256:(\w+)$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -294,8 +355,9 @@ func (h *registryHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
manifestMatches := manifestRegex.FindStringSubmatch(r.RequestURI)
|
manifestMatches := manifestRegex.FindStringSubmatch(r.RequestURI)
|
||||||
if len(manifestMatches) == 3 {
|
if len(manifestMatches) == 3 {
|
||||||
imageName := manifestMatches[1]
|
imageName := manifestMatches[1]
|
||||||
log.Printf("Requesting manifest for image '%s'", imageName)
|
imageTag := manifestMatches[2]
|
||||||
image := imageFromName(manifestMatches[1])
|
log.Printf("Requesting manifest for image %q at tag %q", imageName, imageTag)
|
||||||
|
image := imageFromName(imageName, imageTag)
|
||||||
manifest, err := buildImage(h.ctx, h.cfg, &image, h.bucket)
|
manifest, err := buildImage(h.ctx, h.cfg, &image, h.bucket)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -328,6 +390,7 @@ func main() {
|
||||||
builder: getConfig("NIX_BUILDER", "Nix image builder code"),
|
builder: getConfig("NIX_BUILDER", "Nix image builder code"),
|
||||||
web: getConfig("WEB_DIR", "Static web file dir"),
|
web: getConfig("WEB_DIR", "Static web file dir"),
|
||||||
port: getConfig("PORT", "HTTP port"),
|
port: getConfig("PORT", "HTTP port"),
|
||||||
|
pkgs: pkgSourceFromEnv(),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
Loading…
Reference in a new issue