Repository navigation
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·159 lines (144 loc) · 5.06 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·159 lines (144 loc) · 5.06 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
#!/bin/sh
# Installs the latest tk release binary for this machine.
#
# curl --proto '=https' --tlsv1.2 -LsSf https://raw.githubusercontent.com/tkhq/tk/main/install.sh | sh
#
# Set TK_INSTALL_DIR to an absolute directory to install somewhere other than
# $HOME/.local/bin. Set TK_VERSION to a release tag (v0.2.0) or a pull request
# prerelease tag (pr-44-abc1234) to install that build instead of the latest
# release.
set -eu
repository_url="https://github.com/tkhq/tk"
for tool in awk curl install mkdir mktemp mv rm tar uname; do
if ! command -v "$tool" >/dev/null 2>&1; then
echo "error: $tool is required to install tk" >&2
exit 1
fi
done
install_dir=${TK_INSTALL_DIR:-}
if [ -z "$install_dir" ]; then
if [ -z "${HOME:-}" ]; then
echo "error: HOME is not set; set TK_INSTALL_DIR to an absolute directory" >&2
exit 1
fi
install_dir="$HOME/.local/bin"
fi
case "$install_dir" in
/*) ;;
*)
echo "error: TK_INSTALL_DIR must be an absolute path" >&2
exit 1
;;
esac
operating_system=$(uname -s)
architecture=$(uname -m)
case "$operating_system:$architecture" in
Linux:x86_64) target="x86_64-unknown-linux-musl" ;;
Linux:aarch64) target="aarch64-unknown-linux-musl" ;;
Darwin:arm64) target="aarch64-apple-darwin" ;;
*)
echo "error: tk releases do not support $operating_system $architecture" >&2
exit 1
;;
esac
temporary_dir=$(mktemp -d "${TMPDIR:-/tmp}/tk-install.XXXXXX")
staged_binary=
cleanup() {
if [ -n "$staged_binary" ]; then
rm -f "$staged_binary"
fi
rm -rf "$temporary_dir"
}
trap cleanup EXIT HUP INT TERM
version=${TK_VERSION:-}
if [ -n "$version" ]; then
case "$version" in
*[!A-Za-z0-9._-]*)
echo "error: TK_VERSION must be a release or prerelease tag such as v0.2.0 or pr-44-abc1234" >&2
exit 1
;;
esac
else
# The /releases/latest redirect names the newest release without an API token.
latest_url=$(curl --proto '=https' --tlsv1.2 -LsSf --head \
-o /dev/null -w '%{url_effective}' "$repository_url/releases/latest")
version=${latest_url##*/}
case "$version" in
v[0-9]*[!A-Za-z0-9._-]*)
echo "error: GitHub returned an invalid tk release version: $version" >&2
exit 1
;;
v[0-9]*) ;;
*)
echo "error: could not determine the latest tk release from $latest_url" >&2
exit 1
;;
esac
fi
archive_name="tk-$target-$version.tar.gz"
checksum_name="$archive_name.sha256"
download_url="$repository_url/releases/download/$version"
archive="$temporary_dir/$archive_name"
checksum="$temporary_dir/$checksum_name"
curl --proto '=https' --tlsv1.2 -LsSf --fail-early \
-o "$archive" "$download_url/$archive_name" \
-o "$checksum" "$download_url/$checksum_name"
# A checksum file that validates some other filename proves nothing about the
# archive we downloaded, so require it to name exactly this archive.
listed_name=$(awk 'NF == 2 && NR == 1 { name = $2 } END { if (NR != 1 || name == "") exit 1; print name }' "$checksum")
listed_name=${listed_name#\*}
if [ "$listed_name" != "$archive_name" ]; then
echo "error: checksum file names $listed_name instead of $archive_name" >&2
exit 1
fi
(
cd "$temporary_dir"
if command -v sha256sum >/dev/null 2>&1; then
sha256sum -c "$checksum_name"
elif command -v shasum >/dev/null 2>&1; then
shasum -a 256 -c "$checksum_name"
else
echo "error: install sha256sum or shasum to verify the tk archive" >&2
exit 1
fi
)
package="tk-$target-$version"
expected_binary="$package/tk"
if ! tar -tzf "$archive" | awk -v root="$package/" -v binary="$expected_binary" '
index($0, root) != 1 || $0 ~ /(^|\/)\.\.(\/|$)/ { bad = 1; exit }
$0 == binary { count++ }
END { exit bad || count != 1 }
'; then
echo "error: release archive must contain exactly one $expected_binary and no paths outside $package/" >&2
exit 1
fi
extract_dir="$temporary_dir/extracted"
mkdir "$extract_dir"
tar -xzf "$archive" -C "$extract_dir" "$expected_binary"
binary="$extract_dir/$expected_binary"
if [ ! -f "$binary" ] || [ -L "$binary" ]; then
echo "error: release archive's tk entry is not a regular file" >&2
exit 1
fi
# Stage next to the destination and smoke-test before the atomic move, so a
# broken download never replaces a working binary.
mkdir -p "$install_dir"
destination="$install_dir/tk"
if [ -d "$destination" ]; then
echo "error: installation destination is a directory: $destination" >&2
exit 1
fi
staged_binary=$(mktemp "$install_dir/.tk.XXXXXX")
install -m 755 "$binary" "$staged_binary"
if ! "$staged_binary" --version >/dev/null 2>&1; then
echo "error: downloaded tk binary cannot run on this system" >&2
exit 1
fi
mv -f "$staged_binary" "$destination"
staged_binary=
echo "Installed tk $version to $destination"
echo "Install the agent skills with: tk skills install --into <your skills directory>"
case ":${PATH:-}:" in
*":$install_dir:"*) ;;
*) echo "Add $install_dir to PATH to run tk." ;;
esac