Skip to content

Commit d17be6c

Browse files
committed
feat: separate interactive and one-click install modes
- /install: interactive mode with git config, preset, package selection - /username: one-click mode, direct install with progress only - Add DotfilesRepo to RemoteConfig struct - Fix --user flag parsing (move to PersistentPreRunE)
1 parent bbf04fc commit d17be6c

3 files changed

Lines changed: 67 additions & 64 deletions

File tree

internal/cli/root.go

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
)
1111

1212
var (
13-
version = "0.6.0"
13+
version = "0.7.0"
1414
cfg = &config.Config{}
1515
)
1616

@@ -19,6 +19,35 @@ var rootCmd = &cobra.Command{
1919
Short: "One-line macOS development environment setup",
2020
Long: `OpenBoot bootstraps your Mac development environment in minutes.
2121
Install Homebrew, CLI tools, GUI apps, dotfiles, and Oh-My-Zsh with a single command.`,
22+
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
23+
if cfg.Silent {
24+
if name := os.Getenv("OPENBOOT_GIT_NAME"); name != "" {
25+
cfg.GitName = name
26+
}
27+
if email := os.Getenv("OPENBOOT_GIT_EMAIL"); email != "" {
28+
cfg.GitEmail = email
29+
}
30+
if preset := os.Getenv("OPENBOOT_PRESET"); preset != "" && cfg.Preset == "" {
31+
cfg.Preset = preset
32+
}
33+
}
34+
35+
if user := os.Getenv("OPENBOOT_USER"); user != "" && cfg.User == "" {
36+
cfg.User = user
37+
}
38+
39+
if cfg.User != "" {
40+
rc, err := config.FetchRemoteConfig(cfg.User)
41+
if err != nil {
42+
return fmt.Errorf("error fetching remote config: %v", err)
43+
}
44+
cfg.RemoteConfig = rc
45+
if cfg.Preset == "" {
46+
cfg.Preset = rc.Preset
47+
}
48+
}
49+
return nil
50+
},
2251
RunE: func(cmd *cobra.Command, args []string) error {
2352
return installer.Run(cfg)
2453
},
@@ -48,33 +77,5 @@ var versionCmd = &cobra.Command{
4877
}
4978

5079
func Execute() error {
51-
if cfg.Silent {
52-
if name := os.Getenv("OPENBOOT_GIT_NAME"); name != "" {
53-
cfg.GitName = name
54-
}
55-
if email := os.Getenv("OPENBOOT_GIT_EMAIL"); email != "" {
56-
cfg.GitEmail = email
57-
}
58-
if preset := os.Getenv("OPENBOOT_PRESET"); preset != "" && cfg.Preset == "" {
59-
cfg.Preset = preset
60-
}
61-
}
62-
63-
if user := os.Getenv("OPENBOOT_USER"); user != "" && cfg.User == "" {
64-
cfg.User = user
65-
}
66-
67-
if cfg.User != "" {
68-
rc, err := config.FetchRemoteConfig(cfg.User)
69-
if err != nil {
70-
fmt.Fprintf(os.Stderr, "Error fetching remote config: %v\n", err)
71-
os.Exit(1)
72-
}
73-
cfg.RemoteConfig = rc
74-
if cfg.Preset == "" {
75-
cfg.Preset = rc.Preset
76-
}
77-
}
78-
7980
return rootCmd.Execute()
8081
}

internal/config/config.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@ type Config struct {
3232
}
3333

3434
type RemoteConfig struct {
35-
Username string `json:"username"`
36-
Slug string `json:"slug"`
37-
Name string `json:"name"`
38-
Preset string `json:"preset"`
39-
Packages []string `json:"packages"`
35+
Username string `json:"username"`
36+
Slug string `json:"slug"`
37+
Name string `json:"name"`
38+
Preset string `json:"preset"`
39+
Packages []string `json:"packages"`
40+
DotfilesRepo string `json:"dotfiles_repo"`
4041
}
4142

4243
type Preset struct {
@@ -85,7 +86,7 @@ func FetchRemoteConfig(userSlug string) (*RemoteConfig, error) {
8586
}
8687

8788
url := fmt.Sprintf("https://openboot.dev/%s/%s/config", username, slug)
88-
89+
8990
resp, err := http.Get(url)
9091
if err != nil {
9192
return nil, fmt.Errorf("failed to fetch config: %w", err)

internal/installer/installer.go

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,43 @@ func Run(cfg *config.Config) error {
2727

2828
func runInstall(cfg *config.Config) error {
2929
fmt.Println()
30-
ui.Header("OpenBoot Installer v0.6.0")
30+
ui.Header("OpenBoot Installer v0.7.0")
3131
fmt.Println()
3232

33-
if cfg.RemoteConfig != nil {
34-
ui.Info(fmt.Sprintf("Using remote config: @%s/%s", cfg.RemoteConfig.Username, cfg.RemoteConfig.Slug))
35-
fmt.Println()
36-
}
37-
3833
if cfg.DryRun {
3934
ui.Muted("[DRY-RUN MODE - No changes will be made]")
4035
fmt.Println()
4136
}
4237

38+
if cfg.RemoteConfig != nil {
39+
return runCustomInstall(cfg)
40+
}
41+
42+
return runInteractiveInstall(cfg)
43+
}
44+
45+
func runCustomInstall(cfg *config.Config) error {
46+
ui.Info(fmt.Sprintf("Custom config: @%s/%s", cfg.RemoteConfig.Username, cfg.RemoteConfig.Slug))
47+
ui.Info(fmt.Sprintf("Installing %d packages...", len(cfg.RemoteConfig.Packages)))
48+
fmt.Println()
49+
50+
cfg.SelectedPkgs = make(map[string]bool)
51+
for _, pkg := range cfg.RemoteConfig.Packages {
52+
cfg.SelectedPkgs[pkg] = true
53+
}
54+
55+
if err := stepInstallPackages(cfg); err != nil {
56+
return err
57+
}
58+
59+
fmt.Println()
60+
ui.Success("Package installation complete!")
61+
ui.Muted("Dotfiles and shell setup will be handled by the install script.")
62+
fmt.Println()
63+
return nil
64+
}
65+
66+
func runInteractiveInstall(cfg *config.Config) error {
4367
if err := stepGitConfig(cfg); err != nil {
4468
return err
4569
}
@@ -56,14 +80,6 @@ func runInstall(cfg *config.Config) error {
5680
return err
5781
}
5882

59-
if cfg.RemoteConfig != nil {
60-
fmt.Println()
61-
ui.Success("Package installation complete!")
62-
ui.Muted("Dotfiles and shell setup will be handled by the install script.")
63-
fmt.Println()
64-
return nil
65-
}
66-
6783
if err := stepDotfiles(cfg); err != nil {
6884
ui.Error(fmt.Sprintf("Dotfiles setup failed: %v", err))
6985
}
@@ -86,7 +102,6 @@ func stepGitConfig(cfg *config.Config) error {
86102

87103
var name, email string
88104

89-
// In dry-run mode without TTY, use placeholder values
90105
if cfg.DryRun && !system.HasTTY() {
91106
name = cfg.GitName
92107
email = cfg.GitEmail
@@ -128,10 +143,6 @@ func stepGitConfig(cfg *config.Config) error {
128143
}
129144

130145
func stepPresetSelection(cfg *config.Config) error {
131-
if cfg.RemoteConfig != nil {
132-
return nil
133-
}
134-
135146
ui.Header("Step 2: Preset Selection")
136147
fmt.Println()
137148

@@ -161,16 +172,6 @@ func stepPresetSelection(cfg *config.Config) error {
161172
}
162173

163174
func stepPackageCustomization(cfg *config.Config) error {
164-
if cfg.RemoteConfig != nil {
165-
cfg.SelectedPkgs = make(map[string]bool)
166-
for _, pkg := range cfg.RemoteConfig.Packages {
167-
cfg.SelectedPkgs[pkg] = true
168-
}
169-
ui.Info(fmt.Sprintf("Using %d packages from remote config", len(cfg.RemoteConfig.Packages)))
170-
fmt.Println()
171-
return nil
172-
}
173-
174175
ui.Header("Step 3: Package Selection")
175176
fmt.Println()
176177

0 commit comments

Comments
 (0)