Documentation
¶
Overview ¶
Package initctx is the state and the screens of a bare `lo init`. Detect reads 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; what the project has; whether a terminal is attached. Decide turns the state and the answers into the ordered actions the cli runs through the verbs. The screens (screen.go) and project mode (loop.go) are the huh forms.
Everything here reads the filesystem only. The three git reads go through the execx.Runner seam, so the tests script them.
Index ¶
- Constants
- Variables
- func Bootstrap(s State) bool
- func DefaultDir(s State) string
- func DefaultEnv(s State, dir string) string
- func DefaultName(dir string) string
- func Next(s State, drift bool) string
- func Welcome(w io.Writer, s State)
- func WriteCard(w io.Writer, s State, extra ...row)
- func WriteEntries(w io.Writer, entries []Entry, extra ...row)
- func WriteNext(w io.Writer, next string)
- func WritePlan(w io.Writer, s State)
- func WriteScreen(w io.Writer, sc Screen)
- type Action
- type ActionKind
- type Answers
- type ClusterInput
- type Domain
- type Entry
- type Git
- type IO
- type Loop
- type Plan
- func ClusterPlan(dir, dom, driver string, active, force bool) Plan
- func Decide(s State, a Answers) Plan
- func EjectPlan(dir string) Plan
- func ImplementationPlan(dir, name, impl string) Plan
- func NewProject(s State, out io.Writer, tio IO) (Plan, error)
- func Run(out io.Writer, tio IO, build func() Screen) (Plan, error)
- func ServicePlan(dir, name, path string) Plan
- func TestsPlan(dir, path string) Plan
- func ToolchainPlan(dir string, groups []string) Plan
- func UsePlan(dir, dom string) Plan
- type Project
- type Result
- type Screen
- func ActiveScreen(s State, dom *string) Screen
- func ClusterScreen(dir string, in *ClusterInput) Screen
- func EjectScreen(s State) Screen
- func ImplementationScreen(s State) Screen
- func NewProjectScreen(s State, a *Answers) Screen
- func ServiceScreen(dir string, in *ServiceInput) Screen
- func TestsScreen(dir string, in *TestsInput) Screen
- func ToolchainScreen(dir string, groups *[]string) Screen
- type ServiceInput
- type Situation
- type State
- type StepError
- type Terminal
- type TestsInput
Constants ¶
const ( EntryCluster = "cluster" EntryService = "service" EntryTests = "tests" EntryToolchain = "toolchain" EntryActive = "active" EntryEject = "eject" EntryImplementation = "implementation" EntryExit = "exit" )
The keys of the project list.
const ( MissingDomain = "lo init cluster: give a domain: lo init cluster <domain>" MissingName = "lo init service: give a name: lo init service <name>" )
The error lines of a verb without its value, on a terminal and off.
Variables ¶
var ( ErrAborted = errors.New("lo init: interrupted") ErrCancelled = errors.New("lo init: cancelled") // ErrIncomplete means a value the screen needs stayed empty at the // end of the input (an accessible prompt at EOF): the screen cannot // run. A terminal never ends the input: a required field re-asks. ErrIncomplete = errors.New("lo init: a value is missing") )
ErrAborted means the user pressed Ctrl-C: the run ends with rc 130 and nothing is written. ErrCancelled means Esc or the Cancel choice of a screen: the project loop returns to its list, the bootstrap ends with nothing written.
Functions ¶
func Bootstrap ¶ added in v0.5.0
Bootstrap reports whether the state calls for the bootstrap screen (mode 1): no project here, or a project without a git repository (git installed, no repository). Everything else is project mode.
func DefaultDir ¶
DefaultDir is the project directory the bootstrap defaults to: the project's root inside one, 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 DefaultName ¶ added in v0.5.0
DefaultName is the project name a directory suggests: its base name, lowercased, every run of other characters one `-`, "project" when nothing is left.
func Next ¶ added in v0.5.0
Next is the step a project state calls for. The first that applies wins: the toolchain when a pinned tool is missing; a cluster spec when there is none; the active domain when none is set; the assets diff on drift; `lo up` while the active domain has no kubeconfig; else `lo status`. Outside a project: `lo init`.
func Welcome ¶ added in v0.5.0
Welcome is the one line mode 1 opens with: what `lo init` is about to set up here.
func WriteCard ¶
WriteCard prints the state card of s.Project (nothing outside a project); extra rows (the result of the last action) follow it in the same columns.
func WriteEntries ¶ added in v0.5.0
WriteEntries prints the list as text (--plan): the labels, then the twins dim, then extra rows in the same columns.
func WriteScreen ¶ added in v0.5.0
WriteScreen prints the screen as text: the title, then the rows.
Types ¶
type Action ¶
type Action struct {
Kind ActionKind
// Files lists what the step writes (relative to Plan.Dir); Run names
// what it runs, in the words of the screen ("" = nothing).
Files []string
Run 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, Path, 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" // ActionWriteClusterSpec — clusters/<domain>/cluster.lok8s.yaml into // an existing project. ActionWriteClusterSpec ActionKind = "cluster spec" // 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" // ActionEjectBash — `lo assets eject bash`. ActionEjectBash ActionKind = "eject bash" // ActionSetImplementation — spec.implementation.default in lok8s.yaml. ActionSetImplementation ActionKind = "implementation" )
type Answers ¶
type Answers struct {
// Dir is the project directory ("" = the situation's default: the
// working directory, or the git root below which the user stands).
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).
Env string
// GitInit asks for `git init` (honoured only without a repository).
GitInit bool
// Domain and Driver describe the first 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
}
Answers is what the new-project screen holds (the defaults, or the details the user changed). Every field has a flag twin on `lo init project`, `git init`, `lo toolchain install` or `lo use`.
func DefaultAnswers ¶
DefaultAnswers are the bootstrap defaults the screen shows first. For a new project: the files where the situation suggests; the name from the directory; the first cluster `<name>.dev` on the lo driver, made active; the environment file the directory has, else mise; the toolchain; `git init` when git exists and there is no repository. For a project without a repository: its name and root; a first cluster only when it has none; the toolchain only when a pin is missing; `git init`.
type ClusterInput ¶ added in v0.5.0
type ClusterInput struct {
Domain, Driver string
Active bool
// Force is the verb's --force: an existing spec is replaced.
Force bool
DomainGiven bool
DriverGiven bool
ActiveGiven bool
}
ClusterInput is `lo init cluster`'s values; a *Given flag marks a value from the command line (a fixed row).
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 Entry ¶ added in v0.5.0
type Entry struct {
Key, Label, Twin string
}
Entry is one choice of the project list, with the verb a script runs instead (the twin).
func Entries ¶ added in v0.5.0
Entries lists what the project state allows, in the order of the list. Always: a cluster, a service, Exit. When there is no tests/: the test suite. When a pinned tool is missing or the pin file is unreadable: the toolchain. With several clusters, or with clusters and no valid active domain: the active domain. Without a bash tree: the eject; with one: the implementation switch.
type Git ¶
type Git struct {
// Available is whether git ran at all.
Available bool
// Root is the repository root ("" = not a repository), in the path
// form of State.Cwd (git resolves symlinks; the card prints one form).
Root string
// AtRoot is whether cwd is the repository root.
AtRoot bool
// Branch is the current branch ("" = detached HEAD).
Branch string
// Uncommitted counts the paths `git status --porcelain` lists.
Uncommitted int
// 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 Loop ¶ added in v0.5.0
Loop is project mode. Detect reads the state again after an action; Execute runs a plan (the cli's executor over the subcommands' own functions) and returns a *StepError for a failed step.
func (Loop) Run ¶ added in v0.5.0
Run prints the card and the list until Exit, Esc or Ctrl-C. first are the rows of what ran before the loop (the bootstrap; nil = none): they go under the first card. A cancelled action returns to the list; a failed step returns to the list with the failed and not-run rows; Ctrl-C returns ErrAborted (the cli maps it to rc 130).
type Plan ¶
type Plan struct {
// Dir is the project directory every action runs in (absolute).
Dir string
// Name is the project name the actions use.
Name string
// Force overwrites existing files (a verb's --force; a screen never
// sets it).
Force bool
// Actions in execution order; empty = nothing to do.
Actions []Action
}
Plan is the ordered list of actions for one `lo init` run.
func ClusterPlan ¶ added in v0.5.0
ClusterPlan is `lo init cluster`: the spec, then `lo use` when active. force is the verb's --force: an existing spec is replaced, and the twin carries the flag.
func Decide ¶
Decide turns the state and the answers into the new-project plan: the project files (with the first cluster spec), `git init`, the toolchain, `lo use`. A `git init` inside a repository is ignored.
func ImplementationPlan ¶ added in v0.5.0
ImplementationPlan sets spec.implementation.default for the project name at dir.
func NewProject ¶ added in v0.5.0
NewProject is the new-project flow: the screen with the defaults, the details on request, the plan on Create.
func Run ¶ added in v0.5.0
Run shows the screen and asks. Create returns the plan. Change details runs the fields and shows the screen again. Cancel returns ErrCancelled; Esc and Ctrl-C return ErrAborted. build makes the screen from the current values, so the next render shows a changed detail. The screen goes to out, the forms to tio.
func ServicePlan ¶ added in v0.5.0
ServicePlan is `lo init service`: the service file, its catalog entry and the Tiltfile. path "" = ./<name>.
func TestsPlan ¶ added in v0.5.0
TestsPlan is `lo init test`: the Playwright suite. path "" = tests/.
func ToolchainPlan ¶ added in v0.5.0
ToolchainPlan is `lo toolchain install` for the project at dir.
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
// Kubeconfig is whether the active domain's cluster has a kubeconfig
// under .kubeconfig/ (<metadata.name>.yaml: the cluster was
// provisioned once).
Kubeconfig bool
// 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; BYAMLInvalid whether it exists
// but cannot be read or parsed (then Tools is 0).
BYAML, BYAMLInvalid bool
// Tools counts the pinned tools: b itself plus every `binaries:`
// entry of .bin/b.yaml. ToolsMissing lists the ones that do not
// resolve under the project (by name); nil = all present.
Tools int
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.
func (*Project) ActiveValid ¶ added in v0.5.0
ActiveValid reports whether clusters/.active names a domain with a spec.
func (*Project) ToolchainMissing ¶ added in v0.5.0
ToolchainMissing reports whether `lo toolchain install` is due: no pin file, an unreadable one, or a pinned tool that does not resolve.
type Result ¶ added in v0.5.0
type Result struct {
Key, Value string
}
Result is one row under the card: what the last action did (`added`, `installed`, `failed`, ...).
func FailureRows ¶ added in v0.5.0
FailureRows are the rows of a failed step: the command with its reason, and the commands that did not run.
type Screen ¶ added in v0.5.0
type Screen struct {
// Title heads the screen ("New project").
Title string
// Values are the rows above the writes/runs lines.
Values []row
// Plan is what Create executes.
Plan Plan
// Details builds the editable fields, bound to the values (nil = no
// details: every value came from the command line).
Details func() []huh.Field
// Incomplete is whether a value the screen needs is still empty: the
// details open before the screen is shown, and --plan refuses with
// Missing.
Incomplete bool
// Missing is the error line for an incomplete screen off the details
// (--plan, or a verb off a terminal).
Missing string
}
Screen is what the user sees before a write.
func ActiveScreen ¶ added in v0.5.0
ActiveScreen is the active-domain screen: the domain is chosen first.
func ClusterScreen ¶ added in v0.5.0
func ClusterScreen(dir string, in *ClusterInput) Screen
ClusterScreen is the cluster screen for the project at dir.
func EjectScreen ¶ added in v0.5.0
EjectScreen is the bash tree screen: nothing to change.
func ImplementationScreen ¶ added in v0.5.0
ImplementationScreen switches spec.implementation.default to the other implementation: nothing to change.
func NewProjectScreen ¶ added in v0.5.0
NewProjectScreen is the new-project screen for the answers a: the values, the plan, the details bound to a.
func ServiceScreen ¶ added in v0.5.0
func ServiceScreen(dir string, in *ServiceInput) Screen
ServiceScreen is the service screen for the project at dir.
func TestsScreen ¶ added in v0.5.0
func TestsScreen(dir string, in *TestsInput) Screen
TestsScreen is the test-suite screen for the project at dir.
func ToolchainScreen ¶ added in v0.5.0
ToolchainScreen is the toolchain install screen for the project at dir: the groups are the details.
type ServiceInput ¶ added in v0.5.0
ServiceInput is `lo init service`'s values.
type Situation ¶
type Situation int
Situation is where a bare `lo init` stands. The first three take the bootstrap screen for a new project; the last two are a project (project mode, or the bootstrap screen when the project has no git repository).
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 project goes here. SituationEmptyDir // SituationGitBelowRoot: inside a git repository, below its root, // and no project above. The project goes to the repository root by // default. SituationGitBelowRoot // SituationBareDir: a non-empty directory, no project above, and // either no git or cwd is the git root. The project goes here. SituationBareDir // SituationProjectRoot: cwd is a project root. SituationProjectRoot // SituationInsideProject: cwd is inside a project (a subdirectory, a // service directory, a submodule under the umbrella project). The // actions act on the project root. 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.
type StepError ¶ added in v0.5.0
StepError is a failed action of a plan: the command, the cause and the commands that did not run.
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 through internal/ui (so the test override ui.ForceTTY covers the screens and the card alike) 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.
type TestsInput ¶ added in v0.5.0
TestsInput is `lo init test`'s values.