use crate::result::{BatchError, BatchResult};
use crate::result::{EntryError, EntryResult};
use std::{
env::{consts::EXE_EXTENSION, var_os},
path::{Path, PathBuf},
process::{Command, Output},
};
use crate::binary::BinaryBuilder;
use crate::rustflags;
thread_local! {
static TARGET_BIN: PathBuf = {
let mut tmp: PathBuf = [".", "target", "batch"].iter().collect();
std::fs::create_dir_all(&tmp).expect("Unable to create batch executable in target directory; check your access rights");
tmp.push(&format!("{:x}", rand::random::<u64>()));
tmp.with_extension(EXE_EXTENSION)
};
}
include!(concat!(env!("OUT_DIR"), "/info.rs"));
fn raw_cargo() -> Command {
Command::new(option_env!("CARGO").unwrap_or("cargo"))
}
fn rustc() -> Command {
let mut cmd = Command::new(info::rustc());
cmd.current_dir(var_os("CARGO_MANIFEST_DIR").unwrap());
TARGET_BIN.with(|bin| cmd.args(&["-o", bin.to_str().expect("Non-UTF-8 symbols in path")]));
cmd
}
pub fn capture_test_command(test_name: &str) -> BatchResult<String> {
let mut cmd = raw_cargo();
cmd.current_dir(var_os("CARGO_MANIFEST_DIR").unwrap());
rustflags::set_env(&mut cmd);
cmd.arg("test");
if info::opt_level() == "release" {
cmd.arg("--release");
};
cmd.arg(test_name)
.arg("--verbose")
.output()
.map_err(BatchError::Cargo)
.map_err(Into::into)
.map(|out| extract_test_command(test_name, out))
.map(trim_test_command)
}
fn extract_test_command(test_name: &str, out: Output) -> String {
String::from_utf8(out.stderr)
.expect("Cargo produced non-UTF-8 output")
.lines()
.filter(|line| line.contains(&format!("tests/{}.rs", test_name)))
.last()
.expect("No running command in cargo output")
.to_owned()
}
fn trim_test_command(line: String) -> String {
line.trim_start_matches("Running")
.trim()
.trim_matches('`')
.to_owned()
}
pub fn build_entry(builder: &BinaryBuilder, main: &Path, run: bool) -> EntryResult<Output> {
let mut cmd = rustc();
builder.args_to_command(&mut cmd, main);
cmd.arg(if run {
"--emit=link"
} else {
"--emit=metadata"
});
cmd.output().map_err(EntryError::Rustc).map_err(Into::into)
}
pub fn run_entry() -> EntryResult<Output> {
TARGET_BIN
.with(|bin| Command::new(bin))
.output()
.map_err(EntryError::RunFailed)
.map_err(Into::into)
}