-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·308 lines (275 loc) · 12.2 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·308 lines (275 loc) · 12.2 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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
#!/bin/sh
# Preloop installer — instant install from release binaries.
#
# curl -fsSL https://raw.githubusercontent.com/preloopdev/preloop/main/install.sh | sh
#
# Downloads the prebuilt binaries for your platform (preloop, preloop-server,
# preloop-runner) from the latest GitHub release, verifies the sha256, and
# installs into ~/.local/bin. When no release exists for the platform yet it
# falls back to building from source (git + cargo + zig).
#
# Options: --version <tag> install a specific release (default: latest)
# --prefix <dir> install under <dir>/bin (default: ~/.local)
set -e
PREFIX="${PREFIX:-$HOME/.local}"
VERSION="${VERSION:-latest}"
REPO="preloopdev/preloop"
BIN_DIR="$PREFIX/bin"
say() { printf '\033[1;32m[preloop]\033[0m %s\n' "$*"; }
die() { printf '\033[1;31m[preloop] error:\033[0m %s\n' "$*" >&2; exit 1; }
while [ $# -gt 0 ]; do
case "$1" in
--version) VERSION="${2:?--version needs a value}"; shift 2 ;;
--prefix) PREFIX="${2:?--prefix needs a value}"; shift 2 ;;
-h|--help) grep '^#' "$0" | sed 's/^# \{0,1\}//' | head -12; exit 0 ;;
*) die "unknown option: $1" ;;
esac
done
BIN_DIR="$PREFIX/bin"
# --- platform ---------------------------------------------------------------
os="$(uname -s | tr '[:upper:]' '[:lower:]')"
case "$os" in
linux) os="linux" ;;
darwin) os="darwin" ;;
*) die "unsupported operating system: $os (want linux or darwin)" ;;
esac
arch="$(uname -m | tr '[:upper:]' '[:lower:]')"
case "$arch" in
x86_64|amd64) arch="x86_64" ;;
aarch64|arm64) arch="aarch64" ;;
*) die "unsupported architecture: $arch (want x86_64 or aarch64)" ;;
esac
full_triple() {
case "$os/$arch" in
linux/x86_64) echo "x86_64-unknown-linux-gnu" ;;
linux/aarch64) echo "aarch64-unknown-linux-gnu" ;;
darwin/x86_64) echo "x86_64-apple-darwin" ;;
darwin/aarch64) echo "aarch64-apple-darwin" ;;
esac
}
# --- release download -------------------------------------------------------
release_json() { # tag or latest
if command -v curl >/dev/null 2>&1; then
curl -fsSL "https://api.github.com/repos/$REPO/releases/$1" 2>/dev/null && return 0
fi
if command -v gh >/dev/null 2>&1; then
gh api "repos/$REPO/releases/$1" 2>/dev/null && return 0
fi
return 1
}
# --- smolvm runtime --------------------------------------------------------
ensure_runtime() {
say "installing compatible smolvm runtime..."
# The freshly installed runtime lives in $HOME/.local/bin; put it ahead of
# $BIN_DIR so a stale custom-prefix binary cannot shadow it.
PATH="$HOME/.local/bin:$BIN_DIR:$PATH" \
"$BIN_DIR/preloop" update --ensure-runtime \
|| die "could not install a compatible smolvm runtime"
local smolvm_bin="$HOME/.local/bin/smolvm"
[ -x "$smolvm_bin" ] || die "smolvm was not installed at $smolvm_bin"
local smolvm_version
smolvm_version="$("$smolvm_bin" --version 2>/dev/null | awk '{print $NF}')"
[ -n "$smolvm_version" ] \
|| die "installed smolvm did not report a version"
# Mirror SMOLVM_MIN_VERSION in crates/preloop-cli/src/update.rs: the
# ownership-preserving runtime is the minimum this installer can rely on,
# and `preloop update --ensure-runtime` may be bypassed or regress.
smolvm_version_ge "$smolvm_version" "1.8.1" \
|| die "installed smolvm $smolvm_version is older than the required 1.8.1"
# Keep custom-prefix installs self-contained and ahead of any incompatible
# system smolvm already on PATH.
if [ "$BIN_DIR" != "$HOME/.local/bin" ]; then
ln -sfn "$smolvm_bin" "$BIN_DIR/smolvm"
fi
say "installed smolvm $smolvm_version"
}
# Numeric dotted-version comparison for the smolvm runtime gate (POSIX sh).
# Returns 0 when $1 >= $2, 1 otherwise. Non-numeric suffixes (e.g. "-rc1")
# are ignored, so "1.8.1-rc1" compares as "1.8.1".
smolvm_version_ge() {
awk -v installed="$1" -v min="$2" '
BEGIN {
result = cmp(installed, min) < 0
exit result
}
function nums(v, i, a, out) {
n = split(v, a, /[^0-9]+/)
for (i = 1; i <= 3; i++) out = out (i > 1 ? "." : "") (a[i] + 0)
return out
}
function cmp(a, b, x, y, i) {
split(nums(a), x, "."); split(nums(b), y, ".")
for (i = 1; i <= 3; i++) {
if (x[i] + 0 > y[i] + 0) return 1
if (x[i] + 0 < y[i] + 0) return -1
}
return 0
}
'
}
install_from_release() {
local tag="$VERSION"
local json
if [ "$tag" = "latest" ]; then
json="$(release_json latest)" || return 1
else
json="$(release_json "tags/$tag")" || return 1
fi
tag="$(printf '%s' "$json" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)"
[ -n "$tag" ] || return 1
# cargo-dist names the per-platform archive after the package
# (`preloop-cli-<triple>.tar.gz`); the tag is not part of the filename.
local short="preloop-cli-${os}-${arch}.tar.gz"
local full="preloop-cli-$(full_triple).tar.gz"
local url asset
asset="$(printf '%s' "$json" | sed -n "s/.*\"browser_download_url\":[[:space:]]*\"\([^\"]*\/$short\)\".*/\1/p" | head -1)"
if [ -z "$asset" ]; then
asset="$(printf '%s' "$json" | sed -n "s/.*\"browser_download_url\":[[:space:]]*\"\([^\"]*\/$full\)\".*/\1/p" | head -1)"
fi
[ -n "$asset" ] || return 1
say "downloading $tag ($os/$arch)..."
local tmp
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
local archive="$tmp/$(basename "$asset")"
local asset_name="$(basename "$asset")"
if command -v curl >/dev/null 2>&1; then
curl -fsSL "$asset" -o "$archive" 2>/dev/null || archive=""
elif command -v wget >/dev/null 2>&1; then
wget -q "$asset" -O "$archive" 2>/dev/null || archive=""
fi
if [ -z "${archive:-}" ] || [ ! -s "$archive" ]; then
# Private repositories 404 unauthenticated downloads; the authenticated
# gh client covers them, and works just the same once public.
if command -v gh >/dev/null 2>&1; then
archive="$tmp/$asset_name"
rm -f "$archive"
(cd "$tmp" && gh release download "$tag" --repo "$REPO" --pattern "$asset_name" --clobber >/dev/null 2>&1) \
|| archive=""
fi
fi
[ -n "${archive:-}" ] && [ -s "$archive" ] || return 1
# cargo-dist checksum files bake the build machine's absolute path, so
# compare hashes by value instead of `sha256sum -c`.
local sha_url="${asset}.sha256" expected actual
local sha_name="$(basename "$sha_url")"
expected="$(curl -fsSL "$sha_url" 2>/dev/null | awk '{print $1}')"
if [ -z "$expected" ] && command -v gh >/dev/null 2>&1; then
(cd "$tmp" && gh release download "$tag" --repo "$REPO" --pattern "$sha_name" --clobber >/dev/null 2>&1) \
&& expected="$(awk '{print $1}' "$tmp/$sha_name" 2>/dev/null)"
fi
if [ -n "$expected" ]; then
if command -v sha256sum >/dev/null 2>&1; then
actual="$(sha256sum "$archive" | awk '{print $1}')"
else
actual="$(shasum -a 256 "$archive" | awk '{print $1}')"
fi
[ "$actual" = "$expected" ] || die "checksum mismatch — refusing to install"
say "sha256 verified"
fi
mkdir -p "$tmp/extract"
tar -xzf "$archive" -C "$tmp/extract" --strip-components=1
mkdir -p "$BIN_DIR"
for bin in preloop preloop-server preloop-runner; do
if [ -f "$tmp/extract/$bin" ]; then
install -m 0755 "$tmp/extract/$bin" "$BIN_DIR/$bin"
say "installed $BIN_DIR/$bin"
fi
done
[ -x "$BIN_DIR/preloop" ] || return 1
# macOS installs execute workflows inside Linux microVMs, so the engine
# needs the Linux guest runner at the path it discovers
# (<prefix>/lib/preloop/runner/<linux-triple>/preloop-runner). Without it
# every job queues forever with "Linux runner bundle unavailable". A
# release missing the asset is a warning, not a failure — the engine's
# startup message explains the consequence.
if [ "$os" = "darwin" ]; then
local runner_triple
case "$arch" in
x86_64) runner_triple="x86_64-unknown-linux-gnu" ;;
aarch64) runner_triple="aarch64-unknown-linux-gnu" ;;
esac
local runner_asset="preloop-runner-${runner_triple}"
local runner_url
runner_url="$(printf '%s' "$json" | sed -n "s/.*\"browser_download_url\":[[:space:]]*\"\([^\"]*\/$runner_asset\)\".*/\1/p" | head -1)"
if [ -n "$runner_url" ]; then
local runner_dest="$PREFIX/lib/preloop/runner/$runner_triple"
mkdir -p "$runner_dest"
curl -fsSL "$runner_url" -o "$runner_dest/preloop-runner" 2>/dev/null \
&& chmod 0755 "$runner_dest/preloop-runner" \
&& say "installed $runner_dest/preloop-runner" \
|| say "warning: could not install Linux runner bundle — microVM jobs need it"
else
say "warning: release $tag has no $runner_asset asset — microVM jobs need it"
fi
fi
ensure_runtime
return 0
}
if install_from_release; then
case ":$PATH:" in
*":$BIN_DIR:"*) ;;
*) say "add $BIN_DIR to your PATH: export PATH=\"$BIN_DIR:\$PATH\"" ;;
esac
cat <<EOF
[preloop] next steps:
preloop serve # start the engine on 127.0.0.1:9090
preloop setup github # GitHub App or fine-grained PAT
cd your-repo && preloop run -f .github/workflows/ci.yml
preloop run --push --create-pr # CI first, then a draft PR
[preloop] full guide: https://github.com/preloopdev/preloop/blob/main/docs/setup.md
EOF
exit 0
fi
# --- source fallback (no release for this platform yet) ----------------------
say "no prebuilt binary for $os/$arch in release $VERSION — building from source"
command -v git >/dev/null 2>&1 || die "git is required"
command -v cargo >/dev/null 2>&1 || {
command -v rustup >/dev/null 2>&1 || die "rustup/cargo is required — install from https://rustup.rs"
die "cargo not found — run: rustup toolchain install stable && rustup default stable"
}
if command -v zig >/dev/null 2>&1; then
command -v cargo-zigbuild >/dev/null 2>&1 || say "zig found; cargo-zigbuild missing — the Linux microVM runner will be skipped (run: cargo install cargo-zigbuild)"
ZIGBUILD=1
else
say "zig not found — building host binaries only; microVM runner needs zig (macOS: brew install zig)"
ZIGBUILD=0
fi
PRELOOP_SRC="${PRELOOP_SRC:-$HOME/.preloop-src}"
REPO_URL="${PRELOOP_REPO:-https://github.com/preloopdev/preloop.git}"
mkdir -p "$PRELOOP_SRC"
if [ -d "$PRELOOP_SRC/.git" ]; then
say "refreshing $PRELOOP_SRC"
git -C "$PRELOOP_SRC" fetch --quiet --depth=1 origin main
git -C "$PRELOOP_SRC" checkout --quiet FETCH_HEAD
else
say "cloning $REPO_URL into $PRELOOP_SRC"
git clone --quiet --depth=1 "$REPO_URL" "$PRELOOP_SRC"
fi
cd "$PRELOOP_SRC"
say "building preloop (release)..."
cargo build --release -p preloop-cli -p preloop-runner-server 2>/dev/null \
|| cargo build --release -p preloop-cli -p aksh-runner-server
if [ "$ZIGBUILD" = 1 ] && command -v cargo-zigbuild >/dev/null 2>&1; then
say "cross-compiling the Linux microVM runner (aarch64)..."
cargo zigbuild --release -p preloop-runner --target aarch64-unknown-linux-gnu 2>/dev/null || \
cargo zigbuild --release -p aksh-runner --target aarch64-unknown-linux-gnu 2>/dev/null || \
say "runner build failed — host CLI works, but microVM jobs need it (see docs/setup.md)"
else
say "skipping microVM runner cross-build (no zig/cargo-zigbuild)"
fi
mkdir -p "$BIN_DIR"
ln -sfn "$PRELOOP_SRC/target/release/preloop" "$BIN_DIR/preloop"
say "installed $BIN_DIR/preloop (source build)"
ensure_runtime
case ":$PATH:" in
*":$BIN_DIR:"*) ;;
*) say "add $BIN_DIR to your PATH: export PATH=\"$BIN_DIR:\$PATH\"" ;;
esac
cat <<EOF
[preloop] next steps:
preloop serve # start the engine on 127.0.0.1:9090
preloop setup github # GitHub App or fine-grained PAT
cd your-repo && preloop run -f .github/workflows/ci.yml
[preloop] full guide: https://github.com/preloopdev/preloop/blob/main/docs/setup.md
EOF