Source code

Revision control

Copy as Markdown

Other Tools

use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::net::{TcpListener, TcpStream};
use std::process::Command;
use jobserver::Client;
macro_rules! t {
($e:expr) => {
match $e {
Ok(e) => e,
Err(e) => panic!("{} failed with {}", stringify!($e), e),
}
};
}
fn main() {
if env::var("_DO_THE_TEST").is_ok() {
std::process::exit(
Command::new(env::var_os("MAKE").unwrap())
.env("MAKEFLAGS", env::var_os("CARGO_MAKEFLAGS").unwrap())
.env_remove("_DO_THE_TEST")
.args(&env::args_os().skip(1).collect::<Vec<_>>())
.status()
.unwrap()
.code()
.unwrap_or(1),
);
}
if let Ok(s) = env::var("TEST_ADDR") {
let mut contents = Vec::new();
t!(t!(TcpStream::connect(&s)).read_to_end(&mut contents));
return;
}
let c = t!(Client::new(1));
let td = tempfile::tempdir().unwrap();
let prog = env::var("MAKE").unwrap_or_else(|_| "make".to_string());
let me = t!(env::current_exe());
let me = me.to_str().unwrap();
let mut cmd = Command::new(&me);
cmd.current_dir(td.path());
cmd.env("MAKE", prog);
cmd.env("_DO_THE_TEST", "1");
t!(t!(File::create(td.path().join("Makefile"))).write_all(
format!(
"\
all: foo bar
foo:
\t{0}
bar:
\t{0}
",
me
)
.as_bytes()
));
// We're leaking one extra token to `make` sort of violating the makefile
// jobserver protocol. It has the desired effect though.
c.configure(&mut cmd);
let listener = t!(TcpListener::bind("127.0.0.1:0"));
let addr = t!(listener.local_addr());
cmd.env("TEST_ADDR", addr.to_string());
let mut child = t!(cmd.spawn());
// We should get both connections as the two programs should be run
// concurrently.
let a = t!(listener.accept());
let b = t!(listener.accept());
drop((a, b));
assert!(t!(child.wait()).success());
}