#![cfg_attr(windows, allow(unused))]
use anyhow::Context;
use std::io::Write;
use std::path::Path;
use std::process::Command;
static DOCKER_IMAGE_TAG: &str = "ghcr.io/rust-lang/crates-build-env/linux-micro";
static DOCKER_SOCKET: &str = "/var/run/docker.sock";
static CONTAINER_PREFIX: &str = "/outside";
static TARGET_PREFIX: &str = "/target";
#[test]
#[cfg(unix)]
fn test_hello_world() {
execute("buildtest::test_hello_world").unwrap();
}
#[test]
#[cfg(unix)]
fn test_path_based_patch() {
execute("buildtest::path_based_patch").unwrap();
}
fn execute(test: &str) -> anyhow::Result<()> {
let current_dir = std::fs::canonicalize(".")?;
let target_parent_dir = match option_env!("CARGO_TARGET_DIR") {
Some(t) => Path::new(t).parent().unwrap(),
None => ¤t_dir,
};
let current_exe = std::env::current_exe().unwrap();
let container_prefix = Path::new(CONTAINER_PREFIX);
let target_prefix = Path::new(TARGET_PREFIX);
let container_exe = target_prefix.join(
current_exe
.strip_prefix(target_parent_dir)
.context("could not determine cargo target dir")?,
);
let src_mount = os_string!(¤t_dir, ":", &container_prefix);
let target_mount = os_string!(&target_parent_dir, ":", &target_prefix);
let docker_sock = os_string!(DOCKER_SOCKET, ":", DOCKER_SOCKET);
let nixos_args: &[&str] = if std::fs::exists("/nix")? {
&["-v", "/nix:/nix:ro"]
} else {
&[]
};
Command::new("docker")
.arg("run")
.arg("-v")
.arg(src_mount)
.arg("-v")
.arg(target_mount)
.arg("-v")
.arg(docker_sock)
.args(nixos_args)
.arg("-w")
.arg(container_prefix)
.arg("-e")
.arg("RUST_BACKTRACE=1")
.arg("-e")
.arg("RUSTWIDE_TEST_INSIDE_DOCKER=1")
.map_user_group()?
.arg("--rm")
.arg("-i")
.arg(DOCKER_IMAGE_TAG)
.arg(&container_exe)
.arg(test)
.assert()?;
Ok(())
}
trait CommandExt {
fn map_user_group(&mut self) -> anyhow::Result<&mut Self>;
fn assert(&mut self) -> anyhow::Result<()>;
}
impl CommandExt for Command {
#[cfg(unix)]
fn map_user_group(&mut self) -> anyhow::Result<&mut Self> {
use std::os::unix::fs::MetadataExt;
let gid = std::fs::metadata(DOCKER_SOCKET)?.gid();
let uid = nix::unistd::Uid::effective();
self.arg("--user").arg(format!("{}:{}", uid, gid));
Ok(self)
}
#[cfg(windows)]
fn map_user_group(&mut self) -> anyhow::Result<&mut Self> {
Ok(self)
}
fn assert(&mut self) -> anyhow::Result<()> {
let out = self.output()?;
if !out.status.success() {
eprintln!("failed to execute command {:?}", self);
eprintln!("stdout:");
std::io::stderr().lock().write_all(&out.stdout)?;
eprintln!("stderr:");
std::io::stderr().lock().write_all(&out.stderr)?;
anyhow::bail!("failed to execute command {:?}", self);
}
Ok(())
}
}