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
- Variables
- func CLIMinor(v string) string
- func ComposeImages(data []byte) (map[string]string, error)
- func ComposeSources(data []byte) (services map[string]ServiceSource, include, multiDoc bool, err error)
- func MergeImages(files []SourceFile, owned func(service string) bool, forCompare bool) (merged map[string]string, unverifiable []string, err error)
- func Path(dir string) string
- func Pin(refs map[string]string, r Resolver) (images, unpinned map[string]string)
- func PruneMirror(data []byte, rendered map[string]string) (out []byte, dropped []string, err error)
- func RefDigest(ref string) string
- type Lock
- type Merged
- type Mismatch
- type PluginPin
- type Resolver
- type ServiceSource
- type SourceFile
Constants ¶
const ( KindCLI = "cli" KindImage = "image" KindPlugin = "plugin" KindBundle = "bundle" )
Mismatch kinds.
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]+)?$` )
const Absent = "<absent>"
Absent is the value shown for a side that has no entry.
const MirrorHeader = "# GENERATED BY nself — DO NOT HAND EDIT\n"
MirrorHeader is the first line of the generated file (written by internal/docker).
Variables ¶
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.
var Tiers = []string{TierFree, TierLicensed}
Tiers lists the accepted plugin tiers.
Functions ¶
func ComposeImages ¶
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 PruneMirror ¶
PruneMirror drops the entries of the mirror override file that no longer match rendered (service -> image of the compose files without the file).
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 ¶
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 (*Lock) PluginVersion ¶
PluginVersion returns the pinned version of a plugin, as the ci plugin pin of P7-CANON-13 reads it.
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 ¶
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 ¶
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.
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 ¶
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 ¶
SourceFile is one compose file's bytes. Name is shown in messages.
func LoadSources ¶
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.