-
-
Notifications
You must be signed in to change notification settings - Fork 27
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·221 lines (190 loc) · 6.93 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·221 lines (190 loc) · 6.93 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
#!/bin/sh
# OpenASR CLI installer.
#
# curl -fsSL https://dl.openasr.org/install.sh | sh
#
# POSIX sh on purpose (invoked as `... | sh`, not `| bash`): this must run
# unmodified under dash (Debian/Ubuntu's /bin/sh), busybox ash, and bash.
#
# What it does:
# 1. Detects OS + arch and maps them to a released asset name.
# 2. Resolves the latest GitHub release tag via the `releases/latest`
# redirect (no GitHub API call, so no unauthenticated rate limit).
# 3. Downloads the release tarball and the release's SHA256SUMS file, and
# verifies the tarball's checksum before touching anything else. This
# is fail-closed by design, matching OpenASR's "no cloud, no unverified
# binaries" posture: a checksum mismatch (or missing checksum tool)
# deletes the download and exits non-zero rather than installing
# something unverified.
# 4. Installs the `openasr` binary into --prefix (default ~/.local/bin,
# created if missing), never using sudo.
#
# Usage:
# install.sh [--prefix DIR] [--version vX.Y.Z]
#
# Env overrides (equivalent to the flags above): OPENASR_INSTALL_PREFIX,
# OPENASR_INSTALL_VERSION.
set -eu
REPO="QuintinShaw/openasr"
GITHUB="https://github.com"
prefix="${OPENASR_INSTALL_PREFIX:-$HOME/.local/bin}"
version="${OPENASR_INSTALL_VERSION:-}"
err() {
echo "error: $*" >&2
exit 1
}
info() {
echo "==> $*"
}
while [ $# -gt 0 ]; do
case "$1" in
--prefix)
[ $# -ge 2 ] || err "--prefix requires a directory argument"
prefix="$2"
shift 2
;;
--prefix=*)
prefix="${1#--prefix=}"
shift
;;
--version)
[ $# -ge 2 ] || err "--version requires a tag argument (e.g. v0.1.14)"
version="$2"
shift 2
;;
--version=*)
version="${1#--version=}"
shift
;;
-h | --help)
sed -n '2,25p' "$0" | sed 's/^# \{0,1\}//'
exit 0
;;
*)
err "unknown argument: $1 (see --help)"
;;
esac
done
# -- OS / arch detection -----------------------------------------------------
os_raw="$(uname -s)"
arch_raw="$(uname -m)"
case "$os_raw" in
Darwin) os="macos" ;;
Linux) os="linux" ;;
*) err "unsupported OS: $os_raw (OpenASR ships macOS and Linux builds; see $GITHUB/$REPO/releases for other platforms, e.g. Windows)" ;;
esac
case "$arch_raw" in
arm64 | aarch64) arch="arm64" ;;
x86_64 | amd64) arch="x86_64" ;;
*) err "unsupported architecture: $arch_raw" ;;
esac
# Linux uses the statically linked musl build by default: it runs unmodified
# across glibc and musl distros alike (no dynamic-loader version to match),
# which matters far more for a curl|sh installer hitting arbitrary hosts than
# for the Homebrew tap (Homebrew-on-Linux already requires glibc, so it uses
# the dynamic build instead). macOS has only one libc, so no musl variant
# exists there.
if [ "$os" = "linux" ]; then
target="linux-${arch}-musl"
else
target="${os}-${arch}"
fi
# -- Resolve version ----------------------------------------------------------
if [ -z "$version" ]; then
info "resolving latest release"
# `releases/latest` 302-redirects to `.../releases/tag/vX.Y.Z`; read the
# final URL rather than following it, so this needs one request and no
# GitHub API call (which is rate-limited per-IP for unauthenticated use).
latest_url="$(curl -fsSL -o /dev/null -w '%{url_effective}' "$GITHUB/$REPO/releases/latest")" \
|| err "could not resolve the latest release from $GITHUB/$REPO/releases/latest"
version="${latest_url##*/}"
[ -n "$version" ] || err "could not parse a release tag from $latest_url"
fi
case "$version" in
v*) version_num="${version#v}" ;;
*) version_num="$version" ;;
esac
info "installing openasr $version ($target) to $prefix"
# -- Download + verify --------------------------------------------------------
asset="openasr-${version_num}-${target}.tar.gz"
github_base="$GITHUB/$REPO/releases/download/$version"
china_base="https://dl.bug.im/cli/$version"
china_transport() {
ds="$(printf '%s' "${OPENASR_DOWNLOAD_SOURCE-}" | tr 'A-Z' 'a-z')"
case "$ds" in
china) return 0 ;;
global) return 1 ;;
esac
loc="$(printf '%s' "${LC_ALL:-${LC_MESSAGES:-${LANG:-}}}" | tr 'A-Z' 'a-z')"
loc_lang="$(printf '%s' "$loc" | sed 's/[.@].*//; s/-/_/g')"
case "$loc_lang" in
zh|zh_cn|zh_cn_*|zh_hans|zh_hans_*) return 0 ;;
esac
tz="$(printf '%s' "${TZ:-}" | tr 'A-Z' 'a-z' | tr '\\' '/')"
if [ -z "$tz" ] && [ -L /etc/localtime ]; then
tz="$(readlink /etc/localtime 2>/dev/null | tr 'A-Z' 'a-z' | tr '\\' '/')"
fi
case "$tz" in
*asia/shanghai* | *asia/chongqing* | *asia/harbin* | *asia/urumqi* | *asia/hong_kong* | *asia/macau* | prc) return 0 ;;
esac
return 1
}
workdir="$(mktemp -d)"
cleanup() {
rm -rf "$workdir"
}
trap cleanup EXIT INT TERM
archive="$workdir/$asset"
sums="$workdir/SHA256SUMS"
info "downloading $asset"
if china_transport; then
if ! curl -fsSL -o "$archive" "$china_base/$asset"; then
info "China mirror missed $asset; falling back to GitHub"
curl -fsSL -o "$archive" "$github_base/$asset" \
|| err "download failed: $github_base/$asset (check that $version shipped a $target build)"
fi
else
curl -fsSL -o "$archive" "$github_base/$asset" \
|| err "download failed: $github_base/$asset (check that $version shipped a $target build)"
fi
# Checksums always come from official GitHub, never from an accelerator.
curl -fsSL -o "$sums" "$github_base/SHA256SUMS" \
|| err "download failed: $github_base/SHA256SUMS"
expected_line="$(grep -F " $asset" "$sums" || true)"
[ -n "$expected_line" ] || err "SHA256SUMS has no entry for $asset -- refusing to install an unverifiable binary"
expected_sha="${expected_line%% *}"
if command -v sha256sum >/dev/null 2>&1; then
actual_sha="$(sha256sum "$archive" | awk '{print $1}')"
elif command -v shasum >/dev/null 2>&1; then
actual_sha="$(shasum -a 256 "$archive" | awk '{print $1}')"
else
err "no sha256sum/shasum found -- refusing to install without checksum verification"
fi
if [ "$actual_sha" != "$expected_sha" ]; then
err "checksum mismatch for $asset (expected $expected_sha, got $actual_sha) -- download deleted, not installing"
fi
info "checksum verified"
# -- Extract + install ---------------------------------------------------------
extract_dir="$workdir/extract"
mkdir -p "$extract_dir"
tar -xzf "$archive" -C "$extract_dir"
binary="$(find "$extract_dir" -type f -name openasr -maxdepth 2 | head -n 1)"
[ -n "$binary" ] || err "extracted archive did not contain an 'openasr' binary"
chmod +x "$binary"
mkdir -p "$prefix"
dest="$prefix/openasr"
if [ -x "$dest" ]; then
old_version="$("$dest" --version 2>/dev/null || echo unknown)"
info "found existing install ($old_version) at $dest -- upgrading to $version"
fi
mv "$binary" "$dest"
info "installed $("$dest" --version) to $dest"
case ":$PATH:" in
*":$prefix:"*) ;;
*)
echo
echo "$prefix is not on your PATH. Add it, e.g.:"
echo " export PATH=\"$prefix:\$PATH\""
echo "(append that line to your shell's rc file to make it permanent)"
;;
esac