Skip to content

Commit f7b3324

Browse files
committed
fix(install): use brew tap instead of direct binary download
Direct download placed a plain file at /opt/homebrew/bin/openboot which caused brew link to fail with "Target already exists" on retry or when brew install was run manually. Switch to brew install openbootdotdev/tap/openboot, matching scripts/install.sh. Also align install_homebrew to check known brew paths before attempting a fresh install, mirroring the same fix in the CLI installer.
1 parent 1086d13 commit f7b3324

2 files changed

Lines changed: 38 additions & 94 deletions

File tree

src/lib/server/install-script.test.ts

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ describe('generateInstallScript', () => {
136136
expect(script).toContain('#!/bin/bash');
137137
expect(script).toContain('OpenBoot Installer');
138138
expect(script).toContain('Config: @testuser/my-config');
139-
expect(script).toContain('api.github.com/repos/${OPENBOOT_REPO}/releases/latest');
139+
expect(script).toContain('OPENBOOT_TAP="openbootdotdev/tap"');
140140
expect(script).toContain('openboot install "testuser/my-config"');
141141
});
142142

@@ -156,12 +156,11 @@ describe('generateInstallScript', () => {
156156
expect(script).toContain('Homebrew/install/HEAD/install.sh');
157157
});
158158

159-
it('should handle ARM64 architecture', () => {
159+
it('should handle ARM64 by using brew shellenv after install', () => {
160160
const script = generateInstallScript('testuser', 'my-config');
161161

162-
expect(script).toContain('detect_arch()');
163162
expect(script).toContain('/opt/homebrew/bin/brew');
164-
expect(script).toContain('arm64)');
163+
expect(script).toContain('shellenv');
165164
});
166165

167166
it('should not include custom script or dotfiles sections', () => {
@@ -182,13 +181,13 @@ describe('generateInstallScript', () => {
182181
expect(script).not.toContain('my config!');
183182
});
184183

185-
it('should install openboot via GitHub releases', () => {
184+
it('should install openboot via Homebrew tap', () => {
186185
const script = generateInstallScript('testuser', 'my-config');
187186

188-
expect(script).toContain('OPENBOOT_REPO="openbootdotdev/openboot"');
189-
expect(script).toContain('api.github.com/repos/${OPENBOOT_REPO}/releases/latest');
187+
expect(script).toContain('OPENBOOT_TAP="openbootdotdev/tap"');
190188
expect(script).toContain('install_openboot()');
191-
expect(script).toContain('github.com/${OPENBOOT_REPO}/releases/download/${latest_version}/openboot-');
189+
expect(script).toContain('brew install ${OPENBOOT_TAP}/openboot');
190+
expect(script).toContain('brew list ${OPENBOOT_TAP}/openboot');
192191
});
193192

194193
it('should pass through additional arguments to openboot', () => {
@@ -197,12 +196,10 @@ describe('generateInstallScript', () => {
197196
expect(script).toContain('openboot install "testuser/my-config" "$@"');
198197
});
199198

200-
it('should use /opt/homebrew/bin on arm64 and mkdir -p if dir is missing', () => {
199+
it('should not use direct binary download that conflicts with brew link', () => {
201200
const script = generateInstallScript('testuser', 'my-config');
202201

203-
expect(script).toContain('/opt/homebrew/bin');
204-
expect(script).toContain('mkdir -p');
205-
// must not assume /usr/local/bin always exists
206-
expect(script).not.toMatch(/sudo mv \/tmp\/openboot-install \/usr\/local\/bin\/openboot/);
202+
expect(script).not.toContain('/tmp/openboot-install');
203+
expect(script).not.toContain('releases/download');
207204
});
208205
});

src/lib/server/install-script.ts

Lines changed: 28 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export function generateInstallScript(
105105
return `#!/bin/bash
106106
set -euo pipefail
107107
108-
OPENBOOT_REPO="openbootdotdev/openboot"
108+
OPENBOOT_TAP="openbootdotdev/tap"
109109
110110
main() {
111111
# When run via "curl | bash", stdin is the script content, not the terminal.
@@ -132,17 +132,6 @@ detect_os() {
132132
esac
133133
}
134134
135-
detect_arch() {
136-
local arch
137-
arch=\$(uname -m)
138-
case "\$arch" in
139-
x86_64) echo "amd64" ;;
140-
arm64) echo "arm64" ;;
141-
aarch64) echo "arm64" ;;
142-
*) echo "unsupported: \$arch" >&2; exit 1 ;;
143-
esac
144-
}
145-
146135
install_xcode_clt() {
147136
if xcode-select -p &>/dev/null; then
148137
return 0
@@ -170,94 +159,52 @@ install_homebrew() {
170159
return 0
171160
fi
172161
162+
# brew may be installed but missing from PATH (fresh shell without ~/.zprofile sourced)
163+
local brew_bin=""
164+
if [[ -x "/opt/homebrew/bin/brew" ]]; then
165+
brew_bin="/opt/homebrew/bin/brew"
166+
elif [[ -x "/usr/local/bin/brew" ]]; then
167+
brew_bin="/usr/local/bin/brew"
168+
fi
169+
170+
if [[ -n "\$brew_bin" ]]; then
171+
eval "\$("\$brew_bin" shellenv)"
172+
return 0
173+
fi
174+
173175
echo "Installing Homebrew..."
174176
echo ""
175177
176178
/bin/bash -c "\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
177179
178-
local arch
179-
arch=\$(uname -m)
180-
case "\$arch" in
181-
arm64)
182-
if [[ -x "/opt/homebrew/bin/brew" ]]; then
183-
export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:\$PATH"
184-
export HOMEBREW_PREFIX="/opt/homebrew"
185-
export HOMEBREW_CELLAR="/opt/homebrew/Cellar"
186-
export HOMEBREW_REPOSITORY="/opt/homebrew"
187-
fi
188-
;;
189-
x86_64)
190-
if [[ -x "/usr/local/bin/brew" ]]; then
191-
export PATH="/usr/local/bin:/usr/local/sbin:\$PATH"
192-
export HOMEBREW_PREFIX="/usr/local"
193-
export HOMEBREW_CELLAR="/usr/local/Cellar"
194-
export HOMEBREW_REPOSITORY="/usr/local/Homebrew"
195-
fi
196-
;;
197-
*)
198-
echo "Error: Unsupported architecture: \$arch" >&2
199-
exit 1
200-
;;
201-
esac
180+
if [[ -x "/opt/homebrew/bin/brew" ]]; then
181+
eval "\$(/opt/homebrew/bin/brew shellenv)"
182+
elif [[ -x "/usr/local/bin/brew" ]]; then
183+
eval "\$(/usr/local/bin/brew shellenv)"
184+
fi
202185
203186
echo ""
204187
echo "Homebrew installed!"
205188
echo ""
206189
}
207190
208191
install_openboot() {
209-
local os_name="\$1"
210-
local arch_name="\$2"
211-
212-
echo "Fetching latest OpenBoot version..."
213-
local latest_version
214-
latest_version=\$(curl -fsSL "https://api.github.com/repos/\${OPENBOOT_REPO}/releases/latest" \\
215-
| grep '"tag_name"' | grep -o 'v[0-9][0-9.]*')
216-
217-
if [[ -z "\$latest_version" ]]; then
218-
echo "Error: Could not fetch latest OpenBoot version" >&2
219-
exit 1
220-
fi
221-
222-
local binary_url="https://github.com/\${OPENBOOT_REPO}/releases/download/\${latest_version}/openboot-\${os_name}-\${arch_name}"
223-
224-
echo "Installing OpenBoot \${latest_version}..."
225-
echo ""
226-
227-
curl -fsSL "\$binary_url" -o /tmp/openboot-install
228-
chmod +x /tmp/openboot-install
229-
230-
local install_dir
231-
if [[ "\$arch_name" == "arm64" ]] && [[ -d "/opt/homebrew/bin" ]]; then
232-
install_dir="/opt/homebrew/bin"
233-
else
234-
install_dir="/usr/local/bin"
235-
fi
236-
237-
if [[ ! -d "\$install_dir" ]]; then
238-
sudo mkdir -p "\$install_dir"
239-
fi
240-
241-
if [[ -w "\$install_dir" ]]; then
242-
mv /tmp/openboot-install "\$install_dir/openboot"
192+
if brew list \${OPENBOOT_TAP}/openboot &>/dev/null 2>&1; then
193+
echo "OpenBoot is already installed."
243194
else
244-
sudo mv /tmp/openboot-install "\$install_dir/openboot"
195+
echo "Installing OpenBoot via Homebrew..."
196+
echo ""
197+
brew install \${OPENBOOT_TAP}/openboot
198+
echo ""
199+
echo "OpenBoot installed!"
245200
fi
246-
247-
echo ""
248-
echo "OpenBoot \${latest_version} installed!"
249201
}
250202
251-
local os arch
252-
os=\$(detect_os)
253-
arch=\$(detect_arch)
254-
255-
echo "Detected: \${os}/\${arch}"
256-
echo ""
203+
detect_os
257204
258205
install_xcode_clt
259206
install_homebrew
260-
install_openboot "\$os" "\$arch"
207+
install_openboot
261208
262209
echo ""
263210
echo "Starting OpenBoot setup with config: @${safeUsername}/${safeSlug}"

0 commit comments

Comments
 (0)