extern crate fs_extra; use std::env; use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; use fs_extra::dir::{copy, remove, CopyOptions}; macro_rules! wrap_command { ($cmd:expr, $args:expr, $cwd:expr) => {{ match Command::new($cmd).current_dir($cwd).args($args).output() { Ok(output) => { if !output.status.success() { Err(String::from_utf8_lossy(&output.stderr).into_owned()) } else { Ok(()) } } Err(e) => Err(format!("{:?}", e)), } }}; } fn autogen(path: &Path) -> Result<(), String> { wrap_command!("sh", &["autogen.sh"], path) } #[cfg(feature = "use-gnu-patch")] fn apply_patch(patch: &Path, target: &Path) -> Result<(), String> { wrap_command!( "patch", &["-p0", "-i", &patch.display().to_string()], target ) } #[cfg(feature = "use-git-apply")] fn apply_patch(patch: &Path, target: &Path) -> Result<(), String> { wrap_command!( "git", &["apply", "-p1", &patch.display().to_string()], target ) } fn copy_src(name: &str) -> PathBuf { let original_src = Path::new(env!("CARGO_MANIFEST_DIR")).join(name); let root = PathBuf::from(env::var("OUT_DIR").expect("missing OUT_DIR")).join(name); fs::create_dir_all(&root).expect("Cannot write to `OUT_DIR`"); let path = Path::new(root.to_str().unwrap()).join(name); if path.exists() { remove(&path).expect("Unable to remove src folder"); } copy(original_src, &root, &CopyOptions::new()).expect("Unable to copy src folder"); path.into() } fn get_patches(prefix: &str) -> Vec { let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("patches"); fs::read_dir(&root) .expect("Unable to list patches") .collect::, _>>() .expect("Error listing patches") .into_iter() .filter(|entry| { entry .file_name() .into_string() .expect("Invalid patch name") .starts_with(prefix) }) .map(|entry| entry.path().into()) .collect() } fn main() -> Result<(), Box> { let libevent = copy_src("libevent-src"); let tor = copy_src("tor-src"); for patch in get_patches("libevent") { apply_patch(&patch, &libevent) .map_err(|e| format!("Error applying patch '{}': {:?}", patch.display(), e))?; } for patch in get_patches("tor") { apply_patch(&patch, &tor) .map_err(|e| format!("Error applying patch '{}': {:?}", patch.display(), e))?; } autogen(&libevent)?; autogen(&tor)?; println!("cargo:rustc-env=LIBEVENT_SRC={}", libevent.display()); println!("cargo:rustc-env=TOR_SRC={}", tor.display()); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=tor-src"); println!("cargo:rerun-if-changed=libevent-src"); Ok(()) }