-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·208 lines (191 loc) · 7.52 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·208 lines (191 loc) · 7.52 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
#!/usr/bin/env bash
set -euo pipefail
# Stable ad-hoc identity for local macOS installs. TCC keys removable-volume
# and file grants on the designated requirement. The default ad-hoc
# requirement is `cdhash H"..."`, that binary's exact hash, so an Allow
# does not survive the next rebuild even when the identifier stays
# `dev.tracedecay.cli`. The linker default identifier is the hashed deps
# filename (`tracedecay-<hash>`). Release strip runs after the link and
# writes that filename back into the ad-hoc signature. This runs on the
# final file, after that strip, and embeds
# `designated => identifier "dev.tracedecay.cli"`. A Developer ID or other
# team signature is preserved.
TRACEDECAY_MACOS_CODE_SIGN_IDENTIFIER=dev.tracedecay.cli
# Re-sign `target` when it is an unsigned or ad-hoc Mach-O whose designated
# requirement is not the stable identifier. No-op off Darwin and for
# non-Mach-O files (the Linux installer tests install a shell fixture).
stabilize_macos_adhoc_identity() {
local target=$1
if [[ ${TRACEDECAY_ASSUME_DARWIN:-} != 1 && "$(uname -s)" != Darwin ]]; then
return 0
fi
[[ -f $target ]] || {
printf 'tracedecay installer: cannot sign missing binary %s\n' "$target" >&2
return 1
}
local magic
magic=$(od -An -t x1 -N 4 "$target" | tr -d ' \n')
case $magic in
feedfacf | cffaedfe | feedface | cefaedfe | cafebabe | bebafeca | cafebabf | bfbafeca) ;;
*) return 0 ;;
esac
local report ident team designated
# `-r-` prints `designated => ...`. `-dv` does not, so a cdhash requirement
# is invisible there.
report=$(codesign -d --verbose=2 -r- "$target" 2>&1 || true)
if printf '%s\n' "$report" | grep -q '^Authority='; then
return 0
fi
team=$(printf '%s\n' "$report" | sed -n 's/^TeamIdentifier=//p' | head -n 1)
if [[ -n $team && $team != "not set" ]]; then
return 0
fi
ident=$(printf '%s\n' "$report" | sed -n 's/^Identifier=//p' | head -n 1)
designated=$(printf '%s\n' "$report" | sed -n 's/^designated => //p' | head -n 1)
if [[ $ident == "$TRACEDECAY_MACOS_CODE_SIGN_IDENTIFIER" \
&& $designated == "identifier \"${TRACEDECAY_MACOS_CODE_SIGN_IDENTIFIER}\"" ]]; then
return 0
fi
# `-r=designated => ...` is one argument. The `=` is both how the short
# option takes its value and the marker that the value is requirement
# text rather than a path.
codesign --force --sign - \
--identifier "$TRACEDECAY_MACOS_CODE_SIGN_IDENTIFIER" \
-r="designated => identifier \"${TRACEDECAY_MACOS_CODE_SIGN_IDENTIFIER}\"" \
"$target"
}
# The macOS link wrapper sources this file to reuse the function above.
if [[ ${TRACEDECAY_INSTALL_LIBRARY:-} == 1 && ${BASH_SOURCE[0]} != "$0" ]]; then
return 0
fi
repository=${TRACEDECAY_REPOSITORY:-ScriptedAlchemy/tracedecay}
install_dir=${TRACEDECAY_INSTALL_DIR:-${XDG_BIN_HOME:-${HOME}/.local/bin}}
requested_version=${TRACEDECAY_VERSION:-latest}
release_root="https://github.com/${repository}/releases"
fail() {
printf 'tracedecay installer: %s\n' "$*" >&2
exit 1
}
command -v curl >/dev/null 2>&1 || fail "curl is required"
command -v install >/dev/null 2>&1 || fail "install is required"
command -v tar >/dev/null 2>&1 || fail "tar is required"
case "$(uname -s)/$(uname -m)" in
Linux/x86_64 | Linux/amd64)
platform=x86_64-linux
;;
Linux/aarch64 | Linux/arm64)
platform=aarch64-linux
;;
Darwin/arm64 | Darwin/aarch64)
platform=aarch64-macos
;;
*)
fail "unsupported platform: $(uname -s) $(uname -m)"
;;
esac
# release-beta.yml names prerelease archives `tracedecay-beta-<tag>-...`;
# release.yml names stable ones `tracedecay-<tag>-...`.
asset_name_for_tag() {
local candidate=$1
if [[ $candidate == *-beta.* ]]; then
printf 'tracedecay-beta-%s-%s.tar.gz' "$candidate" "$platform"
else
printf 'tracedecay-%s-%s.tar.gz' "$candidate" "$platform"
fi
}
# True when the releases API payload already lists both the platform archive
# and SHA256SUMS for this tag. Release Please can publish a non-draft
# prerelease before release-beta.yml uploads those assets; matching on
# browser_download_url paths skips that half-published window. The payload is
# far larger than a pipe buffer, so piping it into `grep -q` lets the writer
# die of SIGPIPE and `pipefail` turns a match into 141; grep a here-string.
release_has_install_assets() {
local json=$1
local candidate=$2
local candidate_asset=$3
grep -Fq -- "/download/${candidate}/${candidate_asset}" <<<"$json" &&
grep -Fq -- "/download/${candidate}/SHA256SUMS" <<<"$json"
}
# `latest` is the newest published release including prereleases, because the
# 0.1.0 beta line is where tracedecay ships. GitHub's `releases/latest`
# redirect never resolves to a prerelease, so it pinned installs to the last
# stable tag (v0.0.74, 2026-08-19) and the whole beta line was unreachable.
# Walk recent releases and skip any that lack the platform archive + checksum
# (common while a beta build is still uploading). `TRACEDECAY_VERSION=stable`
# opts back into the releases/latest redirect.
case $requested_version in
latest)
tag=
releases_json=$(
curl -fsSL "https://api.github.com/repos/${repository}/releases?per_page=30"
)
while IFS= read -r candidate; do
[[ -n $candidate ]] || continue
candidate_asset=$(asset_name_for_tag "$candidate")
if release_has_install_assets "$releases_json" "$candidate" "$candidate_asset"; then
tag=$candidate
break
fi
done < <(
printf '%s' "$releases_json" |
grep -o '"tag_name"[[:space:]]*:[[:space:]]*"[^"]*"' |
cut -d'"' -f4
)
[[ -n $tag ]] ||
fail "no published release has install assets for ${platform}"
;;
stable)
resolved_url=$(curl -fsSL -o /dev/null -w '%{url_effective}' "${release_root}/latest")
tag=${resolved_url##*/}
;;
*)
tag="v${requested_version#v}"
;;
esac
[[ $tag == v* ]] || fail "GitHub did not return a valid release tag"
asset=$(asset_name_for_tag "$tag")
asset_root="${release_root}/download/${tag}"
tmp_dir=$(mktemp -d)
trap 'rm -rf "$tmp_dir"' EXIT
curl -fsSL "${asset_root}/${asset}" -o "${tmp_dir}/${asset}"
curl -fsSL "${asset_root}/SHA256SUMS" -o "${tmp_dir}/SHA256SUMS"
if ! expected=$(
awk -v asset="$asset" '
$2 == asset || $2 == "*" asset {
matches += 1
digest = $1
fields = NF
}
END {
if (matches != 1 || fields != 2) {
exit 1
}
print digest
}
' "${tmp_dir}/SHA256SUMS"
); then
fail "SHA256SUMS must contain exactly one entry for ${asset}"
fi
[[ $expected =~ ^[[:xdigit:]]{64}$ ]] ||
fail "SHA256SUMS has an invalid digest for ${asset}"
expected=$(printf '%s' "$expected" | tr '[:upper:]' '[:lower:]')
if command -v sha256sum >/dev/null 2>&1; then
actual=$(sha256sum "${tmp_dir}/${asset}" | awk '{print $1}')
elif command -v shasum >/dev/null 2>&1; then
actual=$(shasum -a 256 "${tmp_dir}/${asset}" | awk '{print $1}')
else
fail "sha256sum or shasum is required"
fi
[[ $actual == "$expected" ]] || fail "checksum mismatch for ${asset}"
tar -xzf "${tmp_dir}/${asset}" -C "$tmp_dir"
[[ -f ${tmp_dir}/tracedecay ]] || fail "archive does not contain tracedecay"
mkdir -p "$install_dir"
install -m 0755 "${tmp_dir}/tracedecay" "${install_dir}/tracedecay"
# After the archive checksum check. Re-signing changes the installed bytes
# only; the published digest still matches the archive.
stabilize_macos_adhoc_identity "${install_dir}/tracedecay"
printf 'Installed tracedecay %s to %s\n' "${tag#v}" "${install_dir}/tracedecay"
case ":${PATH}:" in
*":${install_dir}:"*) ;;
*) printf 'Add %s to PATH to run tracedecay.\n' "$install_dir" ;;
esac