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::into_url
::IntoUrl
;
18 pub use self::into_url_with_base
::IntoUrlWithBase
;
19 pub(crate) use self::io
::LimitErrorReader
;
20 pub use self::lockserver
::{LockServer, LockServerClient, LockServerStarted}
;
21 pub use self::progress
::{Progress, ProgressStyle}
;
22 pub use self::queue
::Queue
;
23 pub use self::restricted_names
::validate_package_name
;
24 pub use self::rustc
::Rustc
;
25 pub use self::semver_ext
::{OptVersionReq, PartialVersion, RustVersion, VersionExt, VersionReqExt}
;
26 pub use self::to_semver
::ToSemver
;
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
,
35 pub mod command_prelude
;
41 pub mod diagnostic_server
;
42 pub mod edit_distance
;
48 pub mod important_paths
;
51 mod into_url_with_base
;
55 pub mod machine_message
;
60 pub mod restricted_names
;
70 pub fn is_rustup() -> bool
{
71 // ALLOWED: `RUSTUP_HOME` should only be read from process env, otherwise
72 // other tools may point to executables from incompatible distributions.
73 #[allow(clippy::disallowed_methods)]
74 std
::env
::var_os("RUSTUP_HOME").is_some()
77 pub fn elapsed(duration
: Duration
) -> String
{
78 let secs
= duration
.as_secs();
81 format
!("{}m {:02}s", secs
/ 60, secs
% 60)
83 format
!("{}.{:02}s", secs
, duration
.subsec_nanos() / 10_000_000)
87 /// Formats a number of bytes into a human readable SI-prefixed size.
88 /// Returns a tuple of `(quantity, units)`.
89 pub fn human_readable_bytes(bytes
: u64) -> (f32, &'
static str) {
90 static UNITS
: [&str; 7] = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"];
91 let bytes
= bytes
as f32;
92 let i
= ((bytes
.log2() / 10.0) as usize).min(UNITS
.len() - 1);
93 (bytes
/ 1024_f32.powi(i
as i32), UNITS
[i
])
96 pub fn iter_join_onto
<W
, I
, T
>(mut w
: W
, iter
: I
, delim
: &str) -> fmt
::Result
99 I
: IntoIterator
<Item
= T
>,
100 T
: std
::fmt
::Display
,
102 let mut it
= iter
.into_iter().peekable();
103 while let Some(n
) = it
.next() {
105 if it
.peek().is_some() {
106 write
!(w
, "{}", delim
)?
;
112 pub fn iter_join
<I
, T
>(iter
: I
, delim
: &str) -> String
114 I
: IntoIterator
<Item
= T
>,
115 T
: std
::fmt
::Display
,
117 let mut s
= String
::new();
118 let _
= iter_join_onto(&mut s
, iter
, delim
);
122 pub fn indented_lines(text
: &str) -> String
{
128 format
!(" {}\n", line
)
134 pub fn truncate_with_ellipsis(s
: &str, max_width
: usize) -> String
{
135 // We should truncate at grapheme-boundary and compute character-widths,
136 // yet the dependencies on unicode-segmentation and unicode-width are
138 let mut chars
= s
.chars();
139 let mut prefix
= (&mut chars
).take(max_width
- 1).collect
::<String
>();
140 if chars
.next().is_some() {
148 pub fn try_canonicalize
<P
: AsRef
<Path
>>(path
: P
) -> std
::io
::Result
<PathBuf
> {
149 std
::fs
::canonicalize(&path
)
154 pub fn try_canonicalize
<P
: AsRef
<Path
>>(path
: P
) -> std
::io
::Result
<PathBuf
> {
155 use std
::ffi
::OsString
;
157 use std
::os
::windows
::ffi
::{OsStrExt, OsStringExt}
;
158 use std
::{io::ErrorKind, ptr}
;
159 use windows_sys
::Win32
::Foundation
::{GetLastError, SetLastError}
;
160 use windows_sys
::Win32
::Storage
::FileSystem
::GetFullPathNameW
;
162 // On Windows `canonicalize` may fail, so we fall back to getting an absolute path.
163 std
::fs
::canonicalize(&path
).or_else(|_
| {
164 // Return an error if a file does not exist for better compatibility with `canonicalize`
165 if !path
.as_ref().try_exists()?
{
166 return Err(Error
::new(ErrorKind
::NotFound
, "the path was not found"));
169 // This code is based on the unstable `std::path::absolute` and could be replaced with it
170 // if it's stabilized.
172 let path
= path
.as_ref().as_os_str();
173 let mut path_u16
= Vec
::with_capacity(path
.len() + 1);
174 path_u16
.extend(path
.encode_wide());
175 if path_u16
.iter().find(|c
| **c
== 0).is_some() {
176 return Err(Error
::new(
177 ErrorKind
::InvalidInput
,
178 "strings passed to WinAPI cannot contain NULs",
187 GetFullPathNameW(path_u16
.as_ptr(), 0, &mut [] as *mut u16, ptr
::null_mut());
189 let error
= GetLastError();
191 return Err(Error
::from_raw_os_error(error
as i32));
194 let mut result
= vec
![0u16; len
as usize];
196 let write_len
= GetFullPathNameW(
198 result
.len().try_into().unwrap(),
199 result
.as_mut_ptr().cast
::<u16>(),
203 let error
= GetLastError();
205 return Err(Error
::from_raw_os_error(error
as i32));
209 if write_len
<= len
{
210 return Ok(PathBuf
::from(OsString
::from_wide(
211 &result
[0..(write_len
as usize)],
219 /// Get the current [`umask`] value.
221 /// [`umask`]: https://man7.org/linux/man-pages/man2/umask.2.html
223 pub fn get_umask() -> u32 {
224 use std
::sync
::OnceLock
;
225 static UMASK
: OnceLock
<libc
::mode_t
> = OnceLock
::new();
226 // SAFETY: Syscalls are unsafe. Calling `umask` twice is even unsafer for
227 // multithreading program, since it doesn't provide a way to retrieve the
228 // value without modifications. We use a static `OnceLock` here to ensure
229 // it only gets call once during the entire program lifetime.
230 *UMASK
.get_or_init(|| unsafe {
231 let umask
= libc
::umask(0o022);
234 }) as u32 // it is u16 on macos
242 fn test_human_readable_bytes() {
243 assert_eq
!(human_readable_bytes(0), (0., "B"));
244 assert_eq
!(human_readable_bytes(8), (8., "B"));
245 assert_eq
!(human_readable_bytes(1000), (1000., "B"));
246 assert_eq
!(human_readable_bytes(1024), (1., "KiB"));
247 assert_eq
!(human_readable_bytes(1024 * 420 + 512), (420.5, "KiB"));
248 assert_eq
!(human_readable_bytes(1024 * 1024), (1., "MiB"));
250 human_readable_bytes(1024 * 1024 + 1024 * 256),
253 assert_eq
!(human_readable_bytes(1024 * 1024 * 1024), (1., "GiB"));
255 human_readable_bytes((1024. * 1024. * 1024. * 3.1415) as u64),
258 assert_eq
!(human_readable_bytes(1024 * 1024 * 1024 * 1024), (1., "TiB"));
260 human_readable_bytes(1024 * 1024 * 1024 * 1024 * 1024),
264 human_readable_bytes(1024 * 1024 * 1024 * 1024 * 1024 * 1024),
267 assert_eq
!(human_readable_bytes(u64::MAX
), (16., "EiB"));