starters

package
v0.25.0 Latest Latest
Warning

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

Go to latest
Published: Oct 10, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package starters owns the embedded, versioned starter trees that sprout ships and the discovery entry points over them. Instantiating a starter into a project directory lives in instantiate.go; this file is the catalogue: which starters are embedded, what version each tree carries, and what its manifest declares.

Layout: each starter is a directory under data/ holding the files a new project should start with, plus a top-level starter.json descriptor. The descriptor is itself a valid .sprout/starter.json document — the same on-disk schema owned by pkg/startermanifest — and is the source of the manifest that instantiation writes into the new project. Because the version lives inside the tree, a tree and its version always move together: bumping a starter's version is a change to its data/ directory, and starter upgrade detection compares a project's manifest version against Version() (the embedded version).

The trees are embedded with //go:embed, so the package is a pure, stdlib-only consumer of the repository: the CLI (sprout new --starter), the web UI starter list and instantiation endpoint, and WASM builds all link the same trees with no on-disk dependency at runtime.

This package ships a single minimal, test-only fixture starter that proves the mechanism. The product starters (static site, web app, web app with data) and their stack skills land later: a new starter is added by dropping a directory with a valid descriptor into data/ — no Go code change.

Index

Constants

View Source
const DescriptorName = "starter.json"

DescriptorName is the file at the root of each embedded starter tree. It is a valid .sprout/starter.json document (the pkg/startermanifest on-disk schema) declaring the starter's id, version, and commands. It is the one tree file that is never copied verbatim into an instantiated project: its validated form becomes .sprout/starter.json instead (instantiate.go).

Variables

View Source
var (
	// ErrUnknownStarter is returned when the requested starter id has no
	// embedded tree (or its descriptor is missing).
	ErrUnknownStarter = errors.New("starters: unknown starter")

	// ErrInvalidStarterID is returned when the requested starter id is
	// not a safe single path segment (empty, ".", "..", or containing a
	// path separator).
	ErrInvalidStarterID = errors.New("starters: invalid starter id")
)

Errors returned by the package's entry points. Callers branch on them with errors.Is.

View Source
var ErrNonEmptyDestination = errors.New("starters: destination directory is not empty")

ErrNonEmptyDestination is returned by Instantiate when the destination exists and contains any file or directory. The refusal happens before any write, so a refused call leaves the destination exactly as it was.

Functions

func FileCount

func FileCount(starterID string) (int, error)

FileCount returns the number of project-content files that Instantiate writes for starterID: every regular file of the embedded tree except the top-level descriptor (DescriptorName), which becomes .sprout/starter.json instead of a copied file. The manifest writeManifest produces is not counted — it is not a tree file.

The embedded catalogue (List) and the web UI starter list report this number, so a caller sees the tree's size without instantiating anything. A tree whose descriptor is missing or invalid is not a starter the catalogue would list, so FileCount refuses it with the same errors as Manifest.

func Instantiate

func Instantiate(starterID, destDir string) error

Instantiate copies the embedded starter tree for starterID into destDir and writes the starter's manifest to .sprout/starter.json under destDir, so the new project immediately carries a manifest that pkg/starterstore.LoadStarterManifest loads — the manifest is the single source of build/test/dev/preview commands for the project's later consumers (verification, preview, deploys).

Destination contract:

  • destDir does not exist: it is created, including any missing parents.
  • destDir exists and is an empty directory: the tree is written into it.
  • destDir exists and is a file: a clear error.
  • destDir exists and contains anything: Instantiate refuses with ErrNonEmptyDestination and writes nothing.

The copy includes every file and directory of the starter tree except the top-level descriptor (DescriptorName): the descriptor is not project content, its validated form is what becomes .sprout/starter.json.

On a mid-copy failure (e.g. disk full) destDir may be left partially populated; retry into a fresh directory. A refused non-empty destination is always left untouched, because the emptiness check runs before any write.

func Manifest

func Manifest(starterID string) (*startermanifest.StarterManifest, error)

Manifest returns the embedded starter's manifest (its descriptor, validated) for starterID. Consumers that need the starter's commands without instantiating anything — e.g. the web UI starter list — use this instead of reading the tree.

func Version

func Version(starterID string) (string, error)

Version returns the version of the embedded tree for starterID. It is the "embedded version" side of the starter upgrade check: an existing project whose manifest names an older version than this one may be offered an upgrade (and the upgrade is never applied silently).

Types

type Starter

type Starter struct {
	// ID is the starter identifier (the data/ directory name, which the
	// descriptor must agree with).
	ID string
	// Version is the version of the embedded tree (the descriptor's
	// starter.version).
	Version string
}

Starter identifies one embedded starter tree.

func List

func List() ([]Starter, error)

List returns the embedded starters (id and version), sorted by id.

A malformed embedded tree (a starter directory with a missing, corrupt, or id-mismatched descriptor) is a build bug in this repository, so it is surfaced as an error, never skipped: the catalogue is what `sprout new --starter` and GET /api/starters display, and a silently dropped entry would be a worse failure than a loud one.

func ListForUsers

func ListForUsers() ([]Starter, error)

ListForUsers returns the embedded starters a user can actually start a new project from: the full catalogue (List) minus the test-only trees named in testOnlyStarters, still sorted by id. It is what `sprout new --starter` and GET /api/starters display, so a test-only starter whose commands cannot run never reaches a chooser. Addressing a starter by id (Instantiate and friends) is unaffected, so tests and the benchmark keep reaching the fixture directly.

Jump to

Keyboard shortcuts

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