diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index de8fa5998aa..61e5eb4c068 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -1327,6 +1327,6 @@ jobs: echo "Running benchmarks for packages: ${{ steps.benchmark_list.outputs.benchmark_packages }}" for package in ${{ steps.benchmark_list.outputs.benchmark_packages }}; do echo "Running benchmarks for $package" - cargo codspeed run -p $package > /dev/null + cargo codspeed run -p $package done token: ${{ secrets.CODSPEED_TOKEN }} diff --git a/.github/workflows/GnuTests.yml b/.github/workflows/GnuTests.yml index dcac7eaf2bf..0a98a36914e 100644 --- a/.github/workflows/GnuTests.yml +++ b/.github/workflows/GnuTests.yml @@ -29,7 +29,7 @@ env: TEST_ROOT_FULL_SUMMARY_FILE: 'gnu-root-full-result.json' TEST_SELINUX_FULL_SUMMARY_FILE: 'selinux-gnu-full-result.json' TEST_SELINUX_ROOT_FULL_SUMMARY_FILE: 'selinux-root-gnu-full-result.json' - REPO_GNU_REF: "v9.8" + REPO_GNU_REF: "v9.7" jobs: native: diff --git a/.vscode/cspell.dictionaries/acronyms+names.wordlist.txt b/.vscode/cspell.dictionaries/acronyms+names.wordlist.txt index e611b5954df..2724d2b1fa2 100644 --- a/.vscode/cspell.dictionaries/acronyms+names.wordlist.txt +++ b/.vscode/cspell.dictionaries/acronyms+names.wordlist.txt @@ -1,5 +1,4 @@ # * abbreviations / acronyms -aarch AIX ASLR # address space layout randomization AST # abstract syntax tree @@ -10,27 +9,23 @@ DevOps Ext3 FIFO FIFOs -flac FQDN # fully qualified domain name GID # group ID GIDs GNU GNUEABI GNUEABIhf -impls JFS -loongarch -lzma MSRV # minimum supported rust version MSVC NixOS POSIX POSIXLY -ReiserFS RISC RISCV RNG # random number generator RNGs +ReiserFS Solaris UID # user ID UIDs @@ -38,6 +33,11 @@ UUID # universally unique identifier WASI WASM XFS +aarch +flac +impls +lzma +loongarch # * names BusyBox @@ -48,23 +48,25 @@ Deno EditorConfig EPEL FreeBSD -genric Gmail +GNU Illumos Irix libfuzzer +MS-DOS +MSDOS MacOS MinGW Minix -MS-DOS -MSDOS NetBSD Novell Nushell OpenBSD +POSIX PowerPC SELinux SkyPack +Solaris SysV Xenix Yargs diff --git a/Cargo.lock b/Cargo.lock index d2cf4d7af1d..e5f2b501c8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3731,9 +3731,7 @@ name = "uu_numfmt" version = "0.2.2" dependencies = [ "clap", - "codspeed-divan-compat", "fluent", - "tempfile", "thiserror 2.0.16", "uucore", ] diff --git a/src/uu/id/locales/en-US.ftl b/src/uu/id/locales/en-US.ftl index a6b4ac2256f..37b477c17a8 100644 --- a/src/uu/id/locales/en-US.ftl +++ b/src/uu/id/locales/en-US.ftl @@ -25,7 +25,6 @@ id-error-cannot-find-user-name = cannot find name for user ID { $uid } id-error-audit-retrieve = couldn't retrieve information # Help text for command-line arguments -id-help-ignore = ignore, for compatibility with other versions id-help-audit = Display the process audit user ID and other process audit properties, which requires privilege (not available on Linux). id-help-user = Display only the effective user ID as a number. diff --git a/src/uu/id/locales/fr-FR.ftl b/src/uu/id/locales/fr-FR.ftl index b606f520757..f69df611e22 100644 --- a/src/uu/id/locales/fr-FR.ftl +++ b/src/uu/id/locales/fr-FR.ftl @@ -25,7 +25,6 @@ id-error-cannot-find-user-name = impossible de trouver le nom pour l'ID utilisat id-error-audit-retrieve = impossible de récupérer les informations # Texte d'aide pour les arguments de ligne de commande -id-help-ignore = ignore, pour compatibilité avec d'autres versions id-help-audit = Affiche l'ID utilisateur d'audit du processus et autres propriétés d'audit, ce qui nécessite des privilèges (non disponible sous Linux). id-help-user = Affiche uniquement l'ID utilisateur effectif sous forme de nombre. diff --git a/src/uu/id/src/id.rs b/src/uu/id/src/id.rs index dcdc692435d..7c1e1c12c5a 100644 --- a/src/uu/id/src/id.rs +++ b/src/uu/id/src/id.rs @@ -69,7 +69,6 @@ fn get_context_help_text() -> String { } mod options { - pub const OPT_IGNORE: &str = "ignore"; pub const OPT_AUDIT: &str = "audit"; // GNU's id does not have this pub const OPT_CONTEXT: &str = "context"; pub const OPT_EFFECTIVE_USER: &str = "user"; @@ -354,13 +353,6 @@ pub fn uu_app() -> Command { .infer_long_args(true) .args_override_self(true) .after_help(translate!("id-after-help")) - .arg( - Arg::new(options::OPT_IGNORE) - .short('a') - .long(options::OPT_IGNORE) - .help(translate!("id-help-ignore")) - .action(ArgAction::SetTrue), - ) .arg( Arg::new(options::OPT_AUDIT) .short('A') diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index ba7f26f1aad..a8ac3227463 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -5,6 +5,7 @@ // spell-checker:ignore (ToDO) somegroup nlink tabsize dired subdired dtype colorterm stringly nohash strtime +use std::borrow::Cow; #[cfg(unix)] use std::collections::HashMap; #[cfg(unix)] @@ -2173,10 +2174,8 @@ fn should_display(entry: &DirEntry, config: &Config) -> bool { // https://github.com/rust-lang/glob/issues/23 // https://github.com/rust-lang/glob/issues/78 // https://github.com/BurntSushi/ripgrep/issues/1250 - let file_name = match file_name.to_str() { - Some(s) => s.to_string(), - None => file_name.to_string_lossy().into_owned(), - }; + let file_name = file_name.to_string_lossy(); + !config .ignore_patterns .iter() @@ -2320,10 +2319,42 @@ fn display_dir_entry_size( } SizeOrDeviceId::Size(size) => (size.len(), 0usize, 0usize), }; + + let long_format = &config.long; + let numeric_uid_gid; + + #[cfg(unix)] + { + numeric_uid_gid = long_format.numeric_uid_gid; + } + + #[cfg(not(unix))] + { + numeric_uid_gid = false; + } + + let display_symlink_count = if numeric_uid_gid { + display_symlink_count(md).len() + } else { + 0 + }; + + let display_uname = if long_format.owner { + display_uname(md, config, state).len() + } else { + 0 + }; + + let display_group = if long_format.group { + display_group(md, config, state).len() + } else { + 0 + }; + ( - display_symlink_count(md).len(), - display_uname(md, config, state).len(), - display_group(md, config, state).len(), + display_symlink_count, + display_uname, + display_group, size_len, major_len, minor_len, @@ -2358,7 +2389,7 @@ impl ExtendPad for Vec { // TODO: Consider converting callers to use ExtendPad instead, as it avoids // additional copies. -fn pad_left(string: &str, count: usize) -> String { +fn pad_left(string: &T, count: usize) -> String { format!("{string:>count$}") } @@ -2395,19 +2426,20 @@ fn display_additional_leading_info( { if config.inode { let i = if let Some(md) = item.get_metadata(out) { - get_inode(md) + &display_inode(md) } else { - "?".to_owned() + "?" }; + write!(result, "{} ", pad_left(&i, padding.inode)).unwrap(); } } if config.alloc_size { let s = if let Some(md) = item.get_metadata(out) { - display_size(get_block_size(md, config), config) + &display_size(get_block_size(md, config), config) } else { - "?".to_owned() + "?" }; // extra space is insert to align the sizes, as needed for all formats, except for the comma format. if config.format == Format::Commas { @@ -2629,10 +2661,7 @@ fn display_grid( }; // FIXME: the Grid crate only supports &str, so can't display raw bytes - let names: Vec<_> = names - .into_iter() - .map(|s| s.to_string_lossy().into_owned()) - .collect(); + let names: Vec> = names.iter().map(|s| s.to_string_lossy()).collect(); // Since tab_size=0 means no \t, use Spaces separator for optimization. let filling = match tab_size { @@ -3017,26 +3046,26 @@ fn file_is_executable(md: &Metadata) -> bool { return md.mode() & ((S_IXUSR | S_IXGRP | S_IXOTH) as u32) != 0; } -fn classify_file(path: &PathData, out: &mut BufWriter) -> Option { +fn classify_file<'a>(path: &'a PathData, out: &mut BufWriter) -> Option<&'a str> { let file_type = path.file_type(out)?; if file_type.is_dir() { - Some('/') + Some("/") } else if file_type.is_symlink() { - Some('@') + Some("@") } else { #[cfg(unix)] { if file_type.is_socket() { - Some('=') + Some("=") } else if file_type.is_fifo() { - Some('|') + Some("|") } else if file_type.is_file() // Safe unwrapping if the file was removed between listing and display // See https://github.com/uutils/coreutils/issues/5371 && path.get_metadata(out).is_some_and(file_is_executable) { - Some('*') + Some("*") } else { None } @@ -3100,19 +3129,19 @@ fn display_item_name( if config.indicator_style != IndicatorStyle::None { let sym = classify_file(path, &mut state.out); - let char_opt = match config.indicator_style { + let char_opt: Option<&str> = match config.indicator_style { IndicatorStyle::Classify => sym, IndicatorStyle::FileType => { // Don't append an asterisk. match sym { - Some('*') => None, + Some("*") => None, _ => sym, } } IndicatorStyle::Slash => { // Append only a slash. match sym { - Some('/') => Some('/'), + Some("/") => Some("/"), _ => None, } } @@ -3120,7 +3149,7 @@ fn display_item_name( }; if let Some(c) = char_opt { - name.push(OsStr::new(&c.to_string())); + name.push(c); } } @@ -3190,13 +3219,12 @@ fn display_item_name( if config.context { if let Some(pad_count) = prefix_context { let security_context = if matches!(config.format, Format::Commas) { - path.security_context.clone() + &path.security_context } else { - pad_left(&path.security_context, pad_count) + &pad_left(&path.security_context, pad_count) }; - let old_name = name; - name = format!("{security_context} ").into(); - name.push(old_name); + let old_name = name.to_string_lossy(); + name = format!("{security_context} {old_name}").into(); } } @@ -3216,16 +3244,16 @@ fn create_hyperlink(name: &OsStr, path: &PathData) -> OsString { let unencoded_chars = "_-.:~/\\"; // percentage encoding of path - let absolute_path: String = absolute_path - .chars() - .map(|c| { - if c.is_alphanumeric() || unencoded_chars.contains(c) { - c.to_string() - } else { - format!("%{:02x}", c as u8) - } - }) - .collect(); + let absolute_path: String = absolute_path.chars().fold(String::new(), |mut acc, c| { + if c.is_alphanumeric() || unencoded_chars.contains(c) { + acc.push(c); + } else { + let x = format!("%{:02x}", c as u8); + acc.push_str(&x); + }; + + acc + }); // \x1b = ESC, \x07 = BEL let mut ret: OsString = format!("\x1b]8;;file://{hostname}{absolute_path}\x07").into(); diff --git a/src/uu/numfmt/Cargo.toml b/src/uu/numfmt/Cargo.toml index 177f2e3b8ac..5cfd2dc4697 100644 --- a/src/uu/numfmt/Cargo.toml +++ b/src/uu/numfmt/Cargo.toml @@ -23,15 +23,6 @@ uucore = { workspace = true, features = ["parser", "ranges"] } thiserror = { workspace = true } fluent = { workspace = true } -[dev-dependencies] -divan = { workspace = true } -tempfile = { workspace = true } -uucore = { workspace = true, features = ["benchmark"] } - [[bin]] name = "numfmt" path = "src/main.rs" - -[[bench]] -name = "numfmt_bench" -harness = false diff --git a/src/uu/numfmt/benches/numfmt_bench.rs b/src/uu/numfmt/benches/numfmt_bench.rs deleted file mode 100644 index ee09b7d0fc7..00000000000 --- a/src/uu/numfmt/benches/numfmt_bench.rs +++ /dev/null @@ -1,120 +0,0 @@ -// This file is part of the uutils coreutils package. -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -use divan::{Bencher, black_box}; -use tempfile::TempDir; -use uu_numfmt::uumain; -use uucore::benchmark::{create_test_file, run_util_function}; - -/// Generate numeric data for benchmarking -fn generate_numbers(count: usize) -> String { - (1..=count) - .map(|n| n.to_string()) - .collect::>() - .join("\n") -} - -/// Setup benchmark environment with test data -fn setup_benchmark(data: String) -> (TempDir, String) { - let temp_dir = tempfile::tempdir().unwrap(); - let file_path = create_test_file(data.as_bytes(), temp_dir.path()); - let file_path_str = file_path.to_str().unwrap().to_string(); - (temp_dir, file_path_str) -} - -/// Benchmark SI formatting with different number counts -#[divan::bench(args = [1_000_000])] -fn numfmt_to_si(bencher: Bencher, count: usize) { - let (_temp_dir, file_path_str) = setup_benchmark(generate_numbers(count)); - - bencher.bench(|| { - black_box(run_util_function(uumain, &["--to=si", &file_path_str])); - }); -} - -/// Benchmark SI formatting with precision format -#[divan::bench(args = [1_000_000])] -fn numfmt_to_si_precision(bencher: Bencher, count: usize) { - let (_temp_dir, file_path_str) = setup_benchmark(generate_numbers(count)); - - bencher.bench(|| { - black_box(run_util_function( - uumain, - &["--to=si", "--format=%.6f", &file_path_str], - )); - }); -} - -/// Benchmark IEC (binary) formatting -#[divan::bench(args = [1_000_000])] -fn numfmt_to_iec(bencher: Bencher, count: usize) { - let (_temp_dir, file_path_str) = setup_benchmark(generate_numbers(count)); - - bencher.bench(|| { - black_box(run_util_function(uumain, &["--to=iec", &file_path_str])); - }); -} - -/// Benchmark parsing from SI format back to raw numbers -#[divan::bench(args = [1_000_000])] -fn numfmt_from_si(bencher: Bencher, count: usize) { - // Generate SI formatted data (e.g., "1.0K", "2.0K", etc.) - let data = (1..=count) - .map(|n| format!("{:.1}K", n as f64 / 1000.0)) - .collect::>() - .join("\n"); - let (_temp_dir, file_path_str) = setup_benchmark(data); - - bencher.bench(|| { - black_box(run_util_function(uumain, &["--from=si", &file_path_str])); - }); -} - -/// Benchmark large numbers with SI formatting -#[divan::bench(args = [1_000_000])] -fn numfmt_large_numbers_si(bencher: Bencher, count: usize) { - // Generate larger numbers (millions to billions range) - let data = (1..=count) - .map(|n| (n * 1_000_000).to_string()) - .collect::>() - .join("\n"); - let (_temp_dir, file_path_str) = setup_benchmark(data); - - bencher.bench(|| { - black_box(run_util_function(uumain, &["--to=si", &file_path_str])); - }); -} - -/// Benchmark different padding widths -#[divan::bench(args = [(1_000_000, 5), (1_000_000, 50)])] -fn numfmt_padding(bencher: Bencher, (count, padding): (usize, usize)) { - let (_temp_dir, file_path_str) = setup_benchmark(generate_numbers(count)); - let padding_arg = format!("--padding={padding}"); - - bencher.bench(|| { - black_box(run_util_function( - uumain, - &["--to=si", &padding_arg, &file_path_str], - )); - }); -} - -/// Benchmark round modes with SI formatting -#[divan::bench(args = [("up", 100_000), ("down", 1_000_000), ("towards-zero", 1_000_000)])] -fn numfmt_round_modes(bencher: Bencher, (round_mode, count): (&str, usize)) { - let (_temp_dir, file_path_str) = setup_benchmark(generate_numbers(count)); - let round_arg = format!("--round={round_mode}"); - - bencher.bench(|| { - black_box(run_util_function( - uumain, - &["--to=si", &round_arg, &file_path_str], - )); - }); -} - -fn main() { - divan::main(); -} diff --git a/src/uu/seq/src/seq.rs b/src/uu/seq/src/seq.rs index 4c050c2c735..a489e54b9a9 100644 --- a/src/uu/seq/src/seq.rs +++ b/src/uu/seq/src/seq.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore (ToDO) bigdecimal extendedbigdecimal numberparse hexadecimalfloat biguint -use std::ffi::{OsStr, OsString}; +use std::ffi::OsString; use std::io::{BufWriter, ErrorKind, Write, stdout}; use clap::{Arg, ArgAction, Command}; @@ -39,8 +39,8 @@ const ARG_NUMBERS: &str = "numbers"; #[derive(Clone)] struct SeqOptions<'a> { - separator: OsString, - terminator: OsString, + separator: String, + terminator: String, equal_width: bool, format: Option<&'a str>, } @@ -105,11 +105,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let options = SeqOptions { separator: matches - .get_one::(OPT_SEPARATOR) - .map_or(OsString::from("\n"), |s| s.to_os_string()), + .get_one::(OPT_SEPARATOR) + .map_or("\n", |s| s.as_str()) + .to_string(), terminator: matches - .get_one::(OPT_TERMINATOR) - .map_or(OsString::from("\n"), |s| s.to_os_string()), + .get_one::(OPT_TERMINATOR) + .map(|s| s.as_str()) + .unwrap_or("\n") + .to_string(), equal_width: matches.get_flag(OPT_EQUAL_WIDTH), format: matches.get_one::(OPT_FORMAT).map(|s| s.as_str()), }; @@ -226,15 +229,13 @@ pub fn uu_app() -> Command { Arg::new(OPT_SEPARATOR) .short('s') .long("separator") - .help(translate!("seq-help-separator")) - .value_parser(clap::value_parser!(OsString)), + .help(translate!("seq-help-separator")), ) .arg( Arg::new(OPT_TERMINATOR) .short('t') .long("terminator") - .help(translate!("seq-help-terminator")) - .value_parser(clap::value_parser!(OsString)), + .help(translate!("seq-help-terminator")), ) .arg( Arg::new(OPT_EQUAL_WIDTH) @@ -266,8 +267,8 @@ fn fast_print_seq( first: &BigUint, increment: u64, last: &BigUint, - separator: &OsStr, - terminator: &OsStr, + separator: &str, + terminator: &str, padding: usize, ) -> std::io::Result<()> { // Nothing to do, just return. @@ -304,7 +305,7 @@ fn fast_print_seq( // Initialize buf with first and separator. buf[start..num_end].copy_from_slice(first_str.as_bytes()); - buf[num_end..].copy_from_slice(separator.as_encoded_bytes()); + buf[num_end..].copy_from_slice(separator.as_bytes()); // Normally, if padding is > 0, it should be equal to last_length, // so start would be == 0, but there are corner cases. @@ -320,7 +321,7 @@ fn fast_print_seq( } // Write the last number without separator, but with terminator. stdout.write_all(&buf[start..num_end])?; - stdout.write_all(terminator.as_encoded_bytes())?; + write!(stdout, "{terminator}")?; stdout.flush()?; Ok(()) } @@ -336,8 +337,8 @@ fn done_printing(next: &T, increment: &T, last: &T) -> boo /// Arbitrary precision decimal number code path ("slow" path) fn print_seq( range: RangeFloat, - separator: &OsStr, - terminator: &OsStr, + separator: &str, + terminator: &str, format: &Format, fast_allowed: bool, padding: usize, // Used by fast path only @@ -374,7 +375,7 @@ fn print_seq( let mut is_first_iteration = true; while !done_printing(&value, &increment, &last) { if !is_first_iteration { - stdout.write_all(separator.as_encoded_bytes())?; + stdout.write_all(separator.as_bytes())?; } format.fmt(&mut stdout, &value)?; // TODO Implement augmenting addition. @@ -382,7 +383,7 @@ fn print_seq( is_first_iteration = false; } if !is_first_iteration { - stdout.write_all(terminator.as_encoded_bytes())?; + stdout.write_all(terminator.as_bytes())?; } stdout.flush()?; Ok(()) diff --git a/src/uu/stat/src/stat.rs b/src/uu/stat/src/stat.rs index 5f9e8841793..797e6971be7 100644 --- a/src/uu/stat/src/stat.rs +++ b/src/uu/stat/src/stat.rs @@ -111,56 +111,9 @@ fn pad_and_print(result: &str, left: bool, width: usize, padding: Padding) { } } -/// Pads and prints raw bytes (Unix-specific) or falls back to string printing -/// -/// On Unix systems, this preserves non-UTF8 data by printing raw bytes -/// On other platforms, falls back to lossy string conversion -fn pad_and_print_bytes( - mut writer: W, - bytes: &[u8], - left: bool, - width: usize, - precision: Precision, -) -> Result<(), std::io::Error> { - let display_bytes = match precision { - Precision::Number(p) if p < bytes.len() => &bytes[..p], - _ => bytes, - }; - - let display_len = display_bytes.len(); - let padding_needed = width.saturating_sub(display_len); - - let (left_pad, right_pad) = if left { - (0, padding_needed) - } else { - (padding_needed, 0) - }; - - if left_pad > 0 { - print_padding(&mut writer, left_pad)?; - } - writer.write_all(display_bytes)?; - if right_pad > 0 { - print_padding(&mut writer, right_pad)?; - } - - Ok(()) -} - -/// print padding based on a writer W and n size -/// writer is genric to be any buffer like: `std::io::stdout` -/// n is the calculated padding size -fn print_padding(writer: &mut W, n: usize) -> Result<(), std::io::Error> { - for _ in 0..n { - writer.write_all(b" ")?; - } - Ok(()) -} - #[derive(Debug)] -pub enum OutputType<'a> { +pub enum OutputType { Str(String), - OsStr(&'a OsString), Integer(i64), Unsigned(u64), UnsignedHex(u64), @@ -353,7 +306,6 @@ fn print_it(output: &OutputType, flags: Flags, width: usize, precision: Precisio match output { OutputType::Str(s) => print_str(s, &flags, width, precision), - OutputType::OsStr(s) => print_os_str(s, &flags, width, precision), OutputType::Integer(num) => print_integer(*num, &flags, width, precision, padding_char), OutputType::Unsigned(num) => print_unsigned(*num, &flags, width, precision, padding_char), OutputType::UnsignedOct(num) => { @@ -402,37 +354,6 @@ fn print_str(s: &str, flags: &Flags, width: usize, precision: Precision) { pad_and_print(s, flags.left, width, Padding::Space); } -/// Prints a `OsString` value based on the provided flags, width, and precision. -/// for unix it converts it to bytes then tries to print it if failed print the lossy string version -/// for windows, `OsString` uses UTF-16 internally which doesn't map directly to bytes like Unix, -/// so we fall back to lossy string conversion to handle invalid UTF-8 sequences gracefully -/// -/// # Arguments -/// -/// * `s` - The `OsString` to be printed. -/// * `flags` - A reference to the Flags struct containing formatting flags. -/// * `width` - The width of the field for the printed string. -/// * `precision` - How many digits of precision, if any. -fn print_os_str(s: &OsString, flags: &Flags, width: usize, precision: Precision) { - #[cfg(unix)] - { - use std::os::unix::ffi::OsStrExt; - - let bytes = s.as_bytes(); - - if pad_and_print_bytes(std::io::stdout(), bytes, flags.left, width, precision).is_err() { - // if an error occurred while trying to print bytes fall back to normal lossy string so it can be printed - let fallback_string = s.to_string_lossy(); - print_str(&fallback_string, flags, width, precision); - } - } - #[cfg(not(unix))] - { - let lossy_string = s.to_string_lossy(); - print_str(&lossy_string, flags, width, precision); - } -} - fn quote_file_name(file_name: &str, quoting_style: &QuotingStyle) -> String { match quoting_style { QuotingStyle::Locale | QuotingStyle::Shell => { @@ -969,12 +890,16 @@ impl Stater { }) } - fn find_mount_point>(&self, p: P) -> Option<&OsString> { + fn find_mount_point>(&self, p: P) -> Option { let path = p.as_ref().canonicalize().ok()?; - self.mount_list - .as_ref()? - .iter() - .find(|root| path.starts_with(root)) + + for root in self.mount_list.as_ref()? { + if path.starts_with(root) { + // TODO: This is probably wrong, we should pass the OsString + return Some(root.to_string_lossy().into_owned()); + } + } + None } fn exec(&self) -> i32 { @@ -1068,11 +993,8 @@ impl Stater { 'h' => OutputType::Unsigned(meta.nlink()), // inode number 'i' => OutputType::Unsigned(meta.ino()), - // mount point - 'm' => match self.find_mount_point(file) { - Some(s) => OutputType::OsStr(s), - None => OutputType::Str(String::new()), - }, + // mount point: TODO: This should be an OsStr + 'm' => OutputType::Str(self.find_mount_point(file).unwrap()), // file name 'n' => OutputType::Str(display_name.to_string()), // quoted file name with dereference if symbolic link @@ -1378,8 +1300,6 @@ fn pretty_time(meta: &Metadata, md_time_field: MetadataTimeField) -> String { #[cfg(test)] mod tests { - use crate::{pad_and_print_bytes, print_padding}; - use super::{Flags, Precision, ScanUtil, Stater, Token, group_num, precision_trunc}; #[test] @@ -1501,32 +1421,4 @@ mod tests { assert_eq!(precision_trunc(123.456, Precision::Number(4)), "123.4560"); assert_eq!(precision_trunc(123.456, Precision::Number(5)), "123.45600"); } - - #[test] - fn test_pad_and_print_bytes() { - // testing non-utf8 with normal settings - let mut buffer = Vec::new(); - let bytes = b"\x80\xFF\x80"; - pad_and_print_bytes(&mut buffer, bytes, false, 3, Precision::NotSpecified).unwrap(); - assert_eq!(&buffer, b"\x80\xFF\x80"); - - // testing left padding - let mut buffer = Vec::new(); - let bytes = b"\x80\xFF\x80"; - pad_and_print_bytes(&mut buffer, bytes, false, 5, Precision::NotSpecified).unwrap(); - assert_eq!(&buffer, b" \x80\xFF\x80"); - - // testing right padding - let mut buffer = Vec::new(); - let bytes = b"\x80\xFF\x80"; - pad_and_print_bytes(&mut buffer, bytes, true, 5, Precision::NotSpecified).unwrap(); - assert_eq!(&buffer, b"\x80\xFF\x80 "); - } - - #[test] - fn test_print_padding() { - let mut buffer = Vec::new(); - print_padding(&mut buffer, 5).unwrap(); - assert_eq!(&buffer, b" "); - } } diff --git a/tests/by-util/test_id.rs b/tests/by-util/test_id.rs index 169fbe2abcf..7a7d5e9a169 100644 --- a/tests/by-util/test_id.rs +++ b/tests/by-util/test_id.rs @@ -17,11 +17,6 @@ fn test_invalid_arg() { new_ucmd!().arg("--definitely-invalid").fails_with_code(1); } -#[test] -fn test_id_ignore() { - new_ucmd!().arg("-a").succeeds(); -} - #[test] #[allow(unused_mut)] fn test_id_no_specified_user() { diff --git a/tests/by-util/test_seq.rs b/tests/by-util/test_seq.rs index f82a6228fe1..a4f49ea4149 100644 --- a/tests/by-util/test_seq.rs +++ b/tests/by-util/test_seq.rs @@ -228,52 +228,6 @@ fn test_separator_and_terminator() { .stdout_is("2\\n3\\n4\\n5\\n6\n"); } -#[test] -#[cfg(target_os = "linux")] -fn test_separator_non_utf8() { - use std::{ffi::OsString, os::unix::ffi::OsStringExt}; - - fn create_arg(prefix: &[u8]) -> OsString { - let separator = [0xFF, 0xFE]; - OsString::from_vec([prefix, &separator].concat()) - } - - let short = create_arg(b"-s"); - let long = create_arg(b"--separator="); - let expected = [b'1', 0xFF, 0xFE, b'2', b'\n']; - - for arg in [short, long] { - new_ucmd!() - .arg(&arg) - .arg("2") - .succeeds() - .stdout_is_bytes(expected); - } -} - -#[test] -#[cfg(target_os = "linux")] -fn test_terminator_non_utf8() { - use std::{ffi::OsString, os::unix::ffi::OsStringExt}; - - fn create_arg(prefix: &[u8]) -> OsString { - let terminator = [0xFF, 0xFE]; - OsString::from_vec([prefix, &terminator].concat()) - } - - let short = create_arg(b"-t"); - let long = create_arg(b"--terminator="); - let expected = [b'1', b'\n', b'2', 0xFF, 0xFE]; - - for arg in [short, long] { - new_ucmd!() - .arg(&arg) - .arg("2") - .succeeds() - .stdout_is_bytes(expected); - } -} - #[test] fn test_equalize_widths() { let args = ["-w", "--equal-width"]; diff --git a/tests/by-util/test_stat.rs b/tests/by-util/test_stat.rs index aeabf88fd43..6c4258189bd 100644 --- a/tests/by-util/test_stat.rs +++ b/tests/by-util/test_stat.rs @@ -514,49 +514,3 @@ fn test_stat_selinux() { let s: Vec<_> = result.stdout_str().split(':').collect(); assert!(s.len() == 4); } - -#[cfg(unix)] -#[test] -fn test_mount_point_basic() { - let ts = TestScenario::new(util_name!()); - let result = ts.ucmd().args(&["-c", "%m", "/"]).succeeds(); - let output = result.stdout_str().trim(); - assert!(!output.is_empty(), "Mount point should not be empty"); - assert_eq!(output, "/"); -} - -#[cfg(unix)] -#[test] -fn test_mount_point_width_and_alignment() { - let ts = TestScenario::new(util_name!()); - - // Right-aligned, width 15 - let result = ts.ucmd().args(&["-c", "%15m", "/"]).succeeds(); - let output = result.stdout_str(); - assert!( - output.trim().len() <= 15 && output.len() >= 15, - "Output should be padded to width 15" - ); - - // Left-aligned, width 15 - let result = ts.ucmd().args(&["-c", "%-15m", "/"]).succeeds(); - let output = result.stdout_str(); - - assert!( - output.trim().len() <= 15 && output.len() >= 15, - "Output should be padded to width 15 (left-aligned)" - ); -} - -#[cfg(unix)] -#[test] -fn test_mount_point_combined_with_other_specifiers() { - let ts = TestScenario::new(util_name!()); - let result = ts.ucmd().args(&["-c", "%m %n %s", "/bin/sh"]).succeeds(); - let output = result.stdout_str(); - let parts: Vec<&str> = output.split_whitespace().collect(); - assert!( - parts.len() >= 3, - "Should print mount point, file name, and size" - ); -} diff --git a/util/build-gnu.sh b/util/build-gnu.sh index db58321414d..4da34b4b324 100755 --- a/util/build-gnu.sh +++ b/util/build-gnu.sh @@ -70,18 +70,18 @@ fi ### -release_tag_GNU="v9.8" +release_tag_GNU="v9.7" # check if the GNU coreutils has been cloned, if not print instructions # note: the ${path_GNU} might already exist, so we check for the .git directory if test ! -d "${path_GNU}/.git"; then - echo "Could not find the GNU coreutils (expected at '${path_GNU}')" - echo "Download them to the expected path:" - echo " git clone --recurse-submodules https://github.com/coreutils/coreutils.git \"${path_GNU}\"" - echo "Afterwards, checkout the latest release tag:" - echo " cd \"${path_GNU}\"" - echo " git fetch --all --tags" - echo " git checkout tags/${release_tag_GNU}" + echo "Could not find GNU coreutils (expected at '${path_GNU}')" + echo "Run the following to download into the expected path:" + echo "git clone --recurse-submodules https://github.com/coreutils/coreutils.git \"${path_GNU}\"" + echo "After downloading GNU coreutils to \"${path_GNU}\" run the following commands to checkout latest release tag" + echo "cd \"${path_GNU}\"" + echo "git fetch --all --tags" + echo "git checkout tags/${release_tag_GNU}" exit 1 fi