diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 52b4584a944..f4bd7f616f5 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 32f1c839e24..12e4fa46487 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,9 +22,9 @@ path = "src/cargo/lib.rs" atty = "0.2" bytesize = "1.0" cargo-platform = { path = "crates/cargo-platform", version = "0.1.1" } +cargo-util = { path = "crates/cargo-util", version = "0.1.0" } crates-io = { path = "crates/crates-io", version = "0.33.0" } crossbeam-utils = "0.8" -crypto-hash = "0.3.1" curl = { version = "0.4.23", features = ["http2"] } curl-sys = "0.4.22" env_logger = "0.8.1" @@ -50,12 +50,10 @@ num_cpus = "1.0" opener = "0.4" percent-encoding = "2.0" rustfix = "0.5.0" -same-file = "1" 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" @@ -75,11 +73,7 @@ im-rc = "15.0.0" rustc-workspace-hack = "1.0.0" rand = "0.8.3" -[target.'cfg(target_os = "macos")'.dependencies] -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 62ff3accf85..9674579e249 100644 --- a/crates/cargo-test-support/Cargo.toml +++ b/crates/cargo-test-support/Cargo.toml @@ -9,8 +9,9 @@ edition = "2018" doctest = false [dependencies] -cargo = { path = "../.." } +anyhow = "1.0.34" 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 ff272d482f3..ca18055dec8 100644 --- a/crates/cargo-test-support/src/cross_compile.rs +++ b/crates/cargo-test-support/src/cross_compile.rs @@ -10,8 +10,7 @@ //! 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}; @@ -41,7 +40,7 @@ pub fn disabled() -> bool { let cross_target = alternate(); - let run_cross_test = || -> CargoResult { + let run_cross_test = || -> anyhow::Result { let p = project() .at("cross_test") .file("Cargo.toml", &basic_manifest("cross_test", "1.0.0")) diff --git a/crates/cargo-test-support/src/lib.rs b/crates/cargo-test-support/src/lib.rs index a8ea76b9c64..c0d05ce36ae 100644 --- a/crates/cargo-test-support/src/lib.rs +++ b/crates/cargo-test-support/src/lib.rs @@ -15,7 +15,7 @@ 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, ProcessBuilder, ProcessError}; use serde_json::{self, Value}; use url::Url; @@ -701,7 +701,7 @@ impl Execs { self } - pub fn exec_with_output(&mut self) -> CargoResult { + pub fn exec_with_output(&mut self) -> anyhow::Result { self.ran = true; // TODO avoid unwrap let p = (&self.process_builder).clone().unwrap(); @@ -1548,33 +1548,52 @@ fn substitute_macros(input: &str) -> String { pub mod install; -thread_local!( -pub static RUSTC: Rustc = Rustc::new( - PathBuf::from("rustc"), - None, - None, - Path::new("should be path to rustup rustc, but we don't care in tests"), - None, -).unwrap() -); +struct RustcInfo { + verbose_version: String, + host: String, +} + +impl RustcInfo { + fn new() -> RustcInfo { + let output = ProcessBuilder::new("rustc") + .arg("-vV") + .exec_with_output() + .expect("rustc should exec"); + let verbose_version = String::from_utf8(output.stdout).expect("utf8 output"); + let host = verbose_version + .lines() + .filter_map(|line| line.strip_prefix("host: ")) + .next() + .expect("verbose version has host: field") + .to_string(); + RustcInfo { + verbose_version, + host, + } + } +} + +lazy_static::lazy_static! { + static ref RUSTC_INFO: RustcInfo = RustcInfo::new(); +} /// The rustc host such as `x86_64-unknown-linux-gnu`. -pub fn rustc_host() -> String { - RUSTC.with(|r| r.host.to_string()) +pub fn rustc_host() -> &'static str { + &RUSTC_INFO.host } pub fn is_nightly() -> bool { + let vv = &RUSTC_INFO.verbose_version; env::var("CARGO_TEST_DISABLE_NIGHTLY").is_err() - && RUSTC - .with(|r| r.verbose_version.contains("-nightly") || r.verbose_version.contains("-dev")) + && (vv.contains("-nightly") || vv.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 +1662,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-test-support/src/registry.rs b/crates/cargo-test-support/src/registry.rs index 39001ba5ac5..21441c3d975 100644 --- a/crates/cargo-test-support/src/registry.rs +++ b/crates/cargo-test-support/src/registry.rs @@ -1,7 +1,6 @@ use crate::git::repo; use crate::paths; -use cargo::sources::CRATES_IO_INDEX; -use cargo::util::Sha256; +use cargo_util::Sha256; use flate2::write::GzEncoder; use flate2::Compression; use std::collections::BTreeMap; @@ -560,7 +559,7 @@ impl Package { /// Sets the index schema version for this package. /// - /// See [`cargo::sources::registry::RegistryPackage`] for more information. + /// See `cargo::sources::registry::RegistryPackage` for more information. pub fn schema_version(&mut self, version: u32) -> &mut Package { self.v = Some(version); self @@ -585,7 +584,9 @@ impl Package { let registry_url = match (self.alternative, dep.registry.as_deref()) { (false, None) => None, (false, Some("alternative")) => Some(alt_registry_url().to_string()), - (true, None) => Some(CRATES_IO_INDEX.to_string()), + (true, None) => { + Some("https://github.com/rust-lang/crates.io-index".to_string()) + } (true, Some("alternative")) => None, _ => panic!("registry_dep currently only supports `alternative`"), }; diff --git a/crates/cargo-util/Cargo.toml b/crates/cargo-util/Cargo.toml new file mode 100644 index 00000000000..c7848831f67 --- /dev/null +++ b/crates/cargo-util/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "cargo-util" +version = "0.1.0" +authors = ["The Cargo Project Developers"] +edition = "2018" +license = "MIT OR Apache-2.0" +homepage = "https://github.com/rust-lang/cargo" +repository = "https://github.com/rust-lang/cargo" +description = "Miscellaneous support code used by Cargo." + +[dependencies] +anyhow = "1.0.34" +crypto-hash = "0.3.1" +filetime = "0.2.9" +hex = "0.4.2" +jobserver = "0.1.21" +libc = "0.2.88" +log = "0.4.6" +same-file = "1.0.6" +shell-escape = "0.1.4" +tempfile = "3.1.0" +walkdir = "2.3.1" + +[target.'cfg(target_os = "macos")'.dependencies] +core-foundation = { version = "0.9.0", features = ["mac_os_10_7_support"] } + +[target.'cfg(windows)'.dependencies] +miow = "0.3.6" +winapi = { version = "0.3.9", features = ["consoleapi", "minwindef"] } diff --git a/crates/cargo-util/LICENSE-APACHE b/crates/cargo-util/LICENSE-APACHE new file mode 120000 index 00000000000..1cd601d0a3a --- /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 00000000000..b2cfbdc7b0b --- /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 new file mode 100644 index 00000000000..a57aac34ae1 --- /dev/null +++ b/crates/cargo-util/src/lib.rs @@ -0,0 +1,17 @@ +//! 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}; +pub use sha256::Sha256; + +pub mod paths; +mod process_builder; +mod process_error; +mod read2; +mod sha256; + +/// Whether or not this running in a Continuous Integration environment. +pub fn is_ci() -> bool { + std::env::var("CI").is_ok() || std::env::var("TF_BUILD").is_ok() +} diff --git a/src/cargo/util/paths.rs b/crates/cargo-util/src/paths.rs similarity index 75% rename from src/cargo/util/paths.rs rename to crates/cargo-util/src/paths.rs index 5cbea3a1ad9..ea39273a82d 100644 --- a/src/cargo/util/paths.rs +++ b/crates/cargo-util/src/paths.rs @@ -1,3 +1,7 @@ +//! Various utilities for working with files and paths. + +use anyhow::{Context, Result}; +use filetime::FileTime; use std::env; use std::ffi::{OsStr, OsString}; use std::fs::{self, File, OpenOptions}; @@ -5,19 +9,21 @@ use std::io; use std::io::prelude::*; use std::iter; use std::path::{Component, Path, PathBuf}; - -use filetime::FileTime; use tempfile::Builder as TempFileBuilder; -use crate::util::errors::{CargoResult, CargoResultExt}; - -pub fn join_paths>(paths: &[T], env: &str) -> CargoResult { +/// Joins paths into a string suitable for the `PATH` environment variable. +/// +/// This is equivalent to [`std::env::join_paths`], but includes a more +/// detailed error message. The given `env` argument is the name of the +/// environment variable this is will be used for, which is included in the +/// error message. +pub fn join_paths>(paths: &[T], env: &str) -> Result { env::join_paths(paths.iter()) - .chain_err(|| { + .with_context(|| { let paths = paths.iter().map(Path::new).collect::>(); format!("failed to join path array: {:?}", paths) }) - .chain_err(|| { + .with_context(|| { format!( "failed to join search paths together\n\ Does ${} have an unterminated quote character?", @@ -26,6 +32,8 @@ pub fn join_paths>(paths: &[T], env: &str) -> CargoResult &'static str { if cfg!(windows) { "PATH" @@ -51,6 +59,10 @@ pub fn dylib_path_envvar() -> &'static str { } } +/// Returns a list of directories that are searched for dynamic libraries. +/// +/// Note that some operating systems will have defaults if this is empty that +/// will need to be dealt with. pub fn dylib_path() -> Vec { match env::var_os(dylib_path_envvar()) { Some(var) => env::split_paths(&var).collect(), @@ -58,6 +70,14 @@ pub fn dylib_path() -> Vec { } } +/// Normalize a path, removing things like `.` and `..`. +/// +/// CAUTION: This does not resolve symlinks (unlike +/// [`std::fs::canonicalize`]). This may cause incorrect or surprising +/// behavior at times. This should be used carefully. Unfortunately, +/// [`std::fs::canonicalize`] can be hard to use correctly, since it can often +/// fail, or on Windows returns annoying device paths. This is a problem Cargo +/// needs to improve on. pub fn normalize_path(path: &Path) -> PathBuf { let mut components = path.components().peekable(); let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { @@ -85,7 +105,11 @@ pub fn normalize_path(path: &Path) -> PathBuf { ret } -pub fn resolve_executable(exec: &Path) -> CargoResult { +/// Returns the absolute path of where the given executable is located based +/// on searching the `PATH` environment variable. +/// +/// Returns an error if it cannot be found. +pub fn resolve_executable(exec: &Path) -> Result { if exec.components().count() == 1 { let paths = env::var_os("PATH").ok_or_else(|| anyhow::format_err!("no PATH"))?; let candidates = env::split_paths(&paths).flat_map(|path| { @@ -111,24 +135,36 @@ pub fn resolve_executable(exec: &Path) -> CargoResult { } } -pub fn read(path: &Path) -> CargoResult { +/// Reads a file to a string. +/// +/// Equivalent to [`std::fs::read_to_string`] with better error messages. +pub fn read(path: &Path) -> Result { match String::from_utf8(read_bytes(path)?) { Ok(s) => Ok(s), Err(_) => anyhow::bail!("path at `{}` was not valid utf-8", path.display()), } } -pub fn read_bytes(path: &Path) -> CargoResult> { - fs::read(path).chain_err(|| format!("failed to read `{}`", path.display())) +/// Reads a file into a bytes vector. +/// +/// Equivalent to [`std::fs::read`] with better error messages. +pub fn read_bytes(path: &Path) -> Result> { + fs::read(path).with_context(|| format!("failed to read `{}`", path.display())) } -pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> CargoResult<()> { +/// Writes a file to disk. +/// +/// Equivalent to [`std::fs::write`] with better error messages. +pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> { let path = path.as_ref(); - fs::write(path, contents.as_ref()).chain_err(|| format!("failed to write `{}`", path.display())) + fs::write(path, contents.as_ref()) + .with_context(|| format!("failed to write `{}`", path.display())) } -pub fn write_if_changed, C: AsRef<[u8]>>(path: P, contents: C) -> CargoResult<()> { - (|| -> CargoResult<()> { +/// Equivalent to [`write`], but does not write anything if the file contents +/// are identical to the given contents. +pub fn write_if_changed, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> { + (|| -> Result<()> { let contents = contents.as_ref(); let mut f = OpenOptions::new() .read(true) @@ -144,12 +180,14 @@ pub fn write_if_changed, C: AsRef<[u8]>>(path: P, contents: C) -> } Ok(()) })() - .chain_err(|| format!("failed to write `{}`", path.as_ref().display()))?; + .with_context(|| format!("failed to write `{}`", path.as_ref().display()))?; Ok(()) } -pub fn append(path: &Path, contents: &[u8]) -> CargoResult<()> { - (|| -> CargoResult<()> { +/// Equivalent to [`write`], but appends to the end instead of replacing the +/// contents. +pub fn append(path: &Path, contents: &[u8]) -> Result<()> { + (|| -> Result<()> { let mut f = OpenOptions::new() .write(true) .append(true) @@ -159,31 +197,34 @@ pub fn append(path: &Path, contents: &[u8]) -> CargoResult<()> { f.write_all(contents)?; Ok(()) })() - .chain_err(|| format!("failed to write `{}`", path.display()))?; + .with_context(|| format!("failed to write `{}`", path.display()))?; Ok(()) } /// Creates a new file. -pub fn create>(path: P) -> CargoResult { +pub fn create>(path: P) -> Result { let path = path.as_ref(); - File::create(path).chain_err(|| format!("failed to create file `{}`", path.display())) + File::create(path).with_context(|| format!("failed to create file `{}`", path.display())) } /// Opens an existing file. -pub fn open>(path: P) -> CargoResult { +pub fn open>(path: P) -> Result { let path = path.as_ref(); - File::open(path).chain_err(|| format!("failed to open file `{}`", path.display())) + File::open(path).with_context(|| format!("failed to open file `{}`", path.display())) } -pub fn mtime(path: &Path) -> CargoResult { - let meta = fs::metadata(path).chain_err(|| format!("failed to stat `{}`", path.display()))?; +/// Returns the last modification time of a file. +pub fn mtime(path: &Path) -> Result { + let meta = + fs::metadata(path).with_context(|| format!("failed to stat `{}`", path.display()))?; Ok(FileTime::from_last_modification_time(&meta)) } /// Returns the maximum mtime of the given path, recursing into /// subdirectories, and following symlinks. -pub fn mtime_recursive(path: &Path) -> CargoResult { - let meta = fs::metadata(path).chain_err(|| format!("failed to stat `{}`", path.display()))?; +pub fn mtime_recursive(path: &Path) -> Result { + let meta = + fs::metadata(path).with_context(|| format!("failed to stat `{}`", path.display()))?; if !meta.is_dir() { return Ok(FileTime::from_last_modification_time(&meta)); } @@ -263,7 +304,7 @@ pub fn mtime_recursive(path: &Path) -> CargoResult { /// Record the current time on the filesystem (using the filesystem's clock) /// using a file at the given directory. Returns the current time. -pub fn set_invocation_time(path: &Path) -> CargoResult { +pub fn set_invocation_time(path: &Path) -> Result { // note that if `FileTime::from_system_time(SystemTime::now());` is determined to be sufficient, // then this can be removed. let timestamp = path.join("invoked.timestamp"); @@ -276,36 +317,47 @@ pub fn set_invocation_time(path: &Path) -> CargoResult { Ok(ft) } -#[cfg(unix)] -pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> { - use std::os::unix::prelude::*; - Ok(path.as_os_str().as_bytes()) -} -#[cfg(windows)] -pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> { - match path.as_os_str().to_str() { - Some(s) => Ok(s.as_bytes()), - None => Err(anyhow::format_err!( - "invalid non-unicode path: {}", - path.display() - )), +/// Converts a path to UTF-8 bytes. +pub fn path2bytes(path: &Path) -> Result<&[u8]> { + #[cfg(unix)] + { + use std::os::unix::prelude::*; + Ok(path.as_os_str().as_bytes()) + } + #[cfg(windows)] + { + match path.as_os_str().to_str() { + Some(s) => Ok(s.as_bytes()), + None => Err(anyhow::format_err!( + "invalid non-unicode path: {}", + path.display() + )), + } } } -#[cfg(unix)] -pub fn bytes2path(bytes: &[u8]) -> CargoResult { - use std::os::unix::prelude::*; - Ok(PathBuf::from(OsStr::from_bytes(bytes))) -} -#[cfg(windows)] -pub fn bytes2path(bytes: &[u8]) -> CargoResult { - use std::str; - match str::from_utf8(bytes) { - Ok(s) => Ok(PathBuf::from(s)), - Err(..) => Err(anyhow::format_err!("invalid non-unicode path")), +/// Converts UTF-8 bytes to a path. +pub fn bytes2path(bytes: &[u8]) -> Result { + #[cfg(unix)] + { + use std::os::unix::prelude::*; + Ok(PathBuf::from(OsStr::from_bytes(bytes))) + } + #[cfg(windows)] + { + use std::str; + match str::from_utf8(bytes) { + Ok(s) => Ok(PathBuf::from(s)), + Err(..) => Err(anyhow::format_err!("invalid non-unicode path")), + } } } +/// Returns an iterator that walks up the directory hierarchy towards the root. +/// +/// Each item is a [`Path`]. It will start with the given path, finishing at +/// the root. If the `stop_root_at` parameter is given, it will stop at the +/// given path (which will be the last item). pub fn ancestors<'a>(path: &'a Path, stop_root_at: Option<&Path>) -> PathAncestors<'a> { PathAncestors::new(path, stop_root_at) } @@ -349,22 +401,27 @@ impl<'a> Iterator for PathAncestors<'a> { } } -pub fn create_dir_all(p: impl AsRef) -> CargoResult<()> { +/// Equivalent to [`std::fs::create_dir_all`] with better error messages. +pub fn create_dir_all(p: impl AsRef) -> Result<()> { _create_dir_all(p.as_ref()) } -fn _create_dir_all(p: &Path) -> CargoResult<()> { - fs::create_dir_all(p).chain_err(|| format!("failed to create directory `{}`", p.display()))?; +fn _create_dir_all(p: &Path) -> Result<()> { + fs::create_dir_all(p) + .with_context(|| format!("failed to create directory `{}`", p.display()))?; Ok(()) } -pub fn remove_dir_all>(p: P) -> CargoResult<()> { +/// Recursively remove all files and directories at the given directory. +/// +/// This does *not* follow symlinks. +pub fn remove_dir_all>(p: P) -> Result<()> { _remove_dir_all(p.as_ref()) } -fn _remove_dir_all(p: &Path) -> CargoResult<()> { +fn _remove_dir_all(p: &Path) -> Result<()> { if p.symlink_metadata() - .chain_err(|| format!("could not get metadata for `{}` to remove", p.display()))? + .with_context(|| format!("could not get metadata for `{}` to remove", p.display()))? .file_type() .is_symlink() { @@ -372,7 +429,7 @@ fn _remove_dir_all(p: &Path) -> CargoResult<()> { } let entries = p .read_dir() - .chain_err(|| format!("failed to read directory `{}`", p.display()))?; + .with_context(|| format!("failed to read directory `{}`", p.display()))?; for entry in entries { let entry = entry?; let path = entry.path(); @@ -385,20 +442,25 @@ fn _remove_dir_all(p: &Path) -> CargoResult<()> { remove_dir(&p) } -pub fn remove_dir>(p: P) -> CargoResult<()> { +/// Equivalent to [`std::fs::remove_dir`] with better error messages. +pub fn remove_dir>(p: P) -> Result<()> { _remove_dir(p.as_ref()) } -fn _remove_dir(p: &Path) -> CargoResult<()> { - fs::remove_dir(p).chain_err(|| format!("failed to remove directory `{}`", p.display()))?; +fn _remove_dir(p: &Path) -> Result<()> { + fs::remove_dir(p).with_context(|| format!("failed to remove directory `{}`", p.display()))?; Ok(()) } -pub fn remove_file>(p: P) -> CargoResult<()> { +/// Equivalent to [`std::fs::remove_file`] with better error messages. +/// +/// If the file is readonly, this will attempt to change the permissions to +/// force the file to be deleted. +pub fn remove_file>(p: P) -> Result<()> { _remove_file(p.as_ref()) } -fn _remove_file(p: &Path) -> CargoResult<()> { +fn _remove_file(p: &Path) -> Result<()> { let mut err = match fs::remove_file(p) { Ok(()) => return Ok(()), Err(e) => e, @@ -411,7 +473,7 @@ fn _remove_file(p: &Path) -> CargoResult<()> { } } - Err(err).chain_err(|| format!("failed to remove file `{}`", p.display()))?; + Err(err).with_context(|| format!("failed to remove file `{}`", p.display()))?; Ok(()) } @@ -428,13 +490,13 @@ fn set_not_readonly(p: &Path) -> io::Result { /// Hardlink (file) or symlink (dir) src to dst if possible, otherwise copy it. /// /// If the destination already exists, it is removed before linking. -pub fn link_or_copy(src: impl AsRef, dst: impl AsRef) -> CargoResult<()> { +pub fn link_or_copy(src: impl AsRef, dst: impl AsRef) -> Result<()> { let src = src.as_ref(); let dst = dst.as_ref(); _link_or_copy(src, dst) } -fn _link_or_copy(src: &Path, dst: &Path) -> CargoResult<()> { +fn _link_or_copy(src: &Path, dst: &Path) -> Result<()> { log::debug!("linking {} to {}", src.display(), dst.display()); if same_file::is_same_file(src, dst).unwrap_or(false) { return Ok(()); @@ -486,7 +548,7 @@ fn _link_or_copy(src: &Path, dst: &Path) -> CargoResult<()> { log::debug!("link failed {}. falling back to fs::copy", err); fs::copy(src, dst).map(|_| ()) }) - .chain_err(|| { + .with_context(|| { format!( "failed to link or copy `{}` to `{}`", src.display(), @@ -497,11 +559,13 @@ fn _link_or_copy(src: &Path, dst: &Path) -> CargoResult<()> { } /// Copies a file from one location to another. -pub fn copy, Q: AsRef>(from: P, to: Q) -> CargoResult { +/// +/// Equivalent to [`std::fs::copy`] with better error messages. +pub fn copy, Q: AsRef>(from: P, to: Q) -> Result { let from = from.as_ref(); let to = to.as_ref(); fs::copy(from, to) - .chain_err(|| format!("failed to copy `{}` to `{}`", from.display(), to.display())) + .with_context(|| format!("failed to copy `{}` to `{}`", from.display(), to.display())) } /// Changes the filesystem mtime (and atime if possible) for the given file. @@ -551,7 +615,7 @@ pub fn strip_prefix_canonical>( /// /// This function is idempotent and in addition to that it won't exclude ``p`` from cache if it /// already exists. -pub fn create_dir_all_excluded_from_backups_atomic(p: impl AsRef) -> CargoResult<()> { +pub fn create_dir_all_excluded_from_backups_atomic(p: impl AsRef) -> Result<()> { let path = p.as_ref(); if path.is_dir() { return Ok(()); 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 7f5bf6fa392..bc02e677de9 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 00000000000..57feffbef67 --- /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/src/cargo/util/sha256.rs b/crates/cargo-util/src/sha256.rs similarity index 84% rename from src/cargo/util/sha256.rs rename to crates/cargo-util/src/sha256.rs index 36bb2cef6d7..58821f43f7a 100644 --- a/src/cargo/util/sha256.rs +++ b/crates/cargo-util/src/sha256.rs @@ -1,4 +1,5 @@ -use crate::util::{paths, CargoResult, CargoResultExt}; +use super::paths; +use anyhow::{Context, Result}; use crypto_hash::{Algorithm, Hasher}; use std::fs::File; use std::io::{self, Read, Write}; @@ -28,11 +29,11 @@ impl Sha256 { } } - pub fn update_path>(&mut self, path: P) -> CargoResult<&mut Sha256> { + pub fn update_path>(&mut self, path: P) -> Result<&mut Sha256> { let path = path.as_ref(); let file = paths::open(path)?; self.update_file(&file) - .chain_err(|| format!("failed to read `{}`", path.display()))?; + .with_context(|| format!("failed to read `{}`", path.display()))?; Ok(self) } diff --git a/crates/resolver-tests/Cargo.toml b/crates/resolver-tests/Cargo.toml index 1d98c6973cc..5a99241073b 100644 --- a/crates/resolver-tests/Cargo.toml +++ b/crates/resolver-tests/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] cargo = { path = "../.." } +cargo-util = { path = "../cargo-util" } proptest = "0.9.1" lazy_static = "1.3.0" varisat = "0.2.1" diff --git a/crates/resolver-tests/tests/resolve.rs b/crates/resolver-tests/tests/resolve.rs index bd5437faedb..e99c645a53c 100644 --- a/crates/resolver-tests/tests/resolve.rs +++ b/crates/resolver-tests/tests/resolve.rs @@ -1,6 +1,7 @@ use cargo::core::dependency::DepKind; use cargo::core::Dependency; -use cargo::util::{is_ci, Config}; +use cargo::util::Config; +use cargo_util::is_ci; use resolver_tests::{ assert_contains, assert_same, dep, dep_kind, dep_loc, dep_req, dep_req_kind, loc_names, names, diff --git a/publish.py b/publish.py index 4872c4d05a2..5ace18f7282 100755 --- a/publish.py +++ b/publish.py @@ -12,6 +12,7 @@ TO_PUBLISH = [ 'crates/cargo-platform', + 'crates/cargo-util', 'crates/crates-io', '.', ] diff --git a/src/bin/cargo/commands/help.rs b/src/bin/cargo/commands/help.rs index 4871fa530e9..798dd515a42 100644 --- a/src/bin/cargo/commands/help.rs +++ b/src/bin/cargo/commands/help.rs @@ -1,7 +1,7 @@ use crate::aliased_command; use cargo::util::errors::CargoResult; -use cargo::util::paths::resolve_executable; use cargo::Config; +use cargo_util::paths::resolve_executable; use flate2::read::GzDecoder; use std::ffi::OsString; use std::io::Read; diff --git a/src/bin/cargo/commands/run.rs b/src/bin/cargo/commands/run.rs index c8b711364d0..9a09497cb4b 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 3d1cab0822f..2b046464074 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 21bb63a8feb..1ae761b6dc3 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 593aaf2076d..4b488261ccf 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 fd40f4f3e05..b58e1c6dbeb 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::{CargoResult, CargoResultExt, Rustc}; use cargo_platform::{Cfg, CfgExpr}; +use cargo_util::{paths, 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 923894d076f..6ffe24a27e5 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 dbde49eb2c3..c1f5abce34c 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::{paths, 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::{config, 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) } @@ -272,7 +279,7 @@ impl<'cfg> Compilation<'cfg> { } } - let dylib_path = util::dylib_path(); + let dylib_path = paths::dylib_path(); let dylib_path_is_empty = dylib_path.is_empty(); search_path.extend(dylib_path.into_iter()); if cfg!(target_os = "macos") && dylib_path_is_empty { @@ -285,9 +292,9 @@ impl<'cfg> Compilation<'cfg> { search_path.push(PathBuf::from("/usr/local/lib")); search_path.push(PathBuf::from("/usr/lib")); } - let search_path = join_paths(&search_path, util::dylib_path_envvar())?; + let search_path = paths::join_paths(&search_path, paths::dylib_path_envvar())?; - cmd.env(util::dylib_path_envvar(), &search_path); + cmd.env(paths::dylib_path_envvar(), &search_path); if let Some(meta) = script_meta { if let Some(env) = self.extra_env.get(&meta) { for (k, v) in env { diff --git a/src/cargo/core/compiler/custom_build.rs b/src/cargo/core/compiler/custom_build.rs index 55f628f66ed..dbf86e73a1b 100644 --- a/src/cargo/core/compiler/custom_build.rs +++ b/src/cargo/core/compiler/custom_build.rs @@ -6,8 +6,9 @@ use crate::core::{profiles::ProfileRoot, PackageId}; use crate::util::errors::{CargoResult, CargoResultExt}; use crate::util::interning::InternedString; use crate::util::machine_message::{self, Message}; -use crate::util::{self, internal, paths, profile}; +use crate::util::{internal, profile}; use cargo_platform::Cfg; +use cargo_util::paths; use std::collections::hash_map::{Entry, HashMap}; use std::collections::{BTreeSet, HashSet}; use std::path::{Path, PathBuf}; @@ -395,7 +396,7 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { // modified in the middle of the build. paths::set_file_time_no_err(output_file, timestamp); paths::write(&err_file, &output.stderr)?; - paths::write(&root_output_file, util::path2bytes(&script_out_dir)?)?; + paths::write(&root_output_file, paths::path2bytes(&script_out_dir)?)?; let parsed_output = BuildOutput::parse( &output.stdout, pkg_name, @@ -849,7 +850,7 @@ fn prev_build_output(cx: &mut Context<'_, '_>, unit: &Unit) -> (Option return None, }; let bytes = read_bytes(bytes)?; - files.push((ty, util::bytes2path(bytes).ok()?)); + files.push((ty, paths::bytes2path(bytes).ok()?)); } let nenv = read_usize(bytes)?; @@ -1960,7 +1960,7 @@ impl EncodedDepInfo { DepInfoPathType::PackageRootRelative => dst.push(0), DepInfoPathType::TargetRootRelative => dst.push(1), } - write_bytes(dst, util::path2bytes(file)?); + write_bytes(dst, paths::path2bytes(file)?); } write_usize(dst, self.env.len()); diff --git a/src/cargo/core/compiler/job_queue.rs b/src/cargo/core/compiler/job_queue.rs index cf8f74f9acf..91eced6d4b5 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/layout.rs b/src/cargo/core/compiler/layout.rs index 29163122ea1..4f2aa5966c5 100644 --- a/src/cargo/core/compiler/layout.rs +++ b/src/cargo/core/compiler/layout.rs @@ -100,8 +100,8 @@ use crate::core::compiler::CompileTarget; use crate::core::Workspace; -use crate::util::paths; use crate::util::{CargoResult, FileLock}; +use cargo_util::paths; use std::path::{Path, PathBuf}; /// Contains the paths of all target output locations. diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 382e36ce6e0..ef0b6c4494d 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -54,11 +54,11 @@ 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::{add_path_args, internal, join_paths, paths, profile}; +use crate::util::machine_message::{self, Message}; +use crate::util::{add_path_args, internal, profile}; +use cargo_util::{paths, ProcessBuilder, ProcessError}; const RUSTDOC_CRATE_VERSION_FLAG: &str = "--crate-version"; @@ -303,7 +303,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, } } @@ -504,7 +504,7 @@ fn add_plugin_deps( build_scripts: &BuildScripts, root_output: &Path, ) -> CargoResult<()> { - let var = util::dylib_path_envvar(); + let var = paths::dylib_path_envvar(); let search_path = rustc.get_env(var).unwrap_or_default(); let mut search_path = env::split_paths(&search_path).collect::>(); for (pkg_id, metadata) in &build_scripts.plugins { @@ -516,7 +516,7 @@ fn add_plugin_deps( root_output, )); } - let search_path = join_paths(&search_path, var)?; + let search_path = paths::join_paths(&search_path, var)?; rustc.env(var, &search_path); Ok(()) } diff --git a/src/cargo/core/compiler/output_depinfo.rs b/src/cargo/core/compiler/output_depinfo.rs index 9c1cd3cf942..8804c7ba1dc 100644 --- a/src/cargo/core/compiler/output_depinfo.rs +++ b/src/cargo/core/compiler/output_depinfo.rs @@ -26,11 +26,10 @@ use std::collections::{BTreeSet, HashSet}; use std::io::{BufWriter, Write}; use std::path::{Path, PathBuf}; -use log::debug; - use super::{fingerprint, Context, FileFlavor, Unit}; -use crate::util::paths; use crate::util::{internal, CargoResult}; +use cargo_util::paths; +use log::debug; fn render_filename>(path: P, basedir: Option<&str>) -> CargoResult { let path = path.as_ref(); diff --git a/src/cargo/core/compiler/rustdoc.rs b/src/cargo/core/compiler/rustdoc.rs index a6f940785b2..f4de35bc427 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/compiler/timings.rs b/src/cargo/core/compiler/timings.rs index a206023a99e..182c078da74 100644 --- a/src/cargo/core/compiler/timings.rs +++ b/src/cargo/core/compiler/timings.rs @@ -8,7 +8,8 @@ use crate::core::compiler::BuildContext; use crate::core::PackageId; use crate::util::cpu::State; use crate::util::machine_message::{self, Message}; -use crate::util::{paths, CargoResult, CargoResultExt, Config}; +use crate::util::{CargoResult, CargoResultExt, Config}; +use cargo_util::paths; use std::collections::HashMap; use std::io::{BufWriter, Write}; use std::time::{Duration, Instant, SystemTime}; diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index cdebf99a6a7..b2030b2b201 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/core/workspace.rs b/src/cargo/core/workspace.rs index 2a0ef5b5d74..7fcbeaf07dc 100644 --- a/src/cargo/core/workspace.rs +++ b/src/cargo/core/workspace.rs @@ -19,9 +19,9 @@ use crate::ops; use crate::sources::{PathSource, CRATES_IO_INDEX, CRATES_IO_REGISTRY}; use crate::util::errors::{CargoResult, CargoResultExt, ManifestError}; use crate::util::interning::InternedString; -use crate::util::paths; use crate::util::toml::{read_manifest, TomlDependency, TomlProfiles}; use crate::util::{config::ConfigRelativePath, Config, Filesystem, IntoUrl}; +use cargo_util::paths; /// The core abstraction in Cargo for working with a workspace of crates. /// diff --git a/src/cargo/ops/cargo_clean.rs b/src/cargo/ops/cargo_clean.rs index 6680d7a06d8..ad2171e827b 100644 --- a/src/cargo/ops/cargo_clean.rs +++ b/src/cargo/ops/cargo_clean.rs @@ -5,8 +5,8 @@ use crate::ops; use crate::util::errors::{CargoResult, CargoResultExt}; use crate::util::interning::InternedString; use crate::util::lev_distance; -use crate::util::paths; use crate::util::Config; +use cargo_util::paths; use std::fs; use std::path::Path; diff --git a/src/cargo/ops/cargo_install.rs b/src/cargo/ops/cargo_install.rs index 5d3fbb8c658..ca53cbcdd96 100644 --- a/src/cargo/ops/cargo_install.rs +++ b/src/cargo/ops/cargo_install.rs @@ -3,17 +3,17 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use std::{env, fs}; -use anyhow::{bail, format_err}; -use semver::VersionReq; -use tempfile::Builder as TempFileBuilder; - use crate::core::compiler::{CompileKind, DefaultExecutor, Executor, Freshness, UnitOutput}; use crate::core::{Dependency, Edition, Package, PackageId, Source, SourceId, Workspace}; use crate::ops::common_for_install_and_uninstall::*; use crate::sources::{GitSource, PathSource, SourceConfigMap}; use crate::util::errors::{CargoResult, CargoResultExt}; -use crate::util::{paths, Config, Filesystem, Rustc, ToSemver}; +use crate::util::{Config, Filesystem, Rustc, ToSemver}; use crate::{drop_println, ops}; +use anyhow::{bail, format_err}; +use cargo_util::paths; +use semver::VersionReq; +use tempfile::Builder as TempFileBuilder; struct Transaction { bins: Vec, diff --git a/src/cargo/ops/cargo_new.rs b/src/cargo/ops/cargo_new.rs index 25b88d11352..4ad6e7a78b1 100644 --- a/src/cargo/ops/cargo_new.rs +++ b/src/cargo/ops/cargo_new.rs @@ -1,7 +1,8 @@ use crate::core::{Edition, Shell, Workspace}; use crate::util::errors::{CargoResult, CargoResultExt}; use crate::util::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo}; -use crate::util::{paths, restricted_names, Config}; +use crate::util::{restricted_names, Config}; +use cargo_util::paths; use git2::Config as GitConfig; use git2::Repository as GitRepository; use serde::de; diff --git a/src/cargo/ops/cargo_package.rs b/src/cargo/ops/cargo_package.rs index a07f9fe072d..afa41efd21c 100644 --- a/src/cargo/ops/cargo_package.rs +++ b/src/cargo/ops/cargo_package.rs @@ -6,20 +6,19 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use std::sync::Arc; -use flate2::read::GzDecoder; -use flate2::{Compression, GzBuilder}; -use log::debug; -use tar::{Archive, Builder, EntryType, Header, HeaderMode}; - use crate::core::compiler::{BuildConfig, CompileMode, DefaultExecutor, Executor}; use crate::core::{Feature, Shell, Verbosity, Workspace}; use crate::core::{Package, PackageId, PackageSet, Resolve, Source, SourceId}; use crate::sources::PathSource; use crate::util::errors::{CargoResult, CargoResultExt}; -use crate::util::paths; use crate::util::toml::TomlManifest; use crate::util::{self, restricted_names, Config, FileLock}; use crate::{drop_println, ops}; +use cargo_util::paths; +use flate2::read::GzDecoder; +use flate2::{Compression, GzBuilder}; +use log::debug; +use tar::{Archive, Builder, EntryType, Header, HeaderMode}; pub struct PackageOpts<'cfg> { pub config: &'cfg Config, @@ -480,7 +479,7 @@ fn tar( // Prepare the encoder and its header. let filename = Path::new(filename); let encoder = GzBuilder::new() - .filename(util::path2bytes(filename)?) + .filename(paths::path2bytes(filename)?) .write(dst, Compression::best()); // Put all package files into a compressed archive. diff --git a/src/cargo/ops/cargo_read_manifest.rs b/src/cargo/ops/cargo_read_manifest.rs index 95975c8c153..732ef39d613 100644 --- a/src/cargo/ops/cargo_read_manifest.rs +++ b/src/cargo/ops/cargo_read_manifest.rs @@ -3,13 +3,13 @@ use std::fs; use std::io; use std::path::{Path, PathBuf}; -use log::{info, trace}; - use crate::core::{EitherManifest, Package, PackageId, SourceId}; use crate::util::errors::CargoResult; use crate::util::important_paths::find_project_manifest_exact; use crate::util::toml::read_manifest; -use crate::util::{self, Config}; +use crate::util::Config; +use cargo_util::paths; +use log::{info, trace}; pub fn read_package( path: &Path, @@ -192,7 +192,7 @@ fn read_nested_packages( // TODO: filesystem/symlink implications? if !source_id.is_registry() { for p in nested.iter() { - let path = util::normalize_path(&path.join(p)); + let path = paths::normalize_path(&path.join(p)); let result = read_nested_packages(&path, all_packages, source_id, config, visited, errors); // Ignore broken manifests found on git repositories. diff --git a/src/cargo/ops/cargo_test.rs b/src/cargo/ops/cargo_test.rs index 835ba323c59..9fcb94f1336 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/cargo_uninstall.rs b/src/cargo/ops/cargo_uninstall.rs index 6f07940c215..3551544183b 100644 --- a/src/cargo/ops/cargo_uninstall.rs +++ b/src/cargo/ops/cargo_uninstall.rs @@ -1,15 +1,14 @@ -use anyhow::bail; -use std::collections::BTreeSet; -use std::env; - use crate::core::PackageId; use crate::core::{PackageIdSpec, SourceId}; use crate::ops::common_for_install_and_uninstall::*; use crate::sources::PathSource; use crate::util::errors::CargoResult; -use crate::util::paths; use crate::util::Config; use crate::util::Filesystem; +use anyhow::bail; +use cargo_util::paths; +use std::collections::BTreeSet; +use std::env; pub fn uninstall( root: Option<&str>, diff --git a/src/cargo/ops/fix.rs b/src/cargo/ops/fix.rs index 00da8d7b7e4..9cb7bc41b94 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::{paths, 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::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)?; @@ -595,7 +596,7 @@ fn rustfix_and_fix( // Attempt to read the source code for this file. If this fails then // that'd be pretty surprising, so log a message and otherwise keep // going. - let code = match util::paths::read(file.as_ref()) { + let code = match paths::read(file.as_ref()) { Ok(s) => s, Err(e) => { warn!("failed to read `{}`: {}", file, e); diff --git a/src/cargo/ops/registry.rs b/src/cargo/ops/registry.rs index e95918efb90..7fef70b65ac 100644 --- a/src/cargo/ops/registry.rs +++ b/src/cargo/ops/registry.rs @@ -8,6 +8,7 @@ use std::time::Duration; use std::{cmp, env}; use anyhow::{bail, format_err}; +use cargo_util::paths; use crates_io::{self, NewCrate, NewCrateDependency, Registry}; use curl::easy::{Easy, InfoType, SslOpt, SslVersion}; use log::{log, Level}; @@ -22,8 +23,8 @@ use crate::sources::{RegistrySource, SourceConfigMap, CRATES_IO_REGISTRY}; use crate::util::config::{self, Config, SslVersionConfig, SslVersionConfigRange}; use crate::util::errors::{CargoResult, CargoResultExt}; use crate::util::important_paths::find_root_manifest_for_wd; +use crate::util::validate_package_name; use crate::util::IntoUrl; -use crate::util::{paths, validate_package_name}; use crate::{drop_print, drop_println, version}; mod auth; diff --git a/src/cargo/ops/registry/auth.rs b/src/cargo/ops/registry/auth.rs index 660daa40d95..b76a08fc7c5 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/ops/vendor.rs b/src/cargo/ops/vendor.rs index 7c4a8f1050e..cae24d471c6 100644 --- a/src/cargo/ops/vendor.rs +++ b/src/cargo/ops/vendor.rs @@ -2,9 +2,9 @@ use crate::core::shell::Verbosity; use crate::core::{GitReference, Workspace}; use crate::ops; use crate::sources::path::PathSource; -use crate::util::Sha256; -use crate::util::{paths, CargoResult, CargoResultExt, Config}; +use crate::util::{CargoResult, CargoResultExt, Config}; use anyhow::bail; +use cargo_util::{paths, Sha256}; use serde::Serialize; use std::collections::HashSet; use std::collections::{BTreeMap, BTreeSet, HashMap}; diff --git a/src/cargo/sources/directory.rs b/src/cargo/sources/directory.rs index 3e6daf034b8..cc1324087cd 100644 --- a/src/cargo/sources/directory.rs +++ b/src/cargo/sources/directory.rs @@ -2,14 +2,13 @@ use std::collections::HashMap; use std::fmt::{self, Debug, Formatter}; use std::path::{Path, PathBuf}; -use serde::Deserialize; - use crate::core::source::MaybePackage; use crate::core::{Dependency, Package, PackageId, Source, SourceId, Summary}; use crate::sources::PathSource; use crate::util::errors::{CargoResult, CargoResultExt}; -use crate::util::paths; -use crate::util::{Config, Sha256}; +use crate::util::Config; +use cargo_util::{paths, Sha256}; +use serde::Deserialize; pub struct DirectorySource<'cfg> { source_id: SourceId, diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs index 1998f27a23e..fc23a2e221d 100644 --- a/src/cargo/sources/git/utils.rs +++ b/src/cargo/sources/git/utils.rs @@ -3,10 +3,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::{paths, ProcessBuilder}; use curl::easy::List; use git2::{self, ErrorClass, ObjectType}; use log::{debug, info}; @@ -835,7 +834,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/sources/path.rs b/src/cargo/sources/path.rs index 64b0f77ed5a..0de72a1ba6b 100644 --- a/src/cargo/sources/path.rs +++ b/src/cargo/sources/path.rs @@ -2,16 +2,16 @@ use std::fmt::{self, Debug, Formatter}; use std::fs; use std::path::{Path, PathBuf}; +use crate::core::source::MaybePackage; +use crate::core::{Dependency, Package, PackageId, Source, SourceId, Summary}; +use crate::ops; +use crate::util::{internal, CargoResult, CargoResultExt, Config}; +use cargo_util::paths; use filetime::FileTime; use ignore::gitignore::GitignoreBuilder; use ignore::Match; use log::{trace, warn}; -use crate::core::source::MaybePackage; -use crate::core::{Dependency, Package, PackageId, Source, SourceId, Summary}; -use crate::ops; -use crate::util::{internal, paths, CargoResult, CargoResultExt, Config}; - pub struct PathSource<'cfg> { source_id: SourceId, path: PathBuf, diff --git a/src/cargo/sources/registry/index.rs b/src/cargo/sources/registry/index.rs index e454ee7ee2a..ae837d450d6 100644 --- a/src/cargo/sources/registry/index.rs +++ b/src/cargo/sources/registry/index.rs @@ -70,9 +70,9 @@ use crate::core::dependency::Dependency; use crate::core::{PackageId, SourceId, Summary}; use crate::sources::registry::{RegistryData, RegistryPackage, INDEX_V_MAX}; use crate::util::interning::InternedString; -use crate::util::paths; use crate::util::{internal, CargoResult, Config, Filesystem, ToSemver}; use anyhow::bail; +use cargo_util::paths; use log::{debug, info}; use semver::{Version, VersionReq}; use std::collections::{HashMap, HashSet}; diff --git a/src/cargo/sources/registry/local.rs b/src/cargo/sources/registry/local.rs index 7276c688b58..cccc553ee9e 100644 --- a/src/cargo/sources/registry/local.rs +++ b/src/cargo/sources/registry/local.rs @@ -2,8 +2,8 @@ use crate::core::PackageId; use crate::sources::registry::{MaybeLock, RegistryConfig, RegistryData}; use crate::util::errors::CargoResult; use crate::util::interning::InternedString; -use crate::util::paths; -use crate::util::{Config, Filesystem, Sha256}; +use crate::util::{Config, Filesystem}; +use cargo_util::{paths, Sha256}; use std::fs::File; use std::io::prelude::*; use std::io::SeekFrom; diff --git a/src/cargo/sources/registry/remote.rs b/src/cargo/sources/registry/remote.rs index 91bf3301b21..890bb8a68c6 100644 --- a/src/cargo/sources/registry/remote.rs +++ b/src/cargo/sources/registry/remote.rs @@ -7,8 +7,8 @@ use crate::sources::registry::{ }; use crate::util::errors::{CargoResult, CargoResultExt}; use crate::util::interning::InternedString; -use crate::util::paths; -use crate::util::{Config, Filesystem, Sha256}; +use crate::util::{Config, Filesystem}; +use cargo_util::{paths, Sha256}; use lazycell::LazyCell; use log::{debug, trace}; use std::cell::{Cell, Ref, RefCell}; diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index d27fbfb972c..de793b68dce 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -5,13 +5,14 @@ use crate::sources::CRATES_IO_REGISTRY; use crate::util::important_paths::find_root_manifest_for_wd; use crate::util::interning::InternedString; use crate::util::restricted_names::is_glob_pattern; -use crate::util::{paths, toml::TomlProfile, validate_package_name}; use crate::util::{ print_available_benches, print_available_binaries, print_available_examples, print_available_packages, print_available_tests, }; +use crate::util::{toml::TomlProfile, validate_package_name}; use crate::CargoResult; use anyhow::bail; +use cargo_util::paths; use clap::{self, SubCommand}; use std::ffi::{OsStr, OsString}; use std::path::PathBuf; diff --git a/src/cargo/util/config/mod.rs b/src/cargo/util/config/mod.rs index b7b4ed36712..4da14cb1a65 100644 --- a/src/cargo/util/config/mod.rs +++ b/src/cargo/util/config/mod.rs @@ -65,12 +65,6 @@ use std::str::FromStr; use std::sync::Once; use std::time::Instant; -use anyhow::{anyhow, bail, format_err}; -use curl::easy::Easy; -use lazycell::LazyCell; -use serde::Deserialize; -use url::Url; - use self::ConfigValue as CV; use crate::core::compiler::rustdoc::RustdocExternMap; use crate::core::shell::Verbosity; @@ -78,8 +72,14 @@ use crate::core::{features, CliUnstable, Shell, SourceId, Workspace}; use crate::ops; use crate::util::errors::{CargoResult, CargoResultExt}; use crate::util::toml as cargo_toml; -use crate::util::{paths, validate_package_name}; +use crate::util::validate_package_name; use crate::util::{FileLock, Filesystem, IntoUrl, IntoUrlWithBase, Rustc}; +use anyhow::{anyhow, bail, format_err}; +use cargo_util::paths; +use curl::easy::Easy; +use lazycell::LazyCell; +use serde::Deserialize; +use url::Url; mod de; use de::Deserializer; diff --git a/src/cargo/util/diagnostic_server.rs b/src/cargo/util/diagnostic_server.rs index 1fedf621cba..cd1ae0c41ef 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 cf4ceb4bfdb..94e255bca53 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/flock.rs b/src/cargo/util/flock.rs index 985ef6e24e0..98a77865c37 100644 --- a/src/cargo/util/flock.rs +++ b/src/cargo/util/flock.rs @@ -3,12 +3,11 @@ use std::io; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::{Display, Path, PathBuf}; -use termcolor::Color::Cyan; - use crate::util::errors::{CargoResult, CargoResultExt}; -use crate::util::paths; use crate::util::Config; +use cargo_util::paths; use sys::*; +use termcolor::Color::Cyan; #[derive(Debug)] pub struct FileLock { diff --git a/src/cargo/util/important_paths.rs b/src/cargo/util/important_paths.rs index a03cbcc8223..4d34519c2ba 100644 --- a/src/cargo/util/important_paths.rs +++ b/src/cargo/util/important_paths.rs @@ -1,5 +1,5 @@ use crate::util::errors::CargoResult; -use crate::util::paths; +use cargo_util::paths; use std::path::{Path, PathBuf}; /// Finds the root `Cargo.toml`. diff --git a/src/cargo/util/mod.rs b/src/cargo/util/mod.rs index 42b243bf917..9dcf6b0c084 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; @@ -15,15 +14,10 @@ pub use self::into_url::IntoUrl; pub use self::into_url_with_base::IntoUrlWithBase; 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; pub use self::to_semver::ToSemver; pub use self::vcs::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo}; pub use self::workspace::{ @@ -51,15 +45,11 @@ pub mod lev_distance; 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; pub mod to_semver; pub mod toml; mod vcs; @@ -75,11 +65,6 @@ pub fn elapsed(duration: Duration) -> String { } } -/// Whether or not this running in a Continuous Integration environment. -pub fn is_ci() -> bool { - std::env::var("CI").is_ok() || std::env::var("TF_BUILD").is_ok() -} - pub fn indented_lines(text: &str) -> String { text.lines() .map(|line| { diff --git a/src/cargo/util/progress.rs b/src/cargo/util/progress.rs index 2f58a3d0dc5..7996d8a959d 100644 --- a/src/cargo/util/progress.rs +++ b/src/cargo/util/progress.rs @@ -4,8 +4,8 @@ use std::time::{Duration, Instant}; use crate::core::shell::Verbosity; use crate::util::config::ProgressWhen; -use crate::util::{is_ci, CargoResult, Config}; - +use crate::util::{CargoResult, Config}; +use cargo_util::is_ci; use unicode_width::UnicodeWidthChar; pub struct Progress<'cfg> { diff --git a/src/cargo/util/rustc.rs b/src/cargo/util/rustc.rs index 2b2d1e2950a..fd467b11317 100644 --- a/src/cargo/util/rustc.rs +++ b/src/cargo/util/rustc.rs @@ -4,12 +4,12 @@ use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use std::sync::Mutex; +use cargo_util::{paths, 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 +47,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 +86,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 +232,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 +245,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/toml/mod.rs b/src/cargo/util/toml/mod.rs index b0bf3173608..ac2f90aadb9 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -7,6 +7,7 @@ use std::str; use anyhow::{anyhow, bail}; use cargo_platform::Platform; +use cargo_util::paths; use log::{debug, trace}; use semver::{self, VersionReq}; use serde::de; @@ -23,9 +24,7 @@ use crate::core::{GitReference, PackageIdSpec, SourceId, WorkspaceConfig, Worksp use crate::sources::{CRATES_IO_INDEX, CRATES_IO_REGISTRY}; use crate::util::errors::{CargoResult, CargoResultExt, ManifestError}; use crate::util::interning::InternedString; -use crate::util::{ - self, config::ConfigRelativePath, paths, validate_package_name, Config, IntoUrl, -}; +use crate::util::{self, config::ConfigRelativePath, validate_package_name, Config, IntoUrl}; mod targets; use self::targets::targets; @@ -1774,7 +1773,7 @@ impl DetailedTomlDependency

{ // built from. if cx.source_id.is_path() { let path = cx.root.join(path); - let path = util::normalize_path(&path); + let path = paths::normalize_path(&path); SourceId::for_path(&path)? } else { cx.source_id diff --git a/src/cargo/util/vcs.rs b/src/cargo/util/vcs.rs index 6a66870c8f6..babd0075838 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::paths; +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 0cac29f677f..e8317f101e4 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/internal.rs b/tests/internal.rs index f6d9e5e16c0..41fb43306c5 100644 --- a/tests/internal.rs +++ b/tests/internal.rs @@ -4,7 +4,7 @@ use std::fs; #[test] fn check_forbidden_code() { // Do not use certain macros, functions, etc. - if !cargo::util::is_ci() { + if !cargo_util::is_ci() { // Only check these on CI, otherwise it could be annoying. use std::io::Write; writeln!( diff --git a/tests/testsuite/build.rs b/tests/testsuite/build.rs index 7276aea8710..65aa90862b7 100644 --- a/tests/testsuite/build.rs +++ b/tests/testsuite/build.rs @@ -4,7 +4,6 @@ use cargo::{ core::compiler::CompileMode, core::{Shell, Workspace}, ops::CompileOptions, - util::paths::dylib_path_envvar, Config, }; use cargo_test_support::paths::{root, CargoPathExt}; @@ -14,6 +13,7 @@ use cargo_test_support::{ lines_match_unordered, main_file, paths, process, project, rustc_host, sleep_ms, symlink_supported, t, Execs, ProjectBuilder, }; +use cargo_util::paths::dylib_path_envvar; use std::env; use std::fs; use std::io::Read; @@ -5377,7 +5377,7 @@ fn reduced_reproduction_8249() { .build(); p.cargo("generate-lockfile").run(); - cargo::util::paths::append(&p.root().join("Cargo.toml"), b"c = \"*\"").unwrap(); + cargo_util::paths::append(&p.root().join("Cargo.toml"), b"c = \"*\"").unwrap(); p.cargo("check").run(); p.cargo("check").run(); } diff --git a/tests/testsuite/build_script.rs b/tests/testsuite/build_script.rs index 89b38810aeb..ddaa9a5edd5 100644 --- a/tests/testsuite/build_script.rs +++ b/tests/testsuite/build_script.rs @@ -1,15 +1,14 @@ //! Tests for build.rs scripts. -use std::env; -use std::fs; -use std::io; -use std::thread; - -use cargo::util::paths::remove_dir_all; use cargo_test_support::paths::CargoPathExt; use cargo_test_support::registry::Package; use cargo_test_support::{basic_manifest, cross_compile, is_coarse_mtime, project}; use cargo_test_support::{rustc_host, sleep_ms, slow_cpu_multiplier, symlink_supported}; +use cargo_util::paths::remove_dir_all; +use std::env; +use std::fs; +use std::io; +use std::thread; #[cargo_test] fn custom_build_script_failed() { diff --git a/tests/testsuite/corrupt_git.rs b/tests/testsuite/corrupt_git.rs index 835eb97a44b..066fb7a6645 100644 --- a/tests/testsuite/corrupt_git.rs +++ b/tests/testsuite/corrupt_git.rs @@ -1,11 +1,10 @@ //! Tests for corrupt git repos. -use std::fs; -use std::path::{Path, PathBuf}; - -use cargo::util::paths as cargopaths; use cargo_test_support::paths; use cargo_test_support::{basic_manifest, git, project}; +use cargo_util::paths as cargopaths; +use std::fs; +use std::path::{Path, PathBuf}; #[cargo_test] fn deleting_database_files() { diff --git a/tests/testsuite/credential_process.rs b/tests/testsuite/credential_process.rs index 69d839aa85e..120de20277f 100644 --- a/tests/testsuite/credential_process.rs +++ b/tests/testsuite/credential_process.rs @@ -209,7 +209,7 @@ fn publish() { fn basic_unsupported() { // Non-action commands don't support login/logout. registry::RegistryBuilder::new().add_tokens(false).build(); - cargo::util::paths::append( + cargo_util::paths::append( &paths::home().join(".cargo/config"), br#" [registry] @@ -271,7 +271,7 @@ fn login() { .build(); cred_proj.cargo("build").run(); - cargo::util::paths::append( + cargo_util::paths::append( &paths::home().join(".cargo/config"), format!( r#" @@ -323,7 +323,7 @@ fn logout() { .build(); cred_proj.cargo("build").run(); - cargo::util::paths::append( + cargo_util::paths::append( &paths::home().join(".cargo/config"), format!( r#" @@ -390,7 +390,7 @@ fn owner() { fn libexec_path() { // cargo: prefixed names use the sysroot registry::RegistryBuilder::new().add_tokens(false).build(); - cargo::util::paths::append( + cargo_util::paths::append( &paths::home().join(".cargo/config"), br#" [registry] @@ -428,7 +428,7 @@ fn invalid_token_output() { .build(); cred_proj.cargo("build").run(); - cargo::util::paths::append( + cargo_util::paths::append( &paths::home().join(".cargo/config"), format!( r#" diff --git a/tests/testsuite/old_cargos.rs b/tests/testsuite/old_cargos.rs index 05c2a68626b..f9e239a5546 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"); diff --git a/tests/testsuite/registry.rs b/tests/testsuite/registry.rs index 441e965744a..9b93c02b1e3 100644 --- a/tests/testsuite/registry.rs +++ b/tests/testsuite/registry.rs @@ -1,11 +1,12 @@ //! Tests for normal registry dependencies. -use cargo::{core::SourceId, util::paths::remove_dir_all}; +use cargo::core::SourceId; use cargo_test_support::paths::{self, CargoPathExt}; use cargo_test_support::registry::{self, registry_path, Dependency, Package}; use cargo_test_support::{basic_manifest, project}; use cargo_test_support::{cargo_process, registry::registry_url}; use cargo_test_support::{git, install::cargo_home, t}; +use cargo_util::paths::remove_dir_all; use std::fs::{self, File}; use std::path::Path; diff --git a/tests/testsuite/run.rs b/tests/testsuite/run.rs index 9d52afaf7b0..5b2f274cda3 100644 --- a/tests/testsuite/run.rs +++ b/tests/testsuite/run.rs @@ -1,7 +1,7 @@ //! Tests for the `cargo run` command. -use cargo::util::paths::dylib_path_envvar; use cargo_test_support::{basic_bin_manifest, basic_lib_manifest, project, Project}; +use cargo_util::paths::dylib_path_envvar; #[cargo_test] fn simple() { diff --git a/tests/testsuite/rustdoc_extern_html.rs b/tests/testsuite/rustdoc_extern_html.rs index 820cf7bd644..6281190af98 100644 --- a/tests/testsuite/rustdoc_extern_html.rs +++ b/tests/testsuite/rustdoc_extern_html.rs @@ -69,7 +69,7 @@ fn std_docs() { // For local developers, skip this test if docs aren't installed. let docs = std::path::Path::new(&paths::sysroot()).join("share/doc/rust/html"); if !docs.exists() { - if cargo::util::is_ci() { + if cargo_util::is_ci() { panic!("std docs are not installed, check that the rust-docs component is installed"); } else { eprintln!(