-
-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
154 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// Copyright (c) The nextest Contributors | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
|
||
use crate::cargo_config::TargetTriple; | ||
use camino::Utf8PathBuf; | ||
use std::{borrow::Cow, path::PathBuf}; | ||
|
||
/// Create a rustc CLI call. | ||
#[derive(Clone, Debug)] | ||
pub struct RustcCli<'a> { | ||
rustc_path: Utf8PathBuf, | ||
args: Vec<Cow<'a, str>>, | ||
} | ||
|
||
impl<'a> RustcCli<'a> { | ||
/// Create a rustc CLI call: `rustc --print target-libdir`. | ||
pub fn print_host_libdir() -> Self { | ||
let mut cli = Self::default(); | ||
cli.add_arg("--print").add_arg("target-libdir"); | ||
cli | ||
} | ||
|
||
/// Create a rustc CLI call: `rustc --print target-libdir --target <triple>`. | ||
pub fn print_target_libdir(triple: &'a TargetTriple) -> Self { | ||
let mut cli = Self::default(); | ||
cli.add_arg("--print") | ||
.add_arg("target-libdir") | ||
.add_arg("--target") | ||
.add_arg(triple.platform.triple_str()); | ||
cli | ||
} | ||
|
||
fn add_arg(&mut self, arg: impl Into<Cow<'a, str>>) -> &mut Self { | ||
self.args.push(arg.into()); | ||
self | ||
} | ||
|
||
fn to_expression(&self) -> duct::Expression { | ||
duct::cmd( | ||
self.rustc_path.as_str(), | ||
self.args.iter().map(|arg| arg.as_ref()), | ||
) | ||
} | ||
|
||
/// Execute the command, capture its standard output, and return the captured output as a | ||
/// [`Vec<u8>`]. | ||
pub fn read(&self) -> Option<Vec<u8>> { | ||
let expression = self.to_expression(); | ||
log::trace!("Executing command: {:?}", expression); | ||
let output = match expression | ||
.stdout_capture() | ||
.stderr_capture() | ||
.unchecked() | ||
.run() | ||
{ | ||
Ok(output) => output, | ||
Err(e) => { | ||
log::debug!("Failed to spawn the child process: {}", e); | ||
return None; | ||
} | ||
}; | ||
if !output.status.success() { | ||
log::debug!("The execution of the command failed with {}", output.status); | ||
log::debug!("stdout:"); | ||
log::debug!("{}", String::from_utf8_lossy(&output.stdout)); | ||
log::debug!("stderr:"); | ||
log::debug!("{}", String::from_utf8_lossy(&output.stderr)); | ||
return None; | ||
} | ||
Some(output.stdout) | ||
} | ||
} | ||
|
||
impl<'a> Default for RustcCli<'a> { | ||
fn default() -> Self { | ||
Self { | ||
rustc_path: rustc_path(), | ||
args: vec![], | ||
} | ||
} | ||
} | ||
|
||
fn rustc_path() -> Utf8PathBuf { | ||
match std::env::var_os("RUSTC") { | ||
Some(rustc_path) => PathBuf::from(rustc_path) | ||
.try_into() | ||
.expect("RUSTC env var is not valid UTF-8"), | ||
None => Utf8PathBuf::from("rustc"), | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use camino_tempfile::Utf8TempDir; | ||
use std::env; | ||
|
||
#[test] | ||
fn test_should_run_rustc_version() { | ||
let mut cli = RustcCli::default(); | ||
cli.add_arg("--version"); | ||
let output = cli.read().expect("rustc --version should run successfully"); | ||
let output = String::from_utf8(output).expect("the output should be valid utf-8"); | ||
assert!( | ||
output.starts_with("rustc"), | ||
"The output should start with rustc, but the actual output is: {}", | ||
output | ||
); | ||
} | ||
|
||
#[test] | ||
fn test_should_respect_rustc_env() { | ||
env::set_var("RUSTC", "cargo"); | ||
let mut cli = RustcCli::default(); | ||
cli.add_arg("--version"); | ||
let output = cli.read().expect("cargo --version should run successfully"); | ||
let output = String::from_utf8(output).expect("the output should be valid utf-8"); | ||
assert!( | ||
output.starts_with("cargo"), | ||
"The output should start with cargo, but the actual output is: {}", | ||
output | ||
); | ||
} | ||
|
||
#[test] | ||
fn test_fail_to_spawn() { | ||
let fake_dir = Utf8TempDir::new().expect("should create the temp dir successfully"); | ||
// No OS will allow executing a directory. | ||
env::set_var("RUSTC", fake_dir.path()); | ||
let mut cli = RustcCli::default(); | ||
cli.add_arg("--version"); | ||
let output = cli.read(); | ||
assert_eq!(output, None); | ||
} | ||
|
||
#[test] | ||
fn test_execute_with_failure() { | ||
let mut cli = RustcCli::default(); | ||
// rustc --print Y7uDG1HrrY should fail | ||
cli.add_arg("--print"); | ||
cli.add_arg("Y7uDG1HrrY"); | ||
let output = cli.read(); | ||
assert_eq!(output, None); | ||
} | ||
} |