warmstart

package
v0.0.0-...-d44510c Latest Latest
Warning

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

Go to latest
Published: Aug 12, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package warmstart implements materialization of git repository warm-start snapshots.

A warm-start snapshot enables incremental fetch by restoring a repository's state from a previous scan, avoiding full re-clone. The artifact contains:

  • Raw pack files (*.pack, *.idx, *.promisor, *.rev) from objects/pack/
  • A single loose ref file (e.g., refs/heads/main)
  • Three required git config values for partial clone support

Public parsing, materialization, filesystem, and git-verification boundaries emit structured error records through the package Logger. Records include the operation and commit SHA plus type-specific context such as member, offset, underlying I/O cause, or repository path and reason. If the structured sink fails, Logger writes a plain-text fallback directly to stderr. Logging is side-effect only: callers still receive the original typed operation error and can inspect it with errors.Is or errors.As.

See docs/research/incremental-fetch-warm-start.md for empirical validation.

Package warmstart provides a reference implementation of the cold/warm clone fallback pattern.

This example demonstrates how to integrate warmstart incremental fetch with fallback to full git clone when warmstart extraction fails.

The pattern is: 1. Attempt to fetch and materialize warmstart artifact from ARMOR 2. If warmstart succeeds, perform incremental fetch (git fetch origin) 3. If warmstart fails, evaluate error type and either:

  • Fall back to cold clone (most errors)
  • Fail the job (permission errors, disk space, NotAGitRepo)

See docs/runbooks/warmstart-error-handling.md for detailed error handling guidance.

Package warmstart provides structured logging for warmstart tarball parsing operations.

Index

Constants

View Source
const (
	ErrorTypeTruncated     = "truncated"
	ErrorTypeMissingMember = "missing_member"
	ErrorTypeCorruptPack   = "corrupt_pack"
	ErrorTypeIO            = "io"
	ErrorTypeNotGitRepo    = "not_git_repo"
	ErrorTypeValidation    = "validation"
	ErrorTypeUnknown       = "unknown"
)

Stable error type values used by structured warmstart log entries.

Variables

View Source
var (
	// ErrInvalidTarball indicates the tarball is corrupted or truncated.
	ErrInvalidTarball = errors.New("warmstart: invalid tarball")

	// ErrMissingPackFiles indicates required pack files are missing.
	ErrMissingPackFiles = errors.New("warmstart: missing required pack files")

	// ErrMissingRef indicates the ref file is missing.
	ErrMissingRef = errors.New("warmstart: missing ref file")

	// ErrMissingConfig indicates the git config is missing.
	ErrMissingConfig = errors.New("warmstart: missing git config")

	// ErrInvalidConfig indicates the git config is malformed.
	ErrInvalidConfig = errors.New("warmstart: invalid git config")

	// ErrNotAGitRepo indicates the target directory is not a git repository.
	ErrNotAGitRepo = errors.New("warmstart: not a git repository")
)
View Source
var ErrInvalidRefMetadata = fmt.Errorf("warmstart: invalid ref metadata")

ErrInvalidRefMetadata indicates ref metadata is malformed.

View Source
var ErrMissingRequiredFile = NewMissingMemberError("test-file")

ErrMissingRequiredFile is a sentinel error for missing required file detection in tests. It is used with errors.Is to verify that missing file errors are properly detected.

View Source
var ErrTruncatedFile = NewTruncatedError("test file is truncated", 0)

ErrTruncatedFile is a sentinel error for truncated file detection in tests. It is used with errors.Is to verify that truncated file errors are properly detected.

Functions

func AsOSPermission

func AsOSPermission(err error) bool

AsOSPermission checks if the error chain contains a permission error.

func CloneWithFallback

func CloneWithFallback(
	repoURL string,
	gitDir string,
	fetchWarmstart func() ([]byte, error),
	coldClone func(url string, dir string) error,
) error

CloneWithFallback attempts warmstart incremental fetch, falling back to cold clone on error.

This function demonstrates the recommended pattern for integrating warmstart with fallback to full git clone. It handles all warmstart error types appropriately:

- Truncated, MissingMember, CorruptPack: Fall back to cold clone - IO with permission/disk errors: Fail immediately (local infrastructure issue) - IO with network errors: Fall back to cold clone - Other with NotAGitRepo: Fail immediately (invalid target directory) - Other unknown errors: Fall back to cold clone for robustness

Parameters:

  • repoURL: Git repository URL (e.g., "https://github.com/user/repo")
  • gitDir: Target directory for git repository (must be empty or non-existent)
  • fetchWarmstart: Function to fetch warmstart artifact from storage
  • coldClone: Function to perform full git clone

Returns:

  • error: nil on success, error if both warmstart and cold clone fail

Example usage:

err := CloneWithFallback(repoURL, gitDir,
	func() ([]byte, error) { return fetchFromARMOR(repoURL) },
	func(url, dir string) error { return execGitClone(url, dir) })
if err != nil {
	log.Fatalf("Clone failed: %v", err)
}

func CloneWithFallbackAndMetrics

func CloneWithFallbackAndMetrics(
	repoURL string,
	gitDir string,
	correlationID string,
	fetchWarmstart func() ([]byte, error),
	coldClone func(url string, dir string) error,
	metrics MetricEmitter,
) error

CloneWithFallbackAndMetrics is a production-ready version that includes metrics and observability.

This extends CloneWithFallback with: - Structured logging with correlation IDs - Metrics emission for monitoring - Detailed error context propagation

See docs/runbooks/warmstart-error-handling.md for recommended metrics.

func CollectMissingIdxFiles

func CollectMissingIdxFiles(members []TarballMember) []string

CollectMissingIdxFiles collects all missing .idx files across all pack files. It iterates over each pack file in the members list, checks if the corresponding .idx file exists, and collects the names of missing .idx files.

Parameters:

  • members: Slice of TarballMember representing files in the tarball

Returns:

  • []string: List of missing .idx file names (empty if all present)

Example:

members := []TarballMember{
    {Name: "objects/pack/pack-abc.pack", Data: ...},
    {Name: "objects/pack/pack-def.pack", Data: ...},
    {Name: "objects/pack/pack-abc.idx", Data: ...},
}
missing := CollectMissingIdxFiles(members) // returns ["objects/pack/pack-def.idx"]

func CollectMissingRefFiles

func CollectMissingRefFiles(members []TarballMember) []string

CollectMissingRefFiles collects all missing .ref files across all pack files. It iterates over each pack file in the members list, checks if the corresponding .ref file exists, and collects the names of missing .ref files.

Parameters:

  • members: Slice of TarballMember representing files in the tarball

Returns:

  • []string: List of missing .ref file names (empty if all present)

Example:

members := []TarballMember{
    {Name: "objects/pack/pack-abc.pack", Data: ...},
    {Name: "objects/pack/pack-def.pack", Data: ...},
    {Name: "objects/pack/pack-abc.ref", Data: ...},
}
missing := CollectMissingRefFiles(members) // returns ["objects/pack/pack-def.ref"]

func ComputeSHA256

func ComputeSHA256(data []byte) string

ComputeSHA256 computes the SHA256 hash of data and returns the hex-encoded string. This is a test helper function for byte-for-byte verification tests.

func ExtractWarmStart

func ExtractWarmStart(tarballPath, targetDir string, commitSHAs ...string) (returnErr error)

ExtractWarmStart extracts a warm-start tarball to a target directory.

This function combines git directory initialization, tarball reading, parsing, and materialization into a single operation. It creates a minimal empty git directory structure at targetDir, then extracts and materializes the warm-start snapshot from the tarball file at tarballPath.

Parameters:

  • tarballPath: Path to the warm-start tarball file on disk
  • targetDir: Path where the git directory should be created/initialized

Returns:

  • error: nil if extraction succeeds, error otherwise

Error types returned:

  • *Error with Kind=IO: file I/O errors (reading tarball, creating directories)
  • *Error with Kind=Truncated: tarball is truncated or corrupted
  • *Error with Kind=MissingMember: required tarball members are missing
  • ErrInvalidTarball: tarball format is invalid
  • ErrMissingConfig, ErrMissingRef, ErrMissingPackFiles: validation failures

Example:

if err := ExtractWarmStart("/path/to/snapshot.tar", "/path/to/repo.git"); err != nil {
    return fmt.Errorf("warm-start extraction failed: %w", err)
}

No network access: This function performs only local filesystem operations. It does not make any HTTP requests or network calls.

func IdxFileExistsInTarball

func IdxFileExistsInTarball(packFilename string, members []TarballMember) bool

IdxFileExistsInTarball checks if a .idx file exists in the tarball for a given .pack file. It uses IdxFilenameFromPackFilename to construct the expected .idx filename and searches the provided member list for a matching file.

Parameters:

  • packFilename: The .pack file name (e.g., "objects/pack/pack-abc123.pack")
  • members: Slice of TarballMember representing files in the tarball

Returns:

  • true if the corresponding .idx file is found in the member list, false otherwise

Example:

packFile := "objects/pack/pack-abc123.pack"
members := []TarballMember{{Name: "objects/pack/pack-abc123.idx", Data: ...}}
found := IdxFileExistsInTarball(packFile, members) // returns true

func IdxFilenameFromPackFilename

func IdxFilenameFromPackFilename(packFilename string) string

IdxFilenameFromPackFilename constructs the expected .idx filename from a .pack filename. It strips the .pack extension and appends .idx. For example: "pack-abc123.pack" becomes "pack-abc123.idx" Edge cases handled:

  • No .pack extension: appends .idx to the input as-is
  • Multiple dots: only the final .pack extension is stripped

func IsOsPermissionError

func IsOsPermissionError(err error) bool

IsOsPermissionError checks if an error is an OS permission error.

func Materialize

func Materialize(gitDir string, snapshot *WarmStartSnapshot, commitSHAs ...string) (returnErr error)

Materialize writes the warm-start snapshot to a git directory.

The target directory must be an empty git repository (initialized with `git init --bare` or `git init`). After materialization, the repository will be ready for incremental fetch via `git fetch origin`.

Validation approach: Ref and pack file validation is performed upstream in ParseTarball, not here. By the time Materialize is called, the snapshot has already been validated to ensure all required companion files (.idx, .ref) exist for each .pack file. This separation of concerns allows ParseTarball to fail fast on corrupted input before any filesystem writes occur.

This function focuses solely on idempotent filesystem operations: writing pack files to objects/pack/, creating ref directories, and writing the ref file and git config values. It assumes the snapshot is well-formed.

func RefFileExistsInTarball

func RefFileExistsInTarball(packFilename string, members []TarballMember) bool

RefFileExistsInTarball checks if a .ref file exists in the tarball for a given .pack file. It uses RefFilenameFromPackFilename to construct the expected .ref filename and searches the provided member list for a matching file.

Parameters:

  • packFilename: The .pack file name (e.g., "objects/pack/pack-abc123.pack")
  • members: Slice of TarballMember representing files in the tarball

Returns:

  • true if the corresponding .ref file is found in the member list, false otherwise

Example:

packFile := "objects/pack/pack-abc123.pack"
members := []TarballMember{{Name: "objects/pack/pack-abc123.ref", Data: ...}}
found := RefFileExistsInTarball(packFile, members) // returns true

func RefFilenameFromPackFilename

func RefFilenameFromPackFilename(packFilename string) string

RefFilenameFromPackFilename constructs the expected .ref filename from a .pack filename. It strips the .pack extension and appends .ref. For example: "pack-abc123.pack" becomes "pack-abc123.ref" Edge cases handled:

  • No .pack extension: appends .ref to the input as-is
  • Multiple dots: only the final .pack extension is stripped
  • Double extensions: "pack-abc123.pack.promisor" would become "pack-abc123.pack.promisor.ref"

func RunSanityChecks

func RunSanityChecks(gitDir string, commitSHAs ...string) (returnErr error)

RunSanityChecks runs both git fsck and git log verification on a materialized directory.

This is a convenience function that runs both sanity checks in sequence. It ensures the repository is fully functional after materialization.

Parameters:

  • gitDir: Path to the git directory (e.g., "/path/to/repo.git")

Returns:

  • error: nil if all checks pass, first error encountered if any check fails

Example:

if err := Materialize(gitDir, snapshot); err != nil {
    return err
}
if err := RunSanityChecks(gitDir); err != nil {
    return fmt.Errorf("sanity checks failed: %w", err)
}

func SetLogger

func SetLogger(logger *Logger)

SetLogger replaces the default package-level logger with a custom implementation. This allows callers to configure custom logging destinations or disable logging entirely.

func ShouldFallbackToColdClone

func ShouldFallbackToColdClone(err error) (fallback bool, fatalErr error)

ShouldFallbackToColdClone evaluates whether a warmstart error should trigger fallback to cold clone.

This function implements the error handling logic from docs/runbooks/warmstart-error-handling.md. It distinguishes between:

1. Fallback-appropriate errors: Truncated, MissingMember, CorruptPack, most IO and Other errors 2. Fatal errors: Permission errors, disk space errors, NotAGitRepo (should NOT fall back)

Parameters:

  • err: Error from ParseTarball or Materialize

Returns:

  • fallback: true if caller should fall back to cold clone
  • fatalErr: non-nil if error is fatal (do NOT fall back, fail the job)

Error handling rules:

Fallback to cold clone (fallback=true, fatalErr=nil): - Truncated: Artifact is corrupt, unusable - MissingMember: Artifact is incomplete - CorruptPack: Pack data is corrupted - IO (network): Temporary I/O failure - IO (unknown): Other I/O issues - Other (unknown): Unexpected errors

Fail immediately, do NOT fall back (fallback=false, fatalErr=err): - IO (permission): Local infrastructure issue, cold clone will also fail - IO (disk space): Disk full, cold clone will also fail - Other (NotAGitRepo): Invalid target directory

func UnwrapError

func UnwrapError(err error) error

UnwrapError recursively unwraps errors to find underlying causes.

func ValidateRefFiles

func ValidateRefFiles(packFiles []string) []string

ValidateRefFiles validates .ref file existence for a given list of .pack files. For each .pack file, it constructs the expected .ref filename and checks if it exists on the filesystem using os.Stat.

Parameters:

  • packFiles: List of .pack file paths (e.g., []string{"objects/pack/pack-abc123.pack"})

Returns:

  • []string: List of missing .ref file names (empty if all present)

Edge cases handled:

  • Empty input: returns empty slice
  • Duplicate pack names: each is checked independently (duplicate .ref entries possible)
  • Files with non-.pack extensions: still processed (constructs .ref by appending if no .pack suffix)
  • Filesystem errors: treats non-existence as missing; other errors are ignored

Example:

packFiles := []string{"objects/pack/pack-abc.pack", "objects/pack/pack-def.pack"}
// If only pack-abc.ref exists on filesystem:
missing := ValidateRefFiles(packFiles) // returns ["objects/pack/pack-def.ref"]

func ValidateRefPath

func ValidateRefPath(path string) error

ValidateRefPath validates a git ref path according to git ref naming rules.

Git ref naming rules (from git-check-ref-format(1)): - Ref names can contain slash (/) for hierarchical naming - Ref name components must not begin with a dot (.) - Ref name components must not contain consecutive dots (..) - Ref names must not contain null bytes - Ref names must not contain question mark (?), asterisk (*), open bracket ([), or backslash (\) - Ref names must not begin or end with a slash - Ref names must not end with a dot (.) - Ref names must not contain consecutive slashes (//) - Ref names must not contain the sequence @{ (used for reflogs) - Ref names must not be the single character @ - Ref names must not contain :\\ (Windows paths)

Parameters:

  • path: The ref path to validate (e.g., "refs/heads/main")

Returns:

  • error: nil if valid, ValidationError with details if invalid

func ValidateSHA

func ValidateSHA(sha string) error

ValidateSHA validates a git SHA string. Returns nil if the SHA is valid (exactly 40 hexadecimal characters).

func ValidateSymbolicRefTarget

func ValidateSymbolicRefTarget(target string) error

ValidateSymbolicRefTarget validates the target of a symbolic ref.

func VerifyGitFsck

func VerifyGitFsck(gitDir string, commitSHAs ...string) (returnErr error)

VerifyGitFsck runs git fsck to verify repository integrity without network access.

This function runs 'git fsck --no-full --no-progress' to verify the integrity of the repository object database. It does not require or perform any network operations.

Parameters:

  • gitDir: Path to the git directory (e.g., "/path/to/repo.git")

Returns:

  • error: nil if fsck passes, error with clear message if corruption detected

Error types returned:

  • ErrNotAGitRepo: if gitDir is not a valid git repository
  • Error with Kind=CorruptPack: if git fsck detects corruption

Example:

if err := VerifyGitFsck(gitDir); err != nil {
    return fmt.Errorf("repository integrity check failed: %w", err)
}

func VerifyGitLog

func VerifyGitLog(gitDir string, commitSHAs ...string) (returnErr error)

VerifyGitLog runs git log to verify commit history is accessible without network access.

This function runs 'git log --oneline -n 1' to verify that git can read commit history. It performs only a local read operation and does not fetch from remotes.

Parameters:

  • gitDir: Path to the git directory (e.g., "/path/to/repo.git")

Returns:

  • error: nil if log succeeds, error if commit history is inaccessible

Error types returned:

  • ErrNotAGitRepo: if gitDir is not a valid git repository
  • Error with Kind=CorruptPack: if git cannot read commit history due to corruption

Example:

if err := VerifyGitLog(gitDir); err != nil {
    return fmt.Errorf("commit history verification failed: %w", err)
}

func VerifyLooseRefFormat

func VerifyLooseRefFormat(gitDir string, refPath string, commitSHAs ...string) (returnErr error)

VerifyLooseRefFormat verifies that a loose ref file on disk has the correct format.

For direct refs, the file content must be exactly 41 bytes: 40 hexadecimal characters followed by a newline. For symbolic refs (starting with "ref:"), the content must not have a trailing newline.

This function is useful for testing and validation to ensure ref files are written correctly by WriteLooseRef.

Parameters:

  • gitDir: Path to the git directory (e.g., "/path/to/repo.git")
  • refPath: Relative ref path (e.g., "refs/heads/main")

Returns:

  • error: nil if format is correct, error otherwise

Error types returned:

  • *Error with Kind=IO: file read failures
  • *Error with Kind=Other: incorrect format (wrong size, invalid SHA, etc.)

Example:

if err := warmstart.VerifyLooseRefFormat("/path/to/repo.git", "refs/heads/main"); err != nil {
    t.Fatalf("ref format validation failed: %v", err)
}

func WriteLooseRef

func WriteLooseRef(gitDir string, ref Ref, commitSHAs ...string) (returnErr error)

WriteLooseRef writes a single ref as a loose file to the git directory.

The function creates the ref file at the correct loose path (e.g., .git/refs/heads/main) with the content formatted as exactly 40 hex characters followed by a newline (41 bytes total) for direct refs. Symbolic refs (starting with "ref:") are written without a trailing newline.

Parent directories are created automatically if they do not exist (e.g., refs/heads/).

Parameters:

  • gitDir: Path to the git directory (e.g., "/path/to/repo.git")
  • ref: Ref struct containing Path and SHA fields

Returns:

  • error: nil on success, error on failure

Error types returned:

  • *Error with Kind=IO: filesystem write failures (permission denied, disk full, etc.)
  • *Error with Kind=Other: invalid ref path or SHA format

Example:

ref := warmstart.Ref{Path: "refs/heads/main", SHA: "abc123...def"}
if err := warmstart.WriteLooseRef("/path/to/repo.git", ref); err != nil {
    return fmt.Errorf("failed to write ref: %w", err)
}

Types

type Config

type Config struct {
	// CoreRepositoryFormatVersion must be "1" for promisor packs.
	CoreRepositoryFormatVersion string `json:"core.repositoryformatversion"`

	// RemoteOriginPromisor enables promisor pack functionality.
	RemoteOriginPromisor string `json:"remote.origin.promisor"`

	// RemoteOriginPartialCloneFilter specifies the filter (e.g., "blob:none").
	RemoteOriginPartialCloneFilter string `json:"remote.origin.partialclonefilter"`
}

Config represents the git configuration values required for warm-start.

func (*Config) Validate

func (c *Config) Validate() error

Validate checks that all required config values are present and valid.

type CorruptionError

type CorruptionError struct {
	// Context describes what was corrupted.
	Context string

	// CommitSHA identifies the commit whose data was corrupted.
	CommitSHA string
}

CorruptionError represents data corruption in the tarball. Deprecated: Use Error with Kind=CorruptPack or Kind=Truncated instead.

func (*CorruptionError) Error

func (e *CorruptionError) Error() string

Error implements the error interface.

func (*CorruptionError) GetCommitSHA

func (e *CorruptionError) GetCommitSHA() string

GetCommitSHA returns the commit associated with the error.

type Error

type Error struct {
	// Kind is the category of error.
	Kind ErrorKind

	// Context provides human-readable details about what went wrong.
	Context string

	// MemberName is the tarball member name (if applicable).
	MemberName string

	// Offset is the byte offset in the tarball (if applicable).
	Offset int64

	// Underlying is the original error (if applicable).
	Underlying error

	// CommitSHA identifies the commit whose warm-start data was being parsed.
	CommitSHA string
}

Error is the structured error type for all tarball operation failures.

func NewCorruptPackError

func NewCorruptPackError(memberName string, context string, commitSHAs ...string) *Error

NewCorruptPackError creates an Error with Kind=CorruptPack.

func NewIOError

func NewIOError(context string, err error, commitSHAs ...string) *Error

NewIOError creates an Error with Kind=IO from an io error.

func NewMissingMemberError

func NewMissingMemberError(memberName string, commitSHAs ...string) *Error

NewMissingMemberError creates an Error with Kind=MissingMember.

func NewMissingMemberErrorWithContext

func NewMissingMemberErrorWithContext(memberName string, context string, commitSHAs ...string) *Error

NewMissingMemberErrorWithContext creates an Error with Kind=MissingMember and additional context. The context should provide human-readable details about what went wrong, such as a list of missing files.

func NewTruncatedError

func NewTruncatedError(context string, offset int64, commitSHAs ...string) *Error

NewTruncatedError creates an Error with Kind=Truncated.

func NewTruncatedMemberError

func NewTruncatedMemberError(memberName string, context string, offset int64, commitSHAs ...string) *Error

NewTruncatedMemberError creates an Error with Kind=Truncated for a specific tarball member.

func (*Error) Error

func (e *Error) Error() string

Error implements the error interface.

func (*Error) ErrorLogFormat

func (e *Error) ErrorLogFormat() commiterrors.LogFormat

ErrorLogFormat adapts the warmstart error hierarchy to the repository-wide severity/type/code and what/why/where/how-to-fix logging contract. Error() remains unchanged for callers that depend on its domain-specific text.

func (*Error) GetCommitSHA

func (e *Error) GetCommitSHA() string

GetCommitSHA returns the commit associated with the error.

func (*Error) Is

func (e *Error) Is(target error) bool

Is allows errors.Is to classify errors by their ErrorKind. This is useful for callers that need to distinguish truncated or missing-member failures without depending on the member-specific details in the error message.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the underlying error for errors.Is/As compatibility.

type ErrorContext

type ErrorContext struct {
	Type       string `json:"type"`                  // Error type (truncated, missing_member, corrupt_pack, io, not_git_repo)
	Message    string `json:"message"`               // Human-readable error message
	MemberName string `json:"member_name,omitempty"` // Tarball member name (if applicable)
	Offset     int64  `json:"offset,omitempty"`      // Byte offset in tarball (if applicable)
	Context    string `json:"context,omitempty"`     // Additional error context
	Cause      string `json:"cause,omitempty"`       // Underlying error (if applicable)
	Path       string `json:"path,omitempty"`        // Repository or artifact path (if applicable)
	Field      string `json:"field,omitempty"`       // Validation field (if applicable)
	Value      string `json:"value,omitempty"`       // Invalid validation value (if applicable)
	RefPath    string `json:"ref_path,omitempty"`    // Git ref path (if applicable)
	StackTrace string `json:"stack_trace,omitempty"` // Stack trace captured at error time
	Recovery   string `json:"recovery,omitempty"`    // Suggested recovery action
	Severity   string `json:"severity,omitempty"`    // Error severity (critical, high, medium, low)
	Formatted  string `json:"formatted,omitempty"`   // Canonical severity/type/code + what/why/where/how-to-fix line
}

ErrorContext contains error details for warmstart operations.

type ErrorKind

type ErrorKind int

ErrorKind represents the category of error that occurred during tarball operations.

const (
	// Truncated indicates the tarball was cut off or incomplete.
	Truncated ErrorKind = iota

	// MissingMember indicates a required tarball member was not found.
	MissingMember

	// CorruptPack indicates pack file data corruption was detected.
	CorruptPack

	// IO indicates an underlying input/output error occurred.
	IO

	// Other indicates an uncategorized error.
	Other
)

func (ErrorKind) String

func (k ErrorKind) String() string

type ExampleMetricsEmitter

type ExampleMetricsEmitter struct{}

ExampleMetricsEmitter is a simple logger-based metrics emitter for testing.

func (*ExampleMetricsEmitter) EmitCounter

func (e *ExampleMetricsEmitter) EmitCounter(name string, labels ...string)

type LogEntry

type LogEntry struct {
	Timestamp time.Time              `json:"timestamp"`          // UTC timestamp when the event occurred
	EventType string                 `json:"event_type"`         // "error" or "validation_error"
	Tarball   TarballContext         `json:"tarball"`            // Tarball operation context
	Error     ErrorContext           `json:"error,omitempty"`    // Error details (if applicable)
	Metadata  map[string]interface{} `json:"metadata,omitempty"` // Additional metadata
}

LogEntry represents a structured warmstart log entry.

func NewErrorLogEntry

func NewErrorLogEntry(operation string, err error, commitSHAs ...string) *LogEntry

NewErrorLogEntry converts every warmstart error type into the shared log entry schema without changing the error or its propagation behavior.

type Logger

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

Logger writes structured logs for warmstart tarball operations and errors.

func NewLogger

func NewLogger() *Logger

NewLogger creates a new warmstart logger that writes to stderr.

func NewLoggerWithHandler

func NewLoggerWithHandler(handler slog.Handler) *Logger

NewLoggerWithHandler creates a warmstart logger around a custom slog handler. Callers can use this to configure log levels, attribute replacement, or a non-JSON destination while retaining warmstart's error-entry schema.

func NewLoggerWithOutput deprecated

func NewLoggerWithOutput(output *log.Logger) *Logger

NewLoggerWithOutput creates a warmstart logger from a legacy log.Logger.

Deprecated: use NewLoggerWithWriter, NewLoggerWithHandler, or NewLoggerWithSlog. This compatibility helper keeps existing callers working while all warmstart records are emitted through log/slog.

func NewLoggerWithSlog

func NewLoggerWithSlog(logger *slog.Logger) *Logger

NewLoggerWithSlog creates a warmstart logger around an initialized slog logger. This is useful when the application already owns logging setup.

func NewLoggerWithWriter

func NewLoggerWithWriter(writer io.Writer) *Logger

NewLoggerWithWriter creates a warmstart logger that emits JSON slog records to writer. It is the common initialization path for production and tests.

func (*Logger) LogError

func (l *Logger) LogError(entry *LogEntry) error

LogError logs a warmstart error with structured context. Falls back to stderr logging if the structured logger fails.

func (*Logger) LogErrorContext

func (l *Logger) LogErrorContext(operation string, err error, commitSHAs ...string) error

LogErrorContext formats and logs err using the warmstart error hierarchy. It is the preferred helper for error sites added by subsequent work.

type MetricEmitter

type MetricEmitter interface {
	EmitCounter(name string, labels ...string)
}

MetricEmitter is an interface for emitting metrics (placeholder for production metrics system).

type NotAGitRepoError

type NotAGitRepoError struct {
	// Path is the directory that was checked.
	Path string

	// Reason explains why it's not a git repository.
	Reason string

	// CommitSHA identifies the commit being materialized.
	CommitSHA string
}

NotAGitRepoError indicates the target directory is not a git repository. Deprecated: Use Error with Kind=Other instead.

func (*NotAGitRepoError) Error

func (e *NotAGitRepoError) Error() string

Error implements the error interface.

func (*NotAGitRepoError) GetCommitSHA

func (e *NotAGitRepoError) GetCommitSHA() string

GetCommitSHA returns the commit associated with the error.

func (*NotAGitRepoError) Is

func (e *NotAGitRepoError) Is(target error) bool

Is allows errors.Is to match NotAGitRepoError against ErrNotAGitRepo.

type Ref

type Ref struct {
	// Path is the reference path (e.g., "refs/heads/main", "refs/tags/v1.0", "HEAD").
	Path string

	// SHA is the 40-character hexadecimal SHA that the reference points to.
	// For symbolic refs, this may start with "ref:" (e.g., "ref: refs/heads/main").
	SHA string
}

Ref represents a single git reference with its path and target SHA. Ref captures both direct references (pointing to a commit SHA) and symbolic references (pointing to another reference).

func FindRef

func FindRef(refs []Ref, path string) (*Ref, bool)

FindRef finds a ref by its path. Returns the ref and true if found, nil and false otherwise.

Parameters:

  • refs: Slice of refs to search
  • path: Exact ref path to find (e.g., "refs/heads/main")

Returns:

  • *Ref: Pointer to the found ref (or nil if not found)
  • bool: True if found, false otherwise

func ParseRefMetadata

func ParseRefMetadata(members []TarballMember, commitSHAs ...string) (_ []Ref, returnErr error)

ParseRefMetadata parses ref metadata from tarball members. It extracts ref name → SHA mappings from tarball entries in both legacy and new formats.

The function handles two tarball formats:

  • Legacy format: A single "ref" file containing "refpath SHA" (e.g., "refs/heads/main abc123")
  • New format: Multiple ref files at their original paths (e.g., "refs/heads/main", "refs/tags/v1.0")

Parameters:

  • members: Slice of TarballMember representing files in the tarball

Returns:

  • []Ref: Slice of parsed references (may be empty if no refs found)
  • error: Error if metadata is malformed (e.g., invalid SHA, empty ref path)

Supported ref types:

  • refs/heads/* (branches)
  • refs/tags/* (tags)
  • refs/remotes/* (remote tracking branches)
  • HEAD (symbolic reference to default branch)

Example:

members := []TarballMember{
    {Name: "refs/heads/main", Data: []byte("abc123...")},
    {Name: "refs/tags/v1.0", Data: []byte("def456...")},
}
refs, err := ParseRefMetadata(members)
// refs would contain [{Path: "refs/heads/main", SHA: "abc123..."}, {Path: "refs/tags/v1.0", SHA: "def456..."}]

func RefsByType

func RefsByType(refs []Ref, refType string) []Ref

RefsByType filters refs by their type (heads, tags, remotes, or other). Returns a new slice containing only refs of the specified type.

Parameters:

  • refs: Slice of refs to filter
  • refType: Type of ref to filter ("heads", "tags", "remotes", or "" for all)

Returns:

  • []Ref: Filtered slice of refs

Example:

heads := RefsByType(refs, "heads")  // All refs/heads/* refs
tags := RefsByType(refs, "tags")    // All refs/tags/* refs

func (*Ref) IsSymbolic

func (r *Ref) IsSymbolic() bool

IsSymbolic returns true if this is a symbolic reference (points to another ref).

func (*Ref) SymbolicTarget

func (r *Ref) SymbolicTarget() string

SymbolicTarget returns the target reference for symbolic refs. Returns empty string for direct refs.

func (*Ref) Validate

func (r *Ref) Validate(commitSHAs ...string) (returnErr error)

Validate checks that a Ref has valid path and SHA fields. Returns error if the ref path or SHA is malformed.

This method validates both the ref path format according to git ref naming rules and the SHA format (40 hexadecimal characters for direct refs, or valid ref path for symbolic refs starting with "ref:").

Error types returned:

  • *ValidationError with detailed context for validation failures
  • Wrapped with ErrInvalidRefMetadata for backward compatibility

type TarballContext

type TarballContext struct {
	Operation string `json:"operation"`            // Operation being performed (parse, materialize, validate)
	CommitSHA string `json:"commit_sha,omitempty"` // Commit SHA associated with the tarball (if known)
	FilePath  string `json:"file_path,omitempty"`  // Path to tarball file or git directory (if applicable)
}

TarballContext contains tarball parsing details.

type TarballMember

type TarballMember struct {
	Name string
	Data []byte
}

TarballMember represents a file in the warm-start tarball.

type ValidationError

type ValidationError struct {
	// Kind is the category of validation error.
	Kind ValidationErrorKind

	// Field is the field being validated (e.g., "Path", "SHA").
	Field string

	// Value is the actual value that failed validation.
	Value string

	// RefPath is the ref path (if applicable).
	RefPath string

	// Context provides additional human-readable details.
	Context string
}

ValidationError represents a validation error with detailed context.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Error implements the error interface.

type ValidationErrorKind

type ValidationErrorKind int

ValidationErrorKind represents the category of validation error.

const (
	// ValidationErrEmptyPath indicates the ref path is empty.
	ValidationErrEmptyPath ValidationErrorKind = iota

	// ValidationErrEmptySHA indicates the SHA is empty.
	ValidationErrEmptySHA

	// ValidationErrInvalidSHALength indicates the SHA is not exactly 40 characters.
	ValidationErrInvalidSHALength

	// ValidationErrInvalidSHAChars indicates the SHA contains non-hex characters.
	ValidationErrInvalidSHAChars

	// ValidationErrNullByteInPath indicates the ref path contains null bytes.
	ValidationErrNullByteInPath

	// ValidationErrInvalidRefPath indicates the ref path violates git ref naming rules.
	ValidationErrInvalidRefPath

	// ValidationErrEmptySymbolicTarget indicates a symbolic ref has an empty target.
	ValidationErrEmptySymbolicTarget
)

func (ValidationErrorKind) String

func (k ValidationErrorKind) String() string

type WarmStartSnapshot

type WarmStartSnapshot struct {
	// PackFiles contains all pack-related files (.pack, .idx, .promisor, .rev).
	PackFiles []TarballMember

	// RefPath is the ref path (e.g., "refs/heads/main").
	RefPath string

	// RefSHA is the SHA the ref points to.
	RefSHA string

	// Config holds the git configuration.
	Config Config
}

WarmStartSnapshot represents the extracted warm-start data.

func ParseTarball

func ParseTarball(data []byte, commitSHAs ...string) (_ *WarmStartSnapshot, returnErr error)

ParseTarball extracts and validates a warm-start tarball. When supplied, commitSHAs[0] is attached to every error returned by this entry point.

Jump to

Keyboard shortcuts

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