use crate::cargo_rustc;
use crate::result::BatchResult;
use lazy_static::lazy_static;
use rand::random;
use std::{
env::var_os,
ffi::OsString,
fs::{create_dir, remove_dir, remove_file, write},
ops::Not,
path::{Path, PathBuf},
process::Command,
};
lazy_static! {
static ref TESTS_DIR: PathBuf = [
var_os("CARGO_MANIFEST_DIR").unwrap(),
OsString::from("tests")
]
.iter()
.collect();
pub static ref BUILDER: BinaryBuilder = BinaryBuilder::new().unwrap();
}
fn new() -> BatchResult<(String, bool)> {
let test_dir_needed = TESTS_DIR.exists().not();
let test_dir_created = test_dir_needed && create_dir(&*TESTS_DIR).map(|_| true)?;
let mut name = "batch_runner_check_".to_owned();
loop {
if TESTS_DIR.join(&name).with_extension("rs").exists() {
name.push_str(&format!("{:x}", random::<u8>()));
} else {
break;
}
}
write(TESTS_DIR.join(&name).with_extension("rs"), b"#[test] fn main() {}")?;
Ok((name, test_dir_created))
}
fn into_builder(name: &str) -> BatchResult<BinaryBuilder> {
let cmd = cargo_rustc::capture_test_command(name)?;
let args = cmd
.split_ascii_whitespace()
.scan("", |prev, cur| {
let out = if prev == &"-L" {
vec!["-L", cur]
} else if prev == &"--cfg" {
vec!["--cfg", cur]
} else if prev == &"--extern" {
vec!["--extern", cur]
} else if cur.starts_with("--edition") {
vec![cur]
} else {
vec![]
};
*prev = cur;
Some(out)
})
.flatten()
.map(String::from)
.collect();
Ok(BinaryBuilder { args })
}
fn drop(name: &str, bin_created: bool) {
remove_file(TESTS_DIR.join(name).with_extension("rs")).unwrap_or_else(|_| {
eprintln!(
"Unable to remove temporary file {}, please check it and remove manually",
name
)
});
if bin_created {
remove_dir(&*TESTS_DIR).unwrap_or_else(|_| {
eprintln!(
"Unable to remove directory {}, please check it and remove manually",
TESTS_DIR
.to_str()
.unwrap_or("[ERROR BUILDING TESTS_DIR PATH, PLEASE REPORT THIS ERROR!]")
)
});
}
}
pub struct BinaryBuilder {
args: Vec<String>,
}
impl BinaryBuilder {
pub fn new() -> BatchResult<Self> {
let (name, bin_created) = new()?;
let builder = into_builder(&name);
drop(&name, bin_created);
builder
}
pub fn args_to_command(&self, cmd: &mut Command, main: &Path) {
cmd.args(&self.args).arg(main);
}
}