plan

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: May 12, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package plan provides plan generation and persistence for mooncake configurations.

Index

Constants

This section is empty.

Variables

View Source
var ErrInputFileMissing = errors.New("input file missing")

ErrInputFileMissing is returned by HashInputFiles when one of the recorded input files no longer exists at apply time. Surfaces as part of the stale-plan policy.

Functions

func HashInputFiles

func HashInputFiles(paths []string) (string, error)

HashInputFiles computes a deterministic hash over the contents of the given files. Used at both plan time (to record what the plan was built from) and apply time (to detect that the source files have changed since).

The hash mixes the file path AND content so renames are detected (different path → different hash even with identical content).

Returns ErrInputFileMissing if any path is unreadable; callers should treat that as a stale-plan condition.

func IsStaleError

func IsStaleError(err error) bool

IsStaleError reports whether err is a stale-plan rejection.

func SavePlanToFile

func SavePlanToFile(p *Plan, filePath string) (err error)

SavePlanToFile saves a plan to a file in JSON or YAML format

func ValidateForApply

func ValidateForApply(p *Plan, opts ValidateOptions) error

ValidateForApply checks that a plan loaded from disk is safe to apply against the current host:

  1. The host facts subset (os_family, arch, distro_family) matches the values captured at plan time.
  2. The on-disk contents of every input file (root config + all includes) hash to the value captured at plan time. Detects unrelated edits to the YAML between plan and apply.
  3. If opts.MaxAge is set, the plan must be younger than that.

Returns nil if all checks pass (or AllowStale is set). Returns a *StaleError otherwise.

Types

type ExpansionContext

type ExpansionContext struct {
	Variables  map[string]interface{}
	CurrentDir string
	Tags       []string
}

ExpansionContext holds the context during plan expansion

type HostFacts

type HostFacts struct {
	OsFamily     string `json:"os_family,omitempty" yaml:"os_family,omitempty"`
	Arch         string `json:"arch,omitempty" yaml:"arch,omitempty"`
	DistroFamily string `json:"distro_family,omitempty" yaml:"distro_family,omitempty"`
}

HostFacts captures the minimum set of facts needed to detect a stale plan being applied on the wrong host. Spec 16's stale-plan policy compares these at apply time and refuses on mismatch unless --allow-stale is set.

Deliberately small. Hostname, kernel version, package versions etc. are too strict and would make plans annoyingly unportable across similar dev machines.

type IncludeFrame

type IncludeFrame struct {
	FilePath string
	Line     int
	Column   int
}

IncludeFrame tracks a frame in the include stack for cycle detection and origin tracking

type Plan

type Plan struct {
	Version        string                 `json:"version" yaml:"version"`
	GeneratedAt    time.Time              `json:"generated_at" yaml:"generated_at"`
	GeneratedOn    HostFacts              `json:"generated_on,omitempty" yaml:"generated_on,omitempty"`
	RootFile       string                 `json:"root_file" yaml:"root_file"`
	InputFiles     []string               `json:"input_files,omitempty" yaml:"input_files,omitempty"`
	InputFilesHash string                 `json:"input_files_hash,omitempty" yaml:"input_files_hash,omitempty"`
	Steps          []config.Step          `json:"steps" yaml:"steps"`
	Inspections    []StepInspection       `json:"inspections,omitempty" yaml:"inspections,omitempty"`
	InitialVars    map[string]interface{} `json:"initial_vars,omitempty" yaml:"initial_vars,omitempty"`
	Tags           []string               `json:"tags,omitempty" yaml:"tags,omitempty"`
}

Plan represents a fully expanded, deterministic execution plan.

Spec 16 adds:

  • Inspections: per-step state predictions
  • GeneratedOn: host facts subset for stale-plan detection
  • InputFiles + InputFilesHash: source-file integrity check so `apply --from-plan` refuses to run plans that no longer match the YAML they were built from.

func LoadPlanFromFile

func LoadPlanFromFile(filePath string) (*Plan, error)

LoadPlanFromFile loads a plan from a JSON or YAML file

type Planner

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

Planner builds deterministic execution plans from config files

func NewPlanner

func NewPlanner() (*Planner, error)

NewPlanner creates a new Planner instance. Returns an error if template renderer initialization fails.

func (*Planner) BuildPlan

func (p *Planner) BuildPlan(cfg PlannerConfig) (*Plan, error)

BuildPlan generates a deterministic execution plan from a config file

func (*Planner) ExpandStepsWithContext

func (p *Planner) ExpandStepsWithContext(steps []config.Step, variables map[string]interface{}, currentDir string) ([]config.Step, error)

ExpandStepsWithContext expands a list of steps with the given context. This is useful for expanding preset steps which may contain includes, loops, etc. Returns the expanded steps ready for execution.

type PlannerConfig

type PlannerConfig struct {
	ConfigPath string
	Variables  map[string]interface{}
	Tags       []string
}

PlannerConfig holds configuration for building a plan

type StaleError

type StaleError struct {
	Reason  StaleReason
	Message string
}

StaleError describes a stale-plan rejection. Callers compare Reason to StaleReason constants; the human Message is suitable for direct display.

func (*StaleError) Error

func (e *StaleError) Error() string

type StaleReason

type StaleReason string

StaleReason identifies why a plan was rejected as stale at apply time. Returned via StaleError so callers can present specific messages or honor a typed --allow-stale override.

const (
	StaleReasonHostMismatch StaleReason = "host_mismatch"
	StaleReasonHashMismatch StaleReason = "input_files_changed"
	StaleReasonFileMissing  StaleReason = "input_file_missing"
	StaleReasonAgeExceeded  StaleReason = "max_age_exceeded"
)

type StepInspection

type StepInspection struct {
	StepID      string `json:"step_id" yaml:"step_id"`
	ActionType  string `json:"action_type,omitempty" yaml:"action_type,omitempty"`
	WouldChange bool   `json:"would_change" yaml:"would_change"`
	Checkable   bool   `json:"checkable" yaml:"checkable"`
	Reason      string `json:"reason,omitempty" yaml:"reason,omitempty"`
	// Skipped reflects when/tag filtering decisions made at plan time.
	// Skipped steps have WouldChange=false and Reason explains why.
	Skipped bool `json:"skipped,omitempty" yaml:"skipped,omitempty"`
}

StepInspection is the result of running a handler in ModePlan against a single step. One inspection per Plan.Steps entry (matched by StepID).

type ValidateOptions

type ValidateOptions struct {
	// MaxAge, when non-zero, rejects plans older than this duration.
	MaxAge time.Duration
	// AllowStale, when true, demotes all stale-plan rejections to a
	// best-effort warning (returned as nil error). The caller is
	// responsible for logging the reasons separately if desired.
	AllowStale bool
}

ValidateOptions controls which checks ValidateForApply runs and what overrides the caller has explicitly enabled.

Jump to

Keyboard shortcuts

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