bundler

package
v0.2.0 Latest Latest
Warning

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

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

Documentation

Index

Constants

View Source
const (
	// BundleManifestVersion1 is the original tar-based bundle format.
	BundleManifestVersion1 = 1

	// BundleManifestVersion2 is the content-addressable deduplicated format.
	BundleManifestVersion2 = 2

	// DefaultDedupeThreshold is the minimum file size for individual layer extraction.
	// Files smaller than this are grouped into a single tar layer.
	DefaultDedupeThreshold int64 = 4 * 1024 // 4 KB
)
View Source
const (
	// LockFileVersion is the current lock file format version.
	LockFileVersion = 1

	// DefaultLockFileName is the default lock file name.
	DefaultLockFileName = "solution.lock"
)
View Source
const (
	// BundleManifestPath is the path within the tar archive for the bundle manifest.
	BundleManifestPath = ".scafctl/bundle-manifest.json"

	// DefaultMaxBundleSize is the default maximum total size of bundled files (50 MB).
	DefaultMaxBundleSize int64 = 50 * 1024 * 1024
)
View Source
const (
	// VendorDirName is the directory name within the bundle for vendored artifacts.
	VendorDirName = ".scafctl/vendor"
)

Variables

This section is empty.

Functions

func CheckVersionConstraint

func CheckVersionConstraint(constraint, resolved string) (bool, error)

CheckVersionConstraint checks if a resolved version satisfies a version constraint.

func Compose

func Compose(sol *solution.Solution, bundleRoot string, opts ...ComposeOption) (*solution.Solution, error)

Compose loads and merges all composed files referenced by the solution. The composed files are expected to contain partial YAML with spec.resolvers, spec.workflow.actions, and/or bundle.include sections.

Returns a new Solution with all parts merged. The original is not modified. bundleRoot is the directory containing the root solution YAML — composed file paths are resolved relative to it.

Merge rules:

  • Resolvers: merged by name. Duplicate resolver names across files are rejected.
  • Actions: merged by name. Duplicate action names across files are rejected.
  • Finally actions: merged by name. Same duplicate rules apply.
  • bundle.include: unioned (deduplicated).
  • Circular compose references are detected and rejected.

func ExtractDeduplicatedBundle

func ExtractDeduplicatedBundle(manifest *BundleManifest, destDir string, layerFetcher func(layer int) ([]byte, error)) error

ExtractDeduplicatedBundle extracts a version 2 bundle from individual OCI layers. layerFetcher returns the raw bytes of a layer by its 0-based index.

func MergePluginDefaults

func MergePluginDefaults(sol *solution.Solution)

MergePluginDefaults shallow-merges plugin default inputs beneath inline provider inputs in the solution's resolvers and actions. Inline inputs always win. This should be called before DAG construction so that the DAG sees the merged result.

func ValidatePlugins

func ValidatePlugins(sol *solution.Solution) error

ValidatePlugins validates all plugin declarations in a solution's bundle. Returns an error if any plugin has invalid name, kind, or version constraint.

func VendorFileNameFromRef

func VendorFileNameFromRef(ref string, info catalog.ArtifactInfo) string

VendorFileNameFromRef generates the file name for a vendored artifact (exported).

func WriteLockFile

func WriteLockFile(path string, lf *LockFile) error

WriteLockFile serializes and writes the lock file to the given path.

Types

type BundleFileEntry

type BundleFileEntry struct {
	// Path is the file's path relative to the bundle root.
	Path string `json:"path"`
	// Size is the file size in bytes.
	Size int64 `json:"size"`
	// Digest is the SHA-256 content digest.
	Digest string `json:"digest"`
	// Layer is the OCI layer index for this file (version 2 only).
	// In version 1 manifests, this is omitted (all files are in the tar layer).
	Layer int `json:"layer,omitempty"`
}

BundleFileEntry describes a single file in the bundle.

type BundleManifest

type BundleManifest struct {
	// Version is the manifest format version.
	Version int `json:"version"`
	// Root is the bundle root directory (always ".").
	Root string `json:"root"`
	// Files lists all bundled files with their paths, sizes, and content digests.
	Files []BundleFileEntry `json:"files"`
	// Plugins lists plugin dependencies (informational, recorded from bundle.plugins).
	Plugins []BundlePluginEntry `json:"plugins,omitempty"`
}

BundleManifest describes the contents of a bundle tar archive.

func CreateBundleTar

func CreateBundleTar(bundleRoot string, files []FileEntry, plugins []BundlePluginEntry, opts ...TarOption) ([]byte, *BundleManifest, error)

CreateBundleTar creates a tar archive containing the discovered files and a bundle manifest. Returns the tar bytes and the manifest.

func ExtractBundleTar

func ExtractBundleTar(tarData []byte, destDir string) (*BundleManifest, error)

ExtractBundleTar extracts a bundle tar archive to a destination directory. Returns the bundle manifest.

func ExtractBundleTarFromReader

func ExtractBundleTarFromReader(r io.Reader, destDir string) (*BundleManifest, error)

ExtractBundleTarFromReader extracts a tar archive from a reader to a destination directory.

type BundlePluginEntry

type BundlePluginEntry struct {
	// Name is the plugin's catalog reference.
	Name string `json:"name"`
	// Kind is the plugin type (provider, auth-handler).
	Kind string `json:"kind"`
	// Version is the semver constraint.
	Version string `json:"version"`
}

BundlePluginEntry describes a plugin dependency in the bundle manifest.

func PluginsToBundleEntries

func PluginsToBundleEntries(plugins []solution.PluginDependency) []BundlePluginEntry

PluginsToBundleEntries converts solution plugin dependencies to bundle manifest entries.

type CatalogFetcher

type CatalogFetcher interface {
	// FetchSolution retrieves a solution by name[@version] and returns
	// the content bytes, the resolved reference info, and any error.
	FetchSolution(ctx context.Context, nameWithVersion string) (content []byte, info catalog.ArtifactInfo, err error)
}

CatalogFetcher fetches solution content from a catalog by reference.

type CatalogRefEntry

type CatalogRefEntry struct {
	// Ref is the original catalog reference (e.g., "deploy-to-k8s@2.0.0").
	Ref string
	// VendorPath is the path within the bundle where the vendored artifact is stored.
	VendorPath string
}

CatalogRefEntry represents a catalog dependency to vendor.

type ComposeOption

type ComposeOption func(*composeConfig)

ComposeOption configures Compose behavior.

func WithReadFileFunc

func WithReadFileFunc(fn func(string) ([]byte, error)) ComposeOption

WithReadFileFunc overrides the function used to read composed files. Useful for testing without touching the filesystem.

type DedupeFileBlob

type DedupeFileBlob struct {
	// RelPath is the file path relative to the bundle root.
	RelPath string
	// Content is the file's raw bytes.
	Content []byte
	// Digest is the SHA-256 content digest.
	Digest string
	// Size is the file size in bytes.
	Size int64
	// Layer is the 0-based layer index in the OCI manifest (set after partitioning).
	Layer int
}

DedupeFileBlob represents a single file prepared for content-addressable storage.

type DedupeOption

type DedupeOption func(*dedupeConfig)

DedupeOption configures deduplication behavior.

func WithDedupeMaxSize

func WithDedupeMaxSize(size int64) DedupeOption

WithDedupeMaxSize sets the maximum total size of all bundled files.

func WithDedupeReadFileFunc

func WithDedupeReadFileFunc(fn func(string) ([]byte, error)) DedupeOption

WithDedupeReadFileFunc overrides the file reading function for testing.

func WithDedupeThreshold

func WithDedupeThreshold(size int64) DedupeOption

WithDedupeThreshold sets the minimum file size for individual blob layers. Files smaller than this threshold are grouped into a combined tar layer.

type DedupeResult

type DedupeResult struct {
	// Manifest is the bundle manifest (version 2).
	Manifest *BundleManifest
	// ManifestJSON is the serialized manifest.
	ManifestJSON []byte
	// LargeBlobs are individual file blobs stored as separate OCI layers.
	LargeBlobs []DedupeFileBlob
	// SmallBlobsTar is a tar archive of files below the dedup threshold.
	// May be nil if there are no small files.
	SmallBlobsTar []byte
	// TotalSize is the sum of all file sizes.
	TotalSize int64
}

DedupeResult contains the output of content-addressable deduplication.

func CreateDeduplicatedBundle

func CreateDeduplicatedBundle(bundleRoot string, files []FileEntry, plugins []BundlePluginEntry, opts ...DedupeOption) (*DedupeResult, error)

CreateDeduplicatedBundle prepares files for content-addressable OCI storage. Large files (>= threshold) become individual layers; small files are tarred together. Returns a DedupeResult containing the manifest and all blobs to push.

type DiscoverOption

type DiscoverOption func(*discoverConfig)

DiscoverOption configures DiscoverFiles behavior.

func WithDiscoverReadFileFunc

func WithDiscoverReadFileFunc(fn func(string) ([]byte, error)) DiscoverOption

WithDiscoverReadFileFunc overrides os.ReadFile for testing.

func WithIgnoreChecker

func WithIgnoreChecker(ic IgnoreChecker) DiscoverOption

WithIgnoreChecker sets a custom ignore checker for file exclusion.

func WithStatFunc

func WithStatFunc(fn func(string) (os.FileInfo, error)) DiscoverOption

WithStatFunc overrides os.Stat for testing.

func WithWalkDirFunc

func WithWalkDirFunc(fn func(string, filepath.WalkFunc) error) DiscoverOption

WithWalkDirFunc overrides filepath.Walk for testing.

type DiscoveryResult

type DiscoveryResult struct {
	// LocalFiles are local file paths relative to the bundle root.
	LocalFiles []FileEntry
	// CatalogRefs are catalog references to vendor.
	CatalogRefs []CatalogRefEntry
}

DiscoveryResult contains all files and dependencies discovered during analysis.

func DiscoverFiles

func DiscoverFiles(sol *solution.Solution, bundleRoot string, opts ...DiscoverOption) (*DiscoveryResult, error)

DiscoverFiles performs static analysis on a parsed (and composed) solution to find local file references and catalog references, then combines them with explicit bundle includes.

Returns deduplicated lists of local files and catalog references.

type DiscoverySource

type DiscoverySource int

DiscoverySource indicates how a file was discovered for bundling.

const (
	// StaticAnalysis means the file was discovered by walking provider inputs.
	StaticAnalysis DiscoverySource = iota
	// ExplicitInclude means the file was declared in bundle.include.
	ExplicitInclude
)

func (DiscoverySource) String

func (d DiscoverySource) String() string

String returns a human-readable label for the discovery source.

type DynamicPathWarning

type DynamicPathWarning struct {
	// Location describes where in the solution the dynamic path was found
	// (e.g., "resolver 'templatePath'").
	Location string
	// Kind is the type of dynamic reference ("expr", "tmpl", "rslvr").
	Kind string
	// Expression is the dynamic expression value.
	Expression string
}

DynamicPathWarning describes a provider input that uses a dynamic path (CEL expression, Go template, or resolver binding) which cannot be statically analyzed for file bundling.

func DetectDynamicPaths

func DetectDynamicPaths(sol *solution.Solution) []DynamicPathWarning

DetectDynamicPaths scans a solution for provider inputs that use dynamic paths (CEL, Go templates, resolver bindings) in file-related fields. These paths cannot be statically analyzed and should be covered by bundle.include patterns.

type FileEntry

type FileEntry struct {
	// RelPath is the path relative to the bundle root.
	RelPath string
	// Source indicates how the file was discovered.
	Source DiscoverySource
}

FileEntry represents a local file to be bundled.

type IgnoreChecker

type IgnoreChecker interface {
	// IsIgnored returns true if the given relative path should be excluded.
	IsIgnored(relPath string) bool
}

IgnoreChecker determines whether a file path should be excluded from bundling.

func LoadScafctlIgnore

func LoadScafctlIgnore(bundleRoot string) (IgnoreChecker, error)

LoadScafctlIgnore reads a .scafctlignore file and returns an IgnoreChecker. If the file does not exist, a no-op checker is returned (nothing is ignored).

func LoadScafctlIgnoreFrom

func LoadScafctlIgnoreFrom(path string) (IgnoreChecker, error)

LoadScafctlIgnoreFrom reads ignore patterns from a specific file path.

func ParseIgnorePatterns

func ParseIgnorePatterns(patterns []string) IgnoreChecker

ParseIgnorePatterns creates an IgnoreChecker from a list of pattern strings. Useful for testing.

type LockDependency

type LockDependency struct {
	// Ref is the original catalog reference (e.g., "deploy-to-k8s@2.0.0").
	Ref string `json:"ref" yaml:"ref" doc:"Original catalog reference" maxLength:"255" example:"deploy-to-k8s@2.0.0"`

	// Digest is the SHA-256 content digest of the vendored file.
	Digest string `json:"digest" yaml:"digest" doc:"SHA-256 content digest" maxLength:"128" example:"sha256:abc123..."`

	// ResolvedFrom is the catalog name from which the dependency was fetched.
	ResolvedFrom string `json:"resolvedFrom" yaml:"resolvedFrom" doc:"Source catalog name" maxLength:"255" example:"company-catalog"`

	// VendoredAt is the path relative to the bundle root where the file is stored.
	VendoredAt string `` /* 139-byte string literal not displayed */
}

LockDependency records metadata about a vendored catalog dependency.

type LockFile

type LockFile struct {
	// Version is the lock file format version.
	Version int `json:"version" yaml:"version" doc:"Lock file format version" example:"1"`

	// Dependencies lists vendored solution dependencies with their digests.
	Dependencies []LockDependency `json:"dependencies,omitempty" yaml:"dependencies,omitempty" doc:"Vendored solution dependencies" maxItems:"1000"`

	// Plugins lists vendored plugin dependencies with their digests.
	Plugins []LockPlugin `json:"plugins,omitempty" yaml:"plugins,omitempty" doc:"Vendored plugin dependencies" maxItems:"100"`
}

LockFile represents the lock file that records vendored dependency state. It enables reproducible builds by replaying exact versions and digests.

func LoadLockFile

func LoadLockFile(path string) (*LockFile, error)

LoadLockFile reads and parses a lock file from the given path. Returns nil without error if the file does not exist.

func (*LockFile) FindDependency

func (lf *LockFile) FindDependency(ref string) *LockDependency

FindDependency returns the lock entry for the given ref, or nil if not found.

func (*LockFile) FindPlugin

func (lf *LockFile) FindPlugin(name, kind string) *LockPlugin

FindPlugin returns the lock entry for a plugin by name and kind, or nil if not found.

type LockPlugin

type LockPlugin struct {
	// Name is the plugin name.
	Name string `json:"name" yaml:"name" doc:"Plugin name" maxLength:"100" example:"azure-provider"`

	// Kind is the plugin kind (e.g., "provider", "auth-handler").
	Kind string `json:"kind" yaml:"kind" doc:"Plugin kind" maxLength:"50" example:"provider"`

	// Version is the resolved version string.
	Version string `json:"version" yaml:"version" doc:"Resolved version" maxLength:"50" example:"1.2.3"`

	// Digest is the SHA-256 content digest.
	Digest string `json:"digest" yaml:"digest" doc:"SHA-256 content digest" maxLength:"128" example:"sha256:abc123..."`

	// ResolvedFrom is the source registry or catalog.
	ResolvedFrom string `json:"resolvedFrom" yaml:"resolvedFrom" doc:"Source registry or catalog" maxLength:"255" example:"plugins.example.com"`
}

LockPlugin records metadata about a vendored plugin dependency.

type ScafctlIgnore

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

ScafctlIgnore implements IgnoreChecker using .scafctlignore rules. It supports a subset of .gitignore syntax:

  • Blank lines and lines starting with # are ignored.
  • Patterns are matched against relative paths using filepath.Match.
  • A trailing / matches only directories (not supported yet — treated as prefix match).
  • A leading / anchors to the bundle root.
  • ** is supported via doublestar matching.

func (*ScafctlIgnore) IsIgnored

func (si *ScafctlIgnore) IsIgnored(relPath string) bool

IsIgnored returns true if the relative path matches any ignore pattern.

type TarOption

type TarOption func(*tarConfig)

TarOption configures tar creation behavior.

func WithMaxBundleSize

func WithMaxBundleSize(size int64) TarOption

WithMaxBundleSize sets the maximum total size for the bundle.

func WithTarReadFileFunc

func WithTarReadFileFunc(fn func(string) ([]byte, error)) TarOption

WithTarReadFileFunc overrides the file reading function for testing.

type VendorOptions

type VendorOptions struct {
	// BundleRoot is the root directory of the solution bundle.
	BundleRoot string
	// VendorDir is the directory to store vendored artifacts.
	VendorDir string
	// LockPath is the path to the lock file.
	LockPath string
	// CatalogFetcher fetches artifacts from catalogs by name[@version].
	// If nil, vendoring will fail when catalog refs are discovered.
	CatalogFetcher CatalogFetcher
}

VendorOptions configures the vendoring process.

type VendorResult

type VendorResult struct {
	// VendoredFiles contains relative paths (from bundle root) to vendored files.
	VendoredFiles []string
	// Lock is the updated lock file content.
	Lock *LockFile
}

VendorResult describes the outcome of a vendoring operation.

func VendorDependencies

func VendorDependencies(ctx context.Context, sol *solution.Solution, refs []CatalogRefEntry, opts VendorOptions) (*VendorResult, error)

VendorDependencies fetches catalog dependencies, stores them locally, rewrites source references in the solution, and writes a lock file.

Jump to

Keyboard shortcuts

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