Files
2026-05-27 22:12:14 -05:00

83 lines
2.5 KiB
Go

package bootstrap
import (
"flag"
"fmt"
"io"
)
// Phase identifies a resumable unit of Windows provisioning work.
type Phase string
const (
PhaseOS Phase = "os"
PhaseHost Phase = "host"
PhaseCustom Phase = "custom"
PhaseConfig Phase = "config"
PhaseWSL Phase = "wsl"
)
var PhaseOrder = []Phase{PhaseOS, PhaseHost, PhaseCustom, PhaseConfig, PhaseWSL}
type Options struct {
Only Phase
NoAI bool
NoWSL bool
Yes bool
DryRun bool
Headless bool
LinuxReleaseRepo string
}
func ParseOptions(args []string, stderr io.Writer) (Options, error) {
var opts Options
var only string
fs := flag.NewFlagSet("bootstrap_windows_env", flag.ContinueOnError)
fs.SetOutput(stderr)
fs.StringVar(&only, "only", "", "run one phase: os, host, custom, config, or wsl")
fs.BoolVar(&opts.NoAI, "no-ai", false, "omit native AI CLIs and pass --no-ai to the Fedora guest")
fs.BoolVar(&opts.NoWSL, "no-wsl", false, "omit Fedora WSL provisioning and guest bootstrap")
fs.BoolVar(&opts.Yes, "yes", false, "execute the displayed plan without confirmation")
fs.BoolVar(&opts.DryRun, "dry-run", false, "detect state and display work without making changes")
fs.BoolVar(&opts.Headless, "headless", false, "disable interactive login offers and require --yes to execute")
fs.StringVar(&opts.LinuxReleaseRepo, "linux-release-repo", "JMR-dev/bootstrap_dev_env", "GitHub repository containing Linux bootstrap releases")
if err := fs.Parse(args); err != nil {
return Options{}, err
}
if fs.NArg() != 0 {
return Options{}, fmt.Errorf("unexpected arguments: %v", fs.Args())
}
if only != "" {
opts.Only = Phase(only)
switch opts.Only {
case PhaseOS, PhaseHost, PhaseCustom, PhaseConfig, PhaseWSL:
default:
return Options{}, fmt.Errorf("invalid --only value %q: use os, host, custom, config, or wsl", only)
}
}
if opts.NoWSL && opts.Only == PhaseWSL {
return Options{}, fmt.Errorf("--only wsl cannot be combined with --no-wsl")
}
if opts.Headless && !opts.Yes && !opts.DryRun {
return Options{}, fmt.Errorf("--headless execution requires --yes or --dry-run")
}
return opts, nil
}
func (o Options) Includes(phase Phase) bool {
if o.NoWSL && phase == PhaseWSL {
return false
}
return o.Only == "" || o.Only == phase
}
func SelectedPhases(opts Options) []Phase {
phases := make([]Phase, 0, len(PhaseOrder))
for _, phase := range PhaseOrder {
if opts.Includes(phase) {
phases = append(phases, phase)
}
}
return phases
}