Skip to content

Commit

Permalink
Add RustcCli
Browse files Browse the repository at this point in the history
  • Loading branch information
06393993 committed May 18, 2024
1 parent ead0452 commit 41ac5ac
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions cargo-nextest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ swrite.workspace = true
thiserror = "1.0.60"
nextest-workspace-hack.workspace = true

[dev-dependencies]
camino-tempfile = "1.1.1"

[features]
default = ["default-no-update", "self-update"]
experimental-tokio-console = ["nextest-runner/experimental-tokio-console"]
Expand Down
2 changes: 1 addition & 1 deletion nextest-runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ cfg-if = "1.0.0"
chrono = "0.4.38"
debug-ignore.workspace = true
display-error-chain = "0.2.0"
duct = "0.13.7"
either = "1.11.0"
futures = "0.3.30"
guppy = "0.17.5"
Expand Down Expand Up @@ -130,7 +131,6 @@ self_update = { version = "0.39.0", optional = true }

[dev-dependencies]
color-eyre = { version = "0.6.3", default-features = false }
duct = "0.13.7"
indoc = "2.0.5"
insta = { version = "1.39.0", default-features = false }
maplit = "1.0.2"
Expand Down
4 changes: 4 additions & 0 deletions nextest-runner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub mod redact;
pub mod reporter;
pub mod reuse_build;
pub mod runner;
mod rustc_cli;
pub mod show_config;
pub mod signal;
pub mod target_runner;
Expand All @@ -34,3 +35,6 @@ mod time;
#[cfg(feature = "self-update")]
pub mod update;
pub mod write_str;

#[doc(hidden)]
pub use rustc_cli::RustcCli;
145 changes: 145 additions & 0 deletions nextest-runner/src/rustc_cli.rs
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);
}
}

0 comments on commit 41ac5ac

Please sign in to comment.