Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Expand error handling support #58

Closed
52 changes: 52 additions & 0 deletions src/errors.rs
@@ -0,0 +1,52 @@
// Copyright 2018 The Rust Project Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Custom errors for cargo-bisect-rustc

use std::io;

use failure::Fail;

use super::ToolchainSpec;

#[derive(Fail, Debug)]
pub(crate) enum ArchiveError {
#[fail(display = "Failed to parse archive: {}", _0)]
Archive(#[cause] io::Error),
#[fail(display = "Failed to create directory: {}", _0)]
CreateDir(#[cause] io::Error),
}

#[derive(Fail, Debug)]
pub(crate) enum DownloadError {
#[fail(display = "Tarball not found at {}", _0)]
NotFound(String),
#[fail(display = "A reqwest error occurred: {}", _0)]
Reqwest(#[cause] reqwest::Error),
#[fail(display = "An archive error occurred: {}", _0)]
Archive(#[cause] ArchiveError),
}

#[derive(Debug, Fail)]
#[fail(display = "exiting with {}", _0)]
pub(crate) struct ExitStatusError(pub(crate) i32);

#[derive(Fail, Debug)]
pub(crate) enum InstallError {
#[fail(display = "Could not find {}; url: {}", spec, url)]
NotFound { url: String, spec: ToolchainSpec },
#[fail(display = "Could not download toolchain: {}", _0)]
Download(#[cause] DownloadError),
#[fail(display = "Could not create tempdir: {}", _0)]
TempDir(#[cause] io::Error),
#[fail(display = "Could not move tempdir into destination: {}", _0)]
Move(#[cause] io::Error),
}

#[derive(Fail, Debug)]
#[fail(display = "will never happen")]
pub(crate) struct NeverError {}
39 changes: 25 additions & 14 deletions src/least_satisfying.rs
Expand Up @@ -8,7 +8,9 @@
use std::collections::BTreeMap;
use std::fmt;

pub fn least_satisfying<T, P>(slice: &[T], mut predicate: P) -> usize
use failure::Error;

pub fn least_satisfying<T, P>(slice: &[T], mut predicate: P) -> Result<usize, Error>
where
T: fmt::Display + fmt::Debug,
P: FnMut(&T) -> Satisfies,
Expand All @@ -23,28 +25,28 @@ where
Satisfies::No => {
eprintln!("confirmed the start of the range does not reproduce the regression")
}
_ => panic!("the start of the range to test must not reproduce the regression"),
_ => bail!("the start of the range to test must not reproduce the regression"),
}

let mut lm_yes = slice.len() - 1; // presume that the slice ends with a yes

eprintln!("verifying the end of the range reproduces the regression");
match predicate(lm_yes) {
Satisfies::Yes => eprintln!("confirmed the end of the range reproduces the regression"),
_ => panic!("the end of the range to test must reproduce the regression"),
_ => bail!("the end of the range to test must reproduce the regression"),
}

let mut next = (rm_no + lm_yes) / 2;

loop {
// simple case with no unknown ranges
if rm_no + 1 == lm_yes {
return lm_yes;
return Ok(lm_yes);
}
for (left, right) in unknown_ranges.iter().cloned() {
// if we're straddling an unknown range, then pretend it doesn't exist
if rm_no + 1 == left && right + 1 == lm_yes {
return lm_yes;
return Ok(lm_yes);
}
// check if we're checking inside an unknown range and set the next check outside of it
if left <= next && next <= right {
Expand Down Expand Up @@ -103,59 +105,68 @@ mod tests {
}
}

let res = least_satisfying(&satisfies_v, |i| *i);
let res = least_satisfying(&satisfies_v, |i| *i).unwrap();
let exp = first_yes.unwrap();
TestResult::from_bool(res == exp)
}

#[test]
fn least_satisfying_1() {
assert_eq!(
least_satisfying(&[No, Unknown, Unknown, No, Yes], |i| *i),
least_satisfying(&[No, Unknown, Unknown, No, Yes], |i| *i).unwrap(),
4
);
}

#[test]
fn least_satisfying_2() {
assert_eq!(
least_satisfying(&[No, Unknown, Yes, Unknown, Yes], |i| *i),
least_satisfying(&[No, Unknown, Yes, Unknown, Yes], |i| *i).unwrap(),
2
);
}

#[test]
fn least_satisfying_3() {
assert_eq!(least_satisfying(&[No, No, No, No, Yes], |i| *i), 4);
assert_eq!(least_satisfying(&[No, No, No, No, Yes], |i| *i).unwrap(), 4);
}

#[test]
fn least_satisfying_4() {
assert_eq!(least_satisfying(&[No, No, Yes, Yes, Yes], |i| *i), 2);
assert_eq!(
least_satisfying(&[No, No, Yes, Yes, Yes], |i| *i).unwrap(),
2
);
}

#[test]
fn least_satisfying_5() {
assert_eq!(least_satisfying(&[No, Yes, Yes, Yes, Yes], |i| *i), 1);
assert_eq!(
least_satisfying(&[No, Yes, Yes, Yes, Yes], |i| *i).unwrap(),
1
);
}

#[test]
fn least_satisfying_6() {
assert_eq!(
least_satisfying(&[No, Yes, Yes, Unknown, Unknown, Yes, Unknown, Yes], |i| *i),
least_satisfying(&[No, Yes, Yes, Unknown, Unknown, Yes, Unknown, Yes], |i| *i).unwrap(),
1
);
}

#[test]
fn least_satisfying_7() {
assert_eq!(least_satisfying(&[No, Yes, Unknown, Yes], |i| *i), 1);
assert_eq!(
least_satisfying(&[No, Yes, Unknown, Yes], |i| *i).unwrap(),
1
);
}

#[test]
fn least_satisfying_8() {
assert_eq!(
least_satisfying(&[No, Unknown, No, No, Unknown, Yes, Yes], |i| *i),
least_satisfying(&[No, Unknown, No, No, Unknown, Yes, Yes], |i| *i).unwrap(),
5
);
}
Expand Down