| use std::path::{Path, PathBuf}; |
| use std::time::Duration; |
| |
| pub use self::canonical_url::CanonicalUrl; |
| pub(crate) use self::counter::MetricsCounter; |
| pub use self::dependency_queue::DependencyQueue; |
| pub use self::diagnostic_server::RustfixDiagnosticServer; |
| pub use self::edit_distance::{closest, closest_msg, edit_distance}; |
| pub use self::errors::CliError; |
| pub use self::errors::{CargoResult, CliResult, internal}; |
| pub use self::flock::{FileLock, Filesystem}; |
| pub use self::graph::Graph; |
| pub use self::hasher::StableHasher; |
| pub use self::hex::{hash_u64, short_hash, to_hex}; |
| pub use self::into_url::IntoUrl; |
| pub use self::into_url_with_base::IntoUrlWithBase; |
| pub(crate) use self::io::LimitErrorReader; |
| pub use self::lockserver::{LockServer, LockServerClient, LockServerStarted}; |
| pub use self::logger::BuildLogger; |
| pub use self::once::OnceExt; |
| pub use self::progress::{Progress, ProgressStyle}; |
| pub use self::queue::Queue; |
| pub use self::rustc::Rustc; |
| pub use self::semver_ext::{OptVersionReq, VersionExt}; |
| pub use self::unhashed::Unhashed; |
| pub use self::vcs::{FossilRepo, GitRepo, HgRepo, PijulRepo, existing_vcs_repo}; |
| pub use self::workspace::{ |
| add_path_args, path_args, print_available_benches, print_available_binaries, |
| print_available_examples, print_available_packages, print_available_tests, |
| }; |
| pub use crate::context::{ConfigValue, GlobalContext, homedir}; |
| |
| pub mod auth; |
| pub mod cache_lock; |
| mod canonical_url; |
| pub mod command_prelude; |
| mod counter; |
| pub mod cpu; |
| pub mod credential; |
| mod dependency_queue; |
| pub mod diagnostic_server; |
| pub mod edit_distance; |
| pub mod errors; |
| pub mod flock; |
| pub mod frontmatter; |
| pub mod graph; |
| mod hasher; |
| pub mod hex; |
| pub mod important_paths; |
| pub mod interning; |
| pub mod into_url; |
| mod into_url_with_base; |
| mod io; |
| pub mod job; |
| mod local_poll_adapter; |
| pub use local_poll_adapter::LocalPollAdapter; |
| pub mod data_structures; |
| mod lockserver; |
| pub mod log_message; |
| pub mod logger; |
| pub mod machine_message; |
| pub mod network; |
| mod once; |
| pub mod open; |
| mod progress; |
| mod queue; |
| pub mod restricted_names; |
| pub mod rustc; |
| mod semver_eval_ext; |
| mod semver_ext; |
| pub mod sqlite; |
| pub mod time_span; |
| mod unhashed; |
| mod vcs; |
| mod workspace; |
| |
| pub use cargo_util_terminal::style; |
| pub(crate) use futures::executor::block_on; |
| pub(crate) use futures::executor::block_on_stream; |
| |
| pub fn is_rustup() -> bool { |
| #[expect(clippy::disallowed_methods, reason = "consistency with rustup")] |
| std::env::var_os("RUSTUP_HOME").is_some() |
| } |
| |
| pub fn elapsed(duration: Duration) -> String { |
| let secs = duration.as_secs(); |
| |
| if secs >= 60 { |
| format!("{}m {:02}s", secs / 60, secs % 60) |
| } else { |
| format!("{}.{:02}s", secs, duration.subsec_nanos() / 10_000_000) |
| } |
| } |
| |
| /// Formats a number of bytes into a human readable SI-prefixed size. |
| pub struct HumanBytes(pub u64); |
| |
| impl std::fmt::Display for HumanBytes { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| const UNITS: [&str; 7] = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"]; |
| let bytes = self.0 as f32; |
| let i = ((bytes.log2() / 10.0) as usize).min(UNITS.len() - 1); |
| let unit = UNITS[i]; |
| let size = bytes / 1024_f32.powi(i as i32); |
| |
| // Don't show a fractional number of bytes. |
| if i == 0 { |
| return write!(f, "{size}{unit}"); |
| } |
| |
| let Some(precision) = f.precision() else { |
| return write!(f, "{size}{unit}"); |
| }; |
| write!(f, "{size:.precision$}{unit}",) |
| } |
| } |
| |
| pub fn indented_lines(text: &str) -> String { |
| text.lines() |
| .map(|line| { |
| if line.is_empty() { |
| String::from("\n") |
| } else { |
| format!(" {}\n", line) |
| } |
| }) |
| .collect() |
| } |
| |
| pub fn truncate_with_ellipsis(s: &str, max_width: usize) -> String { |
| // We should truncate at grapheme-boundary and compute character-widths, |
| // yet the dependencies on unicode-segmentation and unicode-width are |
| // not worth it. |
| let mut chars = s.chars(); |
| let mut prefix = (&mut chars).take(max_width - 1).collect::<String>(); |
| if chars.next().is_some() { |
| prefix.push('…'); |
| } |
| prefix |
| } |
| |
| #[cfg(not(windows))] |
| #[inline] |
| pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> { |
| std::fs::canonicalize(&path) |
| } |
| |
| #[cfg(windows)] |
| #[inline] |
| pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> { |
| use std::io::Error; |
| use std::io::ErrorKind; |
| |
| // On Windows `canonicalize` may fail, so we fall back to getting an absolute path. |
| std::fs::canonicalize(&path).or_else(|_| { |
| // Return an error if a file does not exist for better compatibility with `canonicalize` |
| if !path.as_ref().try_exists()? { |
| return Err(Error::new(ErrorKind::NotFound, "the path was not found")); |
| } |
| std::path::absolute(&path) |
| }) |
| } |
| |
| /// Get the current [`umask`] value. |
| /// |
| /// [`umask`]: https://man7.org/linux/man-pages/man2/umask.2.html |
| #[cfg(unix)] |
| pub fn get_umask() -> u32 { |
| use std::sync::OnceLock; |
| static UMASK: OnceLock<libc::mode_t> = OnceLock::new(); |
| // SAFETY: Syscalls are unsafe. Calling `umask` twice is even unsafer for |
| // multithreading program, since it doesn't provide a way to retrieve the |
| // value without modifications. We use a static `OnceLock` here to ensure |
| // it only gets call once during the entire program lifetime. |
| *UMASK.get_or_init(|| unsafe { |
| let umask = libc::umask(0o022); |
| libc::umask(umask); |
| umask |
| }) as u32 // it is u16 on macos |
| } |
| |
| #[cfg(test)] |
| mod test { |
| use super::*; |
| |
| #[track_caller] |
| fn t(bytes: u64, expected: &str) { |
| assert_eq!(&HumanBytes(bytes).to_string(), expected); |
| } |
| |
| #[test] |
| fn test_human_readable_bytes() { |
| t(0, "0B"); |
| t(8, "8B"); |
| t(1000, "1000B"); |
| t(1024, "1KiB"); |
| t(1024 * 420 + 512, "420.5KiB"); |
| t(1024 * 1024, "1MiB"); |
| t(1024 * 1024 + 1024 * 256, "1.25MiB"); |
| t(1024 * 1024 * 1024, "1GiB"); |
| t((1024. * 1024. * 1024. * 1.2345) as u64, "1.2345GiB"); |
| t(1024 * 1024 * 1024 * 1024, "1TiB"); |
| t(1024 * 1024 * 1024 * 1024 * 1024, "1PiB"); |
| t(1024 * 1024 * 1024 * 1024 * 1024 * 1024, "1EiB"); |
| t(u64::MAX, "16EiB"); |
| |
| assert_eq!( |
| &format!("{:.3}", HumanBytes((1024. * 1.23456) as u64)), |
| "1.234KiB" |
| ); |
| } |
| } |