Skip to content

Commit f4b2d7d

Browse files
committed
refactor(cli): replace shared global cfg with per-command installCfg
1 parent 60984b6 commit f4b2d7d

1 file changed

Lines changed: 32 additions & 31 deletions

File tree

internal/cli/install.go

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ import (
1515
"github.com/spf13/cobra"
1616
)
1717

18+
// installCfg holds flag values for the install subcommand.
19+
// It is separate from the root command's cfg so that each command
20+
// owns its own config state and does not share mutable globals.
21+
var installCfg = &config.Config{}
22+
1823
var installCmd = &cobra.Command{
1924
Use: "install [source]",
2025
Short: "Set up your Mac dev environment",
@@ -51,32 +56,28 @@ Explicit flags (--from, --user, -p) override the positional argument.`,
5156
func init() {
5257
installCmd.Flags().SortFlags = false
5358

54-
installCmd.Flags().StringVarP(&cfg.Preset, "preset", "p", "", "use a preset: minimal, developer, full")
55-
installCmd.Flags().StringVarP(&cfg.User, "user", "u", "", "install from an alias or openboot.dev/username/slug config")
59+
installCmd.Flags().StringVarP(&installCfg.Preset, "preset", "p", "", "use a preset: minimal, developer, full")
60+
installCmd.Flags().StringVarP(&installCfg.User, "user", "u", "", "install from an alias or openboot.dev/username/slug config")
5661
installCmd.Flags().String("from", "", "install from a local config or snapshot JSON file")
57-
installCmd.Flags().BoolVarP(&cfg.Silent, "silent", "s", false, "non-interactive mode (for CI/CD)")
58-
installCmd.Flags().BoolVar(&cfg.DryRun, "dry-run", false, "preview changes without installing")
59-
installCmd.Flags().BoolVar(&cfg.PackagesOnly, "packages-only", false, "install packages only, skip system config")
62+
installCmd.Flags().BoolVarP(&installCfg.Silent, "silent", "s", false, "non-interactive mode (for CI/CD)")
63+
installCmd.Flags().BoolVar(&installCfg.DryRun, "dry-run", false, "preview changes without installing")
64+
installCmd.Flags().BoolVar(&installCfg.PackagesOnly, "packages-only", false, "install packages only, skip system config")
6065

61-
installCmd.Flags().StringVar(&cfg.Shell, "shell", "", "shell setup: install, skip")
62-
installCmd.Flags().StringVar(&cfg.Macos, "macos", "", "macOS preferences: configure, skip")
63-
installCmd.Flags().StringVar(&cfg.Dotfiles, "dotfiles", "", "dotfiles: clone, link, skip")
66+
installCmd.Flags().StringVar(&installCfg.Shell, "shell", "", "shell setup: install, skip")
67+
installCmd.Flags().StringVar(&installCfg.Macos, "macos", "", "macOS preferences: configure, skip")
68+
installCmd.Flags().StringVar(&installCfg.Dotfiles, "dotfiles", "", "dotfiles: clone, link, skip")
6469

65-
installCmd.Flags().BoolVar(&cfg.Update, "update", false, "update Homebrew before installing")
66-
installCmd.Flags().BoolVar(&cfg.AllowPostInstall, "allow-post-install", false, "allow post-install scripts in silent mode")
70+
installCmd.Flags().BoolVar(&installCfg.Update, "update", false, "update Homebrew before installing")
71+
installCmd.Flags().BoolVar(&installCfg.AllowPostInstall, "allow-post-install", false, "allow post-install scripts in silent mode")
6772
}
6873

6974
func runInstallCmd(cmd *cobra.Command, args []string) error {
70-
// Root's PersistentPreRunE may already have resolved cfg.User via
71-
// the --user flag or OPENBOOT_USER env var, fetching the RemoteConfig.
72-
// When that happened, skip resolution and go straight to install.
73-
if cfg.RemoteConfig == nil {
75+
if installCfg.RemoteConfig == nil {
7476
src, err := resolveInstallSource(cmd, args)
7577
if err != nil {
7678
return err
7779
}
7880

79-
// Sync-source path uses the pull-like diff+confirm flow.
8081
if src.kind == sourceSyncSource {
8182
return runSyncInstall(src.syncSource)
8283
}
@@ -86,12 +87,12 @@ func runInstallCmd(cmd *cobra.Command, args []string) error {
8687
}
8788
}
8889

89-
err := installer.Run(cfg)
90+
err := installer.Run(installCfg)
9091
if errors.Is(err, installer.ErrUserCancelled) {
9192
return nil
9293
}
9394
if err == nil {
94-
saveSyncSourceIfRemote(cfg)
95+
saveSyncSourceIfRemote(installCfg)
9596
}
9697
return err
9798
}
@@ -121,10 +122,10 @@ func resolveInstallSource(cmd *cobra.Command, args []string) (*installSource, er
121122
if fromFile, _ := cmd.Flags().GetString("from"); fromFile != "" {
122123
return &installSource{kind: sourceFile, path: fromFile}, nil
123124
}
124-
if cfg.User != "" {
125-
return &installSource{kind: sourceCloud, userSlug: cfg.User}, nil
125+
if installCfg.User != "" {
126+
return &installSource{kind: sourceCloud, userSlug: installCfg.User}, nil
126127
}
127-
if cfg.Preset != "" {
128+
if installCfg.Preset != "" {
128129
return &installSource{kind: sourcePreset}, nil
129130
}
130131

@@ -151,7 +152,7 @@ func resolvePositionalArg(arg string) (*installSource, error) {
151152
return &installSource{kind: sourceCloud, userSlug: arg}, nil
152153
}
153154
if _, ok := config.GetPreset(arg); ok {
154-
cfg.Preset = arg
155+
installCfg.Preset = arg
155156
return &installSource{kind: sourcePreset}, nil
156157
}
157158
// Fall through: treat as a cloud alias — FetchRemoteConfig's alias
@@ -184,7 +185,7 @@ func applyInstallSource(src *installSource) error {
184185
return nil
185186

186187
case sourceCloud:
187-
cfg.User = src.userSlug
188+
installCfg.User = src.userSlug
188189
var token string
189190
if stored, _ := auth.LoadToken(); stored != nil {
190191
token = stored.Token
@@ -193,9 +194,9 @@ func applyInstallSource(src *installSource) error {
193194
if err != nil {
194195
return fmt.Errorf("fetch remote config: %w", err)
195196
}
196-
cfg.RemoteConfig = rc
197-
if cfg.Preset == "" {
198-
cfg.Preset = rc.Preset
197+
installCfg.RemoteConfig = rc
198+
if installCfg.Preset == "" {
199+
installCfg.Preset = rc.Preset
199200
}
200201
return nil
201202

@@ -204,14 +205,14 @@ func applyInstallSource(src *installSource) error {
204205
if err != nil {
205206
return fmt.Errorf("load config from file: %w", err)
206207
}
207-
cfg.RemoteConfig = rc
208-
if cfg.Preset == "" {
209-
cfg.Preset = rc.Preset
208+
installCfg.RemoteConfig = rc
209+
if installCfg.Preset == "" {
210+
installCfg.Preset = rc.Preset
210211
}
211212
return nil
212213

213214
case sourcePreset:
214-
// cfg.Preset is already set (by flag or resolvePositionalArg).
215+
// installCfg.Preset is already set (by flag or resolvePositionalArg).
215216
return nil
216217

217218
case sourceSyncSource:
@@ -258,12 +259,12 @@ func runSyncInstall(source *syncpkg.SyncSource) error {
258259

259260
printInstallDiff(diff)
260261

261-
if cfg.DryRun {
262+
if installCfg.DryRun {
262263
ui.Muted(fmt.Sprintf("Dry run: would apply %d change(s) from %s.", missingCount, label))
263264
return nil
264265
}
265266

266-
if !cfg.Silent {
267+
if !installCfg.Silent {
267268
confirmed, err := ui.Confirm(fmt.Sprintf("Apply %d change(s) from %s?", missingCount, label), true)
268269
if err != nil {
269270
return fmt.Errorf("confirm: %w", err)

0 commit comments

Comments
 (0)