Documentation
¶
Overview ¶
Package initctx reads the room for a bare `lo init`: where the user stands (a project root, a subdirectory, a service directory, a submodule under an umbrella project, an empty or a bare directory), what git says about it, what the project already has, and whether a terminal is attached. Detect is the read side; Decide turns the state and the wizard's answers into the ordered list of actions the cli executes through the existing subcommands; Ask is the huh form layer.
Everything here is pure over the filesystem except the two git reads, which go through the execx.Runner seam so the tests script them.
Index ¶
- Variables
- func Confirm(tio IO, network bool) (bool, error)
- func DefaultDir(s State) string
- func DefaultEnv(s State, dir string) string
- func WriteCard(w io.Writer, s State)
- func WriteOptions(w io.Writer, s State)
- func WriteSummary(w io.Writer, p Plan, cwd string)
- type Action
- type ActionKind
- type Answers
- type Domain
- type Git
- type IO
- type Option
- type Plan
- type Project
- type Situation
- type State
- type Terminal
Constants ¶
This section is empty.
Variables ¶
var ErrAborted = errors.New("lo init: aborted")
ErrAborted is returned when the user leaves the form (Ctrl-C, Esc).
Functions ¶
func Confirm ¶
Confirm is the summary step's question; network says whether a step needs the network (the question mentions it).
func DefaultDir ¶
DefaultDir is the project directory a new project defaults to: the git root when the user stands below it, else the working directory.
func DefaultEnv ¶
DefaultEnv is the environment file a directory suggests: the one it already has, else mise.
func WriteOptions ¶
WriteOptions prints the menu of an existing project as hints (the `--plan` output when there is nothing to do).
Types ¶
type Action ¶
type Action struct {
Kind ActionKind
// Summary says what the step writes or runs, in one line.
Summary string
// Command is the flag-twin command line, run from Plan.Dir.
Command string
// Network is whether the step needs the network.
Network bool
// The parameters the executor hands to the functions behind Command.
Name, Env, Domain, Driver, Service, ServicePath, Implementation string
Groups []string
}
Action is one step of a Plan.
type ActionKind ¶
type ActionKind string
ActionKind names one action of a Plan.
const ( // ActionWriteProjectFiles — clusters/, lok8s.yaml, the .gitignore // entries and (with Env) the environment file, plus (with Domain) the // first cluster spec: one `lo init project` run. ActionWriteProjectFiles ActionKind = "project files" // ActionGitInit — `git init` in the project directory. ActionGitInit ActionKind = "git init" // ActionWriteEnvFile — the environment file into an existing project. ActionWriteEnvFile ActionKind = "environment file" // ActionWriteClusterSpec — clusters/<domain>/cluster.lok8s.yaml into // an existing project. ActionWriteClusterSpec ActionKind = "cluster spec" // ActionEjectBash — `lo assets eject bash`. ActionEjectBash ActionKind = "eject bash" // ActionSetImplementation — spec.implementation.default in lok8s.yaml. ActionSetImplementation ActionKind = "implementation" // ActionToolchainInstall — `lo toolchain install` (network). ActionToolchainInstall ActionKind = "toolchain" // ActionUse — `lo use <domain>`. ActionUse ActionKind = "use" // ActionAddService — `lo init service <name>`. ActionAddService ActionKind = "service" // ActionAddTests — `lo init test`. ActionAddTests ActionKind = "tests" // ActionRegisterService — the service directory into services.yaml. ActionRegisterService ActionKind = "register service" )
type Answers ¶
type Answers struct {
// Dir is the project directory for a new project ("" = the situation's
// default: the working directory, or the git root below which the
// user stands). Ignored inside an existing project (its root).
Dir string
// Name is metadata.name ("" = the directory name).
Name string
// Env is the environment file: mise, direnv or none ("" = the one the
// directory already has, else mise). Inside an existing project it
// only matters when none exists yet.
Env string
// GitInit asks for `git init` (honoured only without a repository).
GitInit bool
// Domain and Driver describe the first (or an added) cluster spec;
// "" = none.
Domain, Driver string
// Use makes Domain the active domain (`lo use`).
Use bool
// Toolchain runs `lo toolchain install` with Groups (nil = the
// default groups).
Toolchain bool
Groups []string
// Implementation switches spec.implementation.default ("" = keep;
// "bash" ejects the tree first when the project has none).
Implementation string
// Service adds a service (`lo init service <name>`); Tests the
// Playwright suite; Register adds the service directory the user
// stands in to services.yaml.
Service string
Tests bool
Register bool
}
Answers is what the wizard asked (or the defaults `--plan` assumes). Every field has a flag twin on an existing subcommand; Decide prints it.
func Ask ¶
Ask runs the conversation for s and returns the answers. Nothing is written: the caller decides (Decide), prints the summary and asks Confirm before it executes anything.
func DefaultAnswers ¶
DefaultAnswers are what `--plan` assumes without a conversation: a new project gets its files where the situation suggests, `git init` when git exists and there is no repository, the environment file the directory already has (else mise) and the toolchain; an existing project gets nothing (the card, and the menu as hints).
type Domain ¶
type Domain struct {
Name string
// Kind is the driver of cluster.lok8s.yaml (lowercase), "deploy" for
// a deploy-only domain, "?" when unreadable.
Kind string
}
Domain is one directory under clusters/ that carries a spec.
type Git ¶
type Git struct {
// Available is whether git ran at all.
Available bool
// Root is the repository root ("" = not a repository).
Root string
// AtRoot is whether cwd is the repository root.
AtRoot bool
// Dirty is whether `git status --porcelain` printed anything.
Dirty bool
// Submodule is whether Root carries a `.git` FILE (a submodule
// checkout, or a worktree) rather than a directory.
Submodule bool
}
Git is what git says about the working directory.
type IO ¶
type IO struct {
In io.Reader
Out io.Writer
// Accessible runs the fields as line prompts instead of the
// interactive forms (off a TTY; the tests).
Accessible bool
}
IO is where a form reads and writes.
type Option ¶
Option is one entry of the "what to add" menu in an existing project, with the flag twin the card prints as a hint.
type Plan ¶
type Plan struct {
Situation Situation
// Dir is the project directory every action runs in (absolute).
Dir string
// Name is the project name the actions use.
Name string
// Actions in execution order; empty = nothing to do.
Actions []Action
}
Plan is the ordered list of actions for one `lo init` run.
func Decide ¶
Decide turns the state and the answers into the plan. Answers that do not apply to the situation are ignored (a `git init` inside a repository, a registration outside a service directory).
type Project ¶
type Project struct {
// Root is the project root (the marker walk from cwd).
Root string
// AtRoot is whether cwd is Root.
AtRoot bool
// Name is metadata.name of the project file ("" when the marker is
// clusters/ alone).
Name string
// ProjectFile is whether Root/lok8s.yaml is a `kind: Project` file.
ProjectFile bool
// Clusters is whether Root/clusters exists.
Clusters bool
// Domains lists the domains under clusters/ that carry a spec.
Domains []Domain
// Active is clusters/.active ("" when unset or invalid).
Active string
// EnvFile is the environment file present: "mise" (mise.toml),
// "direnv" (.envrc), "" (none). With both present, mise.
EnvFile string
// BYAML is whether .bin/b.yaml exists; BYAMLMarker whether `lo
// toolchain install` wrote it.
BYAML, BYAMLMarker bool
// ToolsMissing lists the pinned tools that do not resolve under the
// project (b, kustomize, the two exec plugins); nil = all present.
ToolsMissing []string
// BashTree is whether Root/.lok8s/lo exists (an ejected or vendored
// bash tree).
BashTree bool
// Implementation is spec.implementation.default ("go" or "bash";
// "go" when the block is absent), ImplementationErr the loader's
// error text when the block is invalid.
Implementation string
ImplementationErr string
// Services is whether Root/services.yaml exists; Tests whether
// Root/tests is a directory.
Services, Tests bool
}
Project is what exists in the project the user stands in.
type Situation ¶
type Situation int
Situation is one of the five conversations `lo init` can have.
const ( // SituationUnknown is the zero value; Detect never returns it. SituationUnknown Situation = iota // SituationEmptyDir — an empty directory (a `.git` entry does not // count) and no project above: the welcome conversation. SituationEmptyDir // SituationGitBelowRoot — inside a git repository, below its root, // and no project above: the wizard suggests the git root. SituationGitBelowRoot // SituationBareDir — a non-empty directory, no project above, and // either no git or cwd is the git root: the wizard says what it sees // and offers here or a subdirectory. SituationBareDir // SituationProjectRoot — cwd is a project root: the status card, then // what to add. SituationProjectRoot // SituationInsideProject — cwd is inside a project (a subdirectory, a // service directory, a submodule under the umbrella project): the // card, plus the offer to register a service directory. SituationInsideProject )
type State ¶
type State struct {
// Cwd is the working directory, absolute.
Cwd string
// Empty is whether Cwd has no entries besides `.git`.
Empty bool
// Entries counts the entries of Cwd besides `.git`.
Entries int
// ServiceDir is whether Cwd holds a kind-less lok8s.yaml (a service
// directory).
ServiceDir bool
// Git is the git state; Project the project state (nil = no project
// above Cwd).
Git Git
Project *Project
// Terminal is set by the caller (DetectTerminal); Detect leaves it
// zero.
Terminal Terminal
}
State is what Detect found.
func Detect ¶
Detect reads the room from cwd. r runs git (nil = no git: the state reports it unavailable).
func (State) ServiceName ¶
ServiceName is the service name a service directory implies (its base name), "" outside one.
type Terminal ¶
type Terminal struct {
// StdinTTY and StdoutTTY report whether the two streams are terminals.
StdinTTY, StdoutTTY bool
// CI is whether the CI environment variable is set (any value).
CI bool
// Yes is the --yes flag.
Yes bool
}
Terminal is what decides between the wizard and the help text.
func DetectTerminal ¶
DetectTerminal reads the two streams and the CI variable.
func (Terminal) Interactive ¶
Interactive reports whether the wizard may run: both streams are terminals, CI is unset and --yes was not given.