statefile

package
v0.0.3 Latest Latest
Warning

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

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

Documentation

Overview

Package statefile is the one place forge's JSON-record-under-.forge/state helpers live. Three callers — internal/cli (build_state.go), internal/buildtarget (per-service build state), and internal/deploytarget (per-provider deploy state) — each used to hand-roll the same MkdirAll + MarshalIndent + WriteFile dance and the same missing-file-is-nil read, against the same hard-coded `.forge/state` directory. They drifted: only deploytarget sanitized the env/service path segments before joining them into a filename, so buildtarget's statePath was a latent path-traversal smell. Hoisting the IO here makes the on-disk dir, the file mode, and the one sanitizer a single source of truth.

Scope is deliberately small: this package owns *how* a record is read and written (directory, modes, JSON encoding, missing-file semantics), NOT *what* the record is or how its filename is composed. Each caller keeps its own struct and its own filename builder — the filename shapes (build-<env>.json, build-<env>-<service>.json, <provider>-<env>-<service>.json) are part of each caller's on-disk contract and must stay stable so existing state files keep loading.

Index

Constants

View Source
const DirRel = ".forge/state"

DirRel is the per-project on-disk location, relative to the project root (the directory holding forge.yaml), for forge runtime state that must survive across `forge build` / `forge deploy` invocations. Sits under .forge/ so the single existing `.forge/` .gitignore rule covers it alongside checksums.json and the ownership state.

Variables

This section is empty.

Functions

func Path

func Path(projectDir, filename string) string

Path joins the project root, .forge/state, and a caller-built filename into the absolute path of a state file. The filename is the caller's responsibility (each caller owns its own on-disk filename shape); Path just centralizes the directory so the layout lives in one place.

func Read

func Read[T any](path, label string) (*T, error)

Read loads and JSON-decodes the state file at path into a freshly allocated *T. A missing file returns (nil, nil) — every caller treats "no state file" as a non-error "no previous record" signal distinct from "file exists but is malformed", which returns (nil, err). label names the record in error messages.

func SafeSegment

func SafeSegment(s string) string

SafeSegment sanitizes one path segment (an env or service name) down to a flat filename-safe token: [A-Za-z0-9_-] pass through, everything else (path separators included) becomes '_'. The inputs are KCL-validated identifiers in practice, but a state filename is composed from them, so we strip separators defensively to keep the write inside .forge/state. An empty input yields "_" so the segment is never empty.

func Write

func Write(path, label string, v any) error

Write marshals v as indented JSON and persists it to the state file at path, creating .forge/state lazily so projects that never touch a given state path never grow the tree. The 2-space MarshalIndent and 0o644 mode match what all three legacy impls produced, so on-disk files are byte-for-byte unchanged. label names the record in error messages (e.g. "build state", "deploy state").

Types

This section is empty.

Jump to

Keyboard shortcuts

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