Skip to content

Commit

Permalink
Merge pull request #9 from pietroalbini/fail-on-error
Browse files Browse the repository at this point in the history
Fail fast when there is an error
  • Loading branch information
kennytm authored Oct 27, 2018
2 parents d6b3455 + 18310de commit a327e07
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 27 deletions.
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ tar = "0.4"
tee = "0.1"
tempfile = "3"
xz2 = "0.1"
ansi_term = "0.11"
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,28 @@ Installs compiler artifacts generated fresh from Rust's CI into `rustup`.

```
USAGE:
rustup-toolchain-install-master [FLAGS] [OPTIONS] <commits>...
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 <components>... additional components to install, besides rustc and rust-std
-i, --host <host> the triples of host platform
-p, --proxy <proxy> the HTTP proxy for all download requests
-s, --server <server> the server path which stores the compilers [default: https://s3-us-west
-1.amazonaws.com/rust-lang-ci2]
-t, --targets <targets>... additional target platforms to install, besides the host platform
-c, --component <components>... additional components to install, besides rustc and rust-std
--github-token <github_token> An authorization token to access GitHub APIs
-i, --host <host> the triples of host platform
-n, --name <name> the name to call the toolchain
-p, --proxy <proxy> the HTTP proxy for all download requests
-s, --server <server> the server path which stores the compilers [default: https://s3-us-west-1.amazonaws.com/rust-lang-ci2]
-t, --targets <targets>... additional target platforms to install, besides the host platform
ARGS:
<commits>... full commit hashes of the rustc builds; all 40 digits are needed
<commits>... full commit hashes of the rustc builds, all 40 digits are needed; if omitted, the latest master
commit will be installed
```

Installation
Expand Down
86 changes: 71 additions & 15 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
extern crate ansi_term;
#[macro_use]
extern crate failure;
extern crate home;
extern crate pbr;
extern crate reqwest;
#[macro_use]
extern crate structopt;
extern crate tar;
extern crate tee;
Expand All @@ -20,10 +20,12 @@ use std::process::exit;
use std::time::Duration;
use std::process::Command;

use failure::Error;
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};
use reqwest::StatusCode;
use structopt::StructOpt;
use tar::Archive;
use tee::TeeReader;
Expand Down Expand Up @@ -82,6 +84,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 {
Expand All @@ -93,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()
Expand Down Expand Up @@ -171,6 +188,9 @@ fn install_single_toolchain(
),
&path_buf![&component_filename, *component],
Path::new(&*toolchain.dest),
toolchain.commit,
component,
toolchain.host_target,
)?;
}

Expand All @@ -185,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,
)?;
}

Expand All @@ -205,9 +228,10 @@ fn install_single_toolchain(

fn fetch_master_commit(client: &Client, github_token: Option<&str>) -> Result<String, Error> {
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)
Expand Down Expand Up @@ -259,16 +283,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"));
Expand Down Expand Up @@ -306,6 +328,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)
Expand All @@ -314,7 +337,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,
Expand All @@ -326,14 +350,46 @@ fn run() -> Result<(), Error> {
dest,
},
args.force
) {
eprintln!("skipping {} due to failure:\n{:?}", commit, e);
);

if args.keep_going {
if let Err(err) = result {
report_warn(
&err.context(format!("skipping toolchain `{}` due to a failure", commit))
);
failed = true;
}
} else {
result?;
}
}

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 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());
}
}

0 comments on commit a327e07

Please sign in to comment.