From 3acd75bcc4d73df4016c78b45c8fa3dce1f31832 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Sun, 12 Feb 2023 01:36:13 -0700 Subject: [PATCH 01/23] cp: Use PathBuf instead of String for paths I think this should avoid unnecessarily validating utf-8, and avoids a few allocations. --- src/uu/cp/src/cp.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index f0dc762be..234289564 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -26,7 +26,7 @@ use std::os::unix::fs::{FileTypeExt, PermissionsExt}; use std::path::{Path, PathBuf, StripPrefixError}; use std::string::ToString; -use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; +use clap::{builder::ValueParser, crate_version, Arg, ArgAction, ArgMatches, Command}; use filetime::FileTime; use indicatif::{ProgressBar, ProgressStyle}; #[cfg(unix)] @@ -91,7 +91,7 @@ quick_error! { /// Invalid arguments to backup Backup(description: String) { display("{}\nTry '{} --help' for more information.", description, uucore::execution_phrase()) } - NotADirectory(path: String) { display("'{}' is not a directory", path) } + NotADirectory(path: PathBuf) { display("'{}' is not a directory", path.display()) } } } @@ -222,7 +222,7 @@ pub struct Options { attributes: Attributes, recursive: bool, backup_suffix: String, - target_dir: Option, + target_dir: Option, update: bool, verbose: bool, progress_bar: bool, @@ -302,6 +302,7 @@ pub fn uu_app() -> Command { .long(options::TARGET_DIRECTORY) .value_name(options::TARGET_DIRECTORY) .value_hint(clap::ValueHint::DirPath) + .value_parser(ValueParser::path_buf()) .help("copy all SOURCE arguments into target-directory"), ) .arg( @@ -555,7 +556,8 @@ pub fn uu_app() -> Command { .arg( Arg::new(options::PATHS) .action(ArgAction::Append) - .value_hint(clap::ValueHint::AnyPath), + .value_hint(clap::ValueHint::AnyPath) + .value_parser(ValueParser::path_buf()), ) } @@ -576,7 +578,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { clap::error::ErrorKind::DisplayVersion => print!("{}", app.render_version()), _ => return Err(Box::new(e.with_exit_code(1))), }; - } else if let Ok(matches) = matches { + } else if let Ok(mut matches) = matches { let options = Options::from_matches(&matches)?; if options.overwrite == OverwriteMode::NoClobber && options.backup != BackupMode::NoBackup { @@ -586,12 +588,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { )); } - let paths: Vec = matches - .get_many::(options::PATHS) - .map(|v| v.map(ToString::to_string).collect()) + let paths: Vec = matches + .remove_many::(options::PATHS) + .map(|v| v.collect()) .unwrap_or_default(); - let (sources, target) = parse_path_args(&paths, &options)?; + let (sources, target) = parse_path_args(paths, &options)?; if let Err(error) = copy(&sources, &target, &options) { match error { @@ -754,11 +756,11 @@ impl Options { // Parse target directory options let no_target_dir = matches.get_flag(options::NO_TARGET_DIRECTORY); let target_dir = matches - .get_one::(options::TARGET_DIRECTORY) - .map(ToString::to_string); + .get_one::(options::TARGET_DIRECTORY) + .cloned(); if let Some(dir) = &target_dir { - if !Path::new(dir).is_dir() { + if !dir.is_dir() { return Err(Error::NotADirectory(dir.clone())); } }; @@ -915,9 +917,7 @@ impl TargetType { } /// Returns tuple of (Source paths, Target) -fn parse_path_args(path_args: &[String], options: &Options) -> CopyResult<(Vec, Target)> { - let mut paths = path_args.iter().map(PathBuf::from).collect::>(); - +fn parse_path_args(mut paths: Vec, options: &Options) -> CopyResult<(Vec, Target)> { if paths.is_empty() { // No files specified return Err("missing file operand".into()); @@ -933,7 +933,7 @@ fn parse_path_args(path_args: &[String], options: &Options) -> CopyResult<(Vec { // All path args are sources, and the target dir was // specified separately - PathBuf::from(target) + target.clone() } None => { // If there was no explicit target-dir, then use the last From 17f9507e17967738e6ed9d5b9385c998de2c5537 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Mon, 13 Feb 2023 02:00:03 -0700 Subject: [PATCH 02/23] Add tests for non-utf8 --- tests/by-util/test_chown.rs | 8 ++-- tests/by-util/test_chroot.rs | 2 +- tests/by-util/test_cp.rs | 82 +++++++++++++++++++++++++--------- tests/by-util/test_install.rs | 58 ++++++++++++------------ tests/by-util/test_ln.rs | 2 +- tests/by-util/test_ls.rs | 72 ++++++++++++++--------------- tests/by-util/test_mv.rs | 56 +++++++++++------------ tests/by-util/test_realpath.rs | 2 +- tests/common/util.rs | 14 +++--- 9 files changed, 170 insertions(+), 126 deletions(-) diff --git a/tests/by-util/test_chown.rs b/tests/by-util/test_chown.rs index 5237a7cf7..92ee55b1c 100644 --- a/tests/by-util/test_chown.rs +++ b/tests/by-util/test_chown.rs @@ -662,10 +662,10 @@ fn test_chown_recursive() { at.mkdir_all("a/b/c"); at.mkdir("z"); - at.touch(&at.plus_as_string("a/a")); - at.touch(&at.plus_as_string("a/b/b")); - at.touch(&at.plus_as_string("a/b/c/c")); - at.touch(&at.plus_as_string("z/y")); + at.touch(at.plus_as_string("a/a")); + at.touch(at.plus_as_string("a/b/b")); + at.touch(at.plus_as_string("a/b/c/c")); + at.touch(at.plus_as_string("z/y")); let result = scene .ucmd() diff --git a/tests/by-util/test_chroot.rs b/tests/by-util/test_chroot.rs index c7e786f93..0e3468720 100644 --- a/tests/by-util/test_chroot.rs +++ b/tests/by-util/test_chroot.rs @@ -39,7 +39,7 @@ fn test_enter_chroot_fails() { fn test_no_such_directory() { let (at, mut ucmd) = at_and_ucmd!(); - at.touch(&at.plus_as_string("a")); + at.touch(at.plus_as_string("a")); ucmd.arg("a") .fails() diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index e6e8a6ba2..818261220 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -15,11 +15,15 @@ use std::os::unix::fs::PermissionsExt; use std::os::windows::fs::symlink_file; #[cfg(not(windows))] use std::path::Path; +#[cfg(target_os = "linux")] +use std::path::PathBuf; #[cfg(any(target_os = "linux", target_os = "android"))] use filetime::FileTime; #[cfg(any(target_os = "linux", target_os = "android"))] use rlimit::Resource; +#[cfg(target_os = "linux")] +use std::ffi::OsString; #[cfg(any(target_os = "linux", target_os = "android"))] use std::fs as std_fs; use std::thread::sleep; @@ -91,7 +95,7 @@ fn test_cp_existing_target() { assert_eq!(at.read(TEST_EXISTING_FILE), "Hello, World!\n"); // No backup should have been created - assert!(!at.file_exists(&format!("{TEST_EXISTING_FILE}~"))); + assert!(!at.file_exists(format!("{TEST_EXISTING_FILE}~"))); } #[test] @@ -636,7 +640,7 @@ fn test_cp_backup_none() { .no_stderr(); assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); - assert!(!at.file_exists(&format!("{TEST_HOW_ARE_YOU_SOURCE}~"))); + assert!(!at.file_exists(format!("{TEST_HOW_ARE_YOU_SOURCE}~"))); } #[test] @@ -650,7 +654,7 @@ fn test_cp_backup_off() { .no_stderr(); assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); - assert!(!at.file_exists(&format!("{TEST_HOW_ARE_YOU_SOURCE}~"))); + assert!(!at.file_exists(format!("{TEST_HOW_ARE_YOU_SOURCE}~"))); } #[test] @@ -700,7 +704,7 @@ fn test_cp_deref() { .join(TEST_HELLO_WORLD_SOURCE_SYMLINK); // unlike -P/--no-deref, we expect a file, not a link assert!(at.file_exists( - &path_to_new_symlink + path_to_new_symlink .clone() .into_os_string() .into_string() @@ -1062,7 +1066,7 @@ fn test_cp_deref_folder_to_folder() { .join(TEST_COPY_TO_FOLDER_NEW) .join(TEST_HELLO_WORLD_SOURCE_SYMLINK); assert!(at.file_exists( - &path_to_new_symlink + path_to_new_symlink .clone() .into_os_string() .into_string() @@ -1225,8 +1229,8 @@ fn test_cp_archive_recursive() { let file_2 = at.subdir.join(TEST_COPY_TO_FOLDER).join("2"); let file_2_link = at.subdir.join(TEST_COPY_TO_FOLDER).join("2.link"); - at.touch(&file_1.to_string_lossy()); - at.touch(&file_2.to_string_lossy()); + at.touch(file_1); + at.touch(file_2); at.symlink_file("1", &file_1_link.to_string_lossy()); at.symlink_file("2", &file_2_link.to_string_lossy()); @@ -1252,18 +1256,8 @@ fn test_cp_archive_recursive() { .run(); println!("ls dest {}", result.stdout_str()); - assert!(at.file_exists( - &at.subdir - .join(TEST_COPY_TO_FOLDER_NEW) - .join("1") - .to_string_lossy() - )); - assert!(at.file_exists( - &at.subdir - .join(TEST_COPY_TO_FOLDER_NEW) - .join("2") - .to_string_lossy() - )); + assert!(at.file_exists(at.subdir.join(TEST_COPY_TO_FOLDER_NEW).join("1"))); + assert!(at.file_exists(at.subdir.join(TEST_COPY_TO_FOLDER_NEW).join("2"))); assert!(at.is_symlink( &at.subdir @@ -1672,7 +1666,7 @@ fn test_cp_reflink_always_override() { let dst_path: &str = &vec![MOUNTPOINT, USERDIR, "dst"].concat(); scene.fixtures.mkdir(ROOTDIR); - scene.fixtures.mkdir(&vec![ROOTDIR, USERDIR].concat()); + scene.fixtures.mkdir(vec![ROOTDIR, USERDIR].concat()); // Setup: // Because neither `mkfs.btrfs` not btrfs `mount` options allow us to have a mountpoint owned @@ -2532,3 +2526,51 @@ fn test_src_base_dot() { .no_stdout(); assert!(!at.dir_exists("y/x")); } + +#[cfg(target_os = "linux")] +fn non_utf8_name(suffix: &str) -> OsString { + use std::os::unix::ffi::OsStringExt; + let mut name = OsString::from_vec(vec![0xff, 0xff]); + name.push(suffix); + name +} + +#[cfg(target_os = "linux")] +#[test] +fn test_non_utf8_src() { + let (at, mut ucmd) = at_and_ucmd!(); + let src = non_utf8_name("src"); + std::fs::File::create(at.plus(&src)).unwrap(); + ucmd.args(&[src, "dest".into()]) + .succeeds() + .no_stderr() + .no_stdout(); + assert!(at.file_exists("dest")); +} + +#[cfg(target_os = "linux")] +#[test] +fn test_non_utf8_dest() { + let (at, mut ucmd) = at_and_ucmd!(); + let dest = non_utf8_name("dest"); + ucmd.args(&[TEST_HELLO_WORLD_SOURCE.as_ref(), &*dest]) + .succeeds() + .no_stderr() + .no_stdout(); + assert!(at.file_exists(dest)); +} + +#[cfg(target_os = "linux")] +#[test] +fn test_non_utf8_target() { + let (at, mut ucmd) = at_and_ucmd!(); + let dest = non_utf8_name("dest"); + at.mkdir(&dest); + ucmd.args(&["-t".as_ref(), &*dest, TEST_HELLO_WORLD_SOURCE.as_ref()]) + .succeeds() + .no_stderr() + .no_stdout(); + let mut copied_file = PathBuf::from(dest); + copied_file.push(TEST_HELLO_WORLD_SOURCE); + assert!(at.file_exists(copied_file)); +} diff --git a/tests/by-util/test_install.rs b/tests/by-util/test_install.rs index e041fb081..133f1381d 100644 --- a/tests/by-util/test_install.rs +++ b/tests/by-util/test_install.rs @@ -28,8 +28,8 @@ fn test_install_basic() { assert!(at.file_exists(file1)); assert!(at.file_exists(file2)); - assert!(at.file_exists(&format!("{dir}/{file1}"))); - assert!(at.file_exists(&format!("{dir}/{file2}"))); + assert!(at.file_exists(format!("{dir}/{file1}"))); + assert!(at.file_exists(format!("{dir}/{file2}"))); } #[test] @@ -76,7 +76,7 @@ fn test_install_unimplemented_arg() { .fails() .stderr_contains("Unimplemented"); - assert!(!at.file_exists(&format!("{dir}/{file}"))); + assert!(!at.file_exists(format!("{dir}/{file}"))); } #[test] @@ -314,7 +314,7 @@ fn test_install_target_new_file() { .no_stderr(); assert!(at.file_exists(file)); - assert!(at.file_exists(&format!("{dir}/{file}"))); + assert!(at.file_exists(format!("{dir}/{file}"))); } #[test] @@ -341,7 +341,7 @@ fn test_install_target_new_file_with_group() { result.success(); assert!(at.file_exists(file)); - assert!(at.file_exists(&format!("{dir}/{file}"))); + assert!(at.file_exists(format!("{dir}/{file}"))); } #[test] @@ -368,7 +368,7 @@ fn test_install_target_new_file_with_owner() { result.success(); assert!(at.file_exists(file)); - assert!(at.file_exists(&format!("{dir}/{file}"))); + assert!(at.file_exists(format!("{dir}/{file}"))); } #[test] @@ -447,13 +447,13 @@ fn test_install_nested_paths_copy_file() { at.mkdir(dir1); at.mkdir(dir2); - at.touch(&format!("{dir1}/{file1}")); + at.touch(format!("{dir1}/{file1}")); ucmd.arg(format!("{dir1}/{file1}")) .arg(dir2) .succeeds() .no_stderr(); - assert!(at.file_exists(&format!("{dir2}/{file1}"))); + assert!(at.file_exists(format!("{dir2}/{file1}"))); } #[test] @@ -487,7 +487,7 @@ fn test_install_failing_omitting_directory() { .fails() .code_is(1) .stderr_contains("omitting directory"); - assert!(at.file_exists(&format!("{dir3}/{file1}"))); + assert!(at.file_exists(format!("{dir3}/{file1}"))); // install also fails, when only one source param is given scene @@ -785,7 +785,7 @@ fn test_install_creating_leading_dirs_with_single_source_and_target_dir() { .succeeds() .no_stderr(); - assert!(at.file_exists(&format!("{target_dir}/{source1}"))); + assert!(at.file_exists(format!("{target_dir}/{source1}"))); } #[test] @@ -863,8 +863,8 @@ fn test_install_dir() { assert!(at.file_exists(file1)); assert!(at.file_exists(file2)); - assert!(at.file_exists(&format!("{dir}/{file1}"))); - assert!(at.file_exists(&format!("{dir}/{file2}"))); + assert!(at.file_exists(format!("{dir}/{file1}"))); + assert!(at.file_exists(format!("{dir}/{file2}"))); } // // test backup functionality @@ -888,7 +888,7 @@ fn test_install_backup_short_no_args_files() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}~"))); + assert!(at.file_exists(format!("{file_b}~"))); } #[test] @@ -913,7 +913,7 @@ fn test_install_backup_short_no_args_file_to_dir() { assert!(at.file_exists(file)); assert!(at.file_exists(&expect)); - assert!(at.file_exists(&format!("{expect}~"))); + assert!(at.file_exists(format!("{expect}~"))); } // Long --backup option is tested separately as it requires a slightly different @@ -938,7 +938,7 @@ fn test_install_backup_long_no_args_files() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}~"))); + assert!(at.file_exists(format!("{file_b}~"))); } #[test] @@ -963,7 +963,7 @@ fn test_install_backup_long_no_args_file_to_dir() { assert!(at.file_exists(file)); assert!(at.file_exists(&expect)); - assert!(at.file_exists(&format!("{expect}~"))); + assert!(at.file_exists(format!("{expect}~"))); } #[test] @@ -988,7 +988,7 @@ fn test_install_backup_short_custom_suffix() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}{suffix}"))); + assert!(at.file_exists(format!("{file_b}{suffix}"))); } #[test] @@ -1013,7 +1013,7 @@ fn test_install_backup_short_custom_suffix_hyphen_value() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}{suffix}"))); + assert!(at.file_exists(format!("{file_b}{suffix}"))); } #[test] @@ -1038,7 +1038,7 @@ fn test_install_backup_custom_suffix_via_env() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}{suffix}"))); + assert!(at.file_exists(format!("{file_b}{suffix}"))); } #[test] @@ -1061,7 +1061,7 @@ fn test_install_backup_numbered_with_t() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}.~1~"))); + assert!(at.file_exists(format!("{file_b}.~1~"))); } #[test] @@ -1084,7 +1084,7 @@ fn test_install_backup_numbered_with_numbered() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}.~1~"))); + assert!(at.file_exists(format!("{file_b}.~1~"))); } #[test] @@ -1107,7 +1107,7 @@ fn test_install_backup_existing() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}~"))); + assert!(at.file_exists(format!("{file_b}~"))); } #[test] @@ -1130,7 +1130,7 @@ fn test_install_backup_nil() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}~"))); + assert!(at.file_exists(format!("{file_b}~"))); } #[test] @@ -1156,7 +1156,7 @@ fn test_install_backup_numbered_if_existing_backup_existing() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); assert!(at.file_exists(file_b_backup)); - assert!(at.file_exists(&format!("{file_b}.~2~"))); + assert!(at.file_exists(format!("{file_b}.~2~"))); } #[test] @@ -1182,7 +1182,7 @@ fn test_install_backup_numbered_if_existing_backup_nil() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); assert!(at.file_exists(file_b_backup)); - assert!(at.file_exists(&format!("{file_b}.~2~"))); + assert!(at.file_exists(format!("{file_b}.~2~"))); } #[test] @@ -1205,7 +1205,7 @@ fn test_install_backup_simple() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}~"))); + assert!(at.file_exists(format!("{file_b}~"))); } #[test] @@ -1228,7 +1228,7 @@ fn test_install_backup_never() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}~"))); + assert!(at.file_exists(format!("{file_b}~"))); } #[test] @@ -1251,7 +1251,7 @@ fn test_install_backup_none() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(!at.file_exists(&format!("{file_b}~"))); + assert!(!at.file_exists(format!("{file_b}~"))); } #[test] @@ -1274,7 +1274,7 @@ fn test_install_backup_off() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(!at.file_exists(&format!("{file_b}~"))); + assert!(!at.file_exists(format!("{file_b}~"))); } #[test] diff --git a/tests/by-util/test_ln.rs b/tests/by-util/test_ln.rs index bc51fc107..1a4c9095b 100644 --- a/tests/by-util/test_ln.rs +++ b/tests/by-util/test_ln.rs @@ -403,7 +403,7 @@ fn test_symlink_implicit_target_dir() { let file = &path.to_string_lossy(); at.mkdir(dir); - at.touch(file); + at.touch(&path); ucmd.args(&["-s", file]).succeeds().no_stderr(); diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 339c78c12..36ae816b3 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -609,10 +609,10 @@ fn test_ls_a() { fn test_ls_width() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; - at.touch(&at.plus_as_string("test-width-1")); - at.touch(&at.plus_as_string("test-width-2")); - at.touch(&at.plus_as_string("test-width-3")); - at.touch(&at.plus_as_string("test-width-4")); + at.touch(at.plus_as_string("test-width-1")); + at.touch(at.plus_as_string("test-width-2")); + at.touch(at.plus_as_string("test-width-3")); + at.touch(at.plus_as_string("test-width-4")); for option in [ "-w 100", @@ -692,10 +692,10 @@ fn test_ls_width() { fn test_ls_columns() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; - at.touch(&at.plus_as_string("test-columns-1")); - at.touch(&at.plus_as_string("test-columns-2")); - at.touch(&at.plus_as_string("test-columns-3")); - at.touch(&at.plus_as_string("test-columns-4")); + at.touch(at.plus_as_string("test-columns-1")); + at.touch(at.plus_as_string("test-columns-2")); + at.touch(at.plus_as_string("test-columns-3")); + at.touch(at.plus_as_string("test-columns-4")); // Columns is the default let result = scene.ucmd().succeeds(); @@ -753,10 +753,10 @@ fn test_ls_columns() { fn test_ls_across() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; - at.touch(&at.plus_as_string("test-across-1")); - at.touch(&at.plus_as_string("test-across-2")); - at.touch(&at.plus_as_string("test-across-3")); - at.touch(&at.plus_as_string("test-across-4")); + at.touch(at.plus_as_string("test-across-1")); + at.touch(at.plus_as_string("test-across-2")); + at.touch(at.plus_as_string("test-across-3")); + at.touch(at.plus_as_string("test-across-4")); for option in ACROSS_ARGS { let result = scene.ucmd().arg(option).succeeds(); @@ -781,10 +781,10 @@ fn test_ls_across() { fn test_ls_commas() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; - at.touch(&at.plus_as_string("test-commas-1")); - at.touch(&at.plus_as_string("test-commas-2")); - at.touch(&at.plus_as_string("test-commas-3")); - at.touch(&at.plus_as_string("test-commas-4")); + at.touch(at.plus_as_string("test-commas-1")); + at.touch(at.plus_as_string("test-commas-2")); + at.touch(at.plus_as_string("test-commas-3")); + at.touch(at.plus_as_string("test-commas-4")); for option in COMMA_ARGS { let result = scene.ucmd().arg(option).succeeds(); @@ -814,8 +814,8 @@ fn test_ls_zero() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; at.mkdir("0-test-zero"); - at.touch(&at.plus_as_string("2-test-zero")); - at.touch(&at.plus_as_string("3-test-zero")); + at.touch(at.plus_as_string("2-test-zero")); + at.touch(at.plus_as_string("3-test-zero")); let ignored_opts = [ "--quoting-style=c", @@ -870,7 +870,7 @@ fn test_ls_zero() { #[cfg(unix)] { - at.touch(&at.plus_as_string("1\ntest-zero")); + at.touch(at.plus_as_string("1\ntest-zero")); let ignored_opts = [ "--quoting-style=c", @@ -933,9 +933,9 @@ fn test_ls_zero() { fn test_ls_commas_trailing() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; - at.touch(&at.plus_as_string("test-commas-trailing-2")); + at.touch(at.plus_as_string("test-commas-trailing-2")); - at.touch(&at.plus_as_string("test-commas-trailing-1")); + at.touch(at.plus_as_string("test-commas-trailing-1")); at.append( "test-commas-trailing-1", &(0..2000) @@ -957,7 +957,7 @@ fn test_ls_commas_trailing() { fn test_ls_long() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; - at.touch(&at.plus_as_string("test-long")); + at.touch(at.plus_as_string("test-long")); for arg in LONG_ARGS { let result = scene.ucmd().arg(arg).arg("test-long").succeeds(); @@ -975,7 +975,7 @@ fn test_ls_long_format() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; at.mkdir(&at.plus_as_string("test-long-dir")); - at.touch(&at.plus_as_string("test-long-dir/test-long-file")); + at.touch(at.plus_as_string("test-long-dir/test-long-file")); at.mkdir(&at.plus_as_string("test-long-dir/test-long-dir")); for arg in LONG_ARGS { @@ -1231,9 +1231,9 @@ fn test_ls_long_symlink_color() { fn test_ls_long_total_size() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; - at.touch(&at.plus_as_string("test-long")); + at.touch(at.plus_as_string("test-long")); at.append("test-long", "1"); - at.touch(&at.plus_as_string("test-long2")); + at.touch(at.plus_as_string("test-long2")); at.append("test-long2", "2"); let expected_prints: HashMap<_, _> = if cfg!(unix) { @@ -1275,7 +1275,7 @@ fn test_ls_long_total_size() { fn test_ls_long_formats() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; - at.touch(&at.plus_as_string("test-long-formats")); + at.touch(at.plus_as_string("test-long-formats")); // Zero or one "." for indicating a file with security context @@ -1422,8 +1422,8 @@ fn test_ls_long_formats() { fn test_ls_oneline() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; - at.touch(&at.plus_as_string("test-oneline-1")); - at.touch(&at.plus_as_string("test-oneline-2")); + at.touch(at.plus_as_string("test-oneline-1")); + at.touch(at.plus_as_string("test-oneline-2")); // Bit of a weird situation: in the tests oneline and columns have the same output, // except on Windows. @@ -1443,7 +1443,7 @@ fn test_ls_deref() { let path_regexp = r"(.*)test-long.link -> (.*)test-long(.*)"; let re = Regex::new(path_regexp).unwrap(); - at.touch(&at.plus_as_string("test-long")); + at.touch(at.plus_as_string("test-long")); at.symlink_file("test-long", "test-long.link"); assert!(at.is_symlink("test-long.link")); @@ -1808,8 +1808,8 @@ fn test_ls_files_dirs() { at.mkdir("a/b"); at.mkdir("a/b/c"); at.mkdir("z"); - at.touch(&at.plus_as_string("a/a")); - at.touch(&at.plus_as_string("a/b/b")); + at.touch(at.plus_as_string("a/a")); + at.touch(at.plus_as_string("a/b/b")); scene.ucmd().arg("a").succeeds(); scene.ucmd().arg("a/a").succeeds(); @@ -1840,8 +1840,8 @@ fn test_ls_recursive() { at.mkdir("a/b"); at.mkdir("a/b/c"); at.mkdir("z"); - at.touch(&at.plus_as_string("a/a")); - at.touch(&at.plus_as_string("a/b/b")); + at.touch(at.plus_as_string("a/a")); + at.touch(at.plus_as_string("a/b/b")); scene.ucmd().arg("a").succeeds(); scene.ucmd().arg("a/a").succeeds(); @@ -1880,7 +1880,7 @@ fn test_ls_color() { .join("nested_file") .to_string_lossy() .to_string(); - at.touch(&nested_file); + at.touch(nested_file); at.touch("test-color"); let a_with_colors = "\x1b[1;34ma\x1b[0m"; @@ -1985,7 +1985,7 @@ fn test_ls_indicator_style() { at.mkdir("directory"); assert!(at.dir_exists("directory")); - at.touch(&at.plus_as_string("link-src")); + at.touch(at.plus_as_string("link-src")); at.symlink_file("link-src", "link-dest.link"); assert!(at.is_symlink("link-dest.link")); @@ -2077,7 +2077,7 @@ fn test_ls_indicator_style() { at.mkdir("directory"); assert!(at.dir_exists("directory")); - at.touch(&at.plus_as_string("link-src")); + at.touch(at.plus_as_string("link-src")); at.symlink_file("link-src", "link-dest.link"); assert!(at.is_symlink("link-dest.link")); diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index 93693279b..c673e5643 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -55,7 +55,7 @@ fn test_mv_move_file_into_dir() { ucmd.arg(file).arg(dir).succeeds().no_stderr(); - assert!(at.file_exists(&format!("{dir}/{file}"))); + assert!(at.file_exists(format!("{dir}/{file}"))); } #[test] @@ -67,17 +67,17 @@ fn test_mv_move_file_between_dirs() { at.mkdir(dir1); at.mkdir(dir2); - at.touch(&format!("{dir1}/{file}")); + at.touch(format!("{dir1}/{file}")); - assert!(at.file_exists(&format!("{dir1}/{file}"))); + assert!(at.file_exists(format!("{dir1}/{file}"))); ucmd.arg(&format!("{dir1}/{file}")) .arg(dir2) .succeeds() .no_stderr(); - assert!(!at.file_exists(&format!("{dir1}/{file}"))); - assert!(at.file_exists(&format!("{dir2}/{file}"))); + assert!(!at.file_exists(format!("{dir1}/{file}"))); + assert!(at.file_exists(format!("{dir2}/{file}"))); } #[test] @@ -94,7 +94,7 @@ fn test_mv_strip_slashes() { scene.ucmd().arg(&source).arg(dir).fails(); - assert!(!at.file_exists(&format!("{dir}/{file}"))); + assert!(!at.file_exists(format!("{dir}/{file}"))); scene .ucmd() @@ -104,7 +104,7 @@ fn test_mv_strip_slashes() { .succeeds() .no_stderr(); - assert!(at.file_exists(&format!("{dir}/{file}"))); + assert!(at.file_exists(format!("{dir}/{file}"))); } #[test] @@ -124,8 +124,8 @@ fn test_mv_multiple_files() { .succeeds() .no_stderr(); - assert!(at.file_exists(&format!("{target_dir}/{file_a}"))); - assert!(at.file_exists(&format!("{target_dir}/{file_b}"))); + assert!(at.file_exists(format!("{target_dir}/{file_a}"))); + assert!(at.file_exists(format!("{target_dir}/{file_b}"))); } #[test] @@ -305,7 +305,7 @@ fn test_mv_simple_backup() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}~"))); + assert!(at.file_exists(format!("{file_b}~"))); } #[test] @@ -324,7 +324,7 @@ fn test_mv_simple_backup_with_file_extension() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}~"))); + assert!(at.file_exists(format!("{file_b}~"))); } #[test] @@ -339,7 +339,7 @@ fn test_mv_arg_backup_arg_first() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}~"))); + assert!(at.file_exists(format!("{file_b}~"))); } #[test] @@ -360,7 +360,7 @@ fn test_mv_custom_backup_suffix() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}{suffix}"))); + assert!(at.file_exists(format!("{file_b}{suffix}"))); } #[test] @@ -381,7 +381,7 @@ fn test_mv_custom_backup_suffix_hyphen_value() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}{suffix}"))); + assert!(at.file_exists(format!("{file_b}{suffix}"))); } #[test] @@ -401,7 +401,7 @@ fn test_mv_custom_backup_suffix_via_env() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}{suffix}"))); + assert!(at.file_exists(format!("{file_b}{suffix}"))); } #[test] @@ -420,7 +420,7 @@ fn test_mv_backup_numbered_with_t() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}.~1~"))); + assert!(at.file_exists(format!("{file_b}.~1~"))); } #[test] @@ -439,7 +439,7 @@ fn test_mv_backup_numbered() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}.~1~"))); + assert!(at.file_exists(format!("{file_b}.~1~"))); } #[test] @@ -458,7 +458,7 @@ fn test_mv_backup_existing() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}~"))); + assert!(at.file_exists(format!("{file_b}~"))); } #[test] @@ -477,7 +477,7 @@ fn test_mv_backup_nil() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}~"))); + assert!(at.file_exists(format!("{file_b}~"))); } #[test] @@ -498,7 +498,7 @@ fn test_mv_numbered_if_existing_backup_existing() { assert!(at.file_exists(file_b)); assert!(at.file_exists(file_b_backup)); - assert!(at.file_exists(&format!("{file_b}.~2~"))); + assert!(at.file_exists(format!("{file_b}.~2~"))); } #[test] @@ -519,7 +519,7 @@ fn test_mv_numbered_if_existing_backup_nil() { assert!(at.file_exists(file_b)); assert!(at.file_exists(file_b_backup)); - assert!(at.file_exists(&format!("{file_b}.~2~"))); + assert!(at.file_exists(format!("{file_b}.~2~"))); } #[test] @@ -538,7 +538,7 @@ fn test_mv_backup_simple() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}~"))); + assert!(at.file_exists(format!("{file_b}~"))); } #[test] @@ -557,7 +557,7 @@ fn test_mv_backup_never() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{file_b}~"))); + assert!(at.file_exists(format!("{file_b}~"))); } #[test] @@ -576,7 +576,7 @@ fn test_mv_backup_none() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(!at.file_exists(&format!("{file_b}~"))); + assert!(!at.file_exists(format!("{file_b}~"))); } #[test] @@ -595,7 +595,7 @@ fn test_mv_backup_off() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(!at.file_exists(&format!("{file_b}~"))); + assert!(!at.file_exists(format!("{file_b}~"))); } #[test] @@ -660,8 +660,8 @@ fn test_mv_target_dir() { assert!(!at.file_exists(file_a)); assert!(!at.file_exists(file_b)); - assert!(at.file_exists(&format!("{dir}/{file_a}"))); - assert!(at.file_exists(&format!("{dir}/{file_b}"))); + assert!(at.file_exists(format!("{dir}/{file_a}"))); + assert!(at.file_exists(format!("{dir}/{file_b}"))); } #[test] @@ -675,7 +675,7 @@ fn test_mv_target_dir_single_source() { ucmd.arg("-t").arg(dir).arg(file).succeeds().no_stderr(); assert!(!at.file_exists(file)); - assert!(at.file_exists(&format!("{dir}/{file}"))); + assert!(at.file_exists(format!("{dir}/{file}"))); } #[test] diff --git a/tests/by-util/test_realpath.rs b/tests/by-util/test_realpath.rs index 2993d8dbb..691ad29a2 100644 --- a/tests/by-util/test_realpath.rs +++ b/tests/by-util/test_realpath.rs @@ -192,7 +192,7 @@ fn test_realpath_existing() { ucmd.arg("-e") .arg(".") .succeeds() - .stdout_only(at.plus_as_string(&format!("{}\n", at.root_dir_resolved()))); + .stdout_only(at.plus_as_string(format!("{}\n", at.root_dir_resolved()))); } #[test] diff --git a/tests/common/util.rs b/tests/common/util.rs index ed4ecf8e9..b9600e5b6 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -746,14 +746,14 @@ impl AtPath { self.subdir.to_str().unwrap().to_owned() } - pub fn plus(&self, name: &str) -> PathBuf { + pub fn plus>(&self, name: P) -> PathBuf { let mut pathbuf = self.subdir.clone(); pathbuf.push(name); pathbuf } - pub fn plus_as_string(&self, name: &str) -> String { - String::from(self.plus(name).to_str().unwrap()) + pub fn plus_as_string>(&self, name: P) -> String { + self.plus(name).display().to_string() } fn minus(&self, name: &str) -> PathBuf { @@ -876,7 +876,8 @@ impl AtPath { fs::remove_dir(self.plus(dir)).unwrap(); } - pub fn mkdir(&self, dir: &str) { + pub fn mkdir>(&self, dir: P) { + let dir = dir.as_ref(); log_info("mkdir", self.plus_as_string(dir)); fs::create_dir(self.plus(dir)).unwrap(); } @@ -893,7 +894,8 @@ impl AtPath { } } - pub fn touch(&self, file: &str) { + pub fn touch>(&self, file: P) { + let file = file.as_ref(); log_info("touch", self.plus_as_string(file)); File::create(self.plus(file)).unwrap(); } @@ -1016,7 +1018,7 @@ impl AtPath { } } - pub fn file_exists(&self, path: &str) -> bool { + pub fn file_exists>(&self, path: P) -> bool { match fs::metadata(self.plus(path)) { Ok(m) => m.is_file(), Err(_) => false, From f928d2984dc1d4987016b89dd388436485b9e394 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 22 Feb 2023 21:54:31 +0100 Subject: [PATCH 03/23] Freebsd pkg has been remamed to rust-coreutils https://cgit.FreeBSD.org/ports/commit/?id=8014b050aa2f5d3e016d48c98865eabb0e6b12fe --- docs/src/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/installation.md b/docs/src/installation.md index 063935ed6..0bd302a36 100644 --- a/docs/src/installation.md +++ b/docs/src/installation.md @@ -111,7 +111,7 @@ port install coreutils-uutils [![FreeBSD port](https://repology.org/badge/version-for-repo/freebsd/uutils-coreutils.svg)](https://repology.org/project/uutils-coreutils/versions) ```sh -pkg install uutils +pkg install rust-coreutils ``` ## Windows From 422a27d3758f367615ea48d4b635f984b3242303 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Fri, 3 Mar 2023 18:42:38 +0100 Subject: [PATCH 04/23] parent 9d5dc500e6c13e3923f13d3bc4231288d81846b8 author Sylvestre Ledru 1677865358 +0100 committer Sylvestre Ledru 1677951797 +0100 md: Fix a bunch of warnings in the docs --- CODE_OF_CONDUCT.md | 6 +- CONTRIBUTING.md | 9 +-- DEVELOPER_INSTRUCTIONS.md | 40 ++++------ README.md | 118 ++++++++++++++------------- docs/src/build.md | 2 +- docs/src/contributing.md | 4 +- docs/src/index.md | 4 + docs/src/installation.md | 13 ++- docs/src/multicall.md | 8 +- docs/src/test_coverage.md | 2 + src/uu/arch/arch.md | 3 - src/uu/base32/base32.md | 4 +- src/uu/base64/base64.md | 4 +- src/uu/chcon/chcon.md | 4 +- src/uu/cp/README.md | 6 +- src/uu/cut/BENCHMARKING.md | 33 ++++---- src/uu/dd/BENCHMARKING.md | 4 +- src/uu/dd/dd.md | 67 ++++++++-------- src/uu/dircolors/README.md | 16 ++-- src/uu/du/du.md | 6 +- src/uu/expr/expr.md | 16 ++-- src/uu/factor/BENCHMARKING.md | 8 +- src/uu/hashsum/BENCHMARKING.md | 10 ++- src/uu/head/BENCHMARKING.md | 26 ++++-- src/uu/join/BENCHMARKING.md | 35 ++++---- src/uu/ls/BENCHMARKING.md | 11 ++- src/uu/mkdir/mkdir.md | 3 +- src/uu/numfmt/numfmt.md | 22 ++--- src/uu/realpath/realpath.md | 2 +- src/uu/seq/BENCHMARKING.md | 12 ++- src/uu/shuf/BENCHMARKING.md | 6 +- src/uu/shuf/shuf.md | 2 +- src/uu/sleep/sleep.md | 2 +- src/uu/sort/BENCHMARKING.md | 142 ++++++++++++++++----------------- src/uu/split/BENCHMARKING.md | 22 +++-- src/uu/split/README.md | 3 +- src/uu/sum/BENCHMARKING.md | 8 +- src/uu/tac/BENCHMARKING.md | 29 ++++--- src/uu/tail/README.md | 59 +++++++++----- src/uu/truncate/truncate.md | 3 +- src/uu/wc/BENCHMARKING.md | 59 +++++++++----- src/uu/wc/wc.md | 1 + 42 files changed, 470 insertions(+), 364 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index d196c6e95..39474f7ab 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -116,7 +116,7 @@ the community. This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. +. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). @@ -124,5 +124,5 @@ enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. +. Translations are available at +. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7a749ebac..f2e5763a1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -38,20 +38,19 @@ search the issues to make sure no one else is working on it. ## Platforms -We take pride in supporting many operating systems and architectures. +We take pride in supporting many operating systems and architectures. **Tip:** -For Windows, Microsoft provides some images (VMWare, Hyper-V, VirtualBox and Parallels) +For Windows, Microsoft provides some images (VMWare, Hyper-V, VirtualBox and Parallels) for development: -https://developer.microsoft.com/windows/downloads/virtual-machines/ - + ## Commit messages To help the project maintainers review pull requests from contributors across numerous utilities, the team has settled on conventions for commit messages. -From http://git-scm.com/book/ch5-2.html: +From : ``` Short (50 chars or less) summary of changes diff --git a/DEVELOPER_INSTRUCTIONS.md b/DEVELOPER_INSTRUCTIONS.md index 28deb2677..f7dfc689e 100644 --- a/DEVELOPER_INSTRUCTIONS.md +++ b/DEVELOPER_INSTRUCTIONS.md @@ -1,21 +1,19 @@ -Documentation -------------- +# Documentation The source of the documentation is available on: -https://uutils.github.io/dev/coreutils/ + The documentation is updated everyday on this repository: -https://github.com/uutils/uutils.github.io/ + -Running GNU tests ------------------ +## Running GNU tests -- Check out https://github.com/coreutils/coreutils next to your fork as gnu -- Check out https://github.com/coreutils/gnulib next to your fork as gnulib +- Check out next to your fork as gnu +- Check out next to your fork as gnulib - Rename the checkout of your fork to uutils At the end you should have uutils, gnu and gnulib checked out next to each other. @@ -23,9 +21,7 @@ At the end you should have uutils, gnu and gnulib checked out next to each other - Run `cd uutils && ./util/build-gnu.sh && cd ..` to get everything ready (this may take a while) - Finally, you can run tests with `bash uutils/util/run-gnu-test.sh `. Instead of `` insert the tests you want to run, e.g. `tests/misc/wc-proc.sh`. - -Code Coverage Report Generation ---------------------------------- +## Code Coverage Report Generation @@ -36,13 +32,13 @@ Code coverage report can be generated using [grcov](https://github.com/mozilla/g To generate [gcov-based](https://github.com/mozilla/grcov#example-how-to-generate-gcda-files-for-a-rust-project) coverage report ```bash -$ export CARGO_INCREMENTAL=0 -$ export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" -$ export RUSTDOCFLAGS="-Cpanic=abort" -$ cargo build # e.g., --features feat_os_unix -$ cargo test # e.g., --features feat_os_unix test_pathchk -$ grcov . -s . --binary-path ./target/debug/ -t html --branch --ignore-not-existing --ignore build.rs --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?\#\[derive\()" -o ./target/debug/coverage/ -$ # open target/debug/coverage/index.html in browser +export CARGO_INCREMENTAL=0 +export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" +export RUSTDOCFLAGS="-Cpanic=abort" +cargo build # e.g., --features feat_os_unix +cargo test # e.g., --features feat_os_unix test_pathchk +grcov . -s . --binary-path ./target/debug/ -t html --branch --ignore-not-existing --ignore build.rs --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?\#\[derive\()" -o ./target/debug/coverage/ +# open target/debug/coverage/index.html in browser ``` if changes are not reflected in the report then run `cargo clean` and run the above commands. @@ -52,19 +48,17 @@ if changes are not reflected in the report then run `cargo clean` and run the ab If you are using stable version of Rust that doesn't enable code coverage instrumentation by default then add `-Z-Zinstrument-coverage` flag to `RUSTFLAGS` env variable specified above. - -pre-commit hooks ----------------- +## pre-commit hooks A configuration for `pre-commit` is provided in the repository. It allows automatically checking every git commit you make to ensure it compiles, and passes `clippy` and `rustfmt` without warnings. To use the provided hook: 1. [Install `pre-commit`](https://pre-commit.com/#install) -2. Run `pre-commit install` while in the repository directory +1. Run `pre-commit install` while in the repository directory Your git commits will then automatically be checked. If a check fails, an error message will explain why, and your commit will be canceled. You can then make the suggested changes, and run `git commit ...` again. -### Using Clippy +## Using Clippy The `msrv` key in the clippy configuration file `clippy.toml` is used to disable lints pertaining to newer features by specifying the minimum supported Rust version (MSRV). However, this key is only supported on `nightly`. To invoke clippy without errors, use `cargo +nightly clippy`. In order to also check tests and non-default crate features, use `cargo +nightly clippy --all-targets --all-features`. diff --git a/README.md b/README.md index 66a0395e9..1bd87401c 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,12 @@ or different behavior might be experienced. To install it: -``` -$ cargo install coreutils -$ ~/.cargo/bin/coreutils +```bash +cargo install coreutils +~/.cargo/bin/coreutils ``` + ## Why? uutils aims to work on as many platforms as possible, to be able to use the @@ -35,6 +36,7 @@ chosen not only because it is fast and safe, but is also excellent for writing cross-platform code. ## Documentation + uutils has both user and developer documentation available: - [User Manual](https://uutils.github.io/user/) @@ -46,8 +48,8 @@ Both can also be generated locally, the instructions for that can be found in th ## Requirements -* Rust (`cargo`, `rustc`) -* GNU Make (optional) +- Rust (`cargo`, `rustc`) +- GNU Make (optional) ### Rust Version @@ -65,8 +67,8 @@ or GNU Make. For either method, we first need to fetch the repository: ```bash -$ git clone https://github.com/uutils/coreutils -$ cd coreutils +git clone https://github.com/uutils/coreutils +cd coreutils ``` ### Cargo @@ -75,7 +77,7 @@ Building uutils using Cargo is easy because the process is the same as for every other Rust program: ```bash -$ cargo build --release +cargo build --release ``` This command builds the most portable common core set of uutils into a multicall @@ -86,11 +88,11 @@ expanded sets of uutils for a platform (on that platform) is as simple as specifying it as a feature: ```bash -$ cargo build --release --features macos +cargo build --release --features macos # or ... -$ cargo build --release --features windows +cargo build --release --features windows # or ... -$ cargo build --release --features unix +cargo build --release --features unix ``` If you don't want to build every utility available on your platform into the @@ -98,7 +100,7 @@ final binary, you can also specify which ones you want to build manually. For example: ```bash -$ cargo build --features "base32 cat echo rm" --no-default-features +cargo build --features "base32 cat echo rm" --no-default-features ``` If you don't want to build the multicall binary and would prefer to build @@ -108,7 +110,7 @@ is contained in its own package within the main repository, named specific packages (using the `--package` [aka `-p`] option). For example: ```bash -$ cargo build -p uu_base32 -p uu_cat -p uu_echo -p uu_rm +cargo build -p uu_base32 -p uu_cat -p uu_echo -p uu_rm ``` ### GNU Make @@ -118,29 +120,29 @@ Building using `make` is a simple process as well. To simply build all available utilities: ```bash -$ make +make ``` To build all but a few of the available utilities: ```bash -$ make SKIP_UTILS='UTILITY_1 UTILITY_2' +make SKIP_UTILS='UTILITY_1 UTILITY_2' ``` To build only a few of the available utilities: ```bash -$ make UTILS='UTILITY_1 UTILITY_2' +make UTILS='UTILITY_1 UTILITY_2' ``` ## Installation -### Cargo +### Install with Cargo Likewise, installing can simply be done using: ```bash -$ cargo install --path . +cargo install --path . ``` This command will install uutils into Cargo's *bin* folder (*e.g.* `$HOME/.cargo/bin`). @@ -148,49 +150,49 @@ This command will install uutils into Cargo's *bin* folder (*e.g.* `$HOME/.cargo This does not install files necessary for shell completion. For shell completion to work, use `GNU Make` or see `Manually install shell completions`. -### GNU Make +### Install with GNU Make To install all available utilities: ```bash -$ make install +make install ``` To install using `sudo` switch `-E` must be used: ```bash -$ sudo -E make install +sudo -E make install ``` To install all but a few of the available utilities: ```bash -$ make SKIP_UTILS='UTILITY_1 UTILITY_2' install +make SKIP_UTILS='UTILITY_1 UTILITY_2' install ``` To install only a few of the available utilities: ```bash -$ make UTILS='UTILITY_1 UTILITY_2' install +make UTILS='UTILITY_1 UTILITY_2' install ``` To install every program with a prefix (e.g. uu-echo uu-cat): ```bash -$ make PROG_PREFIX=PREFIX_GOES_HERE install +make PROG_PREFIX=PREFIX_GOES_HERE install ``` To install the multicall binary: ```bash -$ make MULTICALL=y install +make MULTICALL=y install ``` Set install parent directory (default value is /usr/local): ```bash # DESTDIR is also supported -$ make PREFIX=/my/path install +make PREFIX=/my/path install ``` Installing with `make` installs shell completions for all installed utilities @@ -203,6 +205,7 @@ The `coreutils` binary can generate completions for the `bash`, `elvish`, `fish` and `zsh` shells. It prints the result to stdout. The syntax is: + ```bash cargo run completion ``` @@ -220,106 +223,107 @@ Un-installation differs depending on how you have installed uutils. If you used Cargo to install, use Cargo to uninstall. If you used GNU Make to install, use Make to uninstall. -### Cargo +### Uninstall with Cargo To uninstall uutils: ```bash -$ cargo uninstall uutils +cargo uninstall uutils ``` -### GNU Make +### Uninstall with GNU Make To uninstall all utilities: ```bash -$ make uninstall +make uninstall ``` To uninstall every program with a set prefix: ```bash -$ make PROG_PREFIX=PREFIX_GOES_HERE uninstall +make PROG_PREFIX=PREFIX_GOES_HERE uninstall ``` To uninstall the multicall binary: ```bash -$ make MULTICALL=y uninstall +make MULTICALL=y uninstall ``` To uninstall from a custom parent directory: ```bash # DESTDIR is also supported -$ make PREFIX=/my/path uninstall +make PREFIX=/my/path uninstall ``` + ## Testing Testing can be done using either Cargo or `make`. -### Cargo +### Testing with Cargo Just like with building, we follow the standard procedure for testing using Cargo: ```bash -$ cargo test +cargo test ``` By default, `cargo test` only runs the common programs. To run also platform specific tests, run: ```bash -$ cargo test --features unix +cargo test --features unix ``` If you would prefer to test a select few utilities: ```bash -$ cargo test --features "chmod mv tail" --no-default-features +cargo test --features "chmod mv tail" --no-default-features ``` If you also want to test the core utilities: ```bash -$ cargo test -p uucore -p coreutils +cargo test -p uucore -p coreutils ``` To debug: ```bash -$ gdb --args target/debug/coreutils ls +gdb --args target/debug/coreutils ls (gdb) b ls.rs:79 (gdb) run ``` -### GNU Make +### Testing with GNU Make To simply test all available utilities: ```bash -$ make test +make test ``` To test all but a few of the available utilities: ```bash -$ make SKIP_UTILS='UTILITY_1 UTILITY_2' test +make SKIP_UTILS='UTILITY_1 UTILITY_2' test ``` To test only a few of the available utilities: ```bash -$ make UTILS='UTILITY_1 UTILITY_2' test +make UTILS='UTILITY_1 UTILITY_2' test ``` To include tests for unimplemented behavior: ```bash -$ make UTILS='UTILITY_1 UTILITY_2' SPEC=y test +make UTILS='UTILITY_1 UTILITY_2' SPEC=y test ``` ### Run Busybox Tests @@ -330,19 +334,19 @@ requires `make`. To run busybox tests for all utilities for which busybox has tests ```bash -$ make busytest +make busytest ``` To run busybox tests for a few of the available utilities ```bash -$ make UTILS='UTILITY_1 UTILITY_2' busytest +make UTILS='UTILITY_1 UTILITY_2' busytest ``` To pass an argument like "-v" to the busybox test runtime ```bash -$ make UTILS='UTILITY_1 UTILITY_2' RUNTEST_ARGS='-v' busytest +make UTILS='UTILITY_1 UTILITY_2' RUNTEST_ARGS='-v' busytest ``` ### Comparing with GNU @@ -356,14 +360,14 @@ breakdown of the GNU test results of the main branch can be found To run locally: ```bash -$ bash util/build-gnu.sh -$ bash util/run-gnu-test.sh +bash util/build-gnu.sh +bash util/run-gnu-test.sh # To run a single test: -$ bash util/run-gnu-test.sh tests/touch/not-owner.sh # for example +bash util/run-gnu-test.sh tests/touch/not-owner.sh # for example # To run several tests: -$ bash util/run-gnu-test.sh tests/touch/not-owner.sh tests/rm/no-give-up.sh # for example +bash util/run-gnu-test.sh tests/touch/not-owner.sh tests/rm/no-give-up.sh # for example # If this is a perl (.pl) test, to run in debug: -$ DEBUG=1 bash util/run-gnu-test.sh tests/misc/sm3sum.pl +DEBUG=1 bash util/run-gnu-test.sh tests/misc/sm3sum.pl ``` Note that it relies on individual utilities (not the multicall binary). @@ -387,7 +391,6 @@ To improve the GNU compatibility, the following process is recommended: 1. Start to modify the Rust implementation to match the expected behavior 1. Add a test to make sure that we don't regress (our test suite is super quick) - ## Contributing To contribute to uutils, please see [CONTRIBUTING](CONTRIBUTING.md). @@ -395,11 +398,12 @@ To contribute to uutils, please see [CONTRIBUTING](CONTRIBUTING.md). ## Utilities Please note that this is not fully accurate: -* Some new options can be added / removed in the GNU implementation; -* Some error management might be missing; -* Some behaviors might be different. -See https://github.com/uutils/coreutils/issues/3336 for the main meta bugs +- Some new options can be added / removed in the GNU implementation; +- Some error management might be missing; +- Some behaviors might be different. + +See for the main meta bugs (many are missing). | Done | WIP | diff --git a/docs/src/build.md b/docs/src/build.md index 6505b5b6e..e35b0ebe8 100644 --- a/docs/src/build.md +++ b/docs/src/build.md @@ -1,3 +1,3 @@ # Build from source -{{#include ../../README.md:build }} \ No newline at end of file +{{#include ../../README.md:build }} diff --git a/docs/src/contributing.md b/docs/src/contributing.md index 79ef4d13b..f69e1b377 100644 --- a/docs/src/contributing.md +++ b/docs/src/contributing.md @@ -1 +1,3 @@ -{{ #include ../../CONTRIBUTING.md }} \ No newline at end of file + + +{{ #include ../../CONTRIBUTING.md }} diff --git a/docs/src/index.md b/docs/src/index.md index 7bac8b816..0212b7526 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,5 +1,9 @@ + + {{#include logo.svg}} + +