diff --git a/Cargo.toml b/Cargo.toml index 84078dd..1f06b26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] anyhow = "1.0.94" -clap = { version = "4.5.23", features = ["derive"]} +clap = { version = "4.5.23", features = ["derive"] } clap_complete = "4.5.38" clap_mangen = "0.2.24" dialoguer = "0.11.0" @@ -13,9 +13,13 @@ filebuffer = "1.0.0" hex = "0.4.3" rand = "0.8.5" regex = "1.11.1" -reqwest = {version = "0.12.9", features = ["blocking"]} +reqwest = { version = "0.12.9", features = ["blocking"] } rust-embed = "8.5.0" -serde = {version="1.0.215", features = ["derive"]} +serde = { version = "1.0.215", features = ["derive"] } sha2 = "0.10.8" toml = "0.8.19" url = "2.5.4" + +[profile.release] +opt-level = "s" +debug-assertions = false # required to change the default behavior of --temp-dir diff --git a/src/copied.rs b/src/copied.rs index d976e82..d5c6b24 100644 --- a/src/copied.rs +++ b/src/copied.rs @@ -84,6 +84,7 @@ pub fn download_all( to_path: &str, components: Vec<&str>, for_targets: Vec<&str>, + quiet: bool, ) { for channel in channels.clone() { if !crate::targets::RELEASE_CHANNELS.contains(&channel) { @@ -126,36 +127,35 @@ pub fn download_all( let mut value = data.parse::().unwrap(); assert_eq!(value["manifest-version"].as_str(), Some("2")); - println!( - "Channel {} date {}", - channel, - value["date"].as_str().unwrap() - ); + if !quiet { + println!( + "Channel {} date {}", + channel, + value["date"].as_str().unwrap() + ); + } for ele in for_targets.clone() { if ele.contains("windows") { - let artifacts = value["artifacts"]["installer-msi"]["target"][ele][0].as_table_mut().unwrap(); + let artifacts = value["artifacts"]["installer-msi"]["target"][ele][0] + .as_table_mut() + .unwrap(); - let url = - Url::parse(artifacts["url"].as_str().unwrap()) - .unwrap(); + let url = Url::parse(artifacts["url"].as_str().unwrap()).unwrap(); let mirror = Path::new(to_path); let file_name = url.path().replace("%20", " "); let file = mirror.join(&file_name[1..]); let hash_file = mirror.join(format!("{}.sha256", &file_name[1..])); - let hash_file_cont = - File::open(hash_file.clone()).ok().and_then(|mut f| { - let mut cont = String::new(); - f.read_to_string(&mut cont).ok().map(|_| cont) - }); + let hash_file_cont = File::open(hash_file.clone()).ok().and_then(|mut f| { + let mut cont = String::new(); + f.read_to_string(&mut cont).ok().map(|_| cont) + }); let hash_file_missing = hash_file_cont.is_none(); - let mut hash_file_cont = - hash_file_cont.or_else(|| file_sha256(file.as_path())); + let mut hash_file_cont = hash_file_cont.or_else(|| file_sha256(file.as_path())); - let chksum_upstream = - artifacts["hash-sha256"].as_str().unwrap(); + let chksum_upstream = artifacts["hash-sha256"].as_str().unwrap(); let need_download = match hash_file_cont { Some(ref chksum) => chksum_upstream != chksum, @@ -166,7 +166,7 @@ pub fn download_all( download(upstream_url, to_path, &file_name[1..]).unwrap(); hash_file_cont = file_sha256(file.as_path()); assert_eq!(Some(chksum_upstream), hash_file_cont.as_deref()); - } else { + } else if !quiet { println!("File {} already downloaded, skipping", file_name); } @@ -175,31 +175,30 @@ pub fn download_all( .unwrap() .write_all(hash_file_cont.unwrap().as_bytes()) .unwrap(); - println!("Writing checksum for file {}", file_name); + if !quiet { + println!("Writing checksum for file {}", file_name); + } } } else if ele.contains("darwin") { - let artifacts = value["artifacts"]["installer-pkg"]["target"][ele].as_table_mut().unwrap(); + let artifacts = value["artifacts"]["installer-pkg"]["target"][ele] + .as_table_mut() + .unwrap(); - let url = - Url::parse(artifacts["url"].as_str().unwrap()) - .unwrap(); + let url = Url::parse(artifacts["url"].as_str().unwrap()).unwrap(); let mirror = Path::new(to_path); let file_name = url.path().replace("%20", " "); let file = mirror.join(&file_name[1..]); let hash_file = mirror.join(format!("{}.sha256", &file_name[1..])); - let hash_file_cont = - File::open(hash_file.clone()).ok().and_then(|mut f| { - let mut cont = String::new(); - f.read_to_string(&mut cont).ok().map(|_| cont) - }); + let hash_file_cont = File::open(hash_file.clone()).ok().and_then(|mut f| { + let mut cont = String::new(); + f.read_to_string(&mut cont).ok().map(|_| cont) + }); let hash_file_missing = hash_file_cont.is_none(); - let mut hash_file_cont = - hash_file_cont.or_else(|| file_sha256(file.as_path())); + let mut hash_file_cont = hash_file_cont.or_else(|| file_sha256(file.as_path())); - let chksum_upstream = - artifacts["hash-sha256"].as_str().unwrap(); + let chksum_upstream = artifacts["hash-sha256"].as_str().unwrap(); let need_download = match hash_file_cont { Some(ref chksum) => chksum_upstream != chksum, @@ -210,7 +209,7 @@ pub fn download_all( download(upstream_url, to_path, &file_name[1..]).unwrap(); hash_file_cont = file_sha256(file.as_path()); assert_eq!(Some(chksum_upstream), hash_file_cont.as_deref()); - } else { + } else if !quiet { println!("File {} already downloaded, skipping", file_name); } @@ -219,7 +218,9 @@ pub fn download_all( .unwrap() .write_all(hash_file_cont.unwrap().as_bytes()) .unwrap(); - println!("Writing checksum for file {}", file_name); + if !quiet { + println!("Writing checksum for file {}", file_name); + } } } } @@ -281,7 +282,7 @@ pub fn download_all( download(upstream_url, to_path, &file_name[1..]).unwrap(); hash_file_cont = file_sha256(file.as_path()); assert_eq!(Some(chksum_upstream), hash_file_cont.as_deref()); - } else { + } else if !quiet { println!("File {} already downloaded, skipping", file_name); } @@ -290,7 +291,9 @@ pub fn download_all( .unwrap() .write_all(hash_file_cont.unwrap().as_bytes()) .unwrap(); - println!("Writing checksum for file {}", file_name); + if !quiet { + println!("Writing checksum for file {}", file_name); + } } pkg_target.insert( @@ -306,13 +309,17 @@ pub fn download_all( let path = Path::new(to_path).join(&name); create_dir_all(path.parent().unwrap()).unwrap(); let mut file = File::create(path.clone()).unwrap(); - println!("Producing /{}", name); + if !quiet { + println!("Producing /{}", name); + } file.write_all(output.as_bytes()).unwrap(); let sha256_new_file = file_sha256(&path).unwrap(); let sha256_new_file_path = Path::new(to_path).join(&sha256_name); let mut file = File::create(sha256_new_file_path.clone()).unwrap(); - println!("Producing /{}", sha256_name); + if !quiet { + println!("Producing /{}", sha256_name); + } file.write_all(format!("{} channel-rust-{}.toml", sha256_new_file, channel).as_bytes()) .unwrap(); @@ -322,12 +329,16 @@ pub fn download_all( let alt_path = Path::new(to_path).join(&alt_name); create_dir_all(alt_path.parent().unwrap()).unwrap(); copy(path, alt_path).unwrap(); - println!("Producing /{}", alt_name); + if !quiet { + println!("Producing /{}", alt_name); + } let alt_sha256_new_file_name = format!("dist/{}/channel-rust-{}.toml.sha256", date, channel); let alt_sha256_new_file_path = Path::new(to_path).join(&alt_sha256_new_file_name); copy(sha256_new_file_path, alt_sha256_new_file_path).unwrap(); - println!("Producing /{}", alt_sha256_new_file_name); + if !quiet { + println!("Producing /{}", alt_sha256_new_file_name); + } } } diff --git a/src/main.rs b/src/main.rs index 2ed3104..9a6d767 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use clap::Parser; use rand::{Rng, SeedableRng}; use rust_pkg_gen::resources::TemplateAssets; -use std::{fs, path::PathBuf}; +use std::{fs, path::PathBuf, process::Stdio}; fn gen_char() -> u8 { rand::rngs::StdRng::from_entropy().gen_range(65..90) @@ -31,8 +31,30 @@ struct Cli { help = "The equivalent to --yes for overwriting files" )] overwrite: bool, - #[arg(default_value = "rust-config.toml", help = "")] + #[arg( + default_value = "rust-config.toml", + help = "The path to the configuration file" + )] path: PathBuf, + #[arg( + short = 'q', + long = "quiet", + default_value_t = false, + help = "Doesn't display any unnecessary text(still shows confirmation prompts; to remove, use --overwrite" + )] + quiet: bool, + #[arg( + long = "silent", + default_value_t = false, + help = "Equivalent to -y -q --overwrite" + )] + silent: bool, + #[arg( + long = "save-temp", + default_value_t = false, + help = "Saves all temporary files" + )] + save_temp: bool, } fn generate_crates( @@ -47,7 +69,13 @@ fn generate_crates( } fn main() { - let args = Cli::parse(); + let mut args = Cli::parse(); + + if args.silent { + args.quiet = true; + args.yes = true; + args.overwrite = true; + } let path = &PathBuf::from(args.path); @@ -62,18 +90,25 @@ fn main() { let dir = if args.temp_dir.is_some() { if args.temp_dir.clone().unwrap().exists() && !args.overwrite { let confirmation = dialoguer::Confirm::new() - .with_prompt("Provided temporary directory already exists, overwrite?") + .with_prompt("Temporary directory already exists, overwrite?") .default(false) .interact() .unwrap(); if !confirmation { - println!("Aborting."); + if !args.quiet { + println!("Aborting."); + } std::process::exit(1) } else { - println!("Overwriting."); + if !args.quiet { + println!("Overwriting."); + } std::fs::remove_dir_all(args.temp_dir.clone().unwrap()).unwrap(); } } + if args.overwrite { + std::fs::remove_dir_all(args.temp_dir.clone().unwrap()).unwrap(); + } args.temp_dir.unwrap() } else { std::env::temp_dir().join(PathBuf::from(String::from_utf8_lossy(chars).as_ref())) @@ -115,15 +150,21 @@ fn main() { .unwrap(); } - std::process::Command::new("bash") - .arg( - dir.join(PathBuf::from("crates")) - .join(PathBuf::from("build.sh")), - ) - .spawn() - .unwrap() - .wait() - .unwrap(); + let mut build_c = std::process::Command::new("bash"); + let mut build = build_c.arg( + dir.join(PathBuf::from("crates")) + .join(PathBuf::from("build.sh")), + ); + if args.quiet { + build = build + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .stdin(Stdio::null()); + } + if args.save_temp { + build = build.arg("save") + } + build.spawn().unwrap().wait().unwrap(); rust_pkg_gen::copied::download_all( vec![&toolchain.channel], @@ -132,10 +173,13 @@ fn main() { toolchain.targets.iter().map(|s| &**s).collect(), dir.join("toolchain").to_str().unwrap(), toolchain.components.iter().map(|s| &**s).collect(), - toolchain.platforms.iter().map(|s| &**s).collect() + toolchain.platforms.iter().map(|s| &**s).collect(), + args.quiet, ); - fs::remove_dir_all(dir.join("tmp").to_str().unwrap()).unwrap(); + if !args.save_temp { + fs::remove_dir_all(dir.join("tmp").to_str().unwrap()).unwrap(); + } } } } diff --git a/src/resources.rs b/src/resources.rs index 4188ebf..3d3cf06 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -4,5 +4,3 @@ use rust_embed::Embed; #[folder = "src/template/"] #[prefix = "template/"] pub struct TemplateAssets; - -const RUSTUP_INIT_ASSET: &str = include_str!("rustup-init.sh"); \ No newline at end of file diff --git a/src/rustup-init.sh b/src/rustup-init.sh deleted file mode 100644 index c49b6ab..0000000 --- a/src/rustup-init.sh +++ /dev/null @@ -1,811 +0,0 @@ -#!/bin/sh -# shellcheck shell=dash -# shellcheck disable=SC2039 # local is non-POSIX - -# This is just a little script that can be downloaded from the internet to -# install rustup. It just does platform detection, downloads the installer -# and runs it. - -# It runs on Unix shells like {a,ba,da,k,z}sh. It uses the common `local` -# extension. Note: Most shells limit `local` to 1 var per line, contra bash. - -# Some versions of ksh have no `local` keyword. Alias it to `typeset`, but -# beware this makes variables global with f()-style function syntax in ksh93. -# mksh has this alias by default. -has_local() { - # shellcheck disable=SC2034 # deliberately unused - local _has_local -} - -has_local 2>/dev/null || alias local=typeset - -is_zsh() { - [ -n "${ZSH_VERSION-}" ] -} - -set -u - -# If RUSTUP_UPDATE_ROOT is unset or empty, default it. -RUSTUP_UPDATE_ROOT="${RUSTUP_UPDATE_ROOT:-https://static.rust-lang.org/rustup}" - -# NOTICE: If you change anything here, please make the same changes in setup_mode.rs -usage() { - cat < - Choose a default host triple - --default-toolchain - Choose a default toolchain to install. Use 'none' to not install any toolchains at all - --profile - [default: default] [possible values: minimal, default, complete] - -c, --component ... - Component name to also install - -t, --target ... - Target name to also install - --no-update-default-toolchain - Don't update any existing default toolchain after install - --no-modify-path - Don't configure the PATH environment variable - -h, --help - Print help - -V, --version - Print version -EOF -} - -main() { - downloader --check - need_cmd uname - need_cmd mktemp - need_cmd chmod - need_cmd mkdir - need_cmd rm - need_cmd rmdir - - get_architecture || return 1 - local _arch="$RETVAL" - assert_nz "$_arch" "arch" - - local _ext="" - case "$_arch" in - *windows*) - _ext=".exe" - ;; - esac - - local _url="${RUSTUP_UPDATE_ROOT}/dist/${_arch}/rustup-init${_ext}" - - local _dir - if ! _dir="$(ensure mktemp -d)"; then - # Because the previous command ran in a subshell, we must manually - # propagate exit status. - exit 1 - fi - local _file="${_dir}/rustup-init${_ext}" - - local _ansi_escapes_are_valid=false - if [ -t 2 ]; then - if [ "${TERM+set}" = 'set' ]; then - case "$TERM" in - xterm*|rxvt*|urxvt*|linux*|vt*) - _ansi_escapes_are_valid=true - ;; - esac - fi - fi - - # check if we have to use /dev/tty to prompt the user - local need_tty=yes - for arg in "$@"; do - case "$arg" in - --help) - usage - exit 0 - ;; - *) - OPTIND=1 - if [ "${arg%%--*}" = "" ]; then - # Long option (other than --help); - # don't attempt to interpret it. - continue - fi - while getopts :hy sub_arg "$arg"; do - case "$sub_arg" in - h) - usage - exit 0 - ;; - y) - # user wants to skip the prompt -- - # we don't need /dev/tty - need_tty=no - ;; - *) - ;; - esac - done - ;; - esac - done - - if $_ansi_escapes_are_valid; then - printf "\33[1minfo:\33[0m downloading installer\n" 1>&2 - else - printf '%s\n' 'info: downloading installer' 1>&2 - fi - - ensure mkdir -p "$_dir" - ensure downloader "$_url" "$_file" "$_arch" - ensure chmod u+x "$_file" - if [ ! -x "$_file" ]; then - printf '%s\n' "Cannot execute $_file (likely because of mounting /tmp as noexec)." 1>&2 - printf '%s\n' "Please copy the file to a location where you can execute binaries and run ./rustup-init${_ext}." 1>&2 - exit 1 - fi - - if [ "$need_tty" = "yes" ] && [ ! -t 0 ]; then - # The installer is going to want to ask for confirmation by - # reading stdin. This script was piped into `sh` though and - # doesn't have stdin to pass to its children. Instead we're going - # to explicitly connect /dev/tty to the installer's stdin. - if [ ! -t 1 ]; then - err "Unable to run interactively. Run with -y to accept defaults, --help for additional options" - fi - - ignore "$_file" "$@" < /dev/tty - else - ignore "$_file" "$@" - fi - - local _retval=$? - - ignore rm "$_file" - ignore rmdir "$_dir" - - return "$_retval" -} - -check_proc() { - # Check for /proc by looking for the /proc/self/exe link - # This is only run on Linux - if ! test -L /proc/self/exe ; then - err "fatal: Unable to find /proc/self/exe. Is /proc mounted? Installation cannot proceed without /proc." - fi -} - -get_bitness() { - need_cmd head - # Architecture detection without dependencies beyond coreutils. - # ELF files start out "\x7fELF", and the following byte is - # 0x01 for 32-bit and - # 0x02 for 64-bit. - # The printf builtin on some shells like dash only supports octal - # escape sequences, so we use those. - local _current_exe_head - _current_exe_head=$(head -c 5 /proc/self/exe ) - if [ "$_current_exe_head" = "$(printf '\177ELF\001')" ]; then - echo 32 - elif [ "$_current_exe_head" = "$(printf '\177ELF\002')" ]; then - echo 64 - else - err "unknown platform bitness" - fi -} - -is_host_amd64_elf() { - need_cmd head - need_cmd tail - # ELF e_machine detection without dependencies beyond coreutils. - # Two-byte field at offset 0x12 indicates the CPU, - # but we're interested in it being 0x3E to indicate amd64, or not that. - local _current_exe_machine - _current_exe_machine=$(head -c 19 /proc/self/exe | tail -c 1) - [ "$_current_exe_machine" = "$(printf '\076')" ] -} - -get_endianness() { - local cputype=$1 - local suffix_eb=$2 - local suffix_el=$3 - - # detect endianness without od/hexdump, like get_bitness() does. - need_cmd head - need_cmd tail - - local _current_exe_endianness - _current_exe_endianness="$(head -c 6 /proc/self/exe | tail -c 1)" - if [ "$_current_exe_endianness" = "$(printf '\001')" ]; then - echo "${cputype}${suffix_el}" - elif [ "$_current_exe_endianness" = "$(printf '\002')" ]; then - echo "${cputype}${suffix_eb}" - else - err "unknown platform endianness" - fi -} - -# Detect the Linux/LoongArch UAPI flavor, with all errors being non-fatal. -# Returns 0 or 234 in case of successful detection, 1 otherwise (/tmp being -# noexec, or other causes). -check_loongarch_uapi() { - need_cmd base64 - - local _tmp - if ! _tmp="$(ensure mktemp)"; then - return 1 - fi - - # Minimal Linux/LoongArch UAPI detection, exiting with 0 in case of - # upstream ("new world") UAPI, and 234 (-EINVAL truncated) in case of - # old-world (as deployed on several early commercial Linux distributions - # for LoongArch). - # - # See https://gist.github.com/xen0n/5ee04aaa6cecc5c7794b9a0c3b65fc7f for - # source to this helper binary. - ignore base64 -d > "$_tmp" <&2 - echo 'Your Linux kernel does not provide the ABI required by this Rust' >&2 - echo 'distribution. Please check with your OS provider for how to obtain a' >&2 - echo 'compatible Rust package for your system.' >&2 - echo >&2 - exit 1 - ;; - *) - echo "Warning: Cannot determine current system's ABI flavor, continuing anyway." >&2 - echo >&2 - echo 'Note that the official Rust distribution only works with the upstream' >&2 - echo 'kernel ABI. Installation will fail if your running kernel happens to be' >&2 - echo 'incompatible.' >&2 - ;; - esac -} - -get_architecture() { - local _ostype _cputype _bitness _arch _clibtype - _ostype="$(uname -s)" - _cputype="$(uname -m)" - _clibtype="gnu" - - if [ "$_ostype" = Linux ]; then - if [ "$(uname -o)" = Android ]; then - _ostype=Android - fi - if ldd --version 2>&1 | grep -q 'musl'; then - _clibtype="musl" - fi - fi - - if [ "$_ostype" = Darwin ]; then - # Darwin `uname -m` can lie due to Rosetta shenanigans. If you manage to - # invoke a native shell binary and then a native uname binary, you can - # get the real answer, but that's hard to ensure, so instead we use - # `sysctl` (which doesn't lie) to check for the actual architecture. - if [ "$_cputype" = i386 ]; then - # Handling i386 compatibility mode in older macOS versions (<10.15) - # running on x86_64-based Macs. - # Starting from 10.15, macOS explicitly bans all i386 binaries from running. - # See: - - # Avoid `sysctl: unknown oid` stderr output and/or non-zero exit code. - if sysctl hw.optional.x86_64 2> /dev/null || true | grep -q ': 1'; then - _cputype=x86_64 - fi - elif [ "$_cputype" = x86_64 ]; then - # Handling x86-64 compatibility mode (a.k.a. Rosetta 2) - # in newer macOS versions (>=11) running on arm64-based Macs. - # Rosetta 2 is built exclusively for x86-64 and cannot run i386 binaries. - - # Avoid `sysctl: unknown oid` stderr output and/or non-zero exit code. - if sysctl hw.optional.arm64 2> /dev/null || true | grep -q ': 1'; then - _cputype=arm64 - fi - fi - fi - - if [ "$_ostype" = SunOS ]; then - # Both Solaris and illumos presently announce as "SunOS" in "uname -s" - # so use "uname -o" to disambiguate. We use the full path to the - # system uname in case the user has coreutils uname first in PATH, - # which has historically sometimes printed the wrong value here. - if [ "$(/usr/bin/uname -o)" = illumos ]; then - _ostype=illumos - fi - - # illumos systems have multi-arch userlands, and "uname -m" reports the - # machine hardware name; e.g., "i86pc" on both 32- and 64-bit x86 - # systems. Check for the native (widest) instruction set on the - # running kernel: - if [ "$_cputype" = i86pc ]; then - _cputype="$(isainfo -n)" - fi - fi - - case "$_ostype" in - - Android) - _ostype=linux-android - ;; - - Linux) - check_proc - _ostype=unknown-linux-$_clibtype - _bitness=$(get_bitness) - ;; - - FreeBSD) - _ostype=unknown-freebsd - ;; - - NetBSD) - _ostype=unknown-netbsd - ;; - - DragonFly) - _ostype=unknown-dragonfly - ;; - - Darwin) - _ostype=apple-darwin - ;; - - illumos) - _ostype=unknown-illumos - ;; - - MINGW* | MSYS* | CYGWIN* | Windows_NT) - _ostype=pc-windows-gnu - ;; - - *) - err "unrecognized OS type: $_ostype" - ;; - - esac - - case "$_cputype" in - - i386 | i486 | i686 | i786 | x86) - _cputype=i686 - ;; - - xscale | arm) - _cputype=arm - if [ "$_ostype" = "linux-android" ]; then - _ostype=linux-androideabi - fi - ;; - - armv6l) - _cputype=arm - if [ "$_ostype" = "linux-android" ]; then - _ostype=linux-androideabi - else - _ostype="${_ostype}eabihf" - fi - ;; - - armv7l | armv8l) - _cputype=armv7 - if [ "$_ostype" = "linux-android" ]; then - _ostype=linux-androideabi - else - _ostype="${_ostype}eabihf" - fi - ;; - - aarch64 | arm64) - _cputype=aarch64 - ;; - - x86_64 | x86-64 | x64 | amd64) - _cputype=x86_64 - ;; - - mips) - _cputype=$(get_endianness mips '' el) - ;; - - mips64) - if [ "$_bitness" -eq 64 ]; then - # only n64 ABI is supported for now - _ostype="${_ostype}abi64" - _cputype=$(get_endianness mips64 '' el) - fi - ;; - - ppc) - _cputype=powerpc - ;; - - ppc64) - _cputype=powerpc64 - ;; - - ppc64le) - _cputype=powerpc64le - ;; - - s390x) - _cputype=s390x - ;; - riscv64) - _cputype=riscv64gc - ;; - loongarch64) - _cputype=loongarch64 - ensure_loongarch_uapi - ;; - *) - err "unknown CPU type: $_cputype" - - esac - - # Detect 64-bit linux with 32-bit userland - if [ "${_ostype}" = unknown-linux-gnu ] && [ "${_bitness}" -eq 32 ]; then - case $_cputype in - x86_64) - if [ -n "${RUSTUP_CPUTYPE:-}" ]; then - _cputype="$RUSTUP_CPUTYPE" - else { - # 32-bit executable for amd64 = x32 - if is_host_amd64_elf; then { - echo "This host is running an x32 userland; as it stands, x32 support is poor," 1>&2 - echo "and there isn't a native toolchain -- you will have to install" 1>&2 - echo "multiarch compatibility with i686 and/or amd64, then select one" 1>&2 - echo "by re-running this script with the RUSTUP_CPUTYPE environment variable" 1>&2 - echo "set to i686 or x86_64, respectively." 1>&2 - echo 1>&2 - echo "You will be able to add an x32 target after installation by running" 1>&2 - echo " rustup target add x86_64-unknown-linux-gnux32" 1>&2 - exit 1 - }; else - _cputype=i686 - fi - }; fi - ;; - mips64) - _cputype=$(get_endianness mips '' el) - ;; - powerpc64) - _cputype=powerpc - ;; - aarch64) - _cputype=armv7 - if [ "$_ostype" = "linux-android" ]; then - _ostype=linux-androideabi - else - _ostype="${_ostype}eabihf" - fi - ;; - riscv64gc) - err "riscv64 with 32-bit userland unsupported" - ;; - esac - fi - - # Detect armv7 but without the CPU features Rust needs in that build, - # and fall back to arm. - # See https://github.com/rust-lang/rustup.rs/issues/587. - if [ "$_ostype" = "unknown-linux-gnueabihf" ] && [ "$_cputype" = armv7 ]; then - if ensure grep '^Features' /proc/cpuinfo | grep -E -q -v 'neon|simd'; then - # At least one processor does not have NEON (which is asimd on armv8+). - _cputype=arm - fi - fi - - _arch="${_cputype}-${_ostype}" - - RETVAL="$_arch" -} - -say() { - printf 'rustup: %s\n' "$1" -} - -err() { - say "$1" >&2 - exit 1 -} - -need_cmd() { - if ! check_cmd "$1"; then - err "need '$1' (command not found)" - fi -} - -check_cmd() { - command -v "$1" > /dev/null 2>&1 -} - -assert_nz() { - if [ -z "$1" ]; then err "assert_nz $2"; fi -} - -# Run a command that should never fail. If the command fails execution -# will immediately terminate with an error showing the failing -# command. -ensure() { - if ! "$@"; then err "command failed: $*"; fi -} - -# This is just for indicating that commands' results are being -# intentionally ignored. Usually, because it's being executed -# as part of error handling. -ignore() { - "$@" -} - -# This wraps curl or wget. Try curl first, if not installed, -# use wget instead. -downloader() { - # zsh does not split words by default, Required for curl retry arguments below. - is_zsh && setopt local_options shwordsplit - - local _dld - local _ciphersuites - local _err - local _status - local _retry - if check_cmd curl; then - _dld=curl - elif check_cmd wget; then - _dld=wget - else - _dld='curl or wget' # to be used in error message of need_cmd - fi - - if [ "$1" = --check ]; then - need_cmd "$_dld" - elif [ "$_dld" = curl ]; then - check_curl_for_retry_support - _retry="$RETVAL" - get_ciphersuites_for_curl - _ciphersuites="$RETVAL" - if [ -n "$_ciphersuites" ]; then - _err=$(curl $_retry --proto '=https' --tlsv1.2 --ciphers "$_ciphersuites" --silent --show-error --fail --location "$1" --output "$2" 2>&1) - _status=$? - else - echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure" - if ! check_help_for "$3" curl --proto --tlsv1.2; then - echo "Warning: Not enforcing TLS v1.2, this is potentially less secure" - _err=$(curl $_retry --silent --show-error --fail --location "$1" --output "$2" 2>&1) - _status=$? - else - _err=$(curl $_retry --proto '=https' --tlsv1.2 --silent --show-error --fail --location "$1" --output "$2" 2>&1) - _status=$? - fi - fi - if [ -n "$_err" ]; then - echo "$_err" >&2 - if echo "$_err" | grep -q 404$; then - err "installer for platform '$3' not found, this may be unsupported" - fi - fi - return $_status - elif [ "$_dld" = wget ]; then - if [ "$(wget -V 2>&1|head -2|tail -1|cut -f1 -d" ")" = "BusyBox" ]; then - echo "Warning: using the BusyBox version of wget. Not enforcing strong cipher suites for TLS or TLS v1.2, this is potentially less secure" - _err=$(wget "$1" -O "$2" 2>&1) - _status=$? - else - get_ciphersuites_for_wget - _ciphersuites="$RETVAL" - if [ -n "$_ciphersuites" ]; then - _err=$(wget --https-only --secure-protocol=TLSv1_2 --ciphers "$_ciphersuites" "$1" -O "$2" 2>&1) - _status=$? - else - echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure" - if ! check_help_for "$3" wget --https-only --secure-protocol; then - echo "Warning: Not enforcing TLS v1.2, this is potentially less secure" - _err=$(wget "$1" -O "$2" 2>&1) - _status=$? - else - _err=$(wget --https-only --secure-protocol=TLSv1_2 "$1" -O "$2" 2>&1) - _status=$? - fi - fi - fi - if [ -n "$_err" ]; then - echo "$_err" >&2 - if echo "$_err" | grep -q ' 404 Not Found$'; then - err "installer for platform '$3' not found, this may be unsupported" - fi - fi - return $_status - else - err "Unknown downloader" # should not reach here - fi -} - -check_help_for() { - local _arch - local _cmd - local _arg - _arch="$1" - shift - _cmd="$1" - shift - - local _category - if "$_cmd" --help | grep -q 'For all options use the manual or "--help all".'; then - _category="all" - else - _category="" - fi - - case "$_arch" in - - *darwin*) - if check_cmd sw_vers; then - case $(sw_vers -productVersion) in - 10.*) - # If we're running on macOS, older than 10.13, then we always - # fail to find these options to force fallback - if [ "$(sw_vers -productVersion | cut -d. -f2)" -lt 13 ]; then - # Older than 10.13 - echo "Warning: Detected macOS platform older than 10.13" - return 1 - fi - ;; - 11.*) - # We assume Big Sur will be OK for now - ;; - *) - # Unknown product version, warn and continue - echo "Warning: Detected unknown macOS major version: $(sw_vers -productVersion)" - echo "Warning TLS capabilities detection may fail" - ;; - esac - fi - ;; - - esac - - for _arg in "$@"; do - if ! "$_cmd" --help "$_category" | grep -q -- "$_arg"; then - return 1 - fi - done - - true # not strictly needed -} - -# Check if curl supports the --retry flag, then pass it to the curl invocation. -check_curl_for_retry_support() { - local _retry_supported="" - # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc. - if check_help_for "notspecified" "curl" "--retry"; then - _retry_supported="--retry 3" - if check_help_for "notspecified" "curl" "--continue-at"; then - # "-C -" tells curl to automatically find where to resume the download when retrying. - _retry_supported="--retry 3 -C -" - fi - fi - - RETVAL="$_retry_supported" -} - -# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites -# if support by local tools is detected. Detection currently supports these curl backends: -# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty. -get_ciphersuites_for_curl() { - if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then - # user specified custom cipher suites, assume they know what they're doing - RETVAL="$RUSTUP_TLS_CIPHERSUITES" - return - fi - - local _openssl_syntax="no" - local _gnutls_syntax="no" - local _backend_supported="yes" - if curl -V | grep -q ' OpenSSL/'; then - _openssl_syntax="yes" - elif curl -V | grep -iq ' LibreSSL/'; then - _openssl_syntax="yes" - elif curl -V | grep -iq ' BoringSSL/'; then - _openssl_syntax="yes" - elif curl -V | grep -iq ' GnuTLS/'; then - _gnutls_syntax="yes" - else - _backend_supported="no" - fi - - local _args_supported="no" - if [ "$_backend_supported" = "yes" ]; then - # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc. - if check_help_for "notspecified" "curl" "--tlsv1.2" "--ciphers" "--proto"; then - _args_supported="yes" - fi - fi - - local _cs="" - if [ "$_args_supported" = "yes" ]; then - if [ "$_openssl_syntax" = "yes" ]; then - _cs=$(get_strong_ciphersuites_for "openssl") - elif [ "$_gnutls_syntax" = "yes" ]; then - _cs=$(get_strong_ciphersuites_for "gnutls") - fi - fi - - RETVAL="$_cs" -} - -# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites -# if support by local tools is detected. Detection currently supports these wget backends: -# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty. -get_ciphersuites_for_wget() { - if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then - # user specified custom cipher suites, assume they know what they're doing - RETVAL="$RUSTUP_TLS_CIPHERSUITES" - return - fi - - local _cs="" - if wget -V | grep -q '\-DHAVE_LIBSSL'; then - # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc. - if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then - _cs=$(get_strong_ciphersuites_for "openssl") - fi - elif wget -V | grep -q '\-DHAVE_LIBGNUTLS'; then - # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc. - if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then - _cs=$(get_strong_ciphersuites_for "gnutls") - fi - fi - - RETVAL="$_cs" -} - -# Return strong TLS 1.2-1.3 cipher suites in OpenSSL or GnuTLS syntax. TLS 1.2 -# excludes non-ECDHE and non-AEAD cipher suites. DHE is excluded due to bad -# DH params often found on servers (see RFC 7919). Sequence matches or is -# similar to Firefox 68 ESR with weak cipher suites disabled via about:config. -# $1 must be openssl or gnutls. -get_strong_ciphersuites_for() { - if [ "$1" = "openssl" ]; then - # OpenSSL is forgiving of unknown values, no problems with TLS 1.3 values on versions that don't support it yet. - echo "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384" - elif [ "$1" = "gnutls" ]; then - # GnuTLS isn't forgiving of unknown values, so this may require a GnuTLS version that supports TLS 1.3 even if wget doesn't. - # Begin with SECURE128 (and higher) then remove/add to build cipher suites. Produces same 9 cipher suites as OpenSSL but in slightly different order. - echo "SECURE128:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-DTLS-ALL:-CIPHER-ALL:-MAC-ALL:-KX-ALL:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+AES-128-GCM:+CHACHA20-POLY1305:+AES-256-GCM" - fi -} - -main "$@" || exit 1 diff --git a/src/template/build.sh b/src/template/build.sh index d080cac..82e0a36 100644 --- a/src/template/build.sh +++ b/src/template/build.sh @@ -1,7 +1,10 @@ #!/usr/bin/env bash +CI=1 cd "$(dirname "$0")" cargo generate-lockfile --verbose cargo vendor --verbose --locked ./crates mv crates/* . -rm Cargo.lock Cargo.toml rust-toolchain.toml src/main.rs .cargo/config.toml build.sh -rm -d src .cargo \ No newline at end of file +if [[ "$1" != "save" ]]; then + rm Cargo.lock Cargo.toml rust-toolchain.toml src/main.rs .cargo/config.toml build.sh + rm -d src .cargo crates +fi \ No newline at end of file