Documentation
¶
Overview ¶
Package build orchestrates full unattended Windows image builds: media prep, answer volume, VM install, provisioning over gosshd, verification, and clean shutdown. It is the library entry point (the winkit CLI is a thin caller): pass a Config and a *slog.Logger and drive it from any Go program.
Index ¶
- Constants
- func ArtifactManifestPath(image string) string
- func Base(ctx context.Context, c Config) error
- func BootstrapPE(ctx context.Context, c Config, bootVolume, dataDisk string) error
- func FindSiblingVars(baseDisk string) string
- func MergeGuestLog(dst io.Writer, workDir string) error
- func OfflineImportWSL1(opts OfflineImportOpts) error
- func PE(ctx context.Context, c Config) error
- func PEDataDiskPath(bootVolume string) string
- func ResolveBackend() (vm.VMBackend, string, error)
- func ResolveNixHome(flagValue string) string
- func SiblingVarsPath(diskPath string) string
- func WSL(ctx context.Context, c Config) error
- func WriteArtifact(image string, artifact Artifact) error
- type Artifact
- type Config
- type OfflineImportOpts
Constants ¶
const ( // ArtifactSchemaVersion is the on-disk sidecar schema understood by winkit. ArtifactSchemaVersion = 1 // ArtifactKindPEWSL1 is a WinPE boot volume paired with a writable NTFS disk. ArtifactKindPEWSL1 = "pe-wsl1" )
const PECapacity = 4 * 1024 * 1024 * 1024
PECapacity is the virtual size of the FAT boot volume a PE build produces: large enough for boot.wim plus injected payloads.
const PEWSL1DataDiskSizeGB = 32
PEWSL1DataDiskSizeGB is the writable NTFS disk paired with a PE+WSL1 boot volume. It holds the relocated runtime, 4 GB pagefile, user profile, and imported distro. PEWSL1DataDiskSizeGB sizes the writable NTFS disk paired with a PE+WSL1 boot volume. The qcow2 is sparse, so this is a ceiling, not an allocation. The bootstrap places a 4 GB pagefile on it and `wsl --import` unpacks the rootfs next to it; a Nix rootfs with a desktop closure runs past the old 8 GB, which failed the import with "No space left on device".
Variables ¶
This section is empty.
Functions ¶
func ArtifactManifestPath ¶
ArtifactManifestPath returns the sidecar manifest path for image.
func Base ¶
Base performs a full unattended install running the hooks and features from c.Opts after the OS boots.
func BootstrapPE ¶
BootstrapPE boots the PE image during the build, waits for the WSL1 bootstrap to complete (monitoring the structured log for the terminal event), then shuts down QEMU. This moves the heavy provisioning work out of `winkit start` into the build.
func FindSiblingVars ¶
findSiblingVars looks for the NVRAM vars store next to a base disk: first "<base without ext>-vars.fd", then "vars.fd" in the same directory, then inside a .winkit/run/<stem>/ output directory (or the legacy .winkit-run/<stem>/ location). Returns "" if none exists.
func MergeGuestLog ¶
MergeGuestLog appends the raw guest event stream (workDir/guest.jsonl, written by the QEMU process during the build) into dst, which callers point at their unified build.jsonl. Two processes cannot share one append stream while the VM runs, so the merge happens after the build; events carry their own timestamps, so ordering is recoverable.
func OfflineImportWSL1 ¶
func OfflineImportWSL1(opts OfflineImportOpts) error
OfflineImportWSL1 creates a pre-populated NTFS data disk for WinPE WSL1. The disk contains:
- The extracted distro rootfs at wsl-<distroName>/rootfs/
- A user profile at Users/<user>/NTUSER.DAT with Lxss registry entries
- Required directory structure (Users/<user>/AppData/Local/Temp)
At boot, the bootstrap detects the pre-populated disk and skips diskpart and wsl --import.
func PE ¶
PE assembles a WinPE boot volume at c.Dest: gosshd cross-compiled for the guest, PowerShell 7 payload, and the boot files from the Windows/virtio ISOs, mastered onto a FAT32 qcow2. No VM boots; the volume is ephemeral and provisioned at first boot over gosshd.
func PEDataDiskPath ¶
PEDataDiskPath returns the conventional writable-disk path paired with a PE+WSL1 boot volume.
func ResolveBackend ¶
resolveWSLBackend picks the VM backend for the Windows install. Windows guests cannot boot under Virtualization.framework — Apple's firmware provides no ACPI and no vTPM, and there is no API to add them (CELL-523, proven empirically 2026-09-02) — so the platform default of vz-on-darwin does NOT apply here: the install defaults to qemu everywhere, and an explicit vz request fails fast instead of hanging on a black screen.
func ResolveNixHome ¶
resolveNixHome picks the home-manager configuration source for the NixDev rootfs: the --nixhome flag wins, then WINKIT_NIXHOME; empty means the embedded default flake (wsl.DefaultFlakeNix). Values are either a local directory or a remote flake ref — wsl.NixRecipe tells them apart.
func SiblingVarsPath ¶
siblingVarsPath returns the canonical path for a vars.fd file next to a disk image: "<dir>/<stem>-vars.fd".
func WSL ¶
WSL performs a full unattended install with WSL enabled and a distro imported, verifying SSH/RDP, the imported distro, and the SFTP share.
func WriteArtifact ¶
WriteArtifact writes an artifact manifest next to image. Media paths are stored as basenames so the bundle remains relocatable as one directory.
Types ¶
type Artifact ¶
type Artifact struct {
SchemaVersion int `json:"schema_version"`
Kind string `json:"kind"`
BootVolume string `json:"boot_volume"`
DataDisk string `json:"data_disk"`
// Forwards are extra host:guest TCP forwards the image expects at
// start time (winkit.yaml ports.forward), e.g. a VNC server inside
// the guest. `winkit start` merges them with its own flags.
Forwards []string `json:"forwards,omitempty"`
}
Artifact describes the media that make up a built image. Most winkit builds are a single disk and need no manifest. PE+WSL1 needs two devices: the FAT boot volume and an ordinary writable disk for the WSL runtime and distro. Paths in the JSON file are relative to the manifest directory.
func LoadArtifact ¶
LoadArtifact reads image's optional manifest and resolves its media paths. A nil artifact with no error means image is a conventional single disk.
type Config ¶
type Config struct {
// Dest is the produced disk image path (qcow2 for the qemu backend).
Dest string
// CacheDir holds downloaded media and built rootfs tarballs.
CacheDir string
// WindowsISO / VirtIOISO are the cached installer media paths.
WindowsISO string
VirtIOISO string
// WorkDir holds build intermediates (boot volumes, VM state).
WorkDir string
// Logger receives build progress; nil discards it.
Logger *slog.Logger
// NoCache forces rebuilds of cacheable intermediates.
NoCache bool
// Accel overrides the QEMU accelerator (default: best for the host).
Accel string
// DisplayType is the QEMU display option ("" = headless).
DisplayType string
// WSLImage selects the imported distro for WSL builds: "" or a docker
// ref (alpine default), "nix", a published-image URL, or a local
// tarball path. See the wsl package.
WSLImage string
// NixHome selects the home-manager config for WSLImage=nix.
NixHome string
// NixHomeOpts overrides the flake attribute name and user when the
// external flake uses a different naming scheme (e.g. community-home).
NixHomeOpts *wsl.NixHomeOpts
// WSLServices are extra s6 services baked into the distro rootfs and
// supervised by the boot-time s6-svscan loop. Docker-built WSLImage
// values only (a docker ref or nix); URL/tarball images fail the
// build. A service named like a built-in (sshd) overrides it.
WSLServices []s6.Service
// OfflineImport, when true, pre-populates the PE data disk at build
// time: the distro rootfs is extracted onto NTFS and the user registry
// hive is seeded with Lxss entries. This eliminates the wsl --import
// step at boot, trading build time for faster guest startup.
// Requires Docker (privileged, for ntfs-3g mount), mkntfs, hivexregedit,
// and wimextract on the build host.
OfflineImport bool
// StructuredLogPath, when set, is the host-side file that receives
// the guest's structured event stream (pe-agent JSONL via
// virtio-serial). Empty falls back to workDir/guest.jsonl.
StructuredLogPath string
// Opts carries features/hooks for base installs (see buildopts).
Opts *buildopts.BuildOpts
}
Config drives an image build. Dest, CacheDir, WindowsISO, VirtIOISO and WorkDir are required; zero-valued options get the same defaults the CLI uses.
type OfflineImportOpts ¶
type OfflineImportOpts struct {
// DiskPath is the output qcow2 path for the pre-populated data disk.
DiskPath string
// SizeGB is the virtual size of the NTFS data disk.
SizeGB int
// DistroTarball is the path to the .wsl/.tar.gz rootfs.
DistroTarball string
// DistroName is the WSL distribution name (e.g. "winkit").
DistroName string
// User is the Windows user name for the WSL profile.
User string
// BootWimPath is the path to the patched boot.wim (for extracting
// the default NTUSER.DAT).
BootWimPath string
}
OfflineImportOpts configures the build-time WSL1 offline import.