-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuddy
More file actions
executable file
·182 lines (159 loc) · 7.01 KB
/
Copy pathbuddy
File metadata and controls
executable file
·182 lines (159 loc) · 7.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/bin/sh
set -e
ROOT_DIR=$(CDPATH= cd -- "$(dirname "$0")" && pwd)
PANTRY_LOCAL_BIN="${ROOT_DIR}/pantry/.bin"
PANTRY_DIR="${ROOT_DIR}/pantry"
USER_LOCAL_BIN="${HOME}/.local/bin"
PANTRY_INSTALLER="${ROOT_DIR}/storage/framework/scripts/pantry-install"
PANTRY_SETUP_DONE="${PANTRY_DIR}/.postsetup-done"
PANTRY_BOOTSTRAP_TIMEOUT_SECONDS="${PANTRY_BOOTSTRAP_TIMEOUT_SECONDS:-600}"
PANTRY_DEPENDENCIES_TIMEOUT_SECONDS="${PANTRY_DEPENDENCIES_TIMEOUT_SECONDS:-1200}"
# Resolve which CLI entrypoint to invoke. Resolution order matches the
# action-runner fallback chain in `@stacksjs/actions`:
#
# 1. `storage/framework/core/buddy/src/cli.ts` — userland override (legacy
# "framework lives in the project" layout). Kept FIRST so projects that
# have published buddy via `buddy publish:core buddy` still win.
# 2. `node_modules/@stacksjs/buddy/src/cli.ts` — installed package, TS source
# (workspace symlink or a real npm install with `src/` shipped).
# 3. `node_modules/@stacksjs/buddy/dist/cli.js` — published JS-only build.
#
# If none of these are present the script bails with a clear message instead
# of `bun` exploding on a missing file.
resolve_buddy_entry() {
for candidate in \
"${ROOT_DIR}/storage/framework/core/buddy/src/cli.ts" \
"${ROOT_DIR}/node_modules/@stacksjs/buddy/src/cli.ts" \
"${ROOT_DIR}/node_modules/@stacksjs/buddy/dist/cli.js" \
; do
if [ -f "${candidate}" ]; then
echo "${candidate}"
return 0
fi
done
return 1
}
if ! BUDDY_ENTRY=$(resolve_buddy_entry); then
echo "buddy: could not locate CLI entrypoint." >&2
echo " Tried: storage/framework/core/buddy/src/cli.ts, node_modules/@stacksjs/buddy/{src/cli.ts,dist/cli.js}." >&2
echo " Run \`bun install\` or \`buddy publish:core buddy\` to make the CLI available." >&2
exit 1
fi
run_with_timeout() {
timeout_seconds="$1"
shift
timeout_flag="${TMPDIR:-/tmp}/buddy-timeout-$$"
rm -f "${timeout_flag}"
"$@" &
cmd_pid=$!
(
# Do not let the timer inherit the deployment lock or a caller's
# stdout/stderr pipe. If the
# watchdog shell is terminated after the command finishes, its sleep may
# briefly remain orphaned; inherited deploy descriptors would otherwise
# keep the release locked until the full timeout elapsed.
exec 9>&-
sleep "${timeout_seconds}" </dev/null >/dev/null 2>&1
if kill -0 "${cmd_pid}" 2>/dev/null; then
echo "Command timed out after ${timeout_seconds}s: $*" >&2
: > "${timeout_flag}"
kill "${cmd_pid}" 2>/dev/null || true
sleep 2
kill -9 "${cmd_pid}" 2>/dev/null || true
fi
) &
watchdog_pid=$!
wait "${cmd_pid}"
status=$?
kill "${watchdog_pid}" 2>/dev/null || true
wait "${watchdog_pid}" 2>/dev/null || true
if [ -f "${timeout_flag}" ]; then
rm -f "${timeout_flag}"
return 124
fi
rm -f "${timeout_flag}"
return "${status}"
}
is_usable_bun() {
[ -x "$1" ] && sh -c '"$1" --version >/dev/null 2>&1' sh "$1" 2>/dev/null
}
# Run buddy with the correct PATH and NODE_PATH for pantry resolution.
run_buddy() {
BUN_CMD="$1"
shift
# When the framework SOURCE is vendored here (storage/framework/core) AND the
# installed @stacksjs/* packages actually ship src (a workspace/source-linked
# checkout), resolve them from src via the `development` export condition so the
# monorepo runs build-free (a fresh checkout has no dist yet).
#
# Guard on a representative package having src: an app that vendors the core but
# installs the PUBLISHED (dist-only) packages has no src, so the `development`
# condition would resolve to ./src/* files that were never shipped (`error:
# preload not found "@stacksjs/env/plugin.js"`, then Cannot-find-module for
# every other import). In that case omit the flag and let bun/import/default
# resolve the dist.
CONDITIONS=""
if [ -d "${ROOT_DIR}/storage/framework/core" ] && [ -f "${ROOT_DIR}/node_modules/@stacksjs/env/src/index.ts" ]; then
CONDITIONS="--conditions development"
fi
# Installed dependencies are authoritative; Pantry is a fallback for tools
# the app does not install. Keeping node_modules first prevents a stale local
# Pantry snapshot from changing migrations, builds, or production commands.
# Only add Pantry after setup completed so a partial bootstrap cannot affect
# module resolution.
if [ -f "${PANTRY_SETUP_DONE}" ]; then
exec env PATH="${PANTRY_LOCAL_BIN}:${USER_LOCAL_BIN}:${PATH}" NODE_PATH="${ROOT_DIR}/node_modules:${PANTRY_DIR}${NODE_PATH:+:${NODE_PATH}}" "${BUN_CMD}" ${CONDITIONS} "${BUDDY_ENTRY}" "$@"
fi
exec env PATH="${PANTRY_LOCAL_BIN}:${USER_LOCAL_BIN}:${PATH}" "${BUN_CMD}" ${CONDITIONS} "${BUDDY_ENTRY}" "$@"
}
# Fast path: if pantry is already set up, run immediately. We deliberately
# DO NOT run `pantry install` here — re-installing on every invocation
# burned ~1s of `buddy --help` startup time (and made shell completion
# unusable). Once the pantry directory exists and a bun is on PATH, we
# trust that state until the user explicitly runs `bun install` or
# `buddy install`. To force a refresh, set STACKS_FORCE_PANTRY=1.
if is_usable_bun "${PANTRY_LOCAL_BIN}/bun" && [ "${STACKS_FORCE_PANTRY:-}" != "1" ]; then
run_buddy "${PANTRY_LOCAL_BIN}/bun" "$@"
fi
if [ -d "${PANTRY_DIR}" ] && command -v bun >/dev/null 2>&1 && [ "${STACKS_FORCE_PANTRY:-}" != "1" ]; then
run_buddy "$(command -v bun)" "$@"
fi
# node_modules layout (framework from npm, not vendored): there is no per-project
# pantry to bootstrap and none is needed to run the CLI — if a bun runtime is on
# PATH and the pantry installer is absent, just use it.
if command -v bun >/dev/null 2>&1 && [ "${STACKS_FORCE_PANTRY:-}" != "1" ] && [ ! -x "${PANTRY_INSTALLER}" ]; then
run_buddy "$(command -v bun)" "$@"
fi
# Pantry not set up (or an earlier bootstrap died halfway) - bootstrap it.
# Every step is failure-tolerant on purpose: a pantry download/install hiccup
# (a registry outage, or an unpublished release winning the race against CI)
# must not abort this script under `set -e` before the bun fallbacks below
# run. With a bun on PATH and node_modules present, the CLI runs identically
# without pantry.
pantry_bootstrap_failed=0
if ! command -v pantry >/dev/null 2>&1; then
if [ -x "${PANTRY_INSTALLER}" ]; then
run_with_timeout "${PANTRY_BOOTSTRAP_TIMEOUT_SECONDS}" "${PANTRY_INSTALLER}" || pantry_bootstrap_failed=1
export PATH="${USER_LOCAL_BIN}:${PATH}"
else
echo "Pantry installer not found at ${PANTRY_INSTALLER}" >&2
pantry_bootstrap_failed=1
fi
fi
if command -v pantry >/dev/null 2>&1; then
run_with_timeout "${PANTRY_DEPENDENCIES_TIMEOUT_SECONDS}" pantry install || pantry_bootstrap_failed=1
else
pantry_bootstrap_failed=1
fi
# After install, try again
if is_usable_bun "${PANTRY_LOCAL_BIN}/bun"; then
run_buddy "${PANTRY_LOCAL_BIN}/bun" "$@"
fi
if command -v bun >/dev/null 2>&1; then
if [ "${pantry_bootstrap_failed}" = "1" ]; then
echo "buddy: pantry bootstrap incomplete; falling back to the bun on PATH." >&2
fi
run_buddy "$(command -v bun)" "$@"
fi
echo "Pantry did not provide a local bun runtime." >&2
exit 1