//! Common executables that can be reused by various tests. use crate::{basic_manifest, paths, project, Project}; use lazy_static::lazy_static; use std::path::{Path, PathBuf}; use std::sync::Mutex; lazy_static! { static ref ECHO_WRAPPER: Mutex> = Mutex::new(None); static ref ECHO: Mutex> = Mutex::new(None); } /// Returns the path to an executable that works as a wrapper around rustc. /// /// The wrapper will echo the command line it was called with to stderr. pub fn echo_wrapper() -> PathBuf { let mut lock = ECHO_WRAPPER.lock().unwrap(); if let Some(path) = &*lock { return path.clone(); } let p = project() .at(paths::global_root().join("rustc-echo-wrapper")) .file("Cargo.toml", &basic_manifest("rustc-echo-wrapper", "1.0.0")) .file( "src/main.rs", r#" use std::fs::read_to_string; use std::path::PathBuf; fn main() { // Handle args from `@path` argfile for rustc let args = std::env::args() .flat_map(|p| if let Some(p) = p.strip_prefix("@") { read_to_string(p).unwrap().lines().map(String::from).collect() } else { vec![p] }) .collect::>(); eprintln!("WRAPPER CALLED: {}", args[1..].join(" ")); let status = std::process::Command::new(&args[1]) .args(&args[2..]).status().unwrap(); std::process::exit(status.code().unwrap_or(1)); } "#, ) .build(); p.cargo("build").run(); let path = p.bin("rustc-echo-wrapper"); *lock = Some(path.clone()); path } /// Returns the path to an executable that prints its arguments. /// /// Do not expect this to be anything fancy. pub fn echo() -> PathBuf { let mut lock = ECHO.lock().unwrap(); if let Some(path) = &*lock { return path.clone(); } if let Ok(path) = cargo_util::paths::resolve_executable(Path::new("echo")) { *lock = Some(path.clone()); return path; } // Often on Windows, `echo` is not available. let p = project() .at(paths::global_root().join("basic-echo")) .file("Cargo.toml", &basic_manifest("basic-echo", "1.0.0")) .file( "src/main.rs", r#" fn main() { let mut s = String::new(); let mut it = std::env::args().skip(1).peekable(); while let Some(n) = it.next() { s.push_str(&n); if it.peek().is_some() { s.push(' '); } } println!("{}", s); } "#, ) .build(); p.cargo("build").run(); let path = p.bin("basic-echo"); *lock = Some(path.clone()); path } /// Returns a project which builds a cargo-echo simple subcommand pub fn echo_subcommand() -> Project { let p = project() .at("cargo-echo") .file("Cargo.toml", &basic_manifest("cargo-echo", "0.0.1")) .file( "src/main.rs", r#" fn main() { let args: Vec<_> = ::std::env::args().skip(1).collect(); println!("{}", args.join(" ")); } "#, ) .build(); p.cargo("build").run(); p }