Skip to content

Commit a07246b

Browse files
authored
Re-base the nix-installer.sh against rustup's .sh (#1641)
* Revert "Pass --speed-limit and --speed-time when passing --retry" This reverts commit 4dc295b. * Sync with rustup's installer sh * Rebase the speed limit on top of the re-sync'd installer script
1 parent cb0c476 commit a07246b

File tree

1 file changed

+131
-71
lines changed

1 file changed

+131
-71
lines changed

nix-installer.sh

Lines changed: 131 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,21 @@
1111
# It runs on Unix shells like {a,ba,da,k,z}sh. It uses the common `local`
1212
# extension. Note: Most shells limit `local` to 1 var per line, contra bash.
1313

14-
# This script is based off https://github.com/rust-lang/rustup/blob/f8d7b3baba7a63237cb2b82ef49a68a37dd0633c/rustup-init.sh
14+
# This script is based off https://github.com/rust-lang/rustup/blob/2d429e8e172d5854b6dd7244ecbb0dc3da88a678/rustup-init.sh
15+
16+
# Some versions of ksh have no `local` keyword. Alias it to `typeset`, but
17+
# beware this makes variables global with f()-style function syntax in ksh93.
18+
# mksh has this alias by default.
19+
has_local() {
20+
# shellcheck disable=SC2034 # deliberately unused
21+
local _has_local
22+
}
1523

16-
if [ "$KSH_VERSION" = 'Version JM 93t+ 2010-03-05' ]; then
17-
# The version of ksh93 that ships with many illumos systems does not
18-
# support the "local" extension. Print a message rather than fail in
19-
# subtle ways later on:
20-
echo 'nix-installer does not work with this ksh93 version; please try bash!' >&2
21-
exit 1
22-
fi
24+
has_local 2>/dev/null || alias local=typeset
2325

26+
is_zsh() {
27+
[ -n "${ZSH_VERSION-}" ]
28+
}
2429

2530
set -u
2631

@@ -84,18 +89,14 @@ main() {
8489
need_tty=no
8590
fi
8691

87-
if $_ansi_escapes_are_valid; then
88-
printf "\33[1minfo:\33[0m downloading installer \33[4m%s\33[0m\n" "$_url" 1>&2
89-
else
90-
printf 'info: downloading installer (%s)\n' "$_url" 1>&2
91-
fi
92+
say 'downloading installer'
9293

9394
ensure mkdir -p "$_dir"
9495
ensure downloader "$_url" "$_file" "$_arch"
9596
ensure chmod u+x "$_file"
9697
if [ ! -x "$_file" ]; then
97-
printf '%s\n' "Cannot execute $_file (likely because of mounting /tmp as noexec)." 1>&2
98-
printf '%s\n' "Please copy the file to a location where you can execute binaries and run ./nix-installer${_ext}." 1>&2
98+
err "Cannot execute $_file (likely because of mounting /tmp as noexec)." 1>&2
99+
err "Please copy the file to a location where you can execute binaries and run ./nix-installer${_ext}." 1>&2
99100
exit 1
100101
fi
101102

@@ -106,6 +107,7 @@ main() {
106107
# to explicitly connect /dev/tty to the installer's stdin.
107108
if [ ! -t 1 ]; then
108109
err "Unable to run interactively. Run with --no-confirm to accept defaults, --help for additional options"
110+
exit 1;
109111
fi
110112

111113
ignore "$_file" "$@" < /dev/tty
@@ -121,12 +123,23 @@ main() {
121123
return "$_retval"
122124
}
123125

124-
check_proc() {
125-
# Check for /proc by looking for the /proc/self/exe link
126+
get_current_exe() {
127+
# Returns the executable used for system architecture detection
126128
# This is only run on Linux
127-
if ! test -L /proc/self/exe ; then
128-
err "fatal: Unable to find /proc/self/exe. Is /proc mounted? Installation cannot proceed without /proc."
129+
local _current_exe
130+
if test -L /proc/self/exe ; then
131+
_current_exe=/proc/self/exe
132+
else
133+
warn "Unable to find /proc/self/exe. System architecture detection might be inaccurate."
134+
if test -n "$SHELL" ; then
135+
_current_exe=$SHELL
136+
else
137+
need_cmd /bin/sh
138+
_current_exe=/bin/sh
139+
fi
140+
warn "Falling back to $_current_exe."
129141
fi
142+
echo "$_current_exe"
130143
}
131144

132145
get_architecture() {
@@ -138,9 +151,6 @@ get_architecture() {
138151
if [ "$(uname -o)" = Android ]; then
139152
_ostype=Android
140153
fi
141-
if ldd --version 2>&1 | grep -q 'musl'; then
142-
_clibtype="musl"
143-
fi
144154
fi
145155

146156
if [ "$_ostype" = Darwin ]; then
@@ -155,7 +165,7 @@ get_architecture() {
155165
# See: <https://support.apple.com/en-us/HT208436>
156166

157167
# Avoid `sysctl: unknown oid` stderr output and/or non-zero exit code.
158-
if sysctl hw.optional.x86_64 2> /dev/null || true | grep -q ': 1'; then
168+
if (sysctl hw.optional.x86_64 2> /dev/null || true) | grep -q ': 1'; then
159169
_cputype=x86_64
160170
fi
161171
elif [ "$_cputype" = x86_64 ]; then
@@ -164,7 +174,7 @@ get_architecture() {
164174
# Rosetta 2 is built exclusively for x86-64 and cannot run i386 binaries.
165175

166176
# Avoid `sysctl: unknown oid` stderr output and/or non-zero exit code.
167-
if sysctl hw.optional.arm64 2> /dev/null || true | grep -q ': 1'; then
177+
if (sysctl hw.optional.arm64 2> /dev/null || true) | grep -q ': 1'; then
168178
_cputype=arm64
169179
fi
170180
fi
@@ -188,9 +198,10 @@ get_architecture() {
188198
fi
189199
fi
190200

201+
local _current_exe
191202
case "$_ostype" in
192203
Linux)
193-
check_proc
204+
_current_exe=$(get_current_exe)
194205
_ostype=linux
195206
;;
196207

@@ -200,6 +211,7 @@ get_architecture() {
200211

201212
*)
202213
err "unrecognized OS type: $_ostype"
214+
exit 1
203215
;;
204216

205217
esac
@@ -224,18 +236,32 @@ get_architecture() {
224236
RETVAL="$_arch"
225237
}
226238

239+
__print() {
240+
if $_ansi_escapes_are_valid; then
241+
printf '\33[1m%s:\33[0m %s\n' "$1" "$2" >&2
242+
else
243+
printf '%s: %s\n' "$1" "$2" >&2
244+
fi
245+
}
246+
247+
warn() {
248+
__print 'warn' "$1" >&2
249+
}
250+
227251
say() {
228-
printf 'nix-installer: %s\n' "$1"
252+
__print 'info' "$1" >&2
229253
}
230254

255+
# NOTE: you are required to exit yourself
256+
# we don't do it here because of multiline errors
231257
err() {
232-
say "$1" >&2
233-
exit 1
258+
__print 'error' "$1" >&2
234259
}
235260

236261
need_cmd() {
237262
if ! check_cmd "$1"; then
238263
err "need '$1' (command not found)"
264+
exit 1
239265
fi
240266
}
241267

@@ -244,14 +270,20 @@ check_cmd() {
244270
}
245271

246272
assert_nz() {
247-
if [ -z "$1" ]; then err "assert_nz $2"; fi
273+
if [ -z "$1" ]; then
274+
err "assert_nz $2"
275+
exit 1
276+
fi
248277
}
249278

250279
# Run a command that should never fail. If the command fails execution
251280
# will immediately terminate with an error showing the failing
252281
# command.
253282
ensure() {
254-
if ! "$@"; then err "command failed: $*"; fi
283+
if ! "$@"; then
284+
err "command failed: $*"
285+
exit 1
286+
fi
255287
}
256288

257289
# This is just for indicating that commands' results are being
@@ -264,13 +296,31 @@ ignore() {
264296
# This wraps curl or wget. Try curl first, if not installed,
265297
# use wget instead.
266298
downloader() {
299+
# zsh does not split words by default, Required for curl retry arguments below.
300+
is_zsh && setopt local_options shwordsplit
301+
267302
local _dld
268303
local _ciphersuites
269304
local _err
270305
local _status
271306
local _retry
272307
if check_cmd curl; then
273-
_dld=curl
308+
# Check if we have a broken snap curl
309+
# https://github.com/boukendesho/curl-snap/issues/1
310+
_curl_path=$(command -v curl)
311+
if echo "$_curl_path" | grep "/snap/" > /dev/null 2>&1; then
312+
if check_cmd wget; then
313+
_dld=wget
314+
else
315+
err "curl installed with snap cannot be used to install Rust"
316+
err "due to missing permissions. Please uninstall it and"
317+
err "reinstall curl with a different package manager (e.g., apt)."
318+
err "See https://github.com/boukendesho/curl-snap/issues/1"
319+
exit 1
320+
fi
321+
else
322+
_dld=curl
323+
fi
274324
elif check_cmd wget; then
275325
_dld=wget
276326
else
@@ -280,42 +330,38 @@ downloader() {
280330
if [ "$1" = --check ]; then
281331
need_cmd "$_dld"
282332
elif [ "$_dld" = curl ]; then
283-
check_curl_for_retry_and_speed_limit_support
333+
check_curl_for_retry_support
284334
_retry="$RETVAL"
285335
get_ciphersuites_for_curl
286336
_ciphersuites="$RETVAL"
287337
if [ -n "$_ciphersuites" ]; then
288-
if [ -n "${NIX_INSTALLER_FORCE_ALLOW_HTTP-}" ]; then
289-
# shellcheck disable=SC2086 # ignore because $_retry could be a flag (e.g. `--retry 5`)
290-
_err=$(curl $_retry --silent --show-error --fail --location "$1" --output "$2" 2>&1)
291-
else
292-
# shellcheck disable=SC2086 # ignore because $_retry could be a flag (e.g. `--retry 5`)
293-
_err=$(curl $_retry --proto '=https' --tlsv1.2 --ciphers "$_ciphersuites" --silent --show-error --fail --location "$1" --output "$2" 2>&1)
294-
fi
338+
# shellcheck disable=SC2086
339+
_err=$(curl $_retry --proto '=https' --tlsv1.2 --ciphers "$_ciphersuites" --silent --show-error --fail --location "$1" --output "$2" 2>&1)
295340
_status=$?
296341
else
297-
echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
342+
warn "Not enforcing strong cipher suites for TLS, this is potentially less secure"
298343
if ! check_help_for "$3" curl --proto --tlsv1.2; then
299-
echo "Warning: Not enforcing TLS v1.2, this is potentially less secure"
300-
# shellcheck disable=SC2086 # ignore because $_retry could be a flag (e.g. `--retry 5`)
344+
warn "Not enforcing TLS v1.2, this is potentially less secure"
345+
# shellcheck disable=SC2086
301346
_err=$(curl $_retry --silent --show-error --fail --location "$1" --output "$2" 2>&1)
302347
_status=$?
303348
else
304-
# shellcheck disable=SC2086 # ignore because $_retry could be a flag (e.g. `--retry 5`)
349+
# shellcheck disable=SC2086
305350
_err=$(curl $_retry --proto '=https' --tlsv1.2 --silent --show-error --fail --location "$1" --output "$2" 2>&1)
306351
_status=$?
307352
fi
308353
fi
309354
if [ -n "$_err" ]; then
310-
echo "$_err" >&2
355+
warn "$_err"
311356
if echo "$_err" | grep -q 404$; then
312357
err "installer for platform '$3' not found, this may be unsupported"
358+
exit 1
313359
fi
314360
fi
315361
return $_status
316362
elif [ "$_dld" = wget ]; then
317363
if [ "$(wget -V 2>&1|head -2|tail -1|cut -f1 -d" ")" = "BusyBox" ]; then
318-
echo "Warning: using the BusyBox version of wget. Not enforcing strong cipher suites for TLS or TLS v1.2, this is potentially less secure"
364+
warn "using the BusyBox version of wget. Not enforcing strong cipher suites for TLS or TLS v1.2, this is potentially less secure"
319365
_err=$(wget "$1" -O "$2" 2>&1)
320366
_status=$?
321367
else
@@ -325,9 +371,9 @@ downloader() {
325371
_err=$(wget --https-only --secure-protocol=TLSv1_2 --ciphers "$_ciphersuites" "$1" -O "$2" 2>&1)
326372
_status=$?
327373
else
328-
echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
374+
warn "Not enforcing strong cipher suites for TLS, this is potentially less secure"
329375
if ! check_help_for "$3" wget --https-only --secure-protocol; then
330-
echo "Warning: Not enforcing TLS v1.2, this is potentially less secure"
376+
warn "Not enforcing TLS v1.2, this is potentially less secure"
331377
_err=$(wget "$1" -O "$2" 2>&1)
332378
_status=$?
333379
else
@@ -337,14 +383,16 @@ downloader() {
337383
fi
338384
fi
339385
if [ -n "$_err" ]; then
340-
echo "$_err" >&2
386+
warn "$_err"
341387
if echo "$_err" | grep -q ' 404 Not Found$'; then
342388
err "installer for platform '$3' not found, this may be unsupported"
389+
exit 1
343390
fi
344391
fi
345392
return $_status
346393
else
347394
err "Unknown downloader" # should not reach here
395+
exit 1
348396
fi
349397
}
350398

@@ -368,32 +416,35 @@ check_help_for() {
368416

369417
*darwin*)
370418
if check_cmd sw_vers; then
371-
case $(sw_vers -productVersion) in
372-
10.*)
419+
local _os_version
420+
local _os_major
421+
_os_version=$(sw_vers -productVersion)
422+
_os_major=$(echo "$_os_version" | cut -d. -f1)
423+
case $_os_major in
424+
10)
373425
# If we're running on macOS, older than 10.13, then we always
374426
# fail to find these options to force fallback
375-
if [ "$(sw_vers -productVersion | cut -d. -f2)" -lt 13 ]; then
427+
if [ "$(echo "$_os_version" | cut -d. -f2)" -lt 13 ]; then
376428
# Older than 10.13
377-
echo "Warning: Detected macOS platform older than 10.13"
429+
warn "Detected macOS platform older than 10.13"
378430
return 1
379431
fi
380432
;;
381-
11.*)
382-
# We assume Big Sur will be OK for now
383-
;;
384433
*)
385-
# Unknown product version, warn and continue
386-
echo "Warning: Detected unknown macOS major version: $(sw_vers -productVersion)"
387-
echo "Warning TLS capabilities detection may fail"
388-
;;
434+
if ! { [ "$_os_major" -eq "$_os_major" ] 2>/dev/null && [ "$_os_major" -ge 11 ]; }; then
435+
# Unknown product version, warn and continue
436+
warn "Detected unknown macOS major version: $_os_version"
437+
warn "TLS capabilities detection may fail"
438+
fi
439+
;; # We assume that macOS v11+ will always be okay.
389440
esac
390441
fi
391442
;;
392443

393444
esac
394445

395446
for _arg in "$@"; do
396-
if ! "$_cmd" --help $_category | grep -q -- "$_arg"; then
447+
if ! "$_cmd" --help "$_category" | grep -q -- "$_arg"; then
397448
return 1
398449
fi
399450
done
@@ -404,20 +455,29 @@ check_help_for() {
404455
# Check if curl supports the --retry flag, then pass it to the curl invocation.
405456
# Note that --speed-limit and --speed-time were in the very first commit of curl.
406457
# So this should be pretty much ubiquitously safe.
407-
check_curl_for_retry_and_speed_limit_support() {
408-
local _retry_supported=""
458+
check_curl_for_retry_support() {
459+
local _retry_part=""
460+
local _continue_part=""
461+
local _speed_limit_part=""
409462

410463
# "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
411-
if check_help_for "notspecified" "curl" "--retry" \
412-
&& check_help_for "notspecified" "curl" "--speed-limit" \
413-
&& check_help_for "notspecified" "curl" "--speed-time"; then
414-
415-
# 250000 is approximately 20% of the bandwidth of typical DSL
416-
# these limits mean users below these limits will see failures.
417-
# I don't believe we have any users like this, and if we do -- please open a ticket.
418-
_retry_supported="--retry 3 --speed-limit 250000 --speed-time 15"
464+
if check_help_for "notspecified" "curl" "--retry"; then
465+
_retry_part="--retry 3"
466+
467+
if check_help_for "notspecified" "curl" "--continue-at"; then
468+
# "-C -" tells curl to automatically find where to resume the download when retrying.
469+
_continue_part="--continue-at -"
470+
fi
471+
472+
if check_help_for "notspecified" "curl" "--speed-limit" \
473+
&& check_help_for "notspecified" "curl" "--speed-time"; then
474+
# 250000 is approximately 20% of the bandwidth of typical DSL
475+
# these limits mean users below these limits will see failures.
476+
_speed_limit_part="--speed-limit 250000 --speed-time 15"
477+
fi
419478
fi
420-
RETVAL="$_retry_supported"
479+
480+
RETVAL="$_retry_part $_continue_part $_speed_limit_part"
421481
}
422482

423483

0 commit comments

Comments
 (0)