94 lines
3.2 KiB
Go
94 lines
3.2 KiB
Go
// A Dagger module that builds a reproducible Guix installation image
|
|
// inside a container (x86_64 ISO by default; pass --arch for arm64).
|
|
//
|
|
// Edit channels.scm to change which Guix commit is used, then run:
|
|
//
|
|
// dagger call build export --path=./out
|
|
// dagger call build --arch=aarch64 export --path=./out
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
|
|
"dagger/guix-iso/internal/dagger"
|
|
)
|
|
|
|
const guixVersion = "1.5.0"
|
|
|
|
// platformFor maps a Guix system string to the Dagger container platform.
|
|
var platformFor = map[string]dagger.Platform{
|
|
"x86_64": "linux/amd64",
|
|
"aarch64": "linux/arm64",
|
|
}
|
|
|
|
// setupScript runs after the tarball is extracted; it creates the build
|
|
// users and authorizes the substitute servers. It has no dependency on
|
|
// channels.scm, so Dagger caches it as a layer.
|
|
const setupScript = `
|
|
set -euo pipefail
|
|
groupadd --system guixbuild
|
|
for i in $(seq -w 1 10); do
|
|
useradd -g guixbuild -G guixbuild -d /var/empty -s /bin/false \
|
|
-c "Guix build user $i" --system "guixbuilder$i"
|
|
done
|
|
GUIX=/var/guix/profiles/per-user/root/current-guix/bin/guix
|
|
"$GUIX" archive --authorize < /var/guix/profiles/per-user/root/current-guix/share/guix/bordeaux.guix.gnu.org.pub
|
|
"$GUIX" archive --authorize < /var/guix/profiles/per-user/root/current-guix/share/guix/ci.guix.gnu.org.pub
|
|
`
|
|
|
|
type GuixIso struct{}
|
|
|
|
func normalizeArch(arch string) string {
|
|
if arch == "" {
|
|
return "x86_64"
|
|
}
|
|
return arch
|
|
}
|
|
|
|
// setup builds a container with Guix installed for the given architecture
|
|
// (daemon not started).
|
|
func setup(arch string) *dagger.Container {
|
|
tarball := "guix-binary-" + guixVersion + "." + arch + "-linux.tar.xz"
|
|
return dag.Container(dagger.ContainerOpts{Platform: platformFor[arch]}).
|
|
From("debian:bookworm-slim").
|
|
WithEnvVariable("DEBIAN_FRONTEND", "noninteractive").
|
|
WithExec([]string{"apt-get", "update"}).
|
|
WithExec([]string{"apt-get", "install", "-y", "--no-install-recommends",
|
|
"curl", "ca-certificates", "xz-utils", "gnupg", "passwd", "netbase", "git", "python3"}).
|
|
WithExec([]string{"curl", "-fsSL", "-o", "/tmp/" + tarball,
|
|
"https://ftp.gnu.org/gnu/guix/" + tarball}).
|
|
WithExec([]string{"tar", "-C", "/", "--warning=no-timestamp", "-xf", "/tmp/" + tarball}).
|
|
WithExec([]string{"bash", "-c", setupScript})
|
|
}
|
|
|
|
// buildContainer runs the full pull + image build.
|
|
func buildContainer(arch string) *dagger.Container {
|
|
src := dag.CurrentModule().Source()
|
|
return setup(arch).
|
|
WithMountedDirectory("/workspace", src).
|
|
WithExec([]string{"bash", "/workspace/pull.sh"},
|
|
dagger.ContainerWithExecOpts{InsecureRootCapabilities: true}).
|
|
WithExec([]string{"bash", "/workspace/image.sh", arch},
|
|
dagger.ContainerWithExecOpts{InsecureRootCapabilities: true})
|
|
}
|
|
|
|
// Build assembles the Guix installation image and returns it as a directory
|
|
// containing guix-install-<arch>-linux.<ext>.
|
|
func (m *GuixIso) Build(
|
|
ctx context.Context,
|
|
// Architecture of the image: "x86_64" or "aarch64".
|
|
// +optional
|
|
arch string,
|
|
) *dagger.Directory {
|
|
arch = normalizeArch(arch)
|
|
return buildContainer(arch).Directory("/out")
|
|
}
|
|
|
|
// Debug returns the setup container for inspection without running the build.
|
|
func (m *GuixIso) Debug(
|
|
// +optional
|
|
arch string,
|
|
) *dagger.Container {
|
|
return setup(normalizeArch(arch))
|
|
}
|