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 ¶
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 ¶
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.
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 ¶
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 ¶
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.
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 ¶
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 ¶
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.