-
Notifications
You must be signed in to change notification settings - Fork 170
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·378 lines (337 loc) · 13.2 KB
/
install.sh
File metadata and controls
executable file
·378 lines (337 loc) · 13.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
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
#!/usr/bin/env sh
# Determine the platform using 'OS' and 'ARCH'
initPlatform() {
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
if [ "$OS" = "darwin" ] && [ "$ARCH" = "arm64" ]; then
PLATFORM="darwin_arm64"
elif [ "$OS" = "darwin" ] && [ "$ARCH" = "x86_64" ]; then
PLATFORM="darwin_amd64"
elif [ "$OS" = "linux" ] && [ "$ARCH" = "x86_64" ]; then
PLATFORM="linux_amd64"
elif [ "$OS" = "linux" ] && { [ "$ARCH" = "arm64" ] || [ "$ARCH" = "aarch64" ]; }; then
PLATFORM="linux_arm64"
else
printf "Platform not supported: os=%s arch=%s\n" "$OS" "$ARCH"
exit 1
fi
}
# Create a temporary directory and setup deletion on script exit using the 'EXIT' signal
initTmpDir() {
TMP_DIR=$(mktemp -d)
trap 'rm -rf -- "${TMP_DIR}"' EXIT
cd "$TMP_DIR"
}
# Check all required dependencies, printing messages for each missing one before exiting
checkDependencies() {
MISSING=false
if ! [ -x "$(command -v curl)" ]; then
printf "'curl' could not be found, this script depends on it, please install and try again.\n"
MISSING=true
fi
if ! [ -x "$(command -v unzip)" ]; then
printf "'unzip' could not be found, this script depends on it, please install and try again.\n"
MISSING=true
fi
if ! [ -x "$(command -v git)" ]; then
publishSyftEvent git_missing
printf "'git' could not be found, this script depends on it, please install and try again (see instructions at https://github.com/git-guides/install-git).\n"
MISSING=true
fi
if ! [ -x "$(command -v shasum)" ] && ! [ -x "$(command -v sha256sum)" ]; then
printf "Neither 'shasum' nor 'sha256sum' could be found, this script depends on one of them, please install one of them and try again.\n"
MISSING=true
fi
if [ "$MISSING" = "true" ]; then
exit 1
fi
}
# Verify a checksums file using whichever SHA256 tool is available
sha256Verify() {
if [ -x "$(command -v shasum)" ]; then
shasum --algorithm 256 --ignore-missing --check "$1"
else
sha256sum --ignore-missing --check "$1"
fi
}
# Download the binary and check the integrity using the SHA256 checksum
downloadBinary() {
CDN="cdn.rilldata.com"
LATEST_URL="https://${CDN}/rill/latest.txt"
if [ "${VERSION}" = "latest" ]; then
VERSION=$(curl --silent --show-error "${LATEST_URL}")
fi
BINARY_URL="https://${CDN}/rill/${VERSION}/rill_${PLATFORM}.zip"
CHECKSUM_URL="https://${CDN}/rill/${VERSION}/checksums.txt"
printf "Downloading binary: %s\n" "$BINARY_URL"
if [ "$NON_INTERACTIVE" = "true" ]; then
curl --location --silent --show-error "${BINARY_URL}" --output "rill_${PLATFORM}.zip"
else
curl --location --progress-bar "${BINARY_URL}" --output "rill_${PLATFORM}.zip"
fi
printf "\nDownloading checksum: %s\n" "$CHECKSUM_URL"
if [ "$NON_INTERACTIVE" = "true" ]; then
curl --location --silent --show-error "${CHECKSUM_URL}" --output checksums.txt
else
curl --location --progress-bar "${CHECKSUM_URL}" --output checksums.txt
fi
printf "\nVerifying the SHA256 checksum of the downloaded binary:\n"
sha256Verify checksums.txt
printf "\nUnpacking rill_%s.zip\n" "$PLATFORM"
unzip -q "rill_${PLATFORM}.zip"
}
# Print install options
printInstallOptions() {
printf "\nWhere would you like to install rill? (Default [1])\n\n"
printf "[1] /usr/local/bin/rill [recommended, but requires sudo privileges]\n"
printf "[2] ~/.rill/rill [directory will be created & path configured]\n"
printf "[3] ./rill [download to the current directory]\n\n"
}
# Ask for preferred install option
promptInstallChoice() {
printf "Pick install option: (1/2/3)\n"
read -r ans </dev/tty;
case $ans in
1|"")
INSTALL_DIR="/usr/local/bin"
;;
2)
INSTALL_DIR="$HOME/.rill"
;;
3)
INSTALL_DIR=$(pwd)
;;
*)
printf "\nInvalid option '%s'\n\n" "$ans"
promptInstallChoice
;;
esac
}
# Check conflicting installation and exit with a help message
checkConflictingInstallation() {
if [ -x "$(command -v rill)" ]; then
INSTALLED_RILL="$(command -v rill)"
if [ -x "$(command -v brew)" ] && brew list rilldata/tap/rill >/dev/null 2>&1; then
printf "There is a conflicting version of Rill installed using Brew.\n\n"
printf "To upgrade using Brew, run 'brew upgrade rilldata/tap/rill'.\n\n"
printf "To use this script to install Rill, run 'brew remove rilldata/tap/rill' to remove the conflicting version and try again.\n"
exit 1
elif [ "$INSTALLED_RILL" != "${INSTALL_DIR}/rill" ]; then
printf "There is a conflicting version of Rill installed at '%s'\n\n" "$INSTALLED_RILL"
printf "To use this script to install Rill, remove the conflicting version and try again.\n"
exit 1
fi
fi
}
# Install the binary, using sudo if the directory is not directly writable
installBinary() {
if { [ -d "$INSTALL_DIR" ] && [ -w "$INSTALL_DIR" ]; } || { [ ! -d "$INSTALL_DIR" ] && [ -w "$(dirname "$INSTALL_DIR")" ]; }; then
install -d "$INSTALL_DIR"
install rill "$INSTALL_DIR"
else
printf "\nElevated permissions required to install the Rill binary to: %s/rill\n" "$INSTALL_DIR"
sudo install -d "$INSTALL_DIR"
sudo install rill "$INSTALL_DIR"
fi
cd - > /dev/null
}
# Run the installed binary and print the version
testInstalledBinary() {
RILL_VERSION=$("$INSTALL_DIR"/rill version)
"$INSTALL_DIR"/rill verify-install 1>/dev/null || true
printf "\nInstallation of %s completed!\n" "$RILL_VERSION"
}
# Print 'rill start' help intrcutions
printStartHelp() {
# Resolve how to reference the binary in help text.
if [ "$INSTALL_DIR" = "/usr/local/bin" ] || [ "$INSTALL_DIR" = "$HOME/.rill" ]; then
binary="rill"
elif [ "$INSTALL_DIR" = "$(pwd)" ]; then
binary="./rill"
else
binary="$INSTALL_DIR/rill"
fi
# Print instructions for non-interactive callers.
if [ "$NON_INTERACTIVE" = "true" ]; then
printf "\nTo initialize a new project, run '%s init'. Run '%s -h' for an overview of available commands.\n" "$binary" "$binary"
return
fi
# Safely get bold formatting codes.
boldon=$(tput smso 2>/dev/null) || boldon=""
boldoff=$(tput rmso 2>/dev/null) || boldoff=""
# Print instructions for interactive callers.
if [ "$INSTALL_DIR" = "$HOME/.rill" ]; then
printf "\nTo start a new project in Rill, open a %snew terminal%s and execute the command:\n\n %s%s start my-rill-project%s\n\n" "$boldon" "$boldoff" "$boldon" "$binary" "$boldoff"
else
printf "\nTo start a new project in Rill, execute the command:\n\n %s%s start my-rill-project%s\n\n" "$boldon" "$binary" "$boldoff"
fi
}
# Publish Syft install telemetry event, can be disabled by setting the 'RILL_INSTALL_DISABLE_TELEMETRY' environment variable
publishSyftEvent() {
SYFT_URL=https://event.syftdata.com/log
SYFT_ID=clp76quhs0006l908bux79l4v
if [ -z "$RILL_INSTALL_DISABLE_TELEMETRY" ]; then
curl --silent --show-error --header "Authorization: ${SYFT_ID}" --header "Content-Type: application/json" --data "{\"event_name\":\"$1\"}" "$SYFT_URL" > /dev/null 2>&1 || true
fi
}
# Add the Rill binary to the PATH via configuration of the shells we detect on the system
addPathConfigEntries() {
PATH_CONFIG_LINE="export PATH=\$HOME/.rill:\$PATH # Added by Rill install"
if [ "$INSTALL_DIR" = "$HOME/.rill" ]; then
for f in "$HOME/.bashrc" "$HOME/.zshrc"; do
if [ -f "$f" ]; then
if ! grep -Fxq "$PATH_CONFIG_LINE" "$f"; then
printf "\nWould you like to add 'rill' to your PATH by adding an entry in '%s'? (Y/n)\n" "$f"
read -r ans </dev/tty;
case $ans in
n)
;;
*)
printf "\n%s\n" "$PATH_CONFIG_LINE" >> "$f"
;;
esac
fi
fi
done
fi
}
# Remove PATH configurations, we have to do handle this slightly different based on OS because of platform variations in 'sed' behaviour
removePathConfigEntries() {
for f in "$HOME/.bashrc" "$HOME/.zshrc"; do
if [ -f "$f" ]; then
if [ "$OS" = "darwin" ]; then
sed -i "" -e '/# Added by Rill install/d' "$f"
elif [ "$OS" = "linux" ]; then
sed -i -e '/# Added by Rill install/d' "$f"
fi
fi
done
}
# Check if we can install to INSTALL_DIR
installDirIsWritable() {
# Check if it is directly writable
if [ -d "$INSTALL_DIR" ] && [ -w "$INSTALL_DIR" ]; then
return 0
# If it doesn't exist yet, check if the parent directory is writable
elif [ ! -d "$INSTALL_DIR" ] && [ -w "$(dirname "$INSTALL_DIR")" ]; then
return 0
fi
# Lastly, we also consider it writable if we have passwordless sudo (since then we don't need to prompt/error due to lack of permissions)
sudo -n true 2>/dev/null
}
# Resolve the install directory
resolveInstallDir() {
# Detect previous installation
if [ -x "$(command -v rill)" ] && [ -z "${INSTALL_DIR}" ]; then
INSTALLED_RILL="$(command -v rill)"
if [ "$INSTALLED_RILL" = "/usr/local/bin/rill" ]; then
INSTALL_DIR="/usr/local/bin"
elif [ "$INSTALLED_RILL" = "$HOME/.rill/rill" ]; then
INSTALL_DIR="$HOME/.rill"
fi
fi
# Handle non-interactive scenarios where prompt or sudo are not possible
if [ "$NON_INTERACTIVE" = "true" ]; then
# Default to /usr/local/bin if not set.
if [ -z "$INSTALL_DIR" ]; then
INSTALL_DIR="/usr/local/bin"
fi
# Handle if the install directory is not writable and we can't prompt due to non-interactive mode.
if ! installDirIsWritable; then
# Error if the install directory was set explicitly.
if [ "$INSTALL_DIR_EXPLICIT" = "true" ]; then
printf "Install directory '%s' requires elevated permissions, which are not available in non-interactive mode.\n" "$INSTALL_DIR"
exit 1
fi
# Fall back to the current directory otherwise (which we assume is writable).
INSTALL_DIR=$(pwd)
fi
return
fi
# If there is a previous or explicit installation path, we're done
if [ -n "${INSTALL_DIR}" ]; then
return
fi
# Prompt for install directory if there is no previous installation and we are in an interactive shell
printInstallOptions
promptInstallChoice
checkConflictingInstallation # Only check for conflicts in interactive, non-explicit scenarios
}
# Install Rill on the system
installRill() {
if [ "$NON_INTERACTIVE" != "true" ]; then
publishSyftEvent install
fi
checkDependencies
initPlatform
resolveInstallDir
initTmpDir
downloadBinary
installBinary
testInstalledBinary
if [ "$NON_INTERACTIVE" != "true" ]; then
addPathConfigEntries
publishSyftEvent installed
fi
printStartHelp
}
# Uninstall Rill from the system, this function is aware of both the privileged and unprivileged install methods
uninstallRill() {
if ! [ -x "$(command -v sed)" ]; then
printf "'sed' could not be found, this script depends on it, please install and try again.\n"
exit 1
fi
initPlatform
if [ -f "/usr/local/bin/rill" ]
then
printf "\nElevated permissions required to uninstall the Rill binary from: '/usr/local/bin/rill'\n"
sudo rm /usr/local/bin/rill
fi
rm -f "$HOME/.rill/rill"
removePathConfigEntries
printf "Uninstall of Rill completed\n"
}
set -e
# Default values
INSTALL_DIR_EXPLICIT=false
# Detect non-interactive environments (CI, Docker, agents, subprocesses).
# When the script is piped (e.g. "curl | sh"), stdin is not a terminal, but a human may still be present.
# We check /dev/tty to distinguish: in a real terminal, /dev/tty is a terminal device; in CI/Docker/agents, it either doesn't exist or isn't a real terminal.
if [ -t 0 ]; then
# Stdin is a terminal; definitely interactive.
NON_INTERACTIVE=${NON_INTERACTIVE:-false}
elif [ -e /dev/tty ] && sh -c 'exec 3</dev/tty && test -t 3' 2>/dev/null; then
# Stdin is piped but /dev/tty is a real terminal; likely "curl | sh" in an interactive session.
NON_INTERACTIVE=${NON_INTERACTIVE:-false}
else
# Stdin is not a terminal and /dev/tty is not available; default to non-interactive.
NON_INTERACTIVE=${NON_INTERACTIVE:-true}
fi
NON_INTERACTIVE=${NON_INTERACTIVE:-false}
# Parse input flag
case $1 in
--uninstall)
uninstallRill
;;
--nightly)
VERSION=nightly
installRill
;;
--version)
VERSION=${2:-latest}
installRill
;;
--non-interactive)
if [ -n "$2" ]; then
INSTALL_DIR="$2"
INSTALL_DIR_EXPLICIT=true
fi
VERSION=${3:-latest}
NON_INTERACTIVE=true
installRill
;;
*)
VERSION=latest
installRill
;;
esac