@@ -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+
1823var 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.`,
5156func 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
6974func 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