lockfile

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package lockfile reads and writes per-component lock files under the locks/ directory. Each component gets its own <name>.lock TOML file that pins resolved upstream commits and tracks component identity for deterministic builds. Lock files are managed by [azldev component update].

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Exists

func Exists(fs opctx.FS, path string) (bool, error)

Exists checks whether a lock file exists at the given path.

func FindOrphanLockFiles

func FindOrphanLockFiles(
	fs opctx.FS,
	lockDir string,
	components map[string]projectconfig.ComponentConfig,
) ([]string, error)

FindOrphanLockFiles returns component names that have lock files but no corresponding component in config (i.e., the component was removed). Returns an error if the locks directory exists but cannot be read.

func LockPath

func LockPath(lockDir, componentName string) (string, error)

LockPath returns the path to a component's lock file given the lock directory and component name.

func ReadAllAtCommit

func ReadAllAtCommit(
	repo *gogit.Repository,
	commitHash string,
	lockRelDir string,
) (map[string]ComponentLock, error)

ReadAllAtCommit reads and parses all lock files from a directory at a specific commit. Returns a map of component name → ComponentLock. The lockRelDir must be a POSIX-style repo-relative path (e.g., "locks"). Use "" or "." for root. Absolute paths and ".." escapes are rejected.

Returns an empty map (not an error) when the lock directory does not exist in the commit tree. Returns an error if any individual lock file fails to parse.

func Remove

func Remove(fs opctx.FS, path string) error

Remove deletes a lock file at the given path.

func ValidateUpstreamCommit

func ValidateUpstreamCommit(
	fs opctx.FS, lockDir, componentName, configUpstreamCommit string,
) (string, error)

ValidateUpstreamCommit checks that a lock file is consistent with the component's config. Returns the locked commit and an error if:

  • The lock file does not exist or cannot be loaded
  • The component has an explicit 'upstream-commit' in config that doesn't match the lock file (lock is stale, run 'component update')

Types

type ComponentLock

type ComponentLock struct {
	// Version is the lock file format version.
	Version int `toml:"version" comment:"Managed by azldev component update. Do not edit manually."`

	// ImportCommit is the upstream commit hash at the time of initial import
	// (fork point). Upstream changelog up to this commit is inherited verbatim.
	// Write-once: set on first import, never changed afterwards.
	// Empty for local components.
	ImportCommit string `toml:"import-commit,omitempty"`

	// UpstreamCommit is the current resolved upstream commit hash.
	// Updated by 'component update' when upstream sources are re-resolved.
	// Empty for local components.
	UpstreamCommit string `toml:"upstream-commit,omitempty"`

	// ManualBump is an extra rebuild counter for mass-rebuild scenarios.
	// Almost always 0. Incrementing this changes the component's fingerprint,
	// triggering a new release without any other input change.
	ManualBump int `toml:"manual-bump,omitempty"`

	// InputFingerprint is the hash of all render inputs (config, overlays,
	// upstream-commit, manual-bump, distro release version). Recomputed on
	// every update. Used to detect when inputs have changed.
	InputFingerprint string `toml:"input-fingerprint,omitempty"`

	// ResolutionInputHash is a hash of the config inputs that affect upstream
	// commit resolution (snapshot timestamp, distro reference, explicit pin).
	// Used for staleness detection: if the current config's resolution inputs
	// produce a different hash than what's stored, the locked upstream commit
	// may no longer be correct and 'component update' will re-resolve it.
	//
	// This enables a fast check without re-resolving upstream commits:
	//   - Hash matches → resolution inputs unchanged, reuse locked commit
	//   - Hash differs → resolution inputs changed, re-resolve required
	ResolutionInputHash string `toml:"resolution-input-hash,omitempty"`
}

ComponentLock holds the locked state for a single component.

func Load

func Load(fs opctx.FS, path string) (*ComponentLock, error)

Load reads and parses a per-component lock file from the given path. Returns an error if the file cannot be read or parsed, or if the format version is unsupported.

func New

func New() *ComponentLock

New creates a new empty component lock with the current format version.

func Parse

func Parse(data []byte) (*ComponentLock, error)

Parse unmarshals a ComponentLock from raw TOML bytes and validates the format version. Use this when the lock file content has already been read (e.g. from git show); use Load to read from the filesystem.

func ShowAtCommit

func ShowAtCommit(
	repo *gogit.Repository,
	commitHash string,
	lockFileRelPath string,
) (ComponentLock, error)

ShowAtCommit reads and parses a lock file at a specific commit hash using go-git and parses it into a ComponentLock.

func (*ComponentLock) Save

func (lock *ComponentLock) Save(fs opctx.FS, path string) error

Save writes the component lock file to the given path, creating parent directories as needed.

type LockReader

type LockReader interface {
	// Get returns the lock for a component. Returns an error if the lock file
	// does not exist or cannot be parsed.
	Get(componentName string) (*ComponentLock, error)
	// Exists checks whether a lock file exists for the given component.
	Exists(componentName string) (bool, error)
	// LockDir returns the absolute path to the lock file directory.
	LockDir() string
	// ValidateConsistency checks lock files against the resolved component
	// configs. Returns sorted lists of components with missing/stale locks
	// and orphan component names.
	ValidateConsistency(
		components map[string]projectconfig.ComponentConfig,
		checkOrphans bool,
	) (missingOrStale, orphans []string, err error)
}

LockReader provides read-only access to per-component lock files. Use this interface for commands that consume lock state but should not modify it (e.g., render, build, validation).

type LockWriter

type LockWriter interface {
	LockReader
	// GetOrNew returns the lock for a component, creating a new empty lock if
	// none exists on disk. Returns an error if the lock file exists but is
	// corrupt/unreadable.
	GetOrNew(componentName string) (*ComponentLock, error)
	// Save writes the lock for a component to disk.
	Save(componentName string, lock *ComponentLock) error
	// Remove deletes a component's lock file from disk.
	Remove(componentName string) error
}

LockWriter extends LockReader with write operations. Use this interface for commands that create or update lock files (e.g., component update).

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store provides cached access to per-component lock files. It wraps the low-level Load/Save/Exists functions with a lazy-loading cache, avoiding repeated disk reads when commands touch the same component multiple times or when parallel goroutines resolve different components concurrently.

All methods are safe for concurrent use. The cache uses sync.Map for lock-free reads on different keys. Concurrent first-time loads of the same key may result in a redundant disk read, but the result is identical and harmless.

func NewStore

func NewStore(fs opctx.FS, lockDir string) *Store

NewStore creates a new lock store that reads/writes lock files in lockDir.

func (*Store) Exists

func (s *Store) Exists(componentName string) (bool, error)

Exists checks whether a lock file exists for the given component.

func (*Store) FindOrphanLockFiles

func (s *Store) FindOrphanLockFiles(
	components map[string]projectconfig.ComponentConfig,
) ([]string, error)

FindOrphanLockFiles returns component names that have lock files but no corresponding component in the given config map.

func (*Store) Get

func (s *Store) Get(componentName string) (*ComponentLock, error)

Get returns the lock for a component, loading it from disk on first access. Returns a copy — callers may mutate the returned value without affecting cached state. Returns an error if the lock file does not exist or cannot be parsed.

func (*Store) GetOrNew

func (s *Store) GetOrNew(componentName string) (*ComponentLock, error)

GetOrNew returns the lock for a component, creating a new empty lock if the lock file does not exist on disk. Returns an error if the lock file exists but cannot be loaded (e.g., corrupt TOML, unsupported version).

func (*Store) LockDir

func (s *Store) LockDir() string

LockDir returns the absolute path to the lock file directory.

func (*Store) PruneOrphans

func (s *Store) PruneOrphans(
	components map[string]projectconfig.ComponentConfig,
) (int, error)

PruneOrphans removes lock files for components that no longer exist in config. Returns the number of files removed and an error if any removals failed. Also evicts pruned entries from the cache.

func (*Store) Remove

func (s *Store) Remove(componentName string) error

Remove deletes a component's lock file from disk and evicts it from cache.

func (*Store) Save

func (s *Store) Save(componentName string, lock *ComponentLock) error

Save writes the lock for a component to disk and updates the cache. Caches a defensive copy so caller mutations after Save don't affect cached state.

func (*Store) ValidateConsistency

func (s *Store) ValidateConsistency(
	components map[string]projectconfig.ComponentConfig,
	checkOrphans bool,
) (missingOrStale, orphans []string, err error)

ValidateConsistency checks lock files against the resolved component configs. For each non-local component, verifies a lock file exists and any explicit upstream-commit pin matches. When checkOrphans is true, also detects orphan lock files (only appropriate when validating the full project).

Returns sorted lists of components with missing/stale locks and orphan component names. Returns an error if any issues are found.

Jump to

Keyboard shortcuts

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