From 08540cc4eabea441869322bad0125672019b3338 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 26 Oct 2018 19:10:38 +0200 Subject: [PATCH 1/6] update Cargo.lock after version update --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 45c4742..cd39af8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -753,7 +753,7 @@ dependencies = [ [[package]] name = "rustup-toolchain-install-master" -version = "1.2.0" +version = "1.3.0" dependencies = [ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", From e5614b488996cc32418f7f335d19a2470e42d029 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 26 Oct 2018 19:34:45 +0200 Subject: [PATCH 2/6] remove unused_import warning on rust 1.30 --- src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 9d4a268..d450be2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,6 @@ extern crate failure; extern crate home; extern crate pbr; extern crate reqwest; -#[macro_use] extern crate structopt; extern crate tar; extern crate tee; From 98d48fea6b2c76404c64d54a9f83bf0773b14f45 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 26 Oct 2018 19:36:01 +0200 Subject: [PATCH 3/6] fail fast when a toolchain is missing, and add -k to restore old behavior --- src/main.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index d450be2..b13a015 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,7 @@ use std::process::exit; use std::time::Duration; use std::process::Command; -use failure::Error; +use failure::{Error, err_msg}; use pbr::{ProgressBar, Units}; use reqwest::header::{ACCEPT, AUTHORIZATION, CONTENT_LENGTH}; use reqwest::{Client, ClientBuilder, Proxy}; @@ -81,6 +81,9 @@ struct Args { #[structopt(long = "force", short = "f", help = "Replace an existing toolchain of the same name")] force: bool, + + #[structopt(long = "keep-going", short = "k", help = "Continue downloading toolchains even if some of them failed")] + keep_going: bool, } macro_rules! path_buf { @@ -305,6 +308,7 @@ fn run() -> Result<(), Error> { } let dry_run_client = if args.dry_run { None } else { Some(&client) }; + let mut failed = false; for commit in args.commits { let dest = if let Some(name) = args.name.as_ref() { Cow::Borrowed(name) @@ -313,7 +317,8 @@ fn run() -> Result<(), Error> { } else { Cow::Borrowed(&commit) }; - if let Err(e) = install_single_toolchain( + + let result = install_single_toolchain( dry_run_client, &prefix, &toolchains_path, @@ -325,12 +330,23 @@ fn run() -> Result<(), Error> { dest, }, args.force - ) { - eprintln!("skipping {} due to failure:\n{:?}", commit, e); + ); + + match result { + Err(ref err) if args.keep_going => { + eprintln!("skipping {} due to failure:\n{:?}", commit, err); + failed = true; + } + res => res?, } } - Ok(()) + // Return the error only after downloading the toolchains that didn't fail + if failed { + Err(err_msg("failed to download some toolchains")) + } else { + Ok(()) + } } fn main() { From 4c9692168ec042f20d61f999a6c514a5531167a5 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 26 Oct 2018 19:57:58 +0200 Subject: [PATCH 4/6] improve error messages display --- Cargo.lock | 1 + Cargo.toml | 1 + src/main.rs | 48 +++++++++++++++++++++++++++++++++++------------- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd39af8..ab2d42c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -755,6 +755,7 @@ dependencies = [ name = "rustup-toolchain-install-master" version = "1.3.0" dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 19c5a0c..612a9d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,3 +25,4 @@ tar = "0.4" tee = "0.1" tempfile = "3" xz2 = "0.1" +ansi_term = "0.11" diff --git a/src/main.rs b/src/main.rs index b13a015..ea947e1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +extern crate ansi_term; #[macro_use] extern crate failure; extern crate home; @@ -19,7 +20,8 @@ use std::process::exit; use std::time::Duration; use std::process::Command; -use failure::{Error, err_msg}; +use ansi_term::Color::{Red, Yellow}; +use failure::{Fail, Error, err_msg, ResultExt}; use pbr::{ProgressBar, Units}; use reqwest::header::{ACCEPT, AUTHORIZATION, CONTENT_LENGTH}; use reqwest::{Client, ClientBuilder, Proxy}; @@ -207,9 +209,10 @@ fn install_single_toolchain( fn fetch_master_commit(client: &Client, github_token: Option<&str>) -> Result { eprintln!("fetching master commit hash... "); - match fetch_master_commit_via_git() { - Ok(hash) => return Ok(hash), - Err(e) => eprint!("unable to fetch master commit via git, fallback to HTTP. Error: {}", e), + let res = fetch_master_commit_via_git() + .context("unable to fetch master commit via git, falling back to HTTP"); + if let Err(err) = res { + report_warn(&err); } fetch_master_commit_via_http(client, github_token) @@ -261,16 +264,14 @@ fn run() -> Result<(), Error> { let rustup_home = home::rustup_home().expect("$RUSTUP_HOME is undefined?"); let toolchains_path = rustup_home.join("toolchains"); if !toolchains_path.is_dir() { - eprintln!( + bail!( "`{}` is not a directory. please reinstall rustup.", toolchains_path.display() ); - exit(1); } if args.commits.len() > 1 && args.name.is_some() { - eprintln!("name argument can only be provided with a single commit"); - exit(1); + return Err(err_msg("name argument can only be provided with a single commit")); } let host = args.host.as_ref().map(|s| &**s).unwrap_or(env!("HOST")); @@ -332,12 +333,15 @@ fn run() -> Result<(), Error> { args.force ); - match result { - Err(ref err) if args.keep_going => { - eprintln!("skipping {} due to failure:\n{:?}", commit, err); + if args.keep_going { + if let Err(err) = result { + report_warn( + &err.context(format!("skipping toolchain `{}` due to a failure", commit)) + ); failed = true; } - res => res?, + } else { + result?; } } @@ -349,6 +353,24 @@ fn run() -> Result<(), Error> { } } +fn report_error(err: &Fail) { + eprintln!("{} {}", Red.bold().paint("error:"), err); + for cause in err.iter_causes() { + eprintln!("{} {}", Red.bold().paint("caused by:"), cause); + } + exit(1); +} + +fn report_warn(warn: &Fail) { + eprintln!("{} {}", Yellow.bold().paint("warn:"), warn); + for cause in warn.iter_causes() { + eprintln!("{} {}", Yellow.bold().paint("caused by:"), cause); + } + eprintln!(""); +} + fn main() { - run().unwrap(); + if let Err(err) = run() { + report_error(err.as_fail()); + } } From cbb0b9382e77c4a1944f7912054ed17fc238cdc5 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 26 Oct 2018 20:20:02 +0200 Subject: [PATCH 5/6] improve error messages for missing toolchains --- src/main.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index ea947e1..8f256b2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ use failure::{Fail, Error, err_msg, ResultExt}; use pbr::{ProgressBar, Units}; use reqwest::header::{ACCEPT, AUTHORIZATION, CONTENT_LENGTH}; use reqwest::{Client, ClientBuilder, Proxy}; +use reqwest::StatusCode; use structopt::StructOpt; use tar::Archive; use tee::TeeReader; @@ -97,11 +98,23 @@ fn download_tar_xz( url: &str, src: &Path, dest: &Path, + commit: &str, + component: &str, + target: &str, ) -> Result<(), Error> { eprintln!("downloading <{}>...", url); if let Some(client) = client { - let response = client.get(url).send()?.error_for_status()?; + let response = client.get(url).send()?; + + match response.status() { + StatusCode::OK => {} + StatusCode::NOT_FOUND => bail!( + "missing component `{}` on toolchain `{}` for target `{}`", + component, commit, target, + ), + status => bail!("received status {} for GET {}", status, url), + }; let length = response .headers() @@ -175,6 +188,9 @@ fn install_single_toolchain( ), &path_buf![&component_filename, *component], Path::new(&*toolchain.dest), + toolchain.commit, + component, + toolchain.host_target, )?; } @@ -189,6 +205,9 @@ fn install_single_toolchain( ), &path_buf![&rust_std_filename, &format!("rust-std-{}", target), "lib"], &path_buf![&toolchain.dest, "lib"], + toolchain.commit, + "rust-std", + target, )?; } From 18310de5e82289425d3efad09138b1c9ac7eff6b Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 26 Oct 2018 20:22:36 +0200 Subject: [PATCH 6/6] update help in the README --- README.md | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 74e396a..5089253 100644 --- a/README.md +++ b/README.md @@ -7,23 +7,28 @@ Installs compiler artifacts generated fresh from Rust's CI into `rustup`. ``` USAGE: - rustup-toolchain-install-master [FLAGS] [OPTIONS] ... + rustup-toolchain-install-master [FLAGS] [OPTIONS] [--] [commits]... FLAGS: - -a, --alt download the alt build instead of normal build - -h, --help Prints help information - -V, --version Prints version information + -a, --alt download the alt build instead of normal build + --dry-run Only log the URLs, without downloading the artifacts + -f, --force Replace an existing toolchain of the same name + -h, --help Prints help information + -k, --keep-going Continue downloading toolchains even if some of them failed + -V, --version Prints version information OPTIONS: - -c, --component ... additional components to install, besides rustc and rust-std - -i, --host the triples of host platform - -p, --proxy the HTTP proxy for all download requests - -s, --server the server path which stores the compilers [default: https://s3-us-west - -1.amazonaws.com/rust-lang-ci2] - -t, --targets ... additional target platforms to install, besides the host platform + -c, --component ... additional components to install, besides rustc and rust-std + --github-token An authorization token to access GitHub APIs + -i, --host the triples of host platform + -n, --name the name to call the toolchain + -p, --proxy the HTTP proxy for all download requests + -s, --server the server path which stores the compilers [default: https://s3-us-west-1.amazonaws.com/rust-lang-ci2] + -t, --targets ... additional target platforms to install, besides the host platform ARGS: - ... full commit hashes of the rustc builds; all 40 digits are needed + ... full commit hashes of the rustc builds, all 40 digits are needed; if omitted, the latest master + commit will be installed ``` Installation