scaffold

package
v1.6.0 Latest Latest
Warning

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

Go to latest
Published: Jun 25, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package scaffold implements the `harbor scaffold` engine — the template registry, the renderer, and the on-disk writer.

The package is BINARY-INTERNAL. Although it lives at `cmd/harbor/scaffold/` (so `cmd/harbor/cmd_scaffold.go` can import it), nothing outside `cmd/harbor` consumes it; in particular no `internal/...` package depends on this surface. The decision to live here rather than under `cmd/harbor/internal/scaffold/` is stylistic — Go's `internal/` rules already restrict reachability to the parent's import tree, which for `cmd/harbor/` is just the binary itself.

Public entry point

scaffold.Scaffold(opts Options) (Result, error) takes:

  • Options.Name — the project name (validated via validateName).
  • Options.Template — the template to render (default DefaultTemplate = "minimal-react").
  • Options.OutputDir — where to write the project tree. The directory MUST NOT exist; Scaffold creates it.

Returns Result{Name, OutputDir (absolute path), Files (relative paths)} on success; otherwise one of the package's sentinel errors:

  • ErrInvalidName — Options.Name failed validateName.
  • ErrOutputDirExists — Options.OutputDir already exists.
  • ErrUnknownTemplate — Options.Template is not in Templates().
  • ErrRender — a template render or filesystem write failed (wrapped with the offending file path).

Template registry

Templates are embedded at compile time via Go's embed package (templates/*). The registry is a write-once package-level map populated in init(); Templates() returns the keys in deterministic order. Harbor ships exactly one template (`minimal-react`).

Concurrency

Scaffold is a pure function — no shared state, no goroutines, no long-lived artifacts. The concurrent-reuse contract is vacuous here; the package is safe for concurrent invocation by construction.

Index

Constants

View Source
const DefaultTemplate = "minimal-react"

DefaultTemplate is the template `harbor scaffold` selects when the operator omits --template. Harbor ships only minimal-react.

Variables

View Source
var (
	// ErrInvalidName signals Options.Name failed validateName. The
	// wrapped message names the offending name + the rule that
	// rejected it.
	ErrInvalidName = errors.New("scaffold: invalid project name")
	// ErrOutputDirExists signals Options.OutputDir already exists.
	// Scaffold refuses to overwrite — operators delete the directory
	// or pick a fresh path. This is the §13 fail-loud posture for an
	// operator-facing seam.
	ErrOutputDirExists = errors.New("scaffold: output directory already exists")
	// ErrUnknownTemplate signals Options.Template is not in Templates().
	// The wrapped message lists every known template.
	ErrUnknownTemplate = errors.New("scaffold: unknown template")
	// ErrRender signals a template execution or filesystem write
	// failed. The wrapped message names the offending file path.
	ErrRender = errors.New("scaffold: render failed")
	// ErrUpstreamConfigInvalid signals the operator-supplied yaml at
	// FromConfigPath failed to load or validate.
	// Wraps the underlying `internal/config.ErrConfigInvalid`.
	ErrUpstreamConfigInvalid = errors.New("scaffold: upstream harbor.yaml is invalid")
)

Sentinel errors. Callers (cmd/harbor/cmd_scaffold.go) compare via errors.Is and map onto CLIError{Code} values.

Functions

func Templates

func Templates() []string

Templates returns the deterministic-order list of registered template names. Harbor ships exactly one entry.

Types

type Options

type Options struct {
	// Name is the project name. Required. Used as the rendered
	// `go.mod` module name's last component, the `harbor.yaml`
	// service-name, and the README title.
	Name string
	// Template selects which embedded template tree to render. Empty
	// defaults to DefaultTemplate. The set of allowed values comes
	// from Templates().
	Template string
	// OutputDir is the directory Scaffold creates and writes the
	// rendered project into. Required. Without `Patch`, the path is
	// resolved with `filepath.Abs` and MUST NOT exist on disk; with
	// `Patch`, an existing directory is accepted and existing files
	// are skipped.
	OutputDir string
	// FromConfigPath is the optional path to an operator-edited
	// `harbor.yaml`. When set, Scaffold loads +
	// validates it and uses its `tools.custom[]` entries to generate
	// per-tool Go stubs under `OutputDir/tools/`. Empty + no
	// `./harbor.yaml` in the cwd ⇒ Scaffold falls back to the
	// template-only behavior (the existing scaffold-without-init
	// path stays valid).
	FromConfigPath string
	// Patch relaxes the refuse-overwrite default.
	// When true, an existing OutputDir is accepted and Scaffold writes
	// only files that do NOT already exist; existing files are
	// skipped and listed under `Result.Skipped`. The operator-edit
	// survival invariant.
	Patch bool
}

Options is the input to Scaffold.

type Result

type Result struct {
	Name      string   `json:"name"`
	OutputDir string   `json:"output_dir"`
	Files     []string `json:"files"`
	Skipped   []string `json:"skipped,omitempty"`
}

Result reports what Scaffold wrote. Files are paths RELATIVE to OutputDir, in deterministic (lexicographic) order — a smoke script or scripted consumer can rely on the ordering.

`Skipped` lists files that were already on disk at scaffold time and were therefore NOT overwritten. Only populated when `Options.Patch == true`; non-patch runs reject existing output dirs outright.

func Scaffold

func Scaffold(opts Options) (Result, error)

Scaffold materialises the named template at opts.OutputDir.

Validation order (fail-loud, no partial writes):

  1. opts.Name is validated via validateName.
  2. opts.Template (empty → DefaultTemplate) must be a registered template.
  3. opts.OutputDir is resolved via filepath.Abs and (in default mode) MUST NOT exist. With `opts.Patch == true`, an existing directory is accepted; existing files are skipped.

Upstream config: when `opts.FromConfigPath` is set OR `./harbor.yaml` exists in the cwd, Scaffold loads + validates it via `internal/config.Load`. Its `tools.custom[]` entries drive per-tool stub generation; the yaml file itself is copied verbatim into OutputDir/harbor.yaml (overriding the template-rendered yaml).

On success, every template file is rendered through text/template and written to OutputDir/<rel-path>. The returned Result.Files is the lexicographic-order list of relative paths written; Result.Skipped lists files left untouched in patch mode.

On any failure during a NON-patch run after the output dir has been created, Scaffold removes the dir before returning so the operator never sees a half-scaffolded project. Patch runs do not roll back — the operator's pre-existing files are sacred.

Jump to

Keyboard shortcuts

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