Documentation
¶
Overview ¶
Package lockfile stores the immutable identities and installed-file inventory produced by Atmos vendoring.
intentionally throughout this file (map iteration + mutate + reassign, by-value receipt building); pointer indirection would fight the existing read-modify-write pattern LockFile's map requires (Go cannot take the address of a map value).
Index ¶
- Constants
- Variables
- func ArtifactID(config *schema.AtmosConfiguration, kind, target string, writers ...string) (string, error)
- func FilesDigest(files []File) string
- func Path(config *schema.AtmosConfiguration) string
- func Record(ctx context.Context, atmosConfig *schema.AtmosConfiguration, ...) error
- func Replace(config *schema.AtmosConfiguration, id string, artifact Artifact) error
- func Save(config *schema.AtmosConfiguration, lock *LockFile) error
- type Artifact
- type CleanReport
- type Drift
- type File
- type LockFile
- type MaterializationCheck
- type MaterializationParams
- type RecordOptions
- type RecordTarget
- type Source
Constants ¶
const (
// DefaultFileName is the default committed vendor lock file.
DefaultFileName = "vendor.lock.yaml"
)
Variables ¶
var ( // Load/Save. ErrReadVendorLock = errors.New("read vendor lock") ErrParseVendorLock = errors.New("parse vendor lock") ErrUnsupportedVendorLockVersion = errors.New("unsupported vendor lock version") ErrMarshalVendorLock = errors.New("marshal vendor lock") ErrCreateVendorLockDir = errors.New("create vendor lock directory") ErrCreateTempVendorLock = errors.New("create temporary vendor lock") ErrWriteTempVendorLock = errors.New("write temporary vendor lock") ErrSetVendorLockPermissions = errors.New("set vendor lock permissions") ErrCloseTempVendorLock = errors.New("close temporary vendor lock") ErrReplaceVendorLock = errors.New("replace vendor lock") // Inventory / Record. ErrInventoryWalk = errors.New("inventory vendor tree") // Target/path security-boundary checks. ErrNormalizeLockTarget = errors.New("normalize lock target") ErrNormalizeArtifactTarget = errors.New("normalize artifact target") ErrInvalidLockOwnedFilePath = errors.New("invalid lock-owned file path") ErrInvalidVendorLockTarget = errors.New("invalid vendor lock target") ErrAbsoluteVendorLockTarget = errors.New("invalid absolute vendor lock target") ErrVendorLockTargetEscapesRoot = errors.New("vendor lock target escapes project root") ErrMakeTargetRelative = errors.New("make target relative to project root") ErrGetProjectRoot = errors.New("get project root") ErrResolveProjectRoot = errors.New("resolve project root") // Replace/Clean file operations. ErrInspectLockOwnedFile = errors.New("inspect lock-owned file") ErrStaleLockOwnedFileModified = errors.New("stale lock-owned file was modified") ErrRemoveLockOwnedFile = errors.New("remove lock-owned file") )
Sentinel errors for pkg/vendoring/lockfile. These are package-local rather than centralized in errors/errors.go: they're internal invariants of this package's own lock-file contract (corruption, security-boundary checks, I/O failures during Save/Replace/Clean), meaningful only to this package's own callers and tests, not a cross-package contract other packages match against. This mirrors the existing internal/exec/vendor*.go convention of package-local sentinels, applied here for the first time to this package.
Functions ¶
func ArtifactID ¶
func ArtifactID(config *schema.AtmosConfiguration, kind, target string, writers ...string) (string, error)
ArtifactID returns a stable key for the writer that owns a target. The declared source is deliberately not part of the key: a new declared ref for the same target replaces the old receipt and can safely prune its stale files.
Target is relativized against config's project base before hashing (the same projectRelativeTarget normalization Replace/IsMaterialized already apply to the stored Target field) so the same logical artifact hashes to the same ID regardless of the checkout's absolute path. Without this, a vendor.lock.yaml committed to git -- its entire purpose -- would never match on a different developer's or CI runner's checkout, since every installer computes this ID from an absolute path (see ResolveComponentPath's own doc comment on why that path is absolute).
func FilesDigest ¶
FilesDigest returns the deterministic SHA-256 identity for an installation manifest. It is used only when a source has no stronger immutable identity.
func Path ¶
func Path(config *schema.AtmosConfiguration) string
Path returns the absolute vendor lock path for the given Atmos configuration.
func Record ¶
func Record(ctx context.Context, atmosConfig *schema.AtmosConfiguration, target RecordTarget, opts RecordOptions) error
Record inventories target.TempDir (honoring opts), resolves target.DeclaredSource's immutable identity via downloader.ResolveArtifact (falling back to a files digest when the resolver has none), and replaces the lock artifact identified by (target.Kind, target.Path, target.Name[, opts.MixinFilename]). This is the single writer of vendor.lock.yaml artifacts — every install path (vendor.yaml sources, component.yaml sources, and mixins) calls this instead of hand rolling the inventory->resolve->Replace sequence itself.
func Replace ¶
func Replace(config *schema.AtmosConfiguration, id string, artifact Artifact) error
Replace atomically updates one artifact receipt after its files have been materialized. It safely prunes stale, unchanged files from the previous receipt while retaining files claimed by another artifact.
Types ¶
type Artifact ¶
type Artifact struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Kind string `yaml:"kind" json:"kind"`
Target string `yaml:"target" json:"target"`
Source Source `yaml:"source" json:"source"`
Files []File `yaml:"files" json:"files"`
Order int `yaml:"order" json:"order"`
// IncludedPaths/ExcludedPaths are the copy-filter patterns in effect when this artifact was
// recorded (see RecordOptions.IncludedPaths/ExcludedPaths). Omitted entirely for artifacts
// recorded with no filtering (mixins, and unfiltered sources), so a committed lock file written
// before these fields existed loads with both nil -- IsMaterialized treats that identically to
// an explicit empty list, never spuriously reporting drift on an old receipt.
IncludedPaths []string `yaml:"included_paths,omitempty" json:"included_paths,omitempty"`
ExcludedPaths []string `yaml:"excluded_paths,omitempty" json:"excluded_paths,omitempty"`
}
Artifact is one independently materialized source, target, or mixin.
type CleanReport ¶
CleanReport summarizes a vendor clean operation.
func Clean ¶
func Clean(config *schema.AtmosConfiguration, component string, force, dryRun bool) (*CleanReport, error)
Clean removes files owned by selected lock artifacts. A blank component selects every artifact. Modified files are preserved unless force is true. The lock is updated only when every selected artifact was removed cleanly.
type File ¶
type File struct {
Path string `yaml:"path" json:"path"`
Type string `yaml:"type" json:"type"`
Mode uint32 `yaml:"mode" json:"mode"`
SHA256 string `yaml:"sha256" json:"sha256"`
}
File records one lock-owned output path. SHA256 is the file bytes, or the symlink target text for a symlink.
func Inventory ¶
Inventory records every regular file and symlink below root with no exclusions at all (not even .git). Used by tests that need to assert exact directory contents after an operation; production code uses VendorInventory/VendorInventoryWithPatterns instead, both of which apply real skip rules.
func VendorInventory ¶
VendorInventory records the files that the standard directory vendoring copy writes. Git metadata is deliberately excluded because the installer never copies it to the materialized target.
func VendorInventoryWithPatterns ¶
func VendorInventoryWithPatterns(root string, includedPaths, excludedPaths []string) ([]File, error)
VendorInventoryWithPatterns records the exact files selected by the shared vendor copy policy. It allows component.yaml sources to own only copied files, rather than taking a broad snapshot of a component directory that may also contain local configuration or mixin output.
type LockFile ¶
type LockFile struct {
Version int `yaml:"version" json:"version"`
Artifacts map[string]Artifact `yaml:"artifacts" json:"artifacts"`
}
LockFile is the versioned vendor.lock.yaml format.
type MaterializationCheck ¶
type MaterializationCheck struct {
Materialized bool
// Reason is empty when Materialized is true. Otherwise one of: "no lock entry", "target path
// changed", "declared source changed", "included/excluded paths changed", or a per-file reason
// naming the file (e.g. `file "foo.tf" missing`, `file "foo.tf" checksum mismatch`).
Reason string
}
MaterializationCheck is IsMaterialized's structured result: whether a package's on-disk state still matches its vendor.lock.yaml receipt, and -- when it doesn't -- why.
func IsMaterialized ¶
func IsMaterialized(config *schema.AtmosConfiguration, params MaterializationParams) (MaterializationCheck, error)
IsMaterialized reports whether a declared source (identity and copy-filter patterns alike) has a complete, unchanged installation receipt at target. It never treats cache metadata as evidence of integrity.
type MaterializationParams ¶
type MaterializationParams struct {
// ID is the lock artifact key -- see ArtifactID.
ID string
// Declared is the source's currently-declared URI (pre-redaction; IsMaterialized redacts it
// itself before comparing against the receipt's already-redacted Source.Declared).
Declared string
// Target is the source's currently-declared destination path.
Target string
// IncludedPaths/ExcludedPaths are the source's currently-declared copy-filter patterns.
IncludedPaths []string
ExcludedPaths []string
}
MaterializationParams identifies the artifact IsMaterialized checks and the source's currently-declared identity and copy-filter patterns to compare against the lock receipt. A struct rather than positional parameters: with IncludedPaths/ExcludedPaths added to ID/Declared/ Target, this crosses the Options Pattern threshold (CLAUDE.md) of more than four parameters.
type RecordOptions ¶
type RecordOptions struct {
// IncludedPaths/ExcludedPaths select VendorInventoryWithPatterns-style filtered inventory,
// matching a vendor.yaml or component.yaml source's own copy-filter configuration. Passed
// through even when both are empty (an unfiltered patterned source still uses this path,
// matching this package's existing behavior).
IncludedPaths []string
ExcludedPaths []string
// Mixin marks a mixin install: inventoried via plain VendorInventory (no pattern filtering,
// since mixins install a set of individually-declared files rather than a filtered directory
// copy), and its filename is appended to ArtifactID's writer list so a component and its
// mixins never collide on the same lock key.
Mixin bool
MixinFilename string
// HTTPMetadata is best-effort HTTP cache metadata (ETag/Last-Modified) captured during the
// fetch that staged tempDir, when it was an HTTP(S) source -- see downloader.FetchMetadata's
// doc comment. Zero-value for git, OCI, and local sources, whose fetch has no HTTP response to
// observe. Cache metadata only: never read by IsMaterialized or Verify, both of which continue
// to rely solely on Digest and the per-file SHA256 values for integrity/drift decisions.
HTTPMetadata downloader.FetchMetadata
// VersionConstraint/ResolvedVersion record a range-declared `version:`'s resolution -- see
// pkg/vendoring/install/version_resolve.go. Both empty for an exact-pinned version: (the common
// case), matching Source.VersionConstraint/ResolvedVersion's own omitempty fields.
VersionConstraint string
ResolvedVersion string
}
RecordOptions configures how Record inventories and identifies a materialized artifact.
type RecordTarget ¶
type RecordTarget struct {
// Kind is the installer's PkgType.String() (e.g. "remote", "oci", "local").
Kind string
// Name is the vendor.yaml/component.yaml source's declared name.
Name string
// TempDir is the staged fetch content Record inventories.
TempDir string
// Path is the materialized destination (a vendor.yaml target or a component's path).
Path string
// DeclaredSource is the pre-fetch declared URI (oci:// restored, credentials still present --
// Record redacts it via lockfile.RedactSource before it reaches the committed lock).
DeclaredSource string
}
RecordTarget identifies the writer and destination Record is recording a receipt for. A struct rather than five positional string parameters: Options Pattern (CLAUDE.md) applies once a function has more than four parameters, counting ctx/atmosConfig/target/opts.
type Source ¶
type Source struct {
Declared string `yaml:"declared" json:"declared"`
Resolved string `yaml:"resolved,omitempty" json:"resolved,omitempty"`
Digest string `yaml:"digest,omitempty" json:"digest,omitempty"`
ETag string `yaml:"etag,omitempty" json:"etag,omitempty"`
LastModified string `yaml:"last_modified,omitempty" json:"last_modified,omitempty"`
// VersionConstraint is the raw semver-range expression declared in a source's `version:` field
// (e.g. "^1.0.0"), populated only when `version:` was a range rather than an exact pin. Empty
// for every exact-pinned source -- the overwhelming common case. Distinct from Resolved above:
// Resolved is the post-fetch resolved identity (e.g. a resolved commit/digest);
// VersionConstraint/ResolvedVersion are pre-fetch version-range resolution provenance -- see
// pkg/vendoring/install/version_resolve.go.
VersionConstraint string `yaml:"version_constraint,omitempty" json:"version_constraint,omitempty"`
// ResolvedVersion is the concrete version VersionConstraint last resolved to. Empty whenever
// VersionConstraint is empty.
ResolvedVersion string `yaml:"resolved_version,omitempty" json:"resolved_version,omitempty"`
}
Source identifies the immutable artifact that was installed.