From 888100352a35f74dcca728a4ae0403f79f695e94 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 20 Mar 2021 11:28:38 -0700 Subject: [PATCH] Move ProcessBuilder to cargo-util. --- .github/workflows/main.yml | 1 + Cargo.toml | 2 - crates/cargo-test-support/Cargo.toml | 1 + .../cargo-test-support/src/cross_compile.rs | 2 +- crates/cargo-test-support/src/lib.rs | 11 +- crates/cargo-util/Cargo.toml | 8 + crates/cargo-util/LICENSE-APACHE | 1 + crates/cargo-util/LICENSE-MIT | 1 + crates/cargo-util/src/lib.rs | 8 + .../cargo-util/src}/process_builder.rs | 87 ++++---- crates/cargo-util/src/process_error.rs | 194 ++++++++++++++++++ .../util => crates/cargo-util/src}/read2.rs | 0 publish.py | 1 + src/bin/cargo/commands/run.rs | 2 +- src/bin/cargo/commands/test.rs | 3 +- src/bin/cargo/main.rs | 10 +- src/cargo/core/compiler/build_config.rs | 2 +- .../compiler/build_context/target_info.rs | 3 +- src/cargo/core/compiler/build_plan.rs | 3 +- src/cargo/core/compiler/compilation.rs | 17 +- src/cargo/core/compiler/fingerprint.rs | 3 +- src/cargo/core/compiler/job_queue.rs | 3 +- src/cargo/core/compiler/mod.rs | 7 +- src/cargo/core/compiler/rustdoc.rs | 2 +- src/cargo/core/features.rs | 3 +- src/cargo/ops/cargo_test.rs | 6 +- src/cargo/ops/fix.rs | 7 +- src/cargo/ops/registry/auth.rs | 5 +- src/cargo/sources/git/utils.rs | 4 +- src/cargo/util/diagnostic_server.rs | 3 +- src/cargo/util/errors.rs | 186 +---------------- src/cargo/util/mod.rs | 9 +- src/cargo/util/rustc.rs | 15 +- src/cargo/util/vcs.rs | 25 ++- src/cargo/util/workspace.rs | 2 +- tests/testsuite/old_cargos.rs | 4 +- 36 files changed, 347 insertions(+), 294 deletions(-) create mode 120000 crates/cargo-util/LICENSE-APACHE create mode 120000 crates/cargo-util/LICENSE-MIT rename {src/cargo/util => crates/cargo-util/src}/process_builder.rs (85%) create mode 100644 crates/cargo-util/src/process_error.rs rename {src/cargo/util => crates/cargo-util/src}/read2.rs (100%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 52b4584a9..f4bd7f616 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -66,6 +66,7 @@ jobs: - run: cargo test --features 'deny-warnings' - run: cargo test --features 'deny-warnings' -p cargo-test-support - run: cargo test -p cargo-platform + - run: cargo test -p cargo-util - run: cargo test --manifest-path crates/mdman/Cargo.toml - run: cargo build --manifest-path crates/credential/cargo-credential-1password/Cargo.toml - run: cargo build --manifest-path crates/credential/cargo-credential-gnome-secret/Cargo.toml diff --git a/Cargo.toml b/Cargo.toml index febafd3b8..80e43e264 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,6 @@ semver = { version = "0.10", features = ["serde"] } serde = { version = "1.0.123", features = ["derive"] } serde_ignored = "0.1.0" serde_json = { version = "1.0.30", features = ["raw_value"] } -shell-escape = "0.1.4" strip-ansi-escapes = "0.1.0" tar = { version = "0.4.26", default-features = false } tempfile = "3.0" @@ -80,7 +79,6 @@ rand = "0.8.3" core-foundation = { version = "0.9.0", features = ["mac_os_10_7_support"] } [target.'cfg(windows)'.dependencies] -miow = "0.3.6" fwdansi = "1.1.0" [target.'cfg(windows)'.dependencies.winapi] diff --git a/crates/cargo-test-support/Cargo.toml b/crates/cargo-test-support/Cargo.toml index 62ff3accf..5249b713a 100644 --- a/crates/cargo-test-support/Cargo.toml +++ b/crates/cargo-test-support/Cargo.toml @@ -11,6 +11,7 @@ doctest = false [dependencies] cargo = { path = "../.." } cargo-test-macro = { path = "../cargo-test-macro" } +cargo-util = { path = "../cargo-util" } filetime = "0.2" flate2 = { version = "1.0", default-features = false, features = ["zlib"] } git2 = "0.13.16" diff --git a/crates/cargo-test-support/src/cross_compile.rs b/crates/cargo-test-support/src/cross_compile.rs index ff272d482..3b851f221 100644 --- a/crates/cargo-test-support/src/cross_compile.rs +++ b/crates/cargo-test-support/src/cross_compile.rs @@ -10,8 +10,8 @@ //! These tests are all disabled on rust-lang/rust's CI, but run in Cargo's CI. use crate::{basic_manifest, main_file, project}; -use cargo::util::ProcessError; use cargo::CargoResult; +use cargo_util::ProcessError; use std::env; use std::fmt::Write; use std::process::{Command, Output}; diff --git a/crates/cargo-test-support/src/lib.rs b/crates/cargo-test-support/src/lib.rs index a8ea76b9c..7052c4e5a 100644 --- a/crates/cargo-test-support/src/lib.rs +++ b/crates/cargo-test-support/src/lib.rs @@ -15,7 +15,8 @@ use std::process::{Command, Output}; use std::str; use std::time::{self, Duration}; -use cargo::util::{is_ci, CargoResult, ProcessBuilder, ProcessError, Rustc}; +use cargo::util::{is_ci, CargoResult, Rustc}; +use cargo_util::{ProcessBuilder, ProcessError}; use serde_json::{self, Value}; use url::Url; @@ -1569,12 +1570,12 @@ pub fn is_nightly() -> bool { .with(|r| r.verbose_version.contains("-nightly") || r.verbose_version.contains("-dev")) } -pub fn process>(t: T) -> cargo::util::ProcessBuilder { +pub fn process>(t: T) -> ProcessBuilder { _process(t.as_ref()) } -fn _process(t: &OsStr) -> cargo::util::ProcessBuilder { - let mut p = cargo::util::process(t); +fn _process(t: &OsStr) -> ProcessBuilder { + let mut p = ProcessBuilder::new(t); // In general just clear out all cargo-specific configuration already in the // environment. Our tests all assume a "default configuration" unless @@ -1643,7 +1644,7 @@ pub trait ChannelChanger: Sized { fn masquerade_as_nightly_cargo(&mut self) -> &mut Self; } -impl ChannelChanger for cargo::util::ProcessBuilder { +impl ChannelChanger for ProcessBuilder { fn masquerade_as_nightly_cargo(&mut self) -> &mut Self { self.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly") } diff --git a/crates/cargo-util/Cargo.toml b/crates/cargo-util/Cargo.toml index 9c6d9e9bd..e98599e8c 100644 --- a/crates/cargo-util/Cargo.toml +++ b/crates/cargo-util/Cargo.toml @@ -9,3 +9,11 @@ repository = "https://github.com/rust-lang/cargo" description = "Miscellaneous support code used by Cargo." [dependencies] +anyhow = "1.0" +jobserver = "0.1.21" +libc = "0.2" +shell-escape = "0.1.4" + +[target.'cfg(windows)'.dependencies] +miow = "0.3.6" +winapi = { version = "0.3", features = ["consoleapi", "minwindef"] } diff --git a/crates/cargo-util/LICENSE-APACHE b/crates/cargo-util/LICENSE-APACHE new file mode 120000 index 000000000..1cd601d0a --- /dev/null +++ b/crates/cargo-util/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/cargo-util/LICENSE-MIT b/crates/cargo-util/LICENSE-MIT new file mode 120000 index 000000000..b2cfbdc7b --- /dev/null +++ b/crates/cargo-util/LICENSE-MIT @@ -0,0 +1 @@ +../../LICENSE-MIT \ No newline at end of file diff --git a/crates/cargo-util/src/lib.rs b/crates/cargo-util/src/lib.rs index a02f106e3..eb8e46166 100644 --- a/crates/cargo-util/src/lib.rs +++ b/crates/cargo-util/src/lib.rs @@ -1 +1,9 @@ //! Miscellaneous support code used by Cargo. + +pub use self::read2::read2; +pub use process_builder::ProcessBuilder; +pub use process_error::{exit_status_to_string, is_simple_exit_code, ProcessError}; + +mod process_builder; +mod process_error; +mod read2; diff --git a/src/cargo/util/process_builder.rs b/crates/cargo-util/src/process_builder.rs similarity index 85% rename from src/cargo/util/process_builder.rs rename to crates/cargo-util/src/process_builder.rs index 7f5bf6fa3..bc02e677d 100644 --- a/src/cargo/util/process_builder.rs +++ b/crates/cargo-util/src/process_builder.rs @@ -1,5 +1,6 @@ -use crate::util::{process_error, read2, CargoResult, CargoResultExt}; -use anyhow::bail; +use crate::process_error::ProcessError; +use crate::read2; +use anyhow::{bail, Context, Result}; use jobserver::Client; use shell_escape::escape; use std::collections::BTreeMap; @@ -10,7 +11,7 @@ use std::iter::once; use std::path::Path; use std::process::{Command, Output, Stdio}; -/// A builder object for an external process, similar to `std::process::Command`. +/// A builder object for an external process, similar to [`std::process::Command`]. #[derive(Clone, Debug)] pub struct ProcessBuilder { /// The program to execute. @@ -21,10 +22,10 @@ pub struct ProcessBuilder { env: BTreeMap>, /// The directory to run the program from. cwd: Option, - /// The `make` jobserver. See the [jobserver crate][jobserver_docs] for + /// The `make` jobserver. See the [jobserver crate] for /// more information. /// - /// [jobserver_docs]: https://docs.rs/jobserver/0.1.6/jobserver/ + /// [jobserver crate]: https://docs.rs/jobserver/ jobserver: Option, /// `true` to include environment variable in display. display_env_vars: bool, @@ -58,6 +59,18 @@ impl fmt::Display for ProcessBuilder { } impl ProcessBuilder { + /// Creates a new [`ProcessBuilder`] with the given executable path. + pub fn new>(cmd: T) -> ProcessBuilder { + ProcessBuilder { + program: cmd.as_ref().to_os_string(), + args: Vec::new(), + cwd: None, + env: BTreeMap::new(), + jobserver: None, + display_env_vars: false, + } + } + /// (chainable) Sets the executable for the process. pub fn program>(&mut self, program: T) -> &mut ProcessBuilder { self.program = program.as_ref().to_os_string(); @@ -149,16 +162,16 @@ impl ProcessBuilder { } /// Runs the process, waiting for completion, and mapping non-success exit codes to an error. - pub fn exec(&self) -> CargoResult<()> { + pub fn exec(&self) -> Result<()> { let mut command = self.build_command(); - let exit = command.status().chain_err(|| { - process_error(&format!("could not execute process {}", self), None, None) + let exit = command.status().with_context(|| { + ProcessError::new(&format!("could not execute process {}", self), None, None) })?; if exit.success() { Ok(()) } else { - Err(process_error( + Err(ProcessError::new( &format!("process didn't exit successfully: {}", self), Some(exit), None, @@ -182,22 +195,22 @@ impl ProcessBuilder { /// include our child process. If the child terminates then we'll reap them in Cargo /// pretty quickly, and if the child handles the signal then we won't terminate /// (and we shouldn't!) until the process itself later exits. - pub fn exec_replace(&self) -> CargoResult<()> { + pub fn exec_replace(&self) -> Result<()> { imp::exec_replace(self) } /// Executes the process, returning the stdio output, or an error if non-zero exit status. - pub fn exec_with_output(&self) -> CargoResult { + pub fn exec_with_output(&self) -> Result { let mut command = self.build_command(); - let output = command.output().chain_err(|| { - process_error(&format!("could not execute process {}", self), None, None) + let output = command.output().with_context(|| { + ProcessError::new(&format!("could not execute process {}", self), None, None) })?; if output.status.success() { Ok(output) } else { - Err(process_error( + Err(ProcessError::new( &format!("process didn't exit successfully: {}", self), Some(output.status), Some(&output), @@ -217,10 +230,10 @@ impl ProcessBuilder { /// output. pub fn exec_with_streaming( &self, - on_stdout_line: &mut dyn FnMut(&str) -> CargoResult<()>, - on_stderr_line: &mut dyn FnMut(&str) -> CargoResult<()>, + on_stdout_line: &mut dyn FnMut(&str) -> Result<()>, + on_stderr_line: &mut dyn FnMut(&str) -> Result<()>, capture_output: bool, - ) -> CargoResult { + ) -> Result { let mut stdout = Vec::new(); let mut stderr = Vec::new(); @@ -274,7 +287,9 @@ impl ProcessBuilder { })?; child.wait() })() - .chain_err(|| process_error(&format!("could not execute process {}", self), None, None))?; + .with_context(|| { + ProcessError::new(&format!("could not execute process {}", self), None, None) + })?; let output = Output { status, stdout, @@ -284,14 +299,14 @@ impl ProcessBuilder { { let to_print = if capture_output { Some(&output) } else { None }; if let Some(e) = callback_error { - let cx = process_error( + let cx = ProcessError::new( &format!("failed to parse process output: {}", self), Some(output.status), to_print, ); bail!(anyhow::Error::new(cx).context(e)); } else if !output.status.success() { - bail!(process_error( + bail!(ProcessError::new( &format!("process didn't exit successfully: {}", self), Some(output.status), to_print, @@ -333,9 +348,9 @@ impl ProcessBuilder { /// # Examples /// /// ```rust - /// use cargo::util::{ProcessBuilder, process}; + /// use cargo_util::ProcessBuilder; /// // Running this would execute `rustc` - /// let cmd: ProcessBuilder = process("rustc"); + /// let cmd = ProcessBuilder::new("rustc"); /// /// // Running this will execute `sccache rustc` /// let cmd = cmd.wrapped(Some("sccache")); @@ -360,28 +375,16 @@ impl ProcessBuilder { } } -/// A helper function to create a `ProcessBuilder`. -pub fn process>(cmd: T) -> ProcessBuilder { - ProcessBuilder { - program: cmd.as_ref().to_os_string(), - args: Vec::new(), - cwd: None, - env: BTreeMap::new(), - jobserver: None, - display_env_vars: false, - } -} - #[cfg(unix)] mod imp { - use crate::util::{process_error, ProcessBuilder}; - use crate::CargoResult; + use super::{ProcessBuilder, ProcessError}; + use anyhow::Result; use std::os::unix::process::CommandExt; - pub fn exec_replace(process_builder: &ProcessBuilder) -> CargoResult<()> { + pub fn exec_replace(process_builder: &ProcessBuilder) -> Result<()> { let mut command = process_builder.build_command(); let error = command.exec(); - Err(anyhow::Error::from(error).context(process_error( + Err(anyhow::Error::from(error).context(ProcessError::new( &format!("could not execute process {}", process_builder), None, None, @@ -391,8 +394,8 @@ mod imp { #[cfg(windows)] mod imp { - use crate::util::{process_error, ProcessBuilder}; - use crate::CargoResult; + use super::{ProcessBuilder, ProcessError}; + use anyhow::Result; use winapi::shared::minwindef::{BOOL, DWORD, FALSE, TRUE}; use winapi::um::consoleapi::SetConsoleCtrlHandler; @@ -401,10 +404,10 @@ mod imp { TRUE } - pub fn exec_replace(process_builder: &ProcessBuilder) -> CargoResult<()> { + pub fn exec_replace(process_builder: &ProcessBuilder) -> Result<()> { unsafe { if SetConsoleCtrlHandler(Some(ctrlc_handler), TRUE) == FALSE { - return Err(process_error("Could not set Ctrl-C handler.", None, None).into()); + return Err(ProcessError::new("Could not set Ctrl-C handler.", None, None).into()); } } diff --git a/crates/cargo-util/src/process_error.rs b/crates/cargo-util/src/process_error.rs new file mode 100644 index 000000000..57feffbef --- /dev/null +++ b/crates/cargo-util/src/process_error.rs @@ -0,0 +1,194 @@ +//! Error value for [`crate::ProcessBuilder`] when a process fails. + +use std::fmt; +use std::process::{ExitStatus, Output}; +use std::str; + +#[derive(Debug)] +pub struct ProcessError { + /// A detailed description to show to the user why the process failed. + pub desc: String, + + /// The exit status of the process. + /// + /// This can be `None` if the process failed to launch (like process not + /// found) or if the exit status wasn't a code but was instead something + /// like termination via a signal. + pub code: Option, + + /// The stdout from the process. + /// + /// This can be `None` if the process failed to launch, or the output was + /// not captured. + pub stdout: Option>, + + /// The stderr from the process. + /// + /// This can be `None` if the process failed to launch, or the output was + /// not captured. + pub stderr: Option>, +} + +impl fmt::Display for ProcessError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.desc.fmt(f) + } +} + +impl std::error::Error for ProcessError {} + +impl ProcessError { + /// Creates a new [`ProcessError`]. + /// + /// * `status` can be `None` if the process did not launch. + /// * `output` can be `None` if the process did not launch, or output was not captured. + pub fn new(msg: &str, status: Option, output: Option<&Output>) -> ProcessError { + let exit = match status { + Some(s) => exit_status_to_string(s), + None => "never executed".to_string(), + }; + + Self::new_raw( + msg, + status.and_then(|s| s.code()), + &exit, + output.map(|s| s.stdout.as_slice()), + output.map(|s| s.stderr.as_slice()), + ) + } + + /// Creates a new [`ProcessError`] with the raw output data. + /// + /// * `code` can be `None` for situations like being killed by a signal on unix. + pub fn new_raw( + msg: &str, + code: Option, + status: &str, + stdout: Option<&[u8]>, + stderr: Option<&[u8]>, + ) -> ProcessError { + let mut desc = format!("{} ({})", msg, status); + + if let Some(out) = stdout { + match str::from_utf8(out) { + Ok(s) if !s.trim().is_empty() => { + desc.push_str("\n--- stdout\n"); + desc.push_str(s); + } + Ok(..) | Err(..) => {} + } + } + if let Some(out) = stderr { + match str::from_utf8(out) { + Ok(s) if !s.trim().is_empty() => { + desc.push_str("\n--- stderr\n"); + desc.push_str(s); + } + Ok(..) | Err(..) => {} + } + } + + ProcessError { + desc, + code, + stdout: stdout.map(|s| s.to_vec()), + stderr: stderr.map(|s| s.to_vec()), + } + } +} + +/// Converts an [`ExitStatus`] to a human-readable string suitable for +/// displaying to a user. +pub fn exit_status_to_string(status: ExitStatus) -> String { + return status_to_string(status); + + #[cfg(unix)] + fn status_to_string(status: ExitStatus) -> String { + use std::os::unix::process::*; + + if let Some(signal) = status.signal() { + let name = match signal as libc::c_int { + libc::SIGABRT => ", SIGABRT: process abort signal", + libc::SIGALRM => ", SIGALRM: alarm clock", + libc::SIGFPE => ", SIGFPE: erroneous arithmetic operation", + libc::SIGHUP => ", SIGHUP: hangup", + libc::SIGILL => ", SIGILL: illegal instruction", + libc::SIGINT => ", SIGINT: terminal interrupt signal", + libc::SIGKILL => ", SIGKILL: kill", + libc::SIGPIPE => ", SIGPIPE: write on a pipe with no one to read", + libc::SIGQUIT => ", SIGQUIT: terminal quit signal", + libc::SIGSEGV => ", SIGSEGV: invalid memory reference", + libc::SIGTERM => ", SIGTERM: termination signal", + libc::SIGBUS => ", SIGBUS: access to undefined memory", + #[cfg(not(target_os = "haiku"))] + libc::SIGSYS => ", SIGSYS: bad system call", + libc::SIGTRAP => ", SIGTRAP: trace/breakpoint trap", + _ => "", + }; + format!("signal: {}{}", signal, name) + } else { + status.to_string() + } + } + + #[cfg(windows)] + fn status_to_string(status: ExitStatus) -> String { + use winapi::shared::minwindef::DWORD; + use winapi::um::winnt::*; + + let mut base = status.to_string(); + let extra = match status.code().unwrap() as DWORD { + STATUS_ACCESS_VIOLATION => "STATUS_ACCESS_VIOLATION", + STATUS_IN_PAGE_ERROR => "STATUS_IN_PAGE_ERROR", + STATUS_INVALID_HANDLE => "STATUS_INVALID_HANDLE", + STATUS_INVALID_PARAMETER => "STATUS_INVALID_PARAMETER", + STATUS_NO_MEMORY => "STATUS_NO_MEMORY", + STATUS_ILLEGAL_INSTRUCTION => "STATUS_ILLEGAL_INSTRUCTION", + STATUS_NONCONTINUABLE_EXCEPTION => "STATUS_NONCONTINUABLE_EXCEPTION", + STATUS_INVALID_DISPOSITION => "STATUS_INVALID_DISPOSITION", + STATUS_ARRAY_BOUNDS_EXCEEDED => "STATUS_ARRAY_BOUNDS_EXCEEDED", + STATUS_FLOAT_DENORMAL_OPERAND => "STATUS_FLOAT_DENORMAL_OPERAND", + STATUS_FLOAT_DIVIDE_BY_ZERO => "STATUS_FLOAT_DIVIDE_BY_ZERO", + STATUS_FLOAT_INEXACT_RESULT => "STATUS_FLOAT_INEXACT_RESULT", + STATUS_FLOAT_INVALID_OPERATION => "STATUS_FLOAT_INVALID_OPERATION", + STATUS_FLOAT_OVERFLOW => "STATUS_FLOAT_OVERFLOW", + STATUS_FLOAT_STACK_CHECK => "STATUS_FLOAT_STACK_CHECK", + STATUS_FLOAT_UNDERFLOW => "STATUS_FLOAT_UNDERFLOW", + STATUS_INTEGER_DIVIDE_BY_ZERO => "STATUS_INTEGER_DIVIDE_BY_ZERO", + STATUS_INTEGER_OVERFLOW => "STATUS_INTEGER_OVERFLOW", + STATUS_PRIVILEGED_INSTRUCTION => "STATUS_PRIVILEGED_INSTRUCTION", + STATUS_STACK_OVERFLOW => "STATUS_STACK_OVERFLOW", + STATUS_DLL_NOT_FOUND => "STATUS_DLL_NOT_FOUND", + STATUS_ORDINAL_NOT_FOUND => "STATUS_ORDINAL_NOT_FOUND", + STATUS_ENTRYPOINT_NOT_FOUND => "STATUS_ENTRYPOINT_NOT_FOUND", + STATUS_CONTROL_C_EXIT => "STATUS_CONTROL_C_EXIT", + STATUS_DLL_INIT_FAILED => "STATUS_DLL_INIT_FAILED", + STATUS_FLOAT_MULTIPLE_FAULTS => "STATUS_FLOAT_MULTIPLE_FAULTS", + STATUS_FLOAT_MULTIPLE_TRAPS => "STATUS_FLOAT_MULTIPLE_TRAPS", + STATUS_REG_NAT_CONSUMPTION => "STATUS_REG_NAT_CONSUMPTION", + STATUS_HEAP_CORRUPTION => "STATUS_HEAP_CORRUPTION", + STATUS_STACK_BUFFER_OVERRUN => "STATUS_STACK_BUFFER_OVERRUN", + STATUS_ASSERTION_FAILURE => "STATUS_ASSERTION_FAILURE", + _ => return base, + }; + base.push_str(", "); + base.push_str(extra); + base + } +} + +/// Returns `true` if the given process exit code is something a normal +/// process would exit with. +/// +/// This helps differentiate from abnormal termination codes, such as +/// segmentation faults or signals. +pub fn is_simple_exit_code(code: i32) -> bool { + // Typical unix exit codes are 0 to 127. + // Windows doesn't have anything "typical", and is a + // 32-bit number (which appears signed here, but is really + // unsigned). However, most of the interesting NTSTATUS + // codes are very large. This is just a rough + // approximation of which codes are "normal" and which + // ones are abnormal termination. + code >= 0 && code <= 127 +} diff --git a/src/cargo/util/read2.rs b/crates/cargo-util/src/read2.rs similarity index 100% rename from src/cargo/util/read2.rs rename to crates/cargo-util/src/read2.rs diff --git a/publish.py b/publish.py index 4872c4d05..5ace18f72 100755 --- a/publish.py +++ b/publish.py @@ -12,6 +12,7 @@ from urllib.error import HTTPError TO_PUBLISH = [ 'crates/cargo-platform', + 'crates/cargo-util', 'crates/crates-io', '.', ] diff --git a/src/bin/cargo/commands/run.rs b/src/bin/cargo/commands/run.rs index c8b711364..9a09497cb 100644 --- a/src/bin/cargo/commands/run.rs +++ b/src/bin/cargo/commands/run.rs @@ -1,8 +1,8 @@ use crate::command_prelude::*; use crate::util::restricted_names::is_glob_pattern; -use crate::util::ProcessError; use cargo::core::Verbosity; use cargo::ops::{self, CompileFilter, Packages}; +use cargo_util::ProcessError; pub fn cli() -> App { subcommand("run") diff --git a/src/bin/cargo/commands/test.rs b/src/bin/cargo/commands/test.rs index 3d1cab082..2b0464640 100644 --- a/src/bin/cargo/commands/test.rs +++ b/src/bin/cargo/commands/test.rs @@ -1,7 +1,6 @@ use crate::command_prelude::*; use anyhow::Error; use cargo::ops::{self, CompileFilter, FilterRule, LibRule}; -use cargo::util::errors; pub fn cli() -> App { subcommand("test") @@ -128,7 +127,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { let context = anyhow::format_err!("{}", err.hint(&ws, &ops.compile_opts)); let e = match err.code { // Don't show "process didn't exit successfully" for simple errors. - Some(i) if errors::is_simple_exit_code(i) => CliError::new(context, i), + Some(i) if cargo_util::is_simple_exit_code(i) => CliError::new(context, i), Some(i) => CliError::new(Error::from(err).context(context), i), None => CliError::new(Error::from(err).context(context), 101), }; diff --git a/src/bin/cargo/main.rs b/src/bin/cargo/main.rs index 21bb63a8f..1ae761b6d 100644 --- a/src/bin/cargo/main.rs +++ b/src/bin/cargo/main.rs @@ -3,15 +3,15 @@ #![warn(clippy::needless_borrow)] #![warn(clippy::redundant_clone)] +use cargo::core::shell::Shell; +use cargo::util::CliError; +use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config}; +use cargo_util::{ProcessBuilder, ProcessError}; use std::collections::{BTreeMap, BTreeSet}; use std::env; use std::fs; use std::path::{Path, PathBuf}; -use cargo::core::shell::Shell; -use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config}; -use cargo::util::{CliError, ProcessError}; - mod cli; mod commands; @@ -159,7 +159,7 @@ fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> Cli }; let cargo_exe = config.cargo_exe()?; - let err = match util::process(&command) + let err = match ProcessBuilder::new(&command) .env(cargo::CARGO_ENV, cargo_exe) .args(args) .exec_replace() diff --git a/src/cargo/core/compiler/build_config.rs b/src/cargo/core/compiler/build_config.rs index 593aaf207..4b488261c 100644 --- a/src/cargo/core/compiler/build_config.rs +++ b/src/cargo/core/compiler/build_config.rs @@ -1,8 +1,8 @@ use crate::core::compiler::CompileKind; use crate::util::interning::InternedString; -use crate::util::ProcessBuilder; use crate::util::{CargoResult, Config, RustfixDiagnosticServer}; use anyhow::bail; +use cargo_util::ProcessBuilder; use serde::ser; use std::cell::RefCell; use std::path::PathBuf; diff --git a/src/cargo/core/compiler/build_context/target_info.rs b/src/cargo/core/compiler/build_context/target_info.rs index fd40f4f3e..c10a05170 100644 --- a/src/cargo/core/compiler/build_context/target_info.rs +++ b/src/cargo/core/compiler/build_context/target_info.rs @@ -3,8 +3,9 @@ use crate::core::compiler::{ }; use crate::core::{Dependency, Target, TargetKind, Workspace}; use crate::util::config::{Config, StringList, TargetConfig}; -use crate::util::{paths, CargoResult, CargoResultExt, ProcessBuilder, Rustc}; +use crate::util::{paths, CargoResult, CargoResultExt, Rustc}; use cargo_platform::{Cfg, CfgExpr}; +use cargo_util::ProcessBuilder; use serde::{Deserialize, Serialize}; use std::cell::RefCell; use std::collections::hash_map::{Entry, HashMap}; diff --git a/src/cargo/core/compiler/build_plan.rs b/src/cargo/core/compiler/build_plan.rs index 923894d07..6ffe24a27 100644 --- a/src/cargo/core/compiler/build_plan.rs +++ b/src/cargo/core/compiler/build_plan.rs @@ -14,7 +14,8 @@ use serde::Serialize; use super::context::OutputFile; use super::{CompileKind, CompileMode, Context, Unit}; use crate::core::TargetKind; -use crate::util::{internal, CargoResult, Config, ProcessBuilder}; +use crate::util::{internal, CargoResult, Config}; +use cargo_util::ProcessBuilder; #[derive(Debug, Serialize)] struct Invocation { diff --git a/src/cargo/core/compiler/compilation.rs b/src/cargo/core/compiler/compilation.rs index dbde49eb2..5af1a4c0b 100644 --- a/src/cargo/core/compiler/compilation.rs +++ b/src/cargo/core/compiler/compilation.rs @@ -4,12 +4,13 @@ use std::ffi::{OsStr, OsString}; use std::path::PathBuf; use cargo_platform::CfgExpr; +use cargo_util::ProcessBuilder; use semver::Version; use super::BuildContext; use crate::core::compiler::{CompileKind, Metadata, Unit}; use crate::core::Package; -use crate::util::{self, config, join_paths, process, CargoResult, Config, ProcessBuilder}; +use crate::util::{self, config, join_paths, CargoResult, Config}; /// Structure with enough information to run `rustdoc --test`. pub struct Doctest { @@ -184,7 +185,7 @@ impl<'cfg> Compilation<'cfg> { unit: &Unit, script_meta: Option, ) -> CargoResult { - let rustdoc = process(&*self.config.rustdoc()?); + let rustdoc = ProcessBuilder::new(&*self.config.rustdoc()?); let cmd = fill_rustc_tool_env(rustdoc, unit); let mut p = self.fill_env(cmd, &unit.pkg, script_meta, unit.kind, true)?; unit.target.edition().cmd_edition_arg(&mut p); @@ -207,7 +208,13 @@ impl<'cfg> Compilation<'cfg> { cmd: T, pkg: &Package, ) -> CargoResult { - self.fill_env(process(cmd), pkg, None, CompileKind::Host, false) + self.fill_env( + ProcessBuilder::new(cmd), + pkg, + None, + CompileKind::Host, + false, + ) } pub fn target_runner(&self, kind: CompileKind) -> Option<&(PathBuf, Vec)> { @@ -229,12 +236,12 @@ impl<'cfg> Compilation<'cfg> { script_meta: Option, ) -> CargoResult { let builder = if let Some((runner, args)) = self.target_runner(kind) { - let mut builder = process(runner); + let mut builder = ProcessBuilder::new(runner); builder.args(args); builder.arg(cmd); builder } else { - process(cmd) + ProcessBuilder::new(cmd) }; self.fill_env(builder, pkg, script_meta, kind, false) } diff --git a/src/cargo/core/compiler/fingerprint.rs b/src/cargo/core/compiler/fingerprint.rs index a5811dd4a..ce4c6efd1 100644 --- a/src/cargo/core/compiler/fingerprint.rs +++ b/src/cargo/core/compiler/fingerprint.rs @@ -322,6 +322,7 @@ use std::sync::{Arc, Mutex}; use std::time::SystemTime; use anyhow::{bail, format_err}; +use cargo_util::ProcessBuilder; use filetime::FileTime; use log::{debug, info}; use serde::de; @@ -334,7 +335,7 @@ use crate::util; use crate::util::errors::{CargoResult, CargoResultExt}; use crate::util::interning::InternedString; use crate::util::paths; -use crate::util::{internal, path_args, profile, ProcessBuilder}; +use crate::util::{internal, path_args, profile}; use super::custom_build::BuildDeps; use super::job::{Job, Work}; diff --git a/src/cargo/core/compiler/job_queue.rs b/src/cargo/core/compiler/job_queue.rs index cf8f74f9a..91eced6d4 100644 --- a/src/cargo/core/compiler/job_queue.rs +++ b/src/cargo/core/compiler/job_queue.rs @@ -57,6 +57,7 @@ use std::sync::Arc; use std::time::Duration; use anyhow::format_err; +use cargo_util::ProcessBuilder; use crossbeam_utils::thread::Scope; use jobserver::{Acquired, Client, HelperThread}; use log::{debug, info, trace}; @@ -78,7 +79,7 @@ use crate::drop_eprint; use crate::util::diagnostic_server::{self, DiagnosticPrinter}; use crate::util::machine_message::{self, Message as _}; use crate::util::{self, internal, profile}; -use crate::util::{CargoResult, CargoResultExt, ProcessBuilder}; +use crate::util::{CargoResult, CargoResultExt}; use crate::util::{Config, DependencyQueue, Progress, ProgressStyle, Queue}; /// This structure is backed by the `DependencyQueue` type and manages the diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 382e36ce6..16f4eaa11 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -54,11 +54,12 @@ pub use crate::core::compiler::unit::{Unit, UnitInterner}; use crate::core::manifest::TargetSourcePath; use crate::core::profiles::{PanicStrategy, Profile, Strip}; use crate::core::{Feature, PackageId, Target}; -use crate::util::errors::{self, CargoResult, CargoResultExt, ProcessError, VerboseError}; +use crate::util::errors::{CargoResult, CargoResultExt, VerboseError}; use crate::util::interning::InternedString; use crate::util::machine_message::Message; -use crate::util::{self, machine_message, ProcessBuilder}; +use crate::util::{self, machine_message}; use crate::util::{add_path_args, internal, join_paths, paths, profile}; +use cargo_util::{ProcessBuilder, ProcessError}; const RUSTDOC_CRATE_VERSION_FLAG: &str = "--crate-version"; @@ -303,7 +304,7 @@ fn rustc(cx: &mut Context<'_, '_>, unit: &Unit, exec: &Arc) -> Car .as_ref() .and_then(|perr| perr.code) { - Some(n) if errors::is_simple_exit_code(n) => VerboseError::new(err).into(), + Some(n) if cargo_util::is_simple_exit_code(n) => VerboseError::new(err).into(), _ => err, } } diff --git a/src/cargo/core/compiler/rustdoc.rs b/src/cargo/core/compiler/rustdoc.rs index a6f940785..f4de35bc4 100644 --- a/src/cargo/core/compiler/rustdoc.rs +++ b/src/cargo/core/compiler/rustdoc.rs @@ -5,7 +5,7 @@ use crate::core::compiler::unit::Unit; use crate::core::compiler::CompileKind; use crate::sources::CRATES_IO_REGISTRY; use crate::util::errors::{internal, CargoResult}; -use crate::util::ProcessBuilder; +use cargo_util::ProcessBuilder; use std::collections::HashMap; use std::fmt; use std::hash; diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index cdebf99a6..b2030b2b2 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -97,10 +97,11 @@ use std::fmt; use std::str::FromStr; use anyhow::{bail, Error}; +use cargo_util::ProcessBuilder; use serde::{Deserialize, Serialize}; use crate::util::errors::CargoResult; -use crate::util::{indented_lines, ProcessBuilder}; +use crate::util::indented_lines; use crate::Config; pub const SEE_CHANNELS: &str = diff --git a/src/cargo/ops/cargo_test.rs b/src/cargo/ops/cargo_test.rs index 835ba323c..9fcb94f13 100644 --- a/src/cargo/ops/cargo_test.rs +++ b/src/cargo/ops/cargo_test.rs @@ -1,11 +1,11 @@ -use std::ffi::OsString; - use crate::core::compiler::{Compilation, CompileKind, Doctest, UnitOutput}; use crate::core::shell::Verbosity; use crate::core::{TargetKind, Workspace}; use crate::ops; use crate::util::errors::CargoResult; -use crate::util::{add_path_args, CargoTestError, Config, ProcessError, Test}; +use crate::util::{add_path_args, CargoTestError, Config, Test}; +use cargo_util::ProcessError; +use std::ffi::OsString; pub struct TestOptions { pub compile_opts: ops::CompileOptions, diff --git a/src/cargo/ops/fix.rs b/src/cargo/ops/fix.rs index 00da8d7b7..f3deddb39 100644 --- a/src/cargo/ops/fix.rs +++ b/src/cargo/ops/fix.rs @@ -46,6 +46,7 @@ use std::process::{self, Command, ExitStatus}; use std::str; use anyhow::{bail, Context, Error}; +use cargo_util::ProcessBuilder; use log::{debug, trace, warn}; use rustfix::diagnostics::Diagnostic; use rustfix::{self, CodeFix}; @@ -57,7 +58,7 @@ use crate::core::{Edition, MaybePackage, Workspace}; use crate::ops::{self, CompileOptions}; use crate::util::diagnostic_server::{Message, RustfixDiagnosticServer}; use crate::util::errors::CargoResult; -use crate::util::{self, paths, Config, ProcessBuilder}; +use crate::util::{self, paths, Config}; use crate::util::{existing_vcs_repo, LockServer, LockServerClient}; use crate::{drop_eprint, drop_eprintln}; @@ -84,7 +85,7 @@ pub fn fix(ws: &Workspace<'_>, opts: &mut FixOptions) -> CargoResult<()> { // Spin up our lock server, which our subprocesses will use to synchronize fixes. let lock_server = LockServer::new()?; - let mut wrapper = util::process(env::current_exe()?); + let mut wrapper = ProcessBuilder::new(env::current_exe()?); wrapper.env(FIX_ENV, lock_server.addr().to_string()); let _started = lock_server.start()?; @@ -322,7 +323,7 @@ pub fn fix_maybe_exec_rustc(config: &Config) -> CargoResult { let workspace_rustc = std::env::var("RUSTC_WORKSPACE_WRAPPER") .map(PathBuf::from) .ok(); - let rustc = util::process(&args.rustc).wrapped(workspace_rustc.as_ref()); + let rustc = ProcessBuilder::new(&args.rustc).wrapped(workspace_rustc.as_ref()); trace!("start rustfixing {:?}", args.file); let fixes = rustfix_crate(&lock_addr, &rustc, &args.file, &args, config)?; diff --git a/src/cargo/ops/registry/auth.rs b/src/cargo/ops/registry/auth.rs index 660daa40d..b76a08fc7 100644 --- a/src/cargo/ops/registry/auth.rs +++ b/src/cargo/ops/registry/auth.rs @@ -1,9 +1,10 @@ //! Registry authentication support. use crate::sources::CRATES_IO_REGISTRY; -use crate::util::{config, process_error, CargoResult, CargoResultExt, Config}; +use crate::util::{config, CargoResult, CargoResultExt, Config}; use anyhow::bail; use anyhow::format_err; +use cargo_util::ProcessError; use std::io::{Read, Write}; use std::path::PathBuf; use std::process::{Command, Stdio}; @@ -197,7 +198,7 @@ fn run_command( Action::Store(_) => "failed to store token to registry", Action::Erase => "failed to erase token from registry", }; - return Err(process_error( + return Err(ProcessError::new( &format!( "registry credential process `{}` {} `{}`", exe.display(), diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs index 1998f27a2..ce2956696 100644 --- a/src/cargo/sources/git/utils.rs +++ b/src/cargo/sources/git/utils.rs @@ -4,9 +4,9 @@ use crate::core::GitReference; use crate::util::errors::{CargoResult, CargoResultExt}; use crate::util::paths; -use crate::util::process_builder::process; use crate::util::{network, Config, IntoUrl, Progress}; use anyhow::{anyhow, Context}; +use cargo_util::ProcessBuilder; use curl::easy::List; use git2::{self, ErrorClass, ObjectType}; use log::{debug, info}; @@ -835,7 +835,7 @@ fn fetch_with_cli( tags: bool, config: &Config, ) -> CargoResult<()> { - let mut cmd = process("git"); + let mut cmd = ProcessBuilder::new("git"); cmd.arg("fetch"); if tags { cmd.arg("--tags"); diff --git a/src/cargo/util/diagnostic_server.rs b/src/cargo/util/diagnostic_server.rs index 1fedf621c..cd1ae0c41 100644 --- a/src/cargo/util/diagnostic_server.rs +++ b/src/cargo/util/diagnostic_server.rs @@ -10,12 +10,13 @@ use std::sync::Arc; use std::thread::{self, JoinHandle}; use anyhow::{Context, Error}; +use cargo_util::ProcessBuilder; use log::warn; use serde::{Deserialize, Serialize}; use crate::core::Edition; use crate::util::errors::CargoResult; -use crate::util::{Config, ProcessBuilder}; +use crate::util::Config; const DIAGNOSICS_SERVER_VAR: &str = "__CARGO_FIX_DIAGNOSTICS_SERVER"; const PLEASE_REPORT_THIS_BUG: &str = diff --git a/src/cargo/util/errors.rs b/src/cargo/util/errors.rs index cf4ceb4bf..94e255bca 100644 --- a/src/cargo/util/errors.rs +++ b/src/cargo/util/errors.rs @@ -3,10 +3,9 @@ use crate::core::{TargetKind, Workspace}; use crate::ops::CompileOptions; use anyhow::Error; +use cargo_util::ProcessError; use std::fmt; use std::path::PathBuf; -use std::process::{ExitStatus, Output}; -use std::str; pub type CargoResult = anyhow::Result; @@ -186,41 +185,6 @@ impl<'a> Iterator for ManifestCauses<'a> { impl<'a> ::std::iter::FusedIterator for ManifestCauses<'a> {} -// ============================================================================= -// Process errors -#[derive(Debug)] -pub struct ProcessError { - /// A detailed description to show to the user why the process failed. - pub desc: String, - - /// The exit status of the process. - /// - /// This can be `None` if the process failed to launch (like process not - /// found) or if the exit status wasn't a code but was instead something - /// like termination via a signal. - pub code: Option, - - /// The stdout from the process. - /// - /// This can be `None` if the process failed to launch, or the output was - /// not captured. - pub stdout: Option>, - - /// The stderr from the process. - /// - /// This can be `None` if the process failed to launch, or the output was - /// not captured. - pub stderr: Option>, -} - -impl fmt::Display for ProcessError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.desc.fmt(f) - } -} - -impl std::error::Error for ProcessError {} - // ============================================================================= // Cargo test errors. @@ -360,154 +324,6 @@ impl From for CliError { // ============================================================================= // Construction helpers -/// Creates a new process error. -/// -/// `status` can be `None` if the process did not launch. -/// `output` can be `None` if the process did not launch, or output was not captured. -pub fn process_error( - msg: &str, - status: Option, - output: Option<&Output>, -) -> ProcessError { - let exit = match status { - Some(s) => exit_status_to_string(s), - None => "never executed".to_string(), - }; - - process_error_raw( - msg, - status.and_then(|s| s.code()), - &exit, - output.map(|s| s.stdout.as_slice()), - output.map(|s| s.stderr.as_slice()), - ) -} - -pub fn process_error_raw( - msg: &str, - code: Option, - status: &str, - stdout: Option<&[u8]>, - stderr: Option<&[u8]>, -) -> ProcessError { - let mut desc = format!("{} ({})", msg, status); - - if let Some(out) = stdout { - match str::from_utf8(out) { - Ok(s) if !s.trim().is_empty() => { - desc.push_str("\n--- stdout\n"); - desc.push_str(s); - } - Ok(..) | Err(..) => {} - } - } - if let Some(out) = stderr { - match str::from_utf8(out) { - Ok(s) if !s.trim().is_empty() => { - desc.push_str("\n--- stderr\n"); - desc.push_str(s); - } - Ok(..) | Err(..) => {} - } - } - - ProcessError { - desc, - code, - stdout: stdout.map(|s| s.to_vec()), - stderr: stderr.map(|s| s.to_vec()), - } -} - -pub fn exit_status_to_string(status: ExitStatus) -> String { - return status_to_string(status); - - #[cfg(unix)] - fn status_to_string(status: ExitStatus) -> String { - use std::os::unix::process::*; - - if let Some(signal) = status.signal() { - let name = match signal as libc::c_int { - libc::SIGABRT => ", SIGABRT: process abort signal", - libc::SIGALRM => ", SIGALRM: alarm clock", - libc::SIGFPE => ", SIGFPE: erroneous arithmetic operation", - libc::SIGHUP => ", SIGHUP: hangup", - libc::SIGILL => ", SIGILL: illegal instruction", - libc::SIGINT => ", SIGINT: terminal interrupt signal", - libc::SIGKILL => ", SIGKILL: kill", - libc::SIGPIPE => ", SIGPIPE: write on a pipe with no one to read", - libc::SIGQUIT => ", SIGQUIT: terminal quit signal", - libc::SIGSEGV => ", SIGSEGV: invalid memory reference", - libc::SIGTERM => ", SIGTERM: termination signal", - libc::SIGBUS => ", SIGBUS: access to undefined memory", - #[cfg(not(target_os = "haiku"))] - libc::SIGSYS => ", SIGSYS: bad system call", - libc::SIGTRAP => ", SIGTRAP: trace/breakpoint trap", - _ => "", - }; - format!("signal: {}{}", signal, name) - } else { - status.to_string() - } - } - - #[cfg(windows)] - fn status_to_string(status: ExitStatus) -> String { - use winapi::shared::minwindef::DWORD; - use winapi::um::winnt::*; - - let mut base = status.to_string(); - let extra = match status.code().unwrap() as DWORD { - STATUS_ACCESS_VIOLATION => "STATUS_ACCESS_VIOLATION", - STATUS_IN_PAGE_ERROR => "STATUS_IN_PAGE_ERROR", - STATUS_INVALID_HANDLE => "STATUS_INVALID_HANDLE", - STATUS_INVALID_PARAMETER => "STATUS_INVALID_PARAMETER", - STATUS_NO_MEMORY => "STATUS_NO_MEMORY", - STATUS_ILLEGAL_INSTRUCTION => "STATUS_ILLEGAL_INSTRUCTION", - STATUS_NONCONTINUABLE_EXCEPTION => "STATUS_NONCONTINUABLE_EXCEPTION", - STATUS_INVALID_DISPOSITION => "STATUS_INVALID_DISPOSITION", - STATUS_ARRAY_BOUNDS_EXCEEDED => "STATUS_ARRAY_BOUNDS_EXCEEDED", - STATUS_FLOAT_DENORMAL_OPERAND => "STATUS_FLOAT_DENORMAL_OPERAND", - STATUS_FLOAT_DIVIDE_BY_ZERO => "STATUS_FLOAT_DIVIDE_BY_ZERO", - STATUS_FLOAT_INEXACT_RESULT => "STATUS_FLOAT_INEXACT_RESULT", - STATUS_FLOAT_INVALID_OPERATION => "STATUS_FLOAT_INVALID_OPERATION", - STATUS_FLOAT_OVERFLOW => "STATUS_FLOAT_OVERFLOW", - STATUS_FLOAT_STACK_CHECK => "STATUS_FLOAT_STACK_CHECK", - STATUS_FLOAT_UNDERFLOW => "STATUS_FLOAT_UNDERFLOW", - STATUS_INTEGER_DIVIDE_BY_ZERO => "STATUS_INTEGER_DIVIDE_BY_ZERO", - STATUS_INTEGER_OVERFLOW => "STATUS_INTEGER_OVERFLOW", - STATUS_PRIVILEGED_INSTRUCTION => "STATUS_PRIVILEGED_INSTRUCTION", - STATUS_STACK_OVERFLOW => "STATUS_STACK_OVERFLOW", - STATUS_DLL_NOT_FOUND => "STATUS_DLL_NOT_FOUND", - STATUS_ORDINAL_NOT_FOUND => "STATUS_ORDINAL_NOT_FOUND", - STATUS_ENTRYPOINT_NOT_FOUND => "STATUS_ENTRYPOINT_NOT_FOUND", - STATUS_CONTROL_C_EXIT => "STATUS_CONTROL_C_EXIT", - STATUS_DLL_INIT_FAILED => "STATUS_DLL_INIT_FAILED", - STATUS_FLOAT_MULTIPLE_FAULTS => "STATUS_FLOAT_MULTIPLE_FAULTS", - STATUS_FLOAT_MULTIPLE_TRAPS => "STATUS_FLOAT_MULTIPLE_TRAPS", - STATUS_REG_NAT_CONSUMPTION => "STATUS_REG_NAT_CONSUMPTION", - STATUS_HEAP_CORRUPTION => "STATUS_HEAP_CORRUPTION", - STATUS_STACK_BUFFER_OVERRUN => "STATUS_STACK_BUFFER_OVERRUN", - STATUS_ASSERTION_FAILURE => "STATUS_ASSERTION_FAILURE", - _ => return base, - }; - base.push_str(", "); - base.push_str(extra); - base - } -} - -pub fn is_simple_exit_code(code: i32) -> bool { - // Typical unix exit codes are 0 to 127. - // Windows doesn't have anything "typical", and is a - // 32-bit number (which appears signed here, but is really - // unsigned). However, most of the interesting NTSTATUS - // codes are very large. This is just a rough - // approximation of which codes are "normal" and which - // ones are abnormal termination. - code >= 0 && code <= 127 -} - pub fn internal(error: S) -> anyhow::Error { InternalError::new(anyhow::format_err!("{}", error)).into() } diff --git a/src/cargo/util/mod.rs b/src/cargo/util/mod.rs index 42b243bf9..7b3786dca 100644 --- a/src/cargo/util/mod.rs +++ b/src/cargo/util/mod.rs @@ -4,9 +4,8 @@ pub use self::canonical_url::CanonicalUrl; pub use self::config::{homedir, Config, ConfigValue}; pub use self::dependency_queue::DependencyQueue; pub use self::diagnostic_server::RustfixDiagnosticServer; -pub use self::errors::{exit_status_to_string, internal, process_error, process_error_raw}; -pub use self::errors::{CargoResult, CargoResultExt, CliResult, Test}; -pub use self::errors::{CargoTestError, CliError, ProcessError}; +pub use self::errors::{internal, CargoResult, CargoResultExt, CliResult, Test}; +pub use self::errors::{CargoTestError, CliError}; pub use self::flock::{FileLock, Filesystem}; pub use self::graph::Graph; pub use self::hasher::StableHasher; @@ -17,10 +16,8 @@ pub use self::lev_distance::{closest, closest_msg, lev_distance}; pub use self::lockserver::{LockServer, LockServerClient, LockServerStarted}; pub use self::paths::{bytes2path, dylib_path, join_paths, path2bytes}; pub use self::paths::{dylib_path_envvar, normalize_path}; -pub use self::process_builder::{process, ProcessBuilder}; pub use self::progress::{Progress, ProgressStyle}; pub use self::queue::Queue; -pub use self::read2::read2; pub use self::restricted_names::validate_package_name; pub use self::rustc::Rustc; pub use self::sha256::Sha256; @@ -52,11 +49,9 @@ mod lockserver; pub mod machine_message; pub mod network; pub mod paths; -pub mod process_builder; pub mod profile; mod progress; mod queue; -mod read2; pub mod restricted_names; pub mod rustc; mod sha256; diff --git a/src/cargo/util/rustc.rs b/src/cargo/util/rustc.rs index 2b2d1e295..7012c8f63 100644 --- a/src/cargo/util/rustc.rs +++ b/src/cargo/util/rustc.rs @@ -4,12 +4,13 @@ use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use std::sync::Mutex; +use cargo_util::{ProcessBuilder, ProcessError}; use log::{debug, info, warn}; use serde::{Deserialize, Serialize}; use crate::util::interning::InternedString; use crate::util::paths; -use crate::util::{self, profile, CargoResult, CargoResultExt, ProcessBuilder, StableHasher}; +use crate::util::{profile, CargoResult, CargoResultExt, StableHasher}; /// Information on the `rustc` executable #[derive(Debug)] @@ -47,7 +48,7 @@ impl Rustc { let mut cache = Cache::load(&path, rustup_rustc, cache_location); - let mut cmd = util::process(&path); + let mut cmd = ProcessBuilder::new(&path); cmd.arg("-vV"); let verbose_version = cache.cached_output(&cmd, 0)?.0; @@ -86,18 +87,18 @@ impl Rustc { /// Gets a process builder set up to use the found rustc version, with a wrapper if `Some`. pub fn process(&self) -> ProcessBuilder { - util::process(self.path.as_path()).wrapped(self.wrapper.as_ref()) + ProcessBuilder::new(self.path.as_path()).wrapped(self.wrapper.as_ref()) } /// Gets a process builder set up to use the found rustc version, with a wrapper if `Some`. pub fn workspace_process(&self) -> ProcessBuilder { - util::process(self.path.as_path()) + ProcessBuilder::new(self.path.as_path()) .wrapped(self.workspace_wrapper.as_ref()) .wrapped(self.wrapper.as_ref()) } pub fn process_no_wrapper(&self) -> ProcessBuilder { - util::process(&self.path) + ProcessBuilder::new(&self.path) } /// Gets the output for the given command. @@ -232,7 +233,7 @@ impl Cache { status: if output.status.success() { String::new() } else { - util::exit_status_to_string(output.status) + cargo_util::exit_status_to_string(output.status) }, code: output.status.code(), stdout, @@ -245,7 +246,7 @@ impl Cache { if output.success { Ok((output.stdout.clone(), output.stderr.clone())) } else { - Err(util::process_error_raw( + Err(ProcessError::new_raw( &format!("process didn't exit successfully: {}", cmd), output.code, &output.status, diff --git a/src/cargo/util/vcs.rs b/src/cargo/util/vcs.rs index 6a66870c8..7aa6c9c33 100644 --- a/src/cargo/util/vcs.rs +++ b/src/cargo/util/vcs.rs @@ -1,5 +1,6 @@ use crate::util::paths; -use crate::util::{process, CargoResult}; +use crate::util::CargoResult; +use cargo_util::ProcessBuilder; use std::path::Path; // Check if we are in an existing repo. We define that to be true if either: @@ -41,11 +42,15 @@ impl GitRepo { impl HgRepo { pub fn init(path: &Path, cwd: &Path) -> CargoResult { - process("hg").cwd(cwd).arg("init").arg(path).exec()?; + ProcessBuilder::new("hg") + .cwd(cwd) + .arg("init") + .arg(path) + .exec()?; Ok(HgRepo) } pub fn discover(path: &Path, cwd: &Path) -> CargoResult { - process("hg") + ProcessBuilder::new("hg") .cwd(cwd) .arg("--cwd") .arg(path) @@ -57,7 +62,11 @@ impl HgRepo { impl PijulRepo { pub fn init(path: &Path, cwd: &Path) -> CargoResult { - process("pijul").cwd(cwd).arg("init").arg(path).exec()?; + ProcessBuilder::new("pijul") + .cwd(cwd) + .arg("init") + .arg(path) + .exec()?; Ok(PijulRepo) } } @@ -73,28 +82,28 @@ impl FossilRepo { db_path.push(db_fname); // then create the fossil DB in that location - process("fossil") + ProcessBuilder::new("fossil") .cwd(cwd) .arg("init") .arg(&db_path) .exec()?; // open it in that new directory - process("fossil") + ProcessBuilder::new("fossil") .cwd(&path) .arg("open") .arg(db_fname) .exec()?; // set `target` as ignoreable and cleanable - process("fossil") + ProcessBuilder::new("fossil") .cwd(cwd) .arg("settings") .arg("ignore-glob") .arg("target") .exec()?; - process("fossil") + ProcessBuilder::new("fossil") .cwd(cwd) .arg("settings") .arg("clean-glob") diff --git a/src/cargo/util/workspace.rs b/src/cargo/util/workspace.rs index 0cac29f67..e8317f101 100644 --- a/src/cargo/util/workspace.rs +++ b/src/cargo/util/workspace.rs @@ -1,10 +1,10 @@ -use super::ProcessBuilder; use crate::core::compiler::Unit; use crate::core::manifest::TargetSourcePath; use crate::core::{Target, Workspace}; use crate::ops::CompileOptions; use crate::util::CargoResult; use anyhow::bail; +use cargo_util::ProcessBuilder; use std::fmt::Write; use std::path::PathBuf; diff --git a/tests/testsuite/old_cargos.rs b/tests/testsuite/old_cargos.rs index 05c2a6862..f9e239a55 100644 --- a/tests/testsuite/old_cargos.rs +++ b/tests/testsuite/old_cargos.rs @@ -10,11 +10,11 @@ //! cargo test --test testsuite -- old_cargos --nocapture --ignored //! ``` -use cargo::util::{ProcessBuilder, ProcessError}; use cargo::CargoResult; use cargo_test_support::paths::CargoPathExt; use cargo_test_support::registry::{self, Dependency, Package}; use cargo_test_support::{cargo_exe, execs, paths, process, project, rustc_host}; +use cargo_util::{ProcessBuilder, ProcessError}; use semver::Version; use std::fs; @@ -68,7 +68,7 @@ fn collect_all_toolchains() -> Vec<(Version, String)> { format!("nightly-{}", host), ]; - let output = cargo::util::process("rustup") + let output = ProcessBuilder::new("rustup") .args(&["toolchain", "list"]) .exec_with_output() .expect("rustup should be installed");