Skip to content

Commit 836ea64

Browse files
authored
Merge pull request #52 from openclaw/chore/modernize-install-sh
fix(installer): harden pnpm resolution for git installs
2 parents 9ea9baa + cc5b087 commit 836ea64

File tree

2 files changed

+203
-47
lines changed

2 files changed

+203
-47
lines changed

public/install.sh

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,7 @@ NPM_SILENT_FLAG="--silent"
734734
VERBOSE="${OPENCLAW_VERBOSE:-0}"
735735
OPENCLAW_USE_GUM="${OPENCLAW_USE_GUM:-auto}"
736736
OPENCLAW_BIN=""
737+
PNPM_CMD=()
737738
HELP=0
738739

739740
print_usage() {
@@ -1194,25 +1195,80 @@ check_existing_openclaw() {
11941195
return 1
11951196
}
11961197

1197-
ensure_pnpm() {
1198+
set_pnpm_cmd() {
1199+
PNPM_CMD=("$@")
1200+
}
1201+
1202+
pnpm_cmd_pretty() {
1203+
if [[ ${#PNPM_CMD[@]} -eq 0 ]]; then
1204+
echo ""
1205+
return 1
1206+
fi
1207+
printf '%s' "${PNPM_CMD[*]}"
1208+
return 0
1209+
}
1210+
1211+
pnpm_cmd_is_ready() {
1212+
if [[ ${#PNPM_CMD[@]} -eq 0 ]]; then
1213+
return 1
1214+
fi
1215+
"${PNPM_CMD[@]}" --version >/dev/null 2>&1
1216+
}
1217+
1218+
detect_pnpm_cmd() {
11981219
if command -v pnpm &> /dev/null; then
1199-
ui_success "pnpm already installed"
1220+
set_pnpm_cmd pnpm
1221+
return 0
1222+
fi
1223+
if command -v corepack &> /dev/null; then
1224+
if corepack pnpm --version >/dev/null 2>&1; then
1225+
set_pnpm_cmd corepack pnpm
1226+
return 0
1227+
fi
1228+
fi
1229+
return 1
1230+
}
1231+
1232+
ensure_pnpm() {
1233+
if detect_pnpm_cmd && pnpm_cmd_is_ready; then
1234+
ui_success "pnpm ready ($(pnpm_cmd_pretty))"
12001235
return 0
12011236
fi
12021237

12031238
if command -v corepack &> /dev/null; then
1204-
ui_info "Installing pnpm via Corepack"
1239+
ui_info "Configuring pnpm via Corepack"
12051240
corepack enable >/dev/null 2>&1 || true
1206-
run_quiet_step "Activating pnpm" corepack prepare pnpm@10 --activate
1207-
ui_success "pnpm installed"
1208-
return 0
1241+
if ! run_quiet_step "Activating pnpm" corepack prepare pnpm@10 --activate; then
1242+
ui_warn "Corepack pnpm activation failed; falling back"
1243+
fi
1244+
refresh_shell_command_cache
1245+
if detect_pnpm_cmd && pnpm_cmd_is_ready; then
1246+
if [[ "${PNPM_CMD[*]}" == "corepack pnpm" ]]; then
1247+
ui_warn "pnpm shim not on PATH; using corepack pnpm fallback"
1248+
fi
1249+
ui_success "pnpm ready ($(pnpm_cmd_pretty))"
1250+
return 0
1251+
fi
12091252
fi
12101253

12111254
ui_info "Installing pnpm via npm"
12121255
fix_npm_permissions
12131256
run_quiet_step "Installing pnpm" npm install -g pnpm@10
1214-
ui_success "pnpm installed"
1215-
return 0
1257+
refresh_shell_command_cache
1258+
if detect_pnpm_cmd && pnpm_cmd_is_ready; then
1259+
ui_success "pnpm ready ($(pnpm_cmd_pretty))"
1260+
return 0
1261+
fi
1262+
1263+
ui_error "pnpm installation failed"
1264+
return 1
1265+
}
1266+
1267+
run_pnpm() {
1268+
if ! pnpm_cmd_is_ready; then
1269+
ensure_pnpm
1270+
fi
1271+
"${PNPM_CMD[@]}" "$@"
12161272
}
12171273

12181274
ensure_user_local_bin_on_path() {
@@ -1395,12 +1451,12 @@ install_openclaw_from_git() {
13951451

13961452
cleanup_legacy_submodules "$repo_dir"
13971453

1398-
run_quiet_step "Installing dependencies" env SHARP_IGNORE_GLOBAL_LIBVIPS="$SHARP_IGNORE_GLOBAL_LIBVIPS" pnpm -C "$repo_dir" install
1454+
run_quiet_step "Installing dependencies" env SHARP_IGNORE_GLOBAL_LIBVIPS="$SHARP_IGNORE_GLOBAL_LIBVIPS" run_pnpm -C "$repo_dir" install
13991455

1400-
if ! run_quiet_step "Building UI" pnpm -C "$repo_dir" ui:build; then
1456+
if ! run_quiet_step "Building UI" run_pnpm -C "$repo_dir" ui:build; then
14011457
ui_warn "UI build failed; continuing (CLI may still work)"
14021458
fi
1403-
run_quiet_step "Building OpenClaw" pnpm -C "$repo_dir" build
1459+
run_quiet_step "Building OpenClaw" run_pnpm -C "$repo_dir" build
14041460

14051461
ensure_user_local_bin_on_path
14061462

@@ -1411,7 +1467,7 @@ exec node "${repo_dir}/dist/entry.js" "\$@"
14111467
EOF
14121468
chmod +x "$HOME/.local/bin/openclaw"
14131469
ui_success "OpenClaw wrapper installed to \$HOME/.local/bin/openclaw"
1414-
ui_info "This checkout uses pnpm — run pnpm install for deps (not npm install)"
1470+
ui_info "This checkout uses pnpm — run pnpm install (or corepack pnpm install) for deps"
14151471
}
14161472

14171473
# Install OpenClaw

scripts/test-install-sh-unit.sh

Lines changed: 135 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -36,95 +36,195 @@ EOF
3636
chmod +x "$path"
3737
}
3838

39+
stub_ui_and_quiet_runner() {
40+
ui_info() { :; }
41+
ui_success() { :; }
42+
ui_warn() { :; }
43+
ui_error() { :; }
44+
run_quiet_step() {
45+
local _title="$1"
46+
shift
47+
"$@"
48+
}
49+
}
50+
3951
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
4052
TMP_DIR="$(mktemp -d)"
4153
trap 'rm -rf "$TMP_DIR"' EXIT
4254

55+
export OPENCLAW_INSTALL_SH_NO_RUN=1
4356
export CLAWDBOT_INSTALL_SH_NO_RUN=1
4457
# shellcheck source=../public/install.sh
4558
source "${ROOT_DIR}/public/install.sh"
4659

47-
echo "==> case: direct PATH"
60+
echo "==> case: resolve_openclaw_bin (direct PATH)"
4861
(
4962
bin="${TMP_DIR}/case-path/bin"
50-
make_exe "${bin}/clawdbot" 'echo "ok" >/dev/null'
63+
make_exe "${bin}/openclaw" 'echo "ok" >/dev/null'
5164
export PATH="${bin}:/usr/bin:/bin"
5265

53-
got="$(resolve_clawdbot_bin)"
54-
assert_eq "$got" "${bin}/clawdbot" "resolve_clawdbot_bin (direct PATH)"
66+
got="$(resolve_openclaw_bin)"
67+
assert_eq "$got" "${bin}/openclaw" "resolve_openclaw_bin (direct PATH)"
5568
)
5669

57-
echo "==> case: npm prefix -g"
58-
(
59-
root="${TMP_DIR}/case-npm-prefix-direct"
60-
prefix="${root}/prefix"
61-
tool_bin="${root}/tool-bin"
62-
63-
make_exe "${tool_bin}/npm" "if [[ \"\$1\" == \"prefix\" && \"\$2\" == \"-g\" ]]; then echo \"${prefix}\"; exit 0; fi; exit 1"
64-
make_exe "${prefix}/bin/clawdbot" 'echo "ok" >/dev/null'
65-
66-
export PATH="${tool_bin}:/usr/bin:/bin"
67-
68-
got="$(resolve_clawdbot_bin)"
69-
assert_eq "$got" "${prefix}/bin/clawdbot" "resolve_clawdbot_bin (npm prefix -g)"
70-
)
71-
72-
echo "==> case: npm prefix -g fallback"
70+
echo "==> case: resolve_openclaw_bin (npm prefix -g)"
7371
(
7472
root="${TMP_DIR}/case-npm-prefix"
7573
prefix="${root}/prefix"
7674
tool_bin="${root}/tool-bin"
7775

78-
make_exe "${tool_bin}/npm" "if [[ \"\$1\" == \"bin\" && \"\$2\" == \"-g\" ]]; then exit 1; fi; if [[ \"\$1\" == \"prefix\" && \"\$2\" == \"-g\" ]]; then echo \"${prefix}\"; exit 0; fi; exit 1"
79-
make_exe "${prefix}/bin/clawdbot" 'echo "ok" >/dev/null'
76+
make_exe "${tool_bin}/npm" "if [[ \"\$1\" == \"prefix\" && \"\$2\" == \"-g\" ]]; then echo \"${prefix}\"; exit 0; fi; if [[ \"\$1\" == \"config\" && \"\$2\" == \"get\" && \"\$3\" == \"prefix\" ]]; then echo \"${prefix}\"; exit 0; fi; exit 1"
77+
make_exe "${prefix}/bin/openclaw" 'echo "ok" >/dev/null'
8078

8179
export PATH="${tool_bin}:/usr/bin:/bin"
8280

83-
got="$(resolve_clawdbot_bin)"
84-
assert_eq "$got" "${prefix}/bin/clawdbot" "resolve_clawdbot_bin (npm prefix -g)"
81+
got="$(resolve_openclaw_bin)"
82+
assert_eq "$got" "${prefix}/bin/openclaw" "resolve_openclaw_bin (npm prefix -g)"
8583
)
8684

87-
echo "==> case: nodenv rehash shim creation"
85+
echo "==> case: resolve_openclaw_bin (nodenv rehash shim creation)"
8886
(
8987
root="${TMP_DIR}/case-nodenv"
9088
shim="${root}/shims"
9189
tool_bin="${root}/tool-bin"
9290

9391
mkdir -p "${shim}"
9492
make_exe "${tool_bin}/npm" "exit 1"
95-
mkdir -p "${tool_bin}"
9693
cat >"${tool_bin}/nodenv" <<EOF
9794
#!/usr/bin/env bash
9895
set -euo pipefail
9996
if [[ "\${1:-}" == "rehash" ]]; then
100-
cat >"${shim}/clawdbot" <<'SHIM'
97+
cat >"${shim}/openclaw" <<'SHIM'
10198
#!/usr/bin/env bash
10299
set -euo pipefail
103100
echo ok >/dev/null
104101
SHIM
105-
chmod +x "${shim}/clawdbot"
102+
chmod +x "${shim}/openclaw"
106103
exit 0
107104
fi
108105
exit 0
109106
EOF
110107
chmod +x "${tool_bin}/nodenv"
111108

112109
export PATH="${shim}:${tool_bin}:/usr/bin:/bin"
113-
command -v clawdbot >/dev/null 2>&1 && fail "precondition: clawdbot unexpectedly present"
110+
command -v openclaw >/dev/null 2>&1 && fail "precondition: openclaw unexpectedly present"
114111

115-
got="$(resolve_clawdbot_bin)"
116-
assert_eq "$got" "${shim}/clawdbot" "resolve_clawdbot_bin (nodenv rehash)"
112+
got="$(resolve_openclaw_bin)"
113+
assert_eq "$got" "${shim}/openclaw" "resolve_openclaw_bin (nodenv rehash)"
117114
)
118115

119-
echo "==> case: warn_clawdbot_not_found (smoke)"
116+
echo "==> case: warn_openclaw_not_found (smoke)"
120117
(
121118
root="${TMP_DIR}/case-warn"
122119
tool_bin="${root}/tool-bin"
123-
make_exe "${tool_bin}/npm" 'if [[ "$1" == "prefix" && "$2" == "-g" ]]; then echo "/tmp/prefix"; exit 0; fi; if [[ "$1" == "bin" && "$2" == "-g" ]]; then echo "/tmp/prefix/bin"; exit 0; fi; exit 1'
120+
make_exe "${tool_bin}/npm" 'if [[ "$1" == "prefix" && "$2" == "-g" ]]; then echo "/tmp/prefix"; exit 0; fi; if [[ "$1" == "config" && "$2" == "get" && "$3" == "prefix" ]]; then echo "/tmp/prefix"; exit 0; fi; exit 1'
121+
export PATH="${tool_bin}:/usr/bin:/bin"
122+
123+
out="$(warn_openclaw_not_found 2>&1 || true)"
124+
assert_nonempty "$out" "warn_openclaw_not_found output"
125+
)
126+
127+
echo "==> case: ensure_pnpm (existing pnpm command)"
128+
(
129+
root="${TMP_DIR}/case-pnpm-existing"
130+
tool_bin="${root}/tool-bin"
131+
make_exe "${tool_bin}/pnpm" 'if [[ "${1:-}" == "--version" ]]; then echo "10.29.2"; exit 0; fi; exit 0'
132+
133+
export PATH="${tool_bin}:/usr/bin:/bin"
134+
PNPM_CMD=()
135+
stub_ui_and_quiet_runner
136+
137+
ensure_pnpm
138+
assert_eq "${PNPM_CMD[*]}" "pnpm" "ensure_pnpm (existing pnpm)"
139+
)
140+
141+
echo "==> case: ensure_pnpm (corepack fallback when pnpm shim missing)"
142+
(
143+
root="${TMP_DIR}/case-pnpm-corepack-fallback"
144+
tool_bin="${root}/tool-bin"
145+
mkdir -p "${tool_bin}"
146+
147+
cat >"${tool_bin}/corepack" <<'EOF'
148+
#!/usr/bin/env bash
149+
set -euo pipefail
150+
if [[ "${1:-}" == "enable" ]]; then
151+
exit 0
152+
fi
153+
if [[ "${1:-}" == "prepare" ]]; then
154+
exit 0
155+
fi
156+
if [[ "${1:-}" == "pnpm" && "${2:-}" == "--version" ]]; then
157+
echo "10.29.2"
158+
exit 0
159+
fi
160+
if [[ "${1:-}" == "pnpm" ]]; then
161+
shift
162+
echo "corepack-pnpm:$*" >/dev/null
163+
exit 0
164+
fi
165+
exit 1
166+
EOF
167+
chmod +x "${tool_bin}/corepack"
168+
169+
export PATH="${tool_bin}:/usr/bin:/bin"
170+
PNPM_CMD=()
171+
stub_ui_and_quiet_runner
172+
173+
ensure_pnpm
174+
assert_eq "${PNPM_CMD[*]}" "corepack pnpm" "ensure_pnpm (corepack fallback)"
175+
out="$(run_pnpm --version)"
176+
assert_nonempty "$out" "run_pnpm --version output"
177+
)
178+
179+
echo "==> case: ensure_pnpm (npm fallback install)"
180+
(
181+
root="${TMP_DIR}/case-pnpm-npm-fallback"
182+
tool_bin="${root}/tool-bin"
183+
mkdir -p "${tool_bin}"
184+
185+
cat >"${tool_bin}/corepack" <<'EOF'
186+
#!/usr/bin/env bash
187+
set -euo pipefail
188+
exit 1
189+
EOF
190+
chmod +x "${tool_bin}/corepack"
191+
192+
cat >"${tool_bin}/npm" <<'EOF'
193+
#!/usr/bin/env bash
194+
set -euo pipefail
195+
if [[ "${1:-}" == "install" && "${2:-}" == "-g" && "${3:-}" == "pnpm@10" ]]; then
196+
cat >"${FAKE_PNPM_BIN_DIR}/pnpm" <<'PNPM'
197+
#!/usr/bin/env bash
198+
set -euo pipefail
199+
if [[ "${1:-}" == "--version" ]]; then
200+
echo "10.29.2"
201+
exit 0
202+
fi
203+
exit 0
204+
PNPM
205+
chmod +x "${FAKE_PNPM_BIN_DIR}/pnpm"
206+
exit 0
207+
fi
208+
if [[ "${1:-}" == "prefix" && "${2:-}" == "-g" ]]; then
209+
echo "${FAKE_PNPM_BIN_DIR%/tool-bin}"
210+
exit 0
211+
fi
212+
if [[ "${1:-}" == "config" && "${2:-}" == "get" && "${3:-}" == "prefix" ]]; then
213+
echo "${FAKE_PNPM_BIN_DIR%/tool-bin}"
214+
exit 0
215+
fi
216+
exit 0
217+
EOF
218+
chmod +x "${tool_bin}/npm"
219+
220+
export FAKE_PNPM_BIN_DIR="${tool_bin}"
124221
export PATH="${tool_bin}:/usr/bin:/bin"
222+
PNPM_CMD=()
223+
stub_ui_and_quiet_runner
224+
fix_npm_permissions() { :; }
125225

126-
out="$(warn_clawdbot_not_found 2>&1 || true)"
127-
assert_nonempty "$out" "warn_clawdbot_not_found output"
226+
ensure_pnpm
227+
assert_eq "${PNPM_CMD[*]}" "pnpm" "ensure_pnpm (npm fallback)"
128228
)
129229

130230
echo "OK"

0 commit comments

Comments
 (0)