Skip to content

Commit 731e874

Browse files
committed
fix: ensure .zshrc and brew shellenv exist after setup (#9)
- Stop renaming Oh-My-Zsh's .zshrc in InstallOhMyZsh (stow already handles backup), so .zshrc survives a fresh install - Add EnsureBrewShellenv to write `eval "$(brew shellenv)"` into .zshrc on Apple Silicon — runs in both stepShell and stepRestoreShell regardless of Oh-My-Zsh choice - Normalize bool values (1/0/yes/no → true/false) for `defaults write` so macos_prefs type=bool accepts all common representations
1 parent 291861f commit 731e874

File tree

3 files changed

+66
-18
lines changed

3 files changed

+66
-18
lines changed

internal/installer/installer.go

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -609,27 +609,22 @@ func stepShell(cfg *config.Config) error {
609609
ui.Header("Step 5: Shell Configuration")
610610
fmt.Println()
611611

612-
// Smart detection: skip if Oh-My-Zsh is already installed
612+
// Smart detection: skip Oh-My-Zsh if already installed
613613
if shell.IsOhMyZshInstalled() && cfg.Shell == "" {
614614
ui.Success("✓ Oh-My-Zsh already installed")
615-
fmt.Println()
616-
return nil
617-
}
618-
619-
if cfg.Shell == "" {
615+
} else if cfg.Shell == "" {
620616
if cfg.Silent || (cfg.DryRun && !system.HasTTY()) {
621617
cfg.Shell = "install"
622618
} else {
623619
install, err := ui.Confirm("Install Oh-My-Zsh and configure shell?", true)
624620
if err != nil {
625621
return err
626622
}
627-
if !install {
628-
ui.Muted("Skipping shell configuration")
629-
fmt.Println()
630-
return nil
623+
if install {
624+
cfg.Shell = "install"
625+
} else {
626+
ui.Muted("Skipping Oh-My-Zsh")
631627
}
632-
cfg.Shell = "install"
633628
}
634629
}
635630

@@ -646,6 +641,13 @@ func stepShell(cfg *config.Config) error {
646641
}
647642
}
648643

644+
// Ensure Homebrew shellenv is in .zshrc (required on Apple Silicon).
645+
// Runs after Oh-My-Zsh so its .zshrc template exists, and regardless of
646+
// the Oh-My-Zsh choice because brew must be in PATH for new shells.
647+
if err := shell.EnsureBrewShellenv(cfg.DryRun); err != nil {
648+
return fmt.Errorf("ensure brew shellenv: %w", err)
649+
}
650+
649651
fmt.Println()
650652
return nil
651653
}
@@ -954,6 +956,10 @@ func stepRestoreShell(cfg *config.Config) error {
954956
return err
955957
}
956958

959+
if err := shell.EnsureBrewShellenv(cfg.DryRun); err != nil {
960+
return fmt.Errorf("ensure brew shellenv: %w", err)
961+
}
962+
957963
if !cfg.DryRun {
958964
ui.Success("Shell configuration restored")
959965
}

internal/macos/macos.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ var DefaultPreferences = []Preference{
5151
{"com.apple.TimeMachine", "DoNotOfferNewDisksForBackup", "bool", "true", "Don't prompt for Time Machine on new disks"},
5252
}
5353

54+
func normalizeBool(value string) string {
55+
switch strings.ToLower(value) {
56+
case "1", "yes":
57+
return "true"
58+
case "0", "no":
59+
return "false"
60+
default:
61+
return value
62+
}
63+
}
64+
5465
func InferPreferenceType(value string) string {
5566
switch strings.ToLower(value) {
5667
case "true", "false", "1", "0", "yes", "no":
@@ -105,7 +116,7 @@ func Configure(prefs []Preference, dryRun bool) error {
105116
args := []string{"write", pref.Domain, pref.Key}
106117
switch pref.Type {
107118
case "bool":
108-
args = append(args, "-bool", value)
119+
args = append(args, "-bool", normalizeBool(value))
109120
case "int":
110121
args = append(args, "-int", value)
111122
case "float":

internal/shell/shell.go

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,53 @@ func InstallOhMyZsh(dryRun bool) error {
4646
cmd := exec.Command("bash", "-c", script)
4747
cmd.Stdout = os.Stdout
4848
cmd.Stderr = os.Stderr
49-
if err := cmd.Run(); err != nil {
50-
return err
49+
return cmd.Run()
50+
}
51+
52+
const brewShellenvLine = `eval "$(/opt/homebrew/bin/brew shellenv)"`
53+
54+
// EnsureBrewShellenv adds the Homebrew shellenv eval to ~/.zshrc on Apple
55+
// Silicon if it isn't already present. This is required because /opt/homebrew
56+
// is not in the default PATH.
57+
func EnsureBrewShellenv(dryRun bool) error {
58+
if _, err := os.Stat("/opt/homebrew/bin/brew"); os.IsNotExist(err) {
59+
return nil // Intel Mac or no Homebrew — not needed
5160
}
5261

5362
home, err := system.HomeDir()
5463
if err != nil {
5564
return err
5665
}
5766
zshrcPath := filepath.Join(home, ".zshrc")
58-
if _, err := os.Stat(zshrcPath); err == nil {
59-
if err := os.Rename(zshrcPath, zshrcPath+".openboot.bak"); err != nil {
60-
return fmt.Errorf("backup %s: %w", zshrcPath, err)
67+
68+
// Create .zshrc if it doesn't exist.
69+
if _, err := os.Stat(zshrcPath); os.IsNotExist(err) {
70+
if dryRun {
71+
fmt.Printf("[DRY-RUN] Would create %s with Homebrew shellenv\n", zshrcPath)
72+
return nil
6173
}
74+
return os.WriteFile(zshrcPath, []byte(brewShellenvLine+"\n"), 0644)
6275
}
6376

64-
return nil
77+
raw, err := os.ReadFile(zshrcPath)
78+
if err != nil {
79+
return fmt.Errorf("read .zshrc: %w", err)
80+
}
81+
if strings.Contains(string(raw), "brew shellenv") {
82+
return nil // already present
83+
}
84+
85+
if dryRun {
86+
fmt.Println("[DRY-RUN] Would add Homebrew shellenv to .zshrc")
87+
return nil
88+
}
89+
90+
content := string(raw)
91+
if len(content) > 0 && content[len(content)-1] != '\n' {
92+
content += "\n"
93+
}
94+
content = brewShellenvLine + "\n" + content
95+
return os.WriteFile(zshrcPath, []byte(content), 0644)
6596
}
6697

6798
func SetDefaultShell(dryRun bool) error {

0 commit comments

Comments
 (0)