]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | #!/bin/sh |
2 | # Copyright 2014 The Rust Project Developers. See the COPYRIGHT | |
3 | # file at the top-level directory of this distribution and at | |
4 | # http://rust-lang.org/COPYRIGHT. | |
5 | # | |
6 | # Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
7 | # http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
8 | # <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
9 | # option. This file may not be copied, modified, or distributed | |
10 | # except according to those terms. | |
11 | ||
12 | ||
13 | msg() { | |
14 | echo "rustup: $1" | |
15 | } | |
16 | ||
17 | step_msg() { | |
18 | msg | |
19 | msg "$1" | |
20 | msg | |
21 | } | |
22 | ||
23 | warn() { | |
24 | echo "rustup: WARNING: $1" | |
25 | } | |
26 | ||
27 | err() { | |
28 | echo "rustup: error: $1" | |
29 | exit 1 | |
30 | } | |
31 | ||
32 | need_ok() { | |
33 | if [ $? -ne 0 ] | |
34 | then | |
35 | err "$1" | |
36 | fi | |
37 | } | |
38 | ||
39 | ||
40 | putvar() { | |
41 | local T | |
42 | eval T=\$$1 | |
43 | eval TLEN=\${#$1} | |
44 | if [ $TLEN -gt 35 ] | |
45 | then | |
46 | printf "rustup: %-20s := %.35s ...\n" $1 "$T" | |
47 | else | |
48 | printf "rustup: %-20s := %s %s\n" $1 "$T" "$2" | |
49 | fi | |
50 | } | |
51 | ||
52 | probe() { | |
53 | local V=$1 | |
54 | shift | |
55 | local P | |
56 | local T | |
57 | for P | |
58 | do | |
59 | T=$(which $P 2>&1) | |
60 | if [ $? -eq 0 ] | |
61 | then | |
62 | VER0=$($P --version 2>/dev/null | head -1 \ | |
63 | | sed -e 's/[^0-9]*\([vV]\?[0-9.]\+[^ ]*\).*/\1/' ) | |
64 | if [ $? -eq 0 -a "x${VER0}" != "x" ] | |
65 | then | |
66 | VER="($VER0)" | |
67 | else | |
68 | VER="" | |
69 | fi | |
70 | break | |
71 | else | |
72 | VER="" | |
73 | T="" | |
74 | fi | |
75 | done | |
76 | eval $V=\$T | |
77 | putvar $V "$VER" | |
78 | } | |
79 | ||
80 | probe_need() { | |
81 | local V=$1 | |
82 | probe $* | |
83 | eval VV=\$$V | |
84 | if [ -z "$VV" ] | |
85 | then | |
86 | err "needed, but unable to find any of: $*" | |
87 | fi | |
88 | } | |
89 | ||
90 | ||
91 | valopt() { | |
92 | VAL_OPTIONS="$VAL_OPTIONS $1" | |
93 | ||
94 | local OP=$1 | |
95 | local DEFAULT=$2 | |
96 | shift | |
97 | shift | |
98 | local DOC="$*" | |
99 | if [ $HELP -eq 0 ] | |
100 | then | |
101 | local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_') | |
102 | local V="CFG_${UOP}" | |
103 | eval $V="$DEFAULT" | |
104 | for arg in $CFG_ARGS | |
105 | do | |
106 | if echo "$arg" | grep -q -- "--$OP=" | |
107 | then | |
108 | val=$(echo "$arg" | cut -f2 -d=) | |
109 | eval $V=$val | |
110 | fi | |
111 | done | |
112 | putvar $V | |
113 | else | |
114 | if [ -z "$DEFAULT" ] | |
115 | then | |
116 | DEFAULT="<none>" | |
117 | fi | |
118 | OP="${OP}=[${DEFAULT}]" | |
119 | printf " --%-30s %s\n" "$OP" "$DOC" | |
120 | fi | |
121 | } | |
122 | ||
123 | opt() { | |
124 | BOOL_OPTIONS="$BOOL_OPTIONS $1" | |
125 | ||
126 | local OP=$1 | |
127 | local DEFAULT=$2 | |
128 | shift | |
129 | shift | |
130 | local DOC="$*" | |
131 | local FLAG="" | |
132 | ||
133 | if [ $DEFAULT -eq 0 ] | |
134 | then | |
135 | FLAG="enable" | |
136 | else | |
137 | FLAG="disable" | |
138 | DOC="don't $DOC" | |
139 | fi | |
140 | ||
141 | if [ $HELP -eq 0 ] | |
142 | then | |
143 | for arg in $CFG_ARGS | |
144 | do | |
145 | if [ "$arg" = "--${FLAG}-${OP}" ] | |
146 | then | |
147 | OP=$(echo $OP | tr 'a-z-' 'A-Z_') | |
148 | FLAG=$(echo $FLAG | tr 'a-z' 'A-Z') | |
149 | local V="CFG_${FLAG}_${OP}" | |
150 | eval $V=1 | |
151 | putvar $V | |
152 | fi | |
153 | done | |
154 | else | |
155 | if [ ! -z "$META" ] | |
156 | then | |
157 | OP="$OP=<$META>" | |
158 | fi | |
159 | printf " --%-30s %s\n" "$FLAG-$OP" "$DOC" | |
160 | fi | |
161 | } | |
162 | ||
163 | flag() { | |
164 | BOOL_OPTIONS="$BOOL_OPTIONS $1" | |
165 | ||
166 | local OP=$1 | |
167 | shift | |
168 | local DOC="$*" | |
169 | ||
170 | if [ $HELP -eq 0 ] | |
171 | then | |
172 | for arg in $CFG_ARGS | |
173 | do | |
174 | if [ "$arg" = "--${OP}" ] | |
175 | then | |
176 | OP=$(echo $OP | tr 'a-z-' 'A-Z_') | |
177 | local V="CFG_${OP}" | |
178 | eval $V=1 | |
179 | putvar $V | |
180 | fi | |
181 | done | |
182 | else | |
183 | if [ ! -z "$META" ] | |
184 | then | |
185 | OP="$OP=<$META>" | |
186 | fi | |
187 | printf " --%-30s %s\n" "$OP" "$DOC" | |
188 | fi | |
189 | } | |
190 | ||
191 | validate_opt() { | |
192 | for arg in $CFG_ARGS | |
193 | do | |
194 | isArgValid=0 | |
195 | for option in $BOOL_OPTIONS | |
196 | do | |
197 | if test --disable-$option = $arg | |
198 | then | |
199 | isArgValid=1 | |
200 | fi | |
201 | if test --enable-$option = $arg | |
202 | then | |
203 | isArgValid=1 | |
204 | fi | |
205 | if test --$option = $arg | |
206 | then | |
207 | isArgValid=1 | |
208 | fi | |
209 | done | |
210 | for option in $VAL_OPTIONS | |
211 | do | |
212 | if echo "$arg" | grep -q -- "--$option=" | |
213 | then | |
214 | isArgValid=1 | |
215 | fi | |
216 | done | |
217 | if [ "$arg" = "--help" ] | |
218 | then | |
219 | echo | |
220 | echo "No more help available for Configure options," | |
221 | echo "check the Wiki or join our IRC channel" | |
222 | break | |
223 | else | |
224 | if test $isArgValid -eq 0 | |
225 | then | |
226 | err "Option '$arg' is not recognized" | |
227 | fi | |
228 | fi | |
229 | done | |
230 | } | |
231 | ||
232 | create_tmp_dir() { | |
233 | local TMP_DIR=`pwd`/rustup-tmp-install | |
234 | ||
235 | rm -Rf "${TMP_DIR}" | |
236 | need_ok "failed to remove temporary installation directory" | |
237 | ||
238 | mkdir -p "${TMP_DIR}" | |
239 | need_ok "failed to create create temporary installation directory" | |
240 | ||
241 | echo $TMP_DIR | |
242 | } | |
243 | ||
85aaf69f SL |
244 | # Make `tr` locale independent |
245 | LC_CTYPE=C | |
246 | ||
1a4d82fc JJ |
247 | probe_need CFG_CURL curl |
248 | probe_need CFG_TAR tar | |
249 | probe_need CFG_FILE file | |
250 | ||
251 | probe CFG_SHA256SUM sha256sum | |
252 | probe CFG_SHASUM shasum | |
253 | ||
254 | if [ -z "$CFG_SHA256SUM" -a -z "$CFG_SHASUM" ]; then | |
255 | err "unable to find either sha256sum or shasum" | |
256 | fi | |
257 | ||
258 | calculate_hash() { | |
259 | if [ -n "$CFG_SHA256SUM" ]; then | |
260 | ${CFG_SHA256SUM} $@ | |
261 | else | |
262 | ${CFG_SHASUM} -a 256 $@ | |
263 | fi | |
264 | } | |
265 | ||
266 | CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/" | |
267 | CFG_SELF="$0" | |
268 | CFG_ARGS="$@" | |
269 | ||
270 | HELP=0 | |
271 | if [ "$1" = "--help" ] | |
272 | then | |
273 | HELP=1 | |
274 | shift | |
275 | echo | |
276 | echo "Usage: $CFG_SELF [options]" | |
277 | echo | |
278 | echo "Options:" | |
279 | echo | |
280 | else | |
281 | step_msg "processing $CFG_SELF args" | |
282 | fi | |
283 | ||
284 | OPTIONS="" | |
285 | BOOL_OPTIONS="" | |
286 | VAL_OPTIONS="" | |
287 | ||
288 | flag uninstall "only uninstall from the installation prefix" | |
289 | valopt prefix "" "set installation prefix" | |
290 | valopt date "" "use the YYYY-MM-DD nightly instead of the current nightly" | |
291 | flag save "save the downloaded nightlies to ~/.rustup" | |
292 | ||
293 | if [ $HELP -eq 1 ] | |
294 | then | |
295 | echo | |
296 | exit 0 | |
297 | fi | |
298 | ||
299 | step_msg "validating $CFG_SELF args" | |
300 | validate_opt | |
301 | ||
302 | ||
303 | # Platform detection copied from `configure` | |
304 | ||
305 | CFG_OSTYPE=$(uname -s) | |
306 | CFG_CPUTYPE=$(uname -m) | |
307 | ||
308 | if [ $CFG_OSTYPE = Darwin -a $CFG_CPUTYPE = i386 ] | |
309 | then | |
310 | # Darwin's `uname -s` lies and always returns i386. We have to use sysctl | |
311 | # instead. | |
312 | if sysctl hw.optional.x86_64 | grep -q ': 1' | |
313 | then | |
314 | CFG_CPUTYPE=x86_64 | |
315 | fi | |
316 | fi | |
317 | ||
318 | # The goal here is to come up with the same triple as LLVM would, | |
319 | # at least for the subset of platforms we're willing to target. | |
320 | ||
321 | case $CFG_OSTYPE in | |
322 | ||
323 | Linux) | |
324 | CFG_OSTYPE=unknown-linux-gnu | |
325 | ;; | |
326 | ||
327 | FreeBSD) | |
328 | CFG_OSTYPE=unknown-freebsd | |
329 | ;; | |
330 | ||
331 | Darwin) | |
332 | CFG_OSTYPE=apple-darwin | |
333 | ;; | |
334 | ||
335 | MINGW32*) | |
336 | CFG_OSTYPE=pc-mingw32 | |
337 | ;; | |
338 | # Thad's Cygwin identifers below | |
339 | ||
340 | # Vista 32 bit | |
341 | CYGWIN_NT-6.0) | |
342 | CFG_OSTYPE=pc-mingw32 | |
343 | CFG_CPUTYPE=i686 | |
344 | ;; | |
345 | ||
346 | # Vista 64 bit | |
347 | CYGWIN_NT-6.0-WOW64) | |
348 | CFG_OSTYPE=w64-mingw32 | |
349 | CFG_CPUTYPE=x86_64 | |
350 | ;; | |
351 | ||
352 | # Win 7 32 bit | |
353 | CYGWIN_NT-6.1) | |
354 | CFG_OSTYPE=pc-mingw32 | |
355 | CFG_CPUTYPE=i686 | |
356 | ;; | |
357 | ||
358 | # Win 7 64 bit | |
359 | CYGWIN_NT-6.1-WOW64) | |
360 | CFG_OSTYPE=w64-mingw32 | |
361 | CFG_CPUTYPE=x86_64 | |
362 | ;; | |
363 | ||
364 | # We do not detect other OS such as XP/2003 using 64 bit using uname. | |
365 | # If we want to in the future, we will need to use Cygwin | |
366 | # Chuck's csih helper in /usr/lib/csih/winProductName.exe or alternative. | |
367 | *) | |
368 | err "unknown OS type: $CFG_OSTYPE" | |
369 | ;; | |
370 | esac | |
371 | ||
372 | ||
373 | case $CFG_CPUTYPE in | |
374 | ||
375 | i386 | i486 | i686 | i786 | x86) | |
376 | CFG_CPUTYPE=i686 | |
377 | ;; | |
378 | ||
379 | xscale | arm) | |
380 | CFG_CPUTYPE=arm | |
381 | ;; | |
382 | ||
383 | x86_64 | x86-64 | x64 | amd64) | |
384 | CFG_CPUTYPE=x86_64 | |
385 | ;; | |
386 | ||
387 | *) | |
388 | err "unknown CPU type: $CFG_CPUTYPE" | |
389 | esac | |
390 | ||
391 | # Detect 64 bit linux systems with 32 bit userland and force 32 bit compilation | |
392 | if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ] | |
393 | then | |
394 | "${CFG_FILE}" -L "$SHELL" | grep -q "x86[_-]64" | |
395 | if [ $? != 0 ]; then | |
396 | CFG_CPUTYPE=i686 | |
397 | fi | |
398 | fi | |
399 | ||
400 | HOST_TRIPLE="${CFG_CPUTYPE}-${CFG_OSTYPE}" | |
401 | ||
402 | # Is this a triple we have nightlies for? | |
403 | case $HOST_TRIPLE in | |
404 | ||
405 | x86_64-unknown-linux-gnu) | |
406 | ;; | |
407 | ||
408 | i686-unknown-linux-gnu) | |
409 | ;; | |
410 | ||
411 | x86_64-apple-darwin) | |
412 | ;; | |
413 | ||
414 | i686-apple-darwin) | |
415 | ;; | |
416 | ||
417 | *) | |
418 | err "rustup.sh doesn't work for host $HOST_TRIPLE" | |
419 | ||
420 | esac | |
421 | ||
422 | msg "host triple: ${HOST_TRIPLE}" | |
423 | ||
424 | CFG_INSTALL_FLAGS="" | |
425 | if [ -n "${CFG_UNINSTALL}" ] | |
426 | then | |
427 | CFG_INSTALL_FLAGS="${CFG_INSTALL_FLAGS} --uninstall" | |
428 | fi | |
429 | ||
430 | if [ -n "${CFG_PREFIX}" ] | |
431 | then | |
432 | CFG_INSTALL_FLAGS="${CFG_INSTALL_FLAGS} --prefix=${CFG_PREFIX}" | |
433 | fi | |
434 | ||
435 | CFG_TMP_DIR=$(mktemp -d 2>/dev/null \ | |
436 | || mktemp -d -t 'rustup-tmp-install' 2>/dev/null \ | |
437 | || create_tmp_dir) | |
438 | ||
85aaf69f SL |
439 | # If we're saving nightlies and we didn't specify which one, grab the latest |
440 | # verison from the perspective of the server. Buildbot has typically finished | |
441 | # building and uploading by ~8UTC, but we want to include a little buffer. | |
442 | # | |
443 | # FIXME It would be better to use the known most recent nightly that has been | |
444 | # built. This is waiting on a change to have buildbot publish metadata that | |
445 | # can be queried. | |
1a4d82fc JJ |
446 | if [ -n "${CFG_SAVE}" -a -z "${CFG_DATE}" ]; |
447 | then | |
85aaf69f | 448 | CFG_DATE=`TZ=Etc/UTC+9 date "+%Y-%m-%d"` |
1a4d82fc JJ |
449 | fi |
450 | ||
451 | RUST_URL="https://static.rust-lang.org/dist" | |
452 | RUST_PACKAGE_NAME=rust-nightly | |
453 | RUST_PACKAGE_NAME_AND_TRIPLE="${RUST_PACKAGE_NAME}-${HOST_TRIPLE}" | |
454 | RUST_TARBALL_NAME="${RUST_PACKAGE_NAME_AND_TRIPLE}.tar.gz" | |
455 | RUST_LOCAL_INSTALL_DIR="${CFG_TMP_DIR}/${RUST_PACKAGE_NAME_AND_TRIPLE}" | |
456 | RUST_LOCAL_INSTALL_SCRIPT="${RUST_LOCAL_INSTALL_DIR}/install.sh" | |
457 | ||
458 | # add a date suffix if we want a particular nighly. | |
459 | if [ -n "${CFG_DATE}" ]; | |
460 | then | |
461 | RUST_URL="${RUST_URL}/${CFG_DATE}" | |
462 | fi | |
463 | ||
85aaf69f | 464 | download_hash() { |
1a4d82fc JJ |
465 | msg "Downloading ${remote_sha256}" |
466 | remote_sha256=`"${CFG_CURL}" -f "${remote_sha256}"` | |
85aaf69f SL |
467 | if [ -n "${CFG_SAVE}" ]; then |
468 | echo "${remote_sha256}" > "${local_sha_file}" | |
469 | fi | |
1a4d82fc JJ |
470 | if [ "$?" -ne 0 ]; then |
471 | rm -Rf "${CFG_TMP_DIR}" | |
472 | err "Failed to download ${remote_url}" | |
473 | fi | |
85aaf69f SL |
474 | } |
475 | ||
476 | verify_hash() { | |
477 | remote_sha256="$1" | |
478 | local_file="$2" | |
479 | local_sha_file="${local_file}.sha256" | |
480 | ||
481 | if [ -n "${CFG_SAVE}" ]; then | |
482 | if [ -f "${local_sha_file}" ]; then | |
483 | msg "Local ${local_sha_file} exists, treating as remote hash" | |
484 | remote_sha256=`cat "${local_sha_file}"` | |
485 | else | |
486 | download_hash | |
487 | fi | |
488 | else | |
489 | download_hash | |
490 | fi | |
1a4d82fc JJ |
491 | |
492 | msg "Verifying hash" | |
493 | local_sha256=$(calculate_hash "${local_file}") | |
494 | if [ "$?" -ne 0 ]; then | |
495 | rm -Rf "${CFG_TMP_DIR}" | |
496 | err "Failed to compute hash for ${local_tarball}" | |
497 | fi | |
498 | ||
499 | # We only need the sha, not the filenames | |
500 | remote_sha256=`echo ${remote_sha256} | cut -f 1 -d ' '` | |
501 | local_sha256=`echo ${local_sha256} | cut -f 1 -d ' '` | |
502 | ||
503 | if [ "${remote_sha256}" != "${local_sha256}" ]; then | |
504 | rm -Rf "${CFG_TMP_DIR}" | |
505 | errmsg="invalid sha256.\n" | |
506 | errmsg="$errmsg ${remote_sha256}\t${remote_tarball}\n" | |
507 | errmsg="$errmsg ${local_sha256}\t${local_tarball}" | |
508 | err "$errmsg" | |
509 | fi | |
510 | } | |
511 | ||
512 | # Fetch the package. Optionally caches the tarballs. | |
513 | download_package() { | |
514 | remote_tarball="$1" | |
515 | local_tarball="$2" | |
516 | remote_sha256="${remote_tarball}.sha256" | |
517 | ||
518 | # Check if we've already downloaded this file. | |
519 | if [ -e "${local_tarball}.tmp" ]; then | |
520 | msg "Resuming ${remote_tarball} to ${local_tarball}" | |
521 | ||
522 | "${CFG_CURL}" -f -C - -o "${local_tarball}.tmp" "${remote_tarball}" | |
523 | if [ $? -ne 0 ] | |
524 | then | |
525 | rm -Rf "${CFG_TMP_DIR}" | |
526 | err "failed to download installer" | |
527 | fi | |
528 | ||
529 | mv "${local_tarball}.tmp" "${local_tarball}" | |
530 | elif [ ! -e "${local_tarball}" ]; then | |
531 | msg "Downloading ${remote_tarball} to ${local_tarball}" | |
532 | ||
533 | "${CFG_CURL}" -f -o "${local_tarball}.tmp" "${remote_tarball}" | |
534 | if [ $? -ne 0 ] | |
535 | then | |
536 | rm -Rf "${CFG_TMP_DIR}" | |
537 | err "failed to download installer" | |
538 | fi | |
539 | ||
540 | mv "${local_tarball}.tmp" "${local_tarball}" | |
541 | fi | |
542 | ||
543 | verify_hash "${remote_sha256}" "${local_tarball}" | |
544 | } | |
545 | ||
546 | # Wrap all the commands needed to install a package. | |
547 | install_package() { | |
548 | local_tarball="$1" | |
549 | install_script="$2" | |
550 | ||
551 | msg "Extracting ${local_tarball}" | |
552 | (cd "${CFG_TMP_DIR}" && "${CFG_TAR}" -xzf "${local_tarball}") | |
553 | if [ $? -ne 0 ]; then | |
554 | rm -Rf "${CFG_TMP_DIR}" | |
555 | err "failed to unpack installer" | |
556 | fi | |
557 | ||
558 | sh "${install_script}" "${CFG_INSTALL_FLAGS}" | |
559 | if [ $? -ne 0 ] | |
560 | then | |
561 | rm -Rf "${CFG_TMP_DIR}" | |
562 | err "failed to install Rust" | |
563 | fi | |
564 | } | |
565 | ||
566 | # It's possible that curl could be interrupted partway though downloading | |
567 | # `rustup.sh`, truncating the file. This could be especially bad if we were in | |
568 | # the middle of a line that would run "rm -rf ". To protect against this, we | |
569 | # wrap up the `rustup.sh` destructive functionality in this helper function, | |
570 | # which we call as the last thing we do. This means we will not do anything | |
571 | # unless we have the entire file downloaded. | |
572 | install_packages() { | |
573 | rm -Rf "${CFG_TMP_DIR}" | |
574 | need_ok "failed to remove temporary installation directory" | |
575 | ||
576 | mkdir -p "${CFG_TMP_DIR}" | |
577 | need_ok "failed to create create temporary installation directory" | |
578 | ||
579 | # If we're saving our nightlies, put them in $HOME/.rustup. | |
580 | if [ -n "${CFG_SAVE}" ] | |
581 | then | |
582 | RUST_DOWNLOAD_DIR="${HOME}/.rustup/${CFG_DATE}" | |
583 | else | |
584 | RUST_DOWNLOAD_DIR="${CFG_TMP_DIR}" | |
585 | fi | |
586 | ||
587 | mkdir -p "${RUST_DOWNLOAD_DIR}" | |
588 | need_ok "failed to create create download directory" | |
589 | ||
590 | RUST_LOCAL_TARBALL="${RUST_DOWNLOAD_DIR}/${RUST_TARBALL_NAME}" | |
591 | ||
592 | download_package \ | |
593 | "${RUST_URL}/${RUST_TARBALL_NAME}" \ | |
594 | "${RUST_LOCAL_TARBALL}" | |
595 | ||
596 | install_package \ | |
597 | "${RUST_LOCAL_TARBALL}" \ | |
598 | "${RUST_LOCAL_INSTALL_SCRIPT}" | |
599 | ||
600 | rm -Rf "${CFG_TMP_DIR}" | |
601 | need_ok "couldn't rm temporary installation directory" | |
602 | } | |
603 | ||
604 | install_packages |