use std::{
env,
error::Error,
fs,
path::{Path, PathBuf},
process::Command,
};
use build_target::Profile;
use path_absolutize::Absolutize;
use walkdir::WalkDir;
const RUNNER_CRATE_NAME: &str = "virtual-desktop-runner";
pub fn main() {
cargo_emit::rerun_if_changed!("{}", source_runner_crate_path().display());
build_runner_inplace()
.or_else(|_| build_runner_in_out_dir())
.or_else(|_| build_runner_in_temp_dir())
.unwrap();
}
fn build_runner_at_target(runner_crate_path: &Path) -> Result<(), Box<dyn Error>> {
let mut command = Command::new("cargo");
command
.arg("build")
.arg("--target")
.arg(build_target::target_triple())
.arg("-Z")
.arg("unstable-options")
.arg("--out-dir")
.arg(out_dir().join(RUNNER_CRATE_NAME).join("out"))
.current_dir(runner_crate_path);
if Profile::current() == Profile::Release {
command.arg("--release");
}
command.spawn()?.wait()?.exit_ok()?;
Ok(())
}
fn copy_runner_crate_to(target_crate_path: &Path) -> Result<(), Box<dyn Error>> {
if target_crate_path.join("Cargo.toml").exists() {
return Ok(());
}
fs::create_dir_all(target_crate_path).unwrap();
let source_runner_crate_path = source_runner_crate_path();
let gitignore_path = source_runner_crate_path.join(".gitignore");
let gitignore_file = gitignore::File::new(&gitignore_path).ok();
let gitignore_filter = move |path: &Path| {
!gitignore_file
.as_ref()
.map(|f| f.is_excluded(path).unwrap())
.unwrap_or(false)
};
for entry in WalkDir::new(&source_runner_crate_path)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| gitignore_filter(e.path()))
{
if entry.path_is_symlink() {
continue;
}
let source_path = entry.path();
let relative_path = source_path.strip_prefix(&source_runner_crate_path)?;
let target_path = target_crate_path.join(relative_path);
if entry.file_type().is_dir() {
fs::create_dir(&target_path).unwrap();
} else {
assert!(entry.file_type().is_file());
fs::copy(source_path, &target_path).unwrap();
}
}
fs::copy(
target_crate_path.join("Cargo.toml.why-no-bin-deps"),
target_crate_path.join("Cargo.toml"),
)
.unwrap();
Ok(())
}
fn build_runner_inplace() -> Result<(), Box<dyn Error>> {
println!("Building {RUNNER_CRATE_NAME} inplace...");
let runner_crate_real_config = source_runner_crate_path().join("Cargo.toml");
if !runner_crate_real_config.exists() {
return Err("Inplace Cargo.toml not present.".into());
}
build_runner_at_target(&source_runner_crate_path())
}
fn build_runner_in_out_dir() -> Result<(), Box<dyn Error>> {
println!("Building {RUNNER_CRATE_NAME} in out dir...");
let target_runner_crate_path = out_dir().join(RUNNER_CRATE_NAME).join("crate");
copy_runner_crate_to(&target_runner_crate_path).unwrap();
build_runner_at_target(&target_runner_crate_path)
}
fn build_runner_in_temp_dir() -> Result<(), Box<dyn Error>> {
println!("Building {RUNNER_CRATE_NAME} in temp dir...");
let target_runner_crate_dir = tempfile::Builder::new()
.prefix(&format!("{RUNNER_CRATE_NAME}-"))
.tempdir()
.unwrap();
let target_runner_crate_path = target_runner_crate_dir.path();
copy_runner_crate_to(target_runner_crate_path).unwrap();
build_runner_at_target(target_runner_crate_path)
}
fn out_dir() -> PathBuf {
PathBuf::from(env::var("OUT_DIR").unwrap())
.absolutize()
.unwrap()
.into_owned()
}
fn current_dir() -> PathBuf {
env::current_dir()
.unwrap()
.absolutize()
.unwrap()
.into_owned()
}
fn source_runner_crate_path() -> PathBuf {
current_dir()
.join(RUNNER_CRATE_NAME)
.absolutize()
.unwrap()
.into_owned()
}