Auto merge of #9292 - ehuss:cargo-util, r=alexcrichton

Split out cargo-util package for cargo-test-support.

This splits out code from `cargo` that was being used by `cargo-test-support` in order to remove the dev-dependency cycle on the `cargo` crate. The intent here is to improve development build times. On my system, `touch src/cargo/lib.rs ; cargo check --profile=test` goes from 6.4 seconds to 3.5. I suspect more substantial changes (more than just `touch`) should exhibit even more improvements.

This has a substantial downside that it is another package to manage publishing, particularly with making sure the version is updated correctly for crates.io. I'm uncertain if on balance it is worth it, but I lean towards moving forward with it.
This commit is contained in:
bors 2021-03-22 14:11:51 +00:00
commit fb45eb132e
74 changed files with 656 additions and 508 deletions

View file

@ -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

View file

@ -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]

View file

@ -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"

View file

@ -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<Output> {
let run_cross_test = || -> anyhow::Result<Output> {
let p = project()
.at("cross_test")
.file("Cargo.toml", &basic_manifest("cross_test", "1.0.0"))

View file

@ -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<Output> {
pub fn exec_with_output(&mut self) -> anyhow::Result<Output> {
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: AsRef<OsStr>>(t: T) -> cargo::util::ProcessBuilder {
pub fn process<T: AsRef<OsStr>>(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")
}

View file

@ -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`"),
};

View file

@ -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"] }

View file

@ -0,0 +1 @@
../../LICENSE-APACHE

View file

@ -0,0 +1 @@
../../LICENSE-MIT

View file

@ -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()
}

View file

@ -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<T: AsRef<OsStr>>(paths: &[T], env: &str) -> CargoResult<OsString> {
/// 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<T: AsRef<OsStr>>(paths: &[T], env: &str) -> Result<OsString> {
env::join_paths(paths.iter())
.chain_err(|| {
.with_context(|| {
let paths = paths.iter().map(Path::new).collect::<Vec<_>>();
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<T: AsRef<OsStr>>(paths: &[T], env: &str) -> CargoResult<OsStri
})
}
/// Returns the name of the environment variable used for searching for
/// dynamic libraries.
pub fn dylib_path_envvar() -> &'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<PathBuf> {
match env::var_os(dylib_path_envvar()) {
Some(var) => env::split_paths(&var).collect(),
@ -58,6 +70,14 @@ pub fn dylib_path() -> Vec<PathBuf> {
}
}
/// 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<PathBuf> {
/// 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<PathBuf> {
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<PathBuf> {
}
}
pub fn read(path: &Path) -> CargoResult<String> {
/// Reads a file to a string.
///
/// Equivalent to [`std::fs::read_to_string`] with better error messages.
pub fn read(path: &Path) -> Result<String> {
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<Vec<u8>> {
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<Vec<u8>> {
fs::read(path).with_context(|| format!("failed to read `{}`", path.display()))
}
pub fn write<P: AsRef<Path>, 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<P: AsRef<Path>, 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<P: AsRef<Path>, 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<P: AsRef<Path>, 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<P: AsRef<Path>, 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<P: AsRef<Path>>(path: P) -> CargoResult<File> {
pub fn create<P: AsRef<Path>>(path: P) -> Result<File> {
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<P: AsRef<Path>>(path: P) -> CargoResult<File> {
pub fn open<P: AsRef<Path>>(path: P) -> Result<File> {
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<FileTime> {
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<FileTime> {
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<FileTime> {
let meta = fs::metadata(path).chain_err(|| format!("failed to stat `{}`", path.display()))?;
pub fn mtime_recursive(path: &Path) -> Result<FileTime> {
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<FileTime> {
/// 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<FileTime> {
pub fn set_invocation_time(path: &Path) -> Result<FileTime> {
// 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<FileTime> {
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<PathBuf> {
use std::os::unix::prelude::*;
Ok(PathBuf::from(OsStr::from_bytes(bytes)))
}
#[cfg(windows)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
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<PathBuf> {
#[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<Path>) -> CargoResult<()> {
/// Equivalent to [`std::fs::create_dir_all`] with better error messages.
pub fn create_dir_all(p: impl AsRef<Path>) -> 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: AsRef<Path>>(p: P) -> CargoResult<()> {
/// Recursively remove all files and directories at the given directory.
///
/// This does *not* follow symlinks.
pub fn remove_dir_all<P: AsRef<Path>>(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: AsRef<Path>>(p: P) -> CargoResult<()> {
/// Equivalent to [`std::fs::remove_dir`] with better error messages.
pub fn remove_dir<P: AsRef<Path>>(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: AsRef<Path>>(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: AsRef<Path>>(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<bool> {
/// 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<Path>, dst: impl AsRef<Path>) -> CargoResult<()> {
pub fn link_or_copy(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> 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<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> CargoResult<u64> {
///
/// Equivalent to [`std::fs::copy`] with better error messages.
pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<u64> {
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<P: AsRef<Path>>(
///
/// 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<Path>) -> CargoResult<()> {
pub fn create_dir_all_excluded_from_backups_atomic(p: impl AsRef<Path>) -> Result<()> {
let path = p.as_ref();
if path.is_dir() {
return Ok(());

View file

@ -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<String, Option<OsString>>,
/// The directory to run the program from.
cwd: Option<OsString>,
/// 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<Client>,
/// `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<T: AsRef<OsStr>>(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<T: AsRef<OsStr>>(&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<Output> {
pub fn exec_with_output(&self) -> Result<Output> {
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<Output> {
) -> Result<Output> {
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<T: AsRef<OsStr>>(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());
}
}

View file

@ -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<i32>,
/// The stdout from the process.
///
/// This can be `None` if the process failed to launch, or the output was
/// not captured.
pub stdout: Option<Vec<u8>>,
/// The stderr from the process.
///
/// This can be `None` if the process failed to launch, or the output was
/// not captured.
pub stderr: Option<Vec<u8>>,
}
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<ExitStatus>, 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<i32>,
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
}

View file

@ -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<P: AsRef<Path>>(&mut self, path: P) -> CargoResult<&mut Sha256> {
pub fn update_path<P: AsRef<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)
}

View file

@ -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"

View file

@ -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,

View file

@ -12,6 +12,7 @@ from urllib.error import HTTPError
TO_PUBLISH = [
'crates/cargo-platform',
'crates/cargo-util',
'crates/crates-io',
'.',
]

View file

@ -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;

View file

@ -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")

View file

@ -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),
};

View file

@ -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()

View file

@ -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;

View file

@ -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};

View file

@ -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 {

View file

@ -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<Metadata>,
) -> CargoResult<ProcessBuilder> {
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<ProcessBuilder> {
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<String>)> {
@ -229,12 +236,12 @@ impl<'cfg> Compilation<'cfg> {
script_meta: Option<Metadata>,
) -> CargoResult<ProcessBuilder> {
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 {

View file

@ -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<Job> {
// 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<BuildOutp
let output_file = script_run_dir.join("output");
let prev_script_out_dir = paths::read_bytes(&root_output_file)
.and_then(|bytes| util::bytes2path(&bytes))
.and_then(|bytes| paths::bytes2path(&bytes))
.unwrap_or_else(|_| script_out_dir.clone());
let extra_link_arg = cx.bcx.config.cli_unstable().extra_link_arg;

View file

@ -322,6 +322,7 @@ use std::sync::{Arc, Mutex};
use std::time::SystemTime;
use anyhow::{bail, format_err};
use cargo_util::{paths, ProcessBuilder};
use filetime::FileTime;
use log::{debug, info};
use serde::de;
@ -333,8 +334,7 @@ use crate::core::Package;
use crate::util;
use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::interning::InternedString;
use crate::util::paths;
use crate::util::{internal, path_args, profile, ProcessBuilder};
use crate::util::{internal, path_args, profile};
use super::custom_build::BuildDeps;
use super::job::{Job, Work};
@ -1915,7 +1915,7 @@ impl EncodedDepInfo {
_ => 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());

View file

@ -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

View file

@ -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.

View file

@ -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<dyn Executor>) -> 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::<Vec<_>>();
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(())
}

View file

@ -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<P: AsRef<Path>>(path: P, basedir: Option<&str>) -> CargoResult<String> {
let path = path.as_ref();

View file

@ -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;

View file

@ -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};

View file

@ -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 =

View file

@ -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.
///

View file

@ -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;

View file

@ -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<PathBuf>,

View file

@ -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;

View file

@ -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.

View file

@ -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.

View file

@ -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,

View file

@ -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>,

View file

@ -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<bool> {
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);

View file

@ -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;

View file

@ -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(),

View file

@ -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};

View file

@ -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,

View file

@ -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");

View file

@ -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,

View file

@ -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};

View file

@ -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;

View file

@ -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};

View file

@ -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;

View file

@ -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;

View file

@ -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 =

View file

@ -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<T> = anyhow::Result<T>;
@ -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<i32>,
/// The stdout from the process.
///
/// This can be `None` if the process failed to launch, or the output was
/// not captured.
pub stdout: Option<Vec<u8>>,
/// The stderr from the process.
///
/// This can be `None` if the process failed to launch, or the output was
/// not captured.
pub stderr: Option<Vec<u8>>,
}
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<clap::Error> 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<ExitStatus>,
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<i32>,
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<S: fmt::Display>(error: S) -> anyhow::Error {
InternalError::new(anyhow::format_err!("{}", error)).into()
}

View file

@ -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 {

View file

@ -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`.

View file

@ -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| {

View file

@ -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> {

View file

@ -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,

View file

@ -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<P: ResolveToPath> DetailedTomlDependency<P> {
// 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

View file

@ -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<HgRepo> {
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<HgRepo> {
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<PijulRepo> {
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")

View file

@ -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;

View file

@ -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!(

View file

@ -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();
}

View file

@ -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() {

View file

@ -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() {

View file

@ -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#"

View file

@ -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");

View file

@ -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;

View file

@ -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() {

View file

@ -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!(