Skip to content

Commit

Permalink
feat(go): Add environment configuration for package set sources
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
tazjin authored and Vincent Ambo committed Jul 31, 2019
1 parent 271c947 commit 00736ab
Showing 1 changed file with 74 additions and 11 deletions.
85 changes: 74 additions & 11 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,65 @@ import (
"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.
type config struct {
bucket string // GCS bucket to cache & serve layers
builder string // Nix derivation for building images
web string // Static files to serve over HTTP
port string // Port on which to launch HTTP server
bucket string // GCS bucket to cache & serve layers
builder string // Nix derivation for building images
web string // Static files to serve over HTTP
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
Expand All @@ -67,6 +120,9 @@ type image struct {
// Name of the container image.
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
// directly to top-level names of Nix packages in the nixpkgs tree.
packages []string
Expand Down Expand Up @@ -94,10 +150,11 @@ type BuildResult struct {
//
// It will expand convenience names under the hood (see the `convenienceNames`
// function below).
func imageFromName(name string) image {
func imageFromName(name string, tag string) image {
packages := strings.Split(name, "/")
return image{
name: name,
tag: tag,
packages: convenienceNames(packages),
}
}
Expand Down Expand Up @@ -132,13 +189,17 @@ func buildImage(ctx *context.Context, cfg *config, image *image, bucket *storage
return nil, err
}

cmd := exec.Command(
"nix-build",
args := []string{
"--no-out-link",
"--show-trace",
"--argstr", "name", image.name,
"--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()
if err != nil {
Expand Down Expand Up @@ -270,7 +331,7 @@ func prepareBucket(ctx *context.Context, cfg *config) *storage.BucketHandle {
// routes required for serving images, since pushing and other such
// functionality is not available.
var (
manifestRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/manifests/(\w+)$`)
manifestRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/manifests/([\w|\-|\.|\_]+)$`)
layerRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/blobs/sha256:(\w+)$`)
)

Expand All @@ -294,8 +355,9 @@ func (h *registryHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
manifestMatches := manifestRegex.FindStringSubmatch(r.RequestURI)
if len(manifestMatches) == 3 {
imageName := manifestMatches[1]
log.Printf("Requesting manifest for image '%s'", imageName)
image := imageFromName(manifestMatches[1])
imageTag := manifestMatches[2]
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)

if err != nil {
Expand Down Expand Up @@ -328,6 +390,7 @@ func main() {
builder: getConfig("NIX_BUILDER", "Nix image builder code"),
web: getConfig("WEB_DIR", "Static web file dir"),
port: getConfig("PORT", "HTTP port"),
pkgs: pkgSourceFromEnv(),
}

ctx := context.Background()
Expand Down

0 comments on commit 00736ab

Please sign in to comment.