1use std::path::{Path, PathBuf};
2use std::time::Duration;
3
4pub use self::canonical_url::CanonicalUrl;
5pub use self::context::{ConfigValue, GlobalContext, homedir};
6pub(crate) use self::counter::MetricsCounter;
7pub use self::dependency_queue::DependencyQueue;
8pub use self::diagnostic_server::RustfixDiagnosticServer;
9pub use self::edit_distance::{closest, closest_msg, edit_distance};
10pub use self::errors::CliError;
11pub use self::errors::{CargoResult, CliResult, internal};
12pub use self::flock::{FileLock, Filesystem};
13pub use self::graph::Graph;
14pub use self::hasher::StableHasher;
15pub use self::hex::{hash_u64, short_hash, to_hex};
16pub use self::hostname::hostname;
17pub use self::into_url::IntoUrl;
18pub use self::into_url_with_base::IntoUrlWithBase;
19pub(crate) use self::io::LimitErrorReader;
20pub use self::lockserver::{LockServer, LockServerClient, LockServerStarted};
21pub use self::progress::{Progress, ProgressStyle};
22pub use self::queue::Queue;
23pub use self::rustc::Rustc;
24pub use self::semver_ext::{OptVersionReq, VersionExt};
25pub use self::vcs::{FossilRepo, GitRepo, HgRepo, PijulRepo, existing_vcs_repo};
26pub use self::workspace::{
27 add_path_args, path_args, print_available_benches, print_available_binaries,
28 print_available_examples, print_available_packages, print_available_tests,
29};
30
31pub mod auth;
32pub mod cache_lock;
33mod canonical_url;
34pub mod command_prelude;
35pub mod context;
36mod counter;
37pub mod cpu;
38pub mod credential;
39mod dependency_queue;
40pub mod diagnostic_server;
41pub mod edit_distance;
42pub mod errors;
43mod flock;
44pub mod frontmatter;
45pub mod graph;
46mod hasher;
47pub mod hex;
48mod hostname;
49pub mod important_paths;
50pub mod interning;
51pub mod into_url;
52mod into_url_with_base;
53mod io;
54pub mod job;
55pub mod lints;
56mod lockserver;
57pub mod machine_message;
58pub mod network;
59mod progress;
60mod queue;
61pub mod restricted_names;
62pub mod rustc;
63mod semver_eval_ext;
64mod semver_ext;
65pub mod sqlite;
66pub mod style;
67pub mod toml;
68pub mod toml_mut;
69mod vcs;
70mod workspace;
71
72pub fn is_rustup() -> bool {
73 #[allow(clippy::disallowed_methods)]
76 std::env::var_os("RUSTUP_HOME").is_some()
77}
78
79pub fn elapsed(duration: Duration) -> String {
80 let secs = duration.as_secs();
81
82 if secs >= 60 {
83 format!("{}m {:02}s", secs / 60, secs % 60)
84 } else {
85 format!("{}.{:02}s", secs, duration.subsec_nanos() / 10_000_000)
86 }
87}
88
89pub struct HumanBytes(pub u64);
91
92impl std::fmt::Display for HumanBytes {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 const UNITS: [&str; 7] = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"];
95 let bytes = self.0 as f32;
96 let i = ((bytes.log2() / 10.0) as usize).min(UNITS.len() - 1);
97 let unit = UNITS[i];
98 let size = bytes / 1024_f32.powi(i as i32);
99
100 if i == 0 {
102 return write!(f, "{size}{unit}");
103 }
104
105 let Some(precision) = f.precision() else {
106 return write!(f, "{size}{unit}");
107 };
108 write!(f, "{size:.precision$}{unit}",)
109 }
110}
111
112pub fn indented_lines(text: &str) -> String {
113 text.lines()
114 .map(|line| {
115 if line.is_empty() {
116 String::from("\n")
117 } else {
118 format!(" {}\n", line)
119 }
120 })
121 .collect()
122}
123
124pub fn truncate_with_ellipsis(s: &str, max_width: usize) -> String {
125 let mut chars = s.chars();
129 let mut prefix = (&mut chars).take(max_width - 1).collect::<String>();
130 if chars.next().is_some() {
131 prefix.push('…');
132 }
133 prefix
134}
135
136#[cfg(not(windows))]
137#[inline]
138pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> {
139 std::fs::canonicalize(&path)
140}
141
142#[cfg(windows)]
143#[inline]
144pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> {
145 use std::io::Error;
146 use std::io::ErrorKind;
147
148 std::fs::canonicalize(&path).or_else(|_| {
150 if !path.as_ref().try_exists()? {
152 return Err(Error::new(ErrorKind::NotFound, "the path was not found"));
153 }
154 std::path::absolute(&path)
155 })
156}
157
158#[cfg(unix)]
162pub fn get_umask() -> u32 {
163 use std::sync::OnceLock;
164 static UMASK: OnceLock<libc::mode_t> = OnceLock::new();
165 *UMASK.get_or_init(|| unsafe {
170 let umask = libc::umask(0o022);
171 libc::umask(umask);
172 umask
173 }) as u32 }
175
176#[cfg(test)]
177mod test {
178 use super::*;
179
180 #[track_caller]
181 fn t(bytes: u64, expected: &str) {
182 assert_eq!(&HumanBytes(bytes).to_string(), expected);
183 }
184
185 #[test]
186 fn test_human_readable_bytes() {
187 t(0, "0B");
188 t(8, "8B");
189 t(1000, "1000B");
190 t(1024, "1KiB");
191 t(1024 * 420 + 512, "420.5KiB");
192 t(1024 * 1024, "1MiB");
193 t(1024 * 1024 + 1024 * 256, "1.25MiB");
194 t(1024 * 1024 * 1024, "1GiB");
195 t((1024. * 1024. * 1024. * 1.2345) as u64, "1.2345GiB");
196 t(1024 * 1024 * 1024 * 1024, "1TiB");
197 t(1024 * 1024 * 1024 * 1024 * 1024, "1PiB");
198 t(1024 * 1024 * 1024 * 1024 * 1024 * 1024, "1EiB");
199 t(u64::MAX, "16EiB");
200
201 assert_eq!(
202 &format!("{:.3}", HumanBytes((1024. * 1.23456) as u64)),
203 "1.234KiB"
204 );
205 }
206}