2 use std
::path
::{Path, PathBuf}
;
3 use std
::time
::Duration
;
5 pub use self::canonical_url
::CanonicalUrl
;
6 pub use self::config
::{homedir, Config, ConfigValue}
;
7 pub(crate) use self::counter
::MetricsCounter
;
8 pub use self::dependency_queue
::DependencyQueue
;
9 pub use self::diagnostic_server
::RustfixDiagnosticServer
;
10 pub use self::edit_distance
::{closest, closest_msg, edit_distance}
;
11 pub use self::errors
::CliError
;
12 pub use self::errors
::{internal, CargoResult, CliResult}
;
13 pub use self::flock
::{FileLock, Filesystem}
;
14 pub use self::graph
::Graph
;
15 pub use self::hasher
::StableHasher
;
16 pub use self::hex
::{hash_u64, short_hash, to_hex}
;
17 pub use self::hostname
::hostname
;
18 pub use self::into_url
::IntoUrl
;
19 pub use self::into_url_with_base
::IntoUrlWithBase
;
20 pub(crate) use self::io
::LimitErrorReader
;
21 pub use self::lockserver
::{LockServer, LockServerClient, LockServerStarted}
;
22 pub use self::progress
::{Progress, ProgressStyle}
;
23 pub use self::queue
::Queue
;
24 pub use self::restricted_names
::validate_package_name
;
25 pub use self::rustc
::Rustc
;
26 pub use self::semver_ext
::{OptVersionReq, RustVersion}
;
27 pub use self::vcs
::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo}
;
28 pub use self::workspace
::{
29 add_path_args
, path_args
, print_available_benches
, print_available_binaries
,
30 print_available_examples
, print_available_packages
, print_available_tests
,
36 pub mod command_prelude
;
42 pub mod diagnostic_server
;
43 pub mod edit_distance
;
50 pub mod important_paths
;
53 mod into_url_with_base
;
57 pub mod machine_message
;
62 pub mod restricted_names
;
71 pub fn is_rustup() -> bool
{
72 // ALLOWED: `RUSTUP_HOME` should only be read from process env, otherwise
73 // other tools may point to executables from incompatible distributions.
74 #[allow(clippy::disallowed_methods)]
75 std
::env
::var_os("RUSTUP_HOME").is_some()
78 pub fn elapsed(duration
: Duration
) -> String
{
79 let secs
= duration
.as_secs();
82 format
!("{}m {:02}s", secs
/ 60, secs
% 60)
84 format
!("{}.{:02}s", secs
, duration
.subsec_nanos() / 10_000_000)
88 /// Formats a number of bytes into a human readable SI-prefixed size.
89 /// Returns a tuple of `(quantity, units)`.
90 pub fn human_readable_bytes(bytes
: u64) -> (f32, &'
static str) {
91 static UNITS
: [&str; 7] = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"];
92 let bytes
= bytes
as f32;
93 let i
= ((bytes
.log2() / 10.0) as usize).min(UNITS
.len() - 1);
94 (bytes
/ 1024_f32.powi(i
as i32), UNITS
[i
])
97 pub fn iter_join_onto
<W
, I
, T
>(mut w
: W
, iter
: I
, delim
: &str) -> fmt
::Result
100 I
: IntoIterator
<Item
= T
>,
101 T
: std
::fmt
::Display
,
103 let mut it
= iter
.into_iter().peekable();
104 while let Some(n
) = it
.next() {
106 if it
.peek().is_some() {
107 write
!(w
, "{}", delim
)?
;
113 pub fn iter_join
<I
, T
>(iter
: I
, delim
: &str) -> String
115 I
: IntoIterator
<Item
= T
>,
116 T
: std
::fmt
::Display
,
118 let mut s
= String
::new();
119 let _
= iter_join_onto(&mut s
, iter
, delim
);
123 pub fn indented_lines(text
: &str) -> String
{
129 format
!(" {}\n", line
)
135 pub fn truncate_with_ellipsis(s
: &str, max_width
: usize) -> String
{
136 // We should truncate at grapheme-boundary and compute character-widths,
137 // yet the dependencies on unicode-segmentation and unicode-width are
139 let mut chars
= s
.chars();
140 let mut prefix
= (&mut chars
).take(max_width
- 1).collect
::<String
>();
141 if chars
.next().is_some() {
149 pub fn try_canonicalize
<P
: AsRef
<Path
>>(path
: P
) -> std
::io
::Result
<PathBuf
> {
150 std
::fs
::canonicalize(&path
)
155 pub fn try_canonicalize
<P
: AsRef
<Path
>>(path
: P
) -> std
::io
::Result
<PathBuf
> {
156 use std
::ffi
::OsString
;
158 use std
::os
::windows
::ffi
::{OsStrExt, OsStringExt}
;
159 use std
::{io::ErrorKind, ptr}
;
160 use windows_sys
::Win32
::Foundation
::{GetLastError, SetLastError}
;
161 use windows_sys
::Win32
::Storage
::FileSystem
::GetFullPathNameW
;
163 // On Windows `canonicalize` may fail, so we fall back to getting an absolute path.
164 std
::fs
::canonicalize(&path
).or_else(|_
| {
165 // Return an error if a file does not exist for better compatibility with `canonicalize`
166 if !path
.as_ref().try_exists()?
{
167 return Err(Error
::new(ErrorKind
::NotFound
, "the path was not found"));
170 // This code is based on the unstable `std::path::absolute` and could be replaced with it
171 // if it's stabilized.
173 let path
= path
.as_ref().as_os_str();
174 let mut path_u16
= Vec
::with_capacity(path
.len() + 1);
175 path_u16
.extend(path
.encode_wide());
176 if path_u16
.iter().find(|c
| **c
== 0).is_some() {
177 return Err(Error
::new(
178 ErrorKind
::InvalidInput
,
179 "strings passed to WinAPI cannot contain NULs",
188 GetFullPathNameW(path_u16
.as_ptr(), 0, &mut [] as *mut u16, ptr
::null_mut());
190 let error
= GetLastError();
192 return Err(Error
::from_raw_os_error(error
as i32));
195 let mut result
= vec
![0u16; len
as usize];
197 let write_len
= GetFullPathNameW(
199 result
.len().try_into().unwrap(),
200 result
.as_mut_ptr().cast
::<u16>(),
204 let error
= GetLastError();
206 return Err(Error
::from_raw_os_error(error
as i32));
210 if write_len
<= len
{
211 return Ok(PathBuf
::from(OsString
::from_wide(
212 &result
[0..(write_len
as usize)],
220 /// Get the current [`umask`] value.
222 /// [`umask`]: https://man7.org/linux/man-pages/man2/umask.2.html
224 pub fn get_umask() -> u32 {
225 use std
::sync
::OnceLock
;
226 static UMASK
: OnceLock
<libc
::mode_t
> = OnceLock
::new();
227 // SAFETY: Syscalls are unsafe. Calling `umask` twice is even unsafer for
228 // multithreading program, since it doesn't provide a way to retrieve the
229 // value without modifications. We use a static `OnceLock` here to ensure
230 // it only gets call once during the entire program lifetime.
231 *UMASK
.get_or_init(|| unsafe {
232 let umask
= libc
::umask(0o022);
235 }) as u32 // it is u16 on macos
243 fn test_human_readable_bytes() {
244 assert_eq
!(human_readable_bytes(0), (0., "B"));
245 assert_eq
!(human_readable_bytes(8), (8., "B"));
246 assert_eq
!(human_readable_bytes(1000), (1000., "B"));
247 assert_eq
!(human_readable_bytes(1024), (1., "KiB"));
248 assert_eq
!(human_readable_bytes(1024 * 420 + 512), (420.5, "KiB"));
249 assert_eq
!(human_readable_bytes(1024 * 1024), (1., "MiB"));
251 human_readable_bytes(1024 * 1024 + 1024 * 256),
254 assert_eq
!(human_readable_bytes(1024 * 1024 * 1024), (1., "GiB"));
256 human_readable_bytes((1024. * 1024. * 1024. * 3.1415) as u64),
259 assert_eq
!(human_readable_bytes(1024 * 1024 * 1024 * 1024), (1., "TiB"));
261 human_readable_bytes(1024 * 1024 * 1024 * 1024 * 1024),
265 human_readable_bytes(1024 * 1024 * 1024 * 1024 * 1024 * 1024),
268 assert_eq
!(human_readable_bytes(u64::MAX
), (16., "EiB"));