Help us shape the future of Go! Take the 2026 Go Developer Survey

lock

package
v1.4.15 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package lock is the project lock nself.lock.yaml (contract:cli.lockfile v1, P7-LIVE-09, EPIC D10): which CLI minor, service images and plugin versions a project was built with.

Purpose: reproducible stacks. `nself build` writes the file when its inputs change and honours its image pins; `nself start --frozen` fails when the stack on disk no longer matches it. The file lives at the project root because init gitignores .nself/ and git cannot re-include a file under an ignored directory. Inputs: the project directory (Load) or bytes (Parse); a Lock value (Marshal). Outputs: canonical bytes (header comment, schema_version, cli, images, unpinned, plugins, bundles; map keys sorted, no timestamps), a parsed Lock, and the Mismatch list of Compare. Constraints: pure (stdlib plus gopkg.in/yaml.v3), no I/O except Load. The `cli` field records major.minor only, so a patch upgrade never rewrites a committed file. Unknown keys are rejected, so a newer schema is never read half-way.

Index

Constants

View Source
const (
	KindCLI    = "cli"
	KindImage  = "image"
	KindPlugin = "plugin"
	KindBundle = "bundle"
)

Mismatch kinds.

View Source
const (
	// FileName is the lock's name at the project root.
	FileName = "nself.lock.yaml"
	// Header is the first line of every written lock.
	Header = "# GENERATED BY nself build — DO NOT HAND EDIT (change pins with nself update)"
	// Trailer is the last line of every written lock. Parse rejects a file
	// that does not end with it, so a file cut short by a crash, a full disk or
	// a concurrent reader is an error and never a valid lock with fewer pins.
	Trailer = "# end of nself.lock.yaml"
	// SchemaVersion is the only schema_version this package reads or writes.
	SchemaVersion = 1
	// MaxBytes caps the size of a lock that Parse and Load accept.
	MaxBytes = 4 << 20

	// TierFree and TierLicensed are the plugin tiers (same words as the bundle ledger).
	TierFree     = "free"
	TierLicensed = "licensed"

	// KeyPattern is the shape of a service, plugin or bundle name used as a key.
	KeyPattern = `^[a-z0-9][a-z0-9._-]*$`
	// PinnedPattern is an image reference carrying a sha256 digest.
	PinnedPattern = `^[^\s@$]+@sha256:[0-9a-f]{64}$`
	// UnpinnedPattern is a tag-only image reference (no digest).
	UnpinnedPattern = `^[^\s@$]+$`
	// ChecksumPattern is a lowercase hex sha256, or empty when unknown.
	ChecksumPattern = `^([0-9a-f]{64})?$`
	// CLIPattern is major.minor, or empty for a build that has no release version.
	CLIPattern = `^([0-9]+\.[0-9]+)?$`
)
View Source
const Absent = "<absent>"

Absent is the value shown for a side that has no entry.

View Source
const MirrorHeader = "# GENERATED BY nself — DO NOT HAND EDIT\n"

MirrorHeader is the first line of the generated file (written by internal/docker).

Variables

View Source
var ErrNotFound = errors.New("lock: no nself.lock.yaml in this project")

ErrNotFound means the project has no nself.lock.yaml. Test with errors.Is.

Tiers lists the accepted plugin tiers.

Functions

func CLIMinor

func CLIMinor(v string) string

CLIMinor returns major.minor of a version string, or "" when it has none.

func ComposeImages

func ComposeImages(data []byte) (map[string]string, error)

ComposeImages reads the image of every service of a compose document. A service without an image (build only) is left out.

func ComposeSources

func ComposeSources(data []byte) (services map[string]ServiceSource, include, multiDoc bool, err error)

ComposeSources reads every service of the first document of a compose file, whether the file has a top-level include (which pulls in services this reader cannot see), and whether it has a second YAML document (Compose merges every document, and this reader sees only the first, so such a file is opaque).

func MergeImages

func MergeImages(files []SourceFile, owned func(service string) bool, forCompare bool) (merged map[string]string, unverifiable []string, err error)

MergeImages merges the image keys of files in order. unverifiable lists, sorted and without duplicates, what could not be read as a plain image.

func Path

func Path(dir string) string

Path is the lock file of the project at dir.

func Pin

func Pin(refs map[string]string, r Resolver) (images, unpinned map[string]string)

Pin sorts refs into digest-pinned images and tag-only unpinned entries.

func PruneMirror

func PruneMirror(data []byte, rendered map[string]string) (out []byte, dropped []string, err error)

PruneMirror drops the entries of the mirror override file that no longer match rendered (service -> image of the compose files without the file).

func RefDigest

func RefDigest(ref string) string

RefDigest returns the "sha256:<hex>" of a reference of the form repo[:tag]@digest, or "" when it has none or the digest is malformed.

Types

type Lock

type Lock struct {
	SchemaVersion int `yaml:"schema_version" json:"schema_version"`
	// CLI is the CLI major.minor that wrote the file.
	CLI string `yaml:"cli" json:"cli"`
	// Images maps a compose service to its digest-pinned reference.
	Images map[string]string `yaml:"images" json:"images"`
	// Unpinned maps a service to a tag-only reference whose digest is unknown.
	Unpinned map[string]string `yaml:"unpinned" json:"unpinned"`
	// Plugins maps a plugin slug to its pin, from the bundle ledger.
	Plugins map[string]PluginPin `yaml:"plugins" json:"plugins"`
	// Bundles lists the installed bundles, sorted.
	Bundles []string `yaml:"bundles" json:"bundles"`
}

Lock is the file. Field order is the on-disk key order.

func Load

func Load(dir string) (*Lock, error)

Load reads the project's lock. A missing file wraps ErrNotFound (and os.ErrNotExist); a damaged one is an error that names the file.

func New

func New() Lock

New returns an empty, valid lock.

func Parse

func Parse(data []byte) (Lock, error)

Parse reads and validates lock bytes.

func (Lock) Marshal

func (l Lock) Marshal() ([]byte, error)

Marshal validates l and renders the canonical bytes. It does not change l.

func (*Lock) Pins

func (l *Lock) Pins() map[string]string

Pins returns every service pin, digest-pinned and tag-only, in one map.

func (*Lock) PluginVersion

func (l *Lock) PluginVersion(slug string) (string, bool)

PluginVersion returns the pinned version of a plugin, as the ci plugin pin of P7-CANON-13 reads it.

func (Lock) Validate

func (l Lock) Validate() error

Validate checks every rule the JSON Schema states.

type Merged

type Merged struct {
	// Images is service -> merged image reference.
	Images map[string]string
	// Unverifiable lists, sorted and without duplicates, what could not be read
	// as a plain image.
	Unverifiable []string
	// Services names the CLI-owned services behind Unverifiable (sorted); an
	// include has no service of its own, so it adds none.
	Services []string
}

Merged is the result of MergeDetailed.

func MergeDetailed

func MergeDetailed(files []SourceFile, owned func(service string) bool, forCompare bool) (Merged, error)

MergeDetailed is MergeImages that also names the unverifiable services.

type Mismatch

type Mismatch struct {
	Kind   string `json:"kind"`
	Name   string `json:"name"`
	Locked string `json:"locked"`
	Actual string `json:"actual"`
}

Mismatch is one difference between the lock and the current state.

func Compare

func Compare(locked, actual Lock) []Mismatch

Compare lists how actual differs from locked. An empty cli or sha256 on either side means "unknown" and is not compared (the plain-start warning).

func CompareStrict

func CompareStrict(locked, actual Lock) []Mismatch

CompareStrict is Compare for `start --frozen`: a cli or sha256 that one side recorded and the other left empty is a mismatch, so a hand edit that blanks them, or a build with no release version, cannot switch the check off.

func (Mismatch) String

func (m Mismatch) String() string

String renders the mismatch for a terminal.

type PluginPin

type PluginPin struct {
	Version string `yaml:"version" json:"version"`
	SHA256  string `yaml:"sha256" json:"sha256"`
	Tier    string `yaml:"tier" json:"tier"`
}

PluginPin pins one installed plugin.

type Resolver

type Resolver struct {
	// LocalDigest returns "sha256:<hex>" for a tag reference whose image is
	// present locally with exactly one repo digest, else "".
	LocalDigest func(ref string) string
	// CLILocked returns the digest-pinned reference of the CLI image lock whose
	// version matches the tag reference, if any.
	CLILocked func(ref string) (string, bool)
}

Resolver supplies the two digest sources. A nil field finds nothing.

type ServiceSource

type ServiceSource struct {
	Image   string
	Extends bool
	Build   bool
	// Reset is set when the service or its image carries Compose's !reset tag:
	// the key is cleared, so an earlier file's image no longer applies. A
	// service-level !override sets Override: it replaces the earlier service
	// whole, so the earlier image does not carry over either.
	Reset    bool
	Override bool
}

ServiceSource is what a compose service says about where its image comes from: the image key, and whether it also carries extends or build, either of which can change the image without an image key.

type SourceFile

type SourceFile struct {
	Name   string
	Data   []byte
	Mirror bool
}

SourceFile is one compose file's bytes. Name is shown in messages.

func LoadSources

func LoadSources(workdir string, base []byte, paths []string, mirror string) ([]SourceFile, error)

LoadSources reads the compose files start runs, in the order start runs them: paths exactly as given (relative ones resolve against workdir), so the merge order (last wins) is the one `docker compose -f ...` sees. An empty paths means workdir's docker-compose.yml alone. A non-empty paths that does not list docker-compose.yml is an error: start would run a stack without the base file. base replaces the bytes of docker-compose.yml when non-nil. A listed file that does not exist is skipped, except the base. mirror is the project-relative path of the registry-mirror override file; its SourceFile has Mirror set.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL