From fa4272a19be7c3d98c034a83ddf56b44732c61b7 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Sun, 4 Apr 2021 19:19:56 +0200 Subject: [PATCH 1/7] ls: --hide and --ignore --- src/uu/ls/Cargo.toml | 1 + src/uu/ls/src/ls.rs | 59 ++++++++++++++++++++++++----- tests/by-util/test_ls.rs | 80 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 9 deletions(-) diff --git a/src/uu/ls/Cargo.toml b/src/uu/ls/Cargo.toml index e1d9b7990..bf3860bf3 100644 --- a/src/uu/ls/Cargo.toml +++ b/src/uu/ls/Cargo.toml @@ -22,6 +22,7 @@ term_grid = "0.1.5" termsize = "0.1.6" time = "0.1.40" unicode-width = "0.1.5" +glob = "0.3.0" uucore = { version=">=0.0.8", package="uucore", path="../../uucore", features=["entries", "fs"] } uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" } diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index ece497bdb..e011b9e52 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -17,6 +17,7 @@ mod quoting_style; mod version_cmp; use clap::{App, Arg}; +use glob; use number_prefix::NumberPrefix; use quoting_style::{escape_name, QuotingStyle}; #[cfg(unix)] @@ -138,6 +139,8 @@ pub mod options { pub static COLOR: &str = "color"; pub static PATHS: &str = "paths"; pub static INDICATOR_STYLE: &str = "indicator-style"; + pub static HIDE: &str = "hide"; + pub static IGNORE: &str = "ignore"; } #[derive(PartialEq, Eq)] @@ -191,7 +194,7 @@ struct Config { recursive: bool, reverse: bool, dereference: bool, - ignore_backups: bool, + ignore_patterns: Vec, size_format: SizeFormat, directory: bool, time: Time, @@ -437,6 +440,28 @@ impl Config { IndicatorStyle::None }; + let mut ignore_patterns = Vec::new(); + if options.is_present(options::IGNORE_BACKUPS) { + ignore_patterns.push(glob::Pattern::new("*~").unwrap()); + ignore_patterns.push(glob::Pattern::new(".*~").unwrap()); + } + + for pattern in options.values_of(options::IGNORE).into_iter().flatten() { + match glob::Pattern::new(pattern) { + Ok(p) => ignore_patterns.push(p), + Err(e) => show_error!("{}", e), + } + } + + if files == Files::Normal { + for pattern in options.values_of(options::HIDE).into_iter().flatten() { + match glob::Pattern::new(pattern) { + Ok(p) => ignore_patterns.push(p), + Err(e) => show_error!("{}", e), + } + } + } + Config { format, files, @@ -444,7 +469,7 @@ impl Config { recursive: options.is_present(options::RECURSIVE), reverse: options.is_present(options::REVERSE), dereference: options.is_present(options::DEREFERENCE), - ignore_backups: options.is_present(options::IGNORE_BACKUPS), + ignore_patterns, size_format, directory: options.is_present(options::DIRECTORY), time, @@ -664,6 +689,26 @@ pub fn uumain(args: impl uucore::Args) -> i32 { ]) ) + // Hide and ignore + .arg( + Arg::with_name(options::HIDE) + .long(options::HIDE) + .takes_value(true) + .multiple(true) + ) + .arg( + Arg::with_name(options::IGNORE) + .long(options::IGNORE) + .takes_value(true) + .multiple(true) + ) + .arg( + Arg::with_name(options::IGNORE_BACKUPS) + .short("B") + .long(options::IGNORE_BACKUPS) + .help("Ignore entries which end with ~."), + ) + // Sort arguments .arg( Arg::with_name(options::SORT) @@ -761,12 +806,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 { '.' and '..'.", ), ) - .arg( - Arg::with_name(options::IGNORE_BACKUPS) - .short("B") - .long(options::IGNORE_BACKUPS) - .help("Ignore entries which end with ~."), - ) .arg( Arg::with_name(options::DIRECTORY) .short("d") @@ -985,10 +1024,12 @@ fn is_hidden(file_path: &DirEntry) -> bool { fn should_display(entry: &DirEntry, config: &Config) -> bool { let ffi_name = entry.file_name(); let name = ffi_name.to_string_lossy(); + if config.files == Files::Normal && is_hidden(entry) { return false; } - if config.ignore_backups && name.ends_with('~') { + + if config.ignore_patterns.iter().any(|p| p.matches(&name)) { return false; } true diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index d403e5577..7d678acea 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -1209,3 +1209,83 @@ fn test_ls_quoting_style() { assert_eq!(result.stdout, format!("{}\n", correct)); } } + +#[test] +fn test_ls_ignore_hide() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + at.touch("README.md"); + at.touch("CONTRIBUTING.md"); + at.touch("some_other_file"); + at.touch("READMECAREFULLY.md"); + + scene.ucmd().arg("--hide").arg("*").succeeds().stdout_is(""); + + scene + .ucmd() + .arg("--ignore") + .arg("*") + .succeeds() + .stdout_is(""); + + scene + .ucmd() + .arg("--ignore") + .arg("irrelevant pattern") + .succeeds() + .stdout_is("CONTRIBUTING.md\nREADME.md\nREADMECAREFULLY.md\nsome_other_file\n"); + + scene + .ucmd() + .arg("--ignore") + .arg("README*.md") + .succeeds() + .stdout_is("CONTRIBUTING.md\nsome_other_file\n"); + + scene + .ucmd() + .arg("--hide") + .arg("README*.md") + .succeeds() + .stdout_is("CONTRIBUTING.md\nsome_other_file\n"); + + scene + .ucmd() + .arg("--ignore") + .arg("*.md") + .succeeds() + .stdout_is("some_other_file\n"); + + scene + .ucmd() + .arg("-a") + .arg("--ignore") + .arg("*.md") + .succeeds() + .stdout_is(".\n..\nsome_other_file\n"); + + scene + .ucmd() + .arg("-a") + .arg("--hide") + .arg("*.md") + .succeeds() + .stdout_is(".\n..\nCONTRIBUTING.md\nREADME.md\nREADMECAREFULLY.md\nsome_other_file\n"); + + scene + .ucmd() + .arg("-A") + .arg("--ignore") + .arg("*.md") + .succeeds() + .stdout_is("some_other_file\n"); + + scene + .ucmd() + .arg("-A") + .arg("--hide") + .arg("*.md") + .succeeds() + .stdout_is("CONTRIBUTING.md\nREADME.md\nREADMECAREFULLY.md\nsome_other_file\n"); +} From 76308dbec9f0538a17c443a01a241cf120c6177e Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Sun, 4 Apr 2021 22:35:22 +0200 Subject: [PATCH 2/7] ls: tests for invalid patterns for hide and ignore --- src/uu/ls/src/ls.rs | 4 ++-- tests/by-util/test_ls.rs | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index e011b9e52..1e6e300ff 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -449,7 +449,7 @@ impl Config { for pattern in options.values_of(options::IGNORE).into_iter().flatten() { match glob::Pattern::new(pattern) { Ok(p) => ignore_patterns.push(p), - Err(e) => show_error!("{}", e), + Err(_) => show_error!("Invalid pattern for ignore: '{}'", pattern), } } @@ -457,7 +457,7 @@ impl Config { for pattern in options.values_of(options::HIDE).into_iter().flatten() { match glob::Pattern::new(pattern) { Ok(p) => ignore_patterns.push(p), - Err(e) => show_error!("{}", e), + Err(_) => show_error!("Invalid pattern for hide: '{}'", pattern), } } } diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 7d678acea..377e12f74 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -1288,4 +1288,29 @@ fn test_ls_ignore_hide() { .arg("*.md") .succeeds() .stdout_is("CONTRIBUTING.md\nREADME.md\nREADMECAREFULLY.md\nsome_other_file\n"); + + // Stacking multiple patterns + scene + .ucmd() + .arg("--ignore") + .arg("README*") + .arg("--ignore") + .arg("CONTRIBUTING*") + .succeeds() + .stdout_is("some_other_file\n"); + + // Invalid patterns + scene + .ucmd() + .arg("--ignore") + .arg("READ[ME") + .succeeds() + .stderr_contains(&"Invalid pattern"); + + scene + .ucmd() + .arg("--ignore") + .arg("READ[ME") + .succeeds() + .stderr_contains(&"Invalid pattern"); } From 51770e6bee24431d104f6345e38648ecc3a34730 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Sun, 4 Apr 2021 22:40:36 +0200 Subject: [PATCH 3/7] ls: invalid pattern move from error to warning --- src/uu/ls/src/ls.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 1e6e300ff..4a0c52955 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -449,7 +449,7 @@ impl Config { for pattern in options.values_of(options::IGNORE).into_iter().flatten() { match glob::Pattern::new(pattern) { Ok(p) => ignore_patterns.push(p), - Err(_) => show_error!("Invalid pattern for ignore: '{}'", pattern), + Err(_) => show_warning!("Invalid pattern for ignore: '{}'", pattern), } } @@ -457,7 +457,7 @@ impl Config { for pattern in options.values_of(options::HIDE).into_iter().flatten() { match glob::Pattern::new(pattern) { Ok(p) => ignore_patterns.push(p), - Err(_) => show_error!("Invalid pattern for hide: '{}'", pattern), + Err(_) => show_warning!("Invalid pattern for hide: '{}'", pattern), } } } From bbb27800c91770a79efc28f29ab42c91d586c1bf Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Sun, 4 Apr 2021 23:14:55 +0200 Subject: [PATCH 4/7] ls: fix windows tests and commit lock --- Cargo.lock | 1 + tests/by-util/test_ls.rs | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index ea1ee53ae..034cb4304 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1949,6 +1949,7 @@ version = "0.0.6" dependencies = [ "atty", "clap", + "glob 0.3.0", "lazy_static", "number_prefix", "term_grid", diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 377e12f74..cde5a8b8a 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -1220,12 +1220,19 @@ fn test_ls_ignore_hide() { at.touch("some_other_file"); at.touch("READMECAREFULLY.md"); - scene.ucmd().arg("--hide").arg("*").succeeds().stdout_is(""); + scene + .ucmd() + .arg("--hide") + .arg("*") + .arg("-1") + .succeeds() + .stdout_is(""); scene .ucmd() .arg("--ignore") .arg("*") + .arg("-1") .succeeds() .stdout_is(""); @@ -1233,6 +1240,7 @@ fn test_ls_ignore_hide() { .ucmd() .arg("--ignore") .arg("irrelevant pattern") + .arg("-1") .succeeds() .stdout_is("CONTRIBUTING.md\nREADME.md\nREADMECAREFULLY.md\nsome_other_file\n"); @@ -1240,6 +1248,7 @@ fn test_ls_ignore_hide() { .ucmd() .arg("--ignore") .arg("README*.md") + .arg("-1") .succeeds() .stdout_is("CONTRIBUTING.md\nsome_other_file\n"); @@ -1247,6 +1256,7 @@ fn test_ls_ignore_hide() { .ucmd() .arg("--hide") .arg("README*.md") + .arg("-1") .succeeds() .stdout_is("CONTRIBUTING.md\nsome_other_file\n"); @@ -1254,6 +1264,7 @@ fn test_ls_ignore_hide() { .ucmd() .arg("--ignore") .arg("*.md") + .arg("-1") .succeeds() .stdout_is("some_other_file\n"); @@ -1262,6 +1273,7 @@ fn test_ls_ignore_hide() { .arg("-a") .arg("--ignore") .arg("*.md") + .arg("-1") .succeeds() .stdout_is(".\n..\nsome_other_file\n"); @@ -1270,6 +1282,7 @@ fn test_ls_ignore_hide() { .arg("-a") .arg("--hide") .arg("*.md") + .arg("-1") .succeeds() .stdout_is(".\n..\nCONTRIBUTING.md\nREADME.md\nREADMECAREFULLY.md\nsome_other_file\n"); @@ -1278,6 +1291,7 @@ fn test_ls_ignore_hide() { .arg("-A") .arg("--ignore") .arg("*.md") + .arg("-1") .succeeds() .stdout_is("some_other_file\n"); @@ -1286,6 +1300,7 @@ fn test_ls_ignore_hide() { .arg("-A") .arg("--hide") .arg("*.md") + .arg("-1") .succeeds() .stdout_is("CONTRIBUTING.md\nREADME.md\nREADMECAREFULLY.md\nsome_other_file\n"); @@ -1296,6 +1311,7 @@ fn test_ls_ignore_hide() { .arg("README*") .arg("--ignore") .arg("CONTRIBUTING*") + .arg("-1") .succeeds() .stdout_is("some_other_file\n"); @@ -1304,6 +1320,7 @@ fn test_ls_ignore_hide() { .ucmd() .arg("--ignore") .arg("READ[ME") + .arg("-1") .succeeds() .stderr_contains(&"Invalid pattern"); @@ -1311,6 +1328,7 @@ fn test_ls_ignore_hide() { .ucmd() .arg("--ignore") .arg("READ[ME") + .arg("-1") .succeeds() .stderr_contains(&"Invalid pattern"); } From 5134348a117481bb257961d71ba4c206de973410 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Sun, 4 Apr 2021 23:39:11 +0200 Subject: [PATCH 5/7] ls: use globset instead of glob --- src/uu/ls/Cargo.toml | 2 +- src/uu/ls/src/ls.rs | 27 ++++++++++++++++----------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/uu/ls/Cargo.toml b/src/uu/ls/Cargo.toml index bf3860bf3..dacdc7cd9 100644 --- a/src/uu/ls/Cargo.toml +++ b/src/uu/ls/Cargo.toml @@ -22,7 +22,7 @@ term_grid = "0.1.5" termsize = "0.1.6" time = "0.1.40" unicode-width = "0.1.5" -glob = "0.3.0" +globset = "0.4.6" uucore = { version=">=0.0.8", package="uucore", path="../../uucore", features=["entries", "fs"] } uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" } diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 4a0c52955..c4f9ae047 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -17,7 +17,7 @@ mod quoting_style; mod version_cmp; use clap::{App, Arg}; -use glob; +use globset::{self, Glob, GlobSet, GlobSetBuilder}; use number_prefix::NumberPrefix; use quoting_style::{escape_name, QuotingStyle}; #[cfg(unix)] @@ -194,7 +194,7 @@ struct Config { recursive: bool, reverse: bool, dereference: bool, - ignore_patterns: Vec, + ignore_patterns: GlobSet, size_format: SizeFormat, directory: bool, time: Time, @@ -440,28 +440,34 @@ impl Config { IndicatorStyle::None }; - let mut ignore_patterns = Vec::new(); + let mut ignore_patterns = GlobSetBuilder::new(); if options.is_present(options::IGNORE_BACKUPS) { - ignore_patterns.push(glob::Pattern::new("*~").unwrap()); - ignore_patterns.push(glob::Pattern::new(".*~").unwrap()); + ignore_patterns.add(Glob::new("*~").unwrap()); + ignore_patterns.add(Glob::new(".*~").unwrap()); } for pattern in options.values_of(options::IGNORE).into_iter().flatten() { - match glob::Pattern::new(pattern) { - Ok(p) => ignore_patterns.push(p), + match Glob::new(pattern) { + Ok(p) => { + ignore_patterns.add(p); + } Err(_) => show_warning!("Invalid pattern for ignore: '{}'", pattern), } } if files == Files::Normal { for pattern in options.values_of(options::HIDE).into_iter().flatten() { - match glob::Pattern::new(pattern) { - Ok(p) => ignore_patterns.push(p), + match Glob::new(pattern) { + Ok(p) => { + ignore_patterns.add(p); + } Err(_) => show_warning!("Invalid pattern for hide: '{}'", pattern), } } } + let ignore_patterns = ignore_patterns.build().unwrap(); + Config { format, files, @@ -1023,13 +1029,12 @@ fn is_hidden(file_path: &DirEntry) -> bool { fn should_display(entry: &DirEntry, config: &Config) -> bool { let ffi_name = entry.file_name(); - let name = ffi_name.to_string_lossy(); if config.files == Files::Normal && is_hidden(entry) { return false; } - if config.ignore_patterns.iter().any(|p| p.matches(&name)) { + if config.ignore_patterns.is_match(&ffi_name) { return false; } true From d68959d69683dbe3ad41f1205fa214ad5ccfe30d Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Mon, 5 Apr 2021 10:12:23 +0200 Subject: [PATCH 6/7] ls: update cargo.lock with globset --- Cargo.lock | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 034cb4304..f6dfc3246 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -644,6 +644,19 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +[[package]] +name = "globset" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + [[package]] name = "half" version = "1.7.1" @@ -1949,7 +1962,7 @@ version = "0.0.6" dependencies = [ "atty", "clap", - "glob 0.3.0", + "globset", "lazy_static", "number_prefix", "term_grid", From a50eae76a499699c0e2e47b4217db331c4a75b4d Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Mon, 5 Apr 2021 12:17:42 +0200 Subject: [PATCH 7/7] ls: some more tests for ignore & hide --- tests/by-util/test_ls.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index cde5a8b8a..0547560cc 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -1315,6 +1315,26 @@ fn test_ls_ignore_hide() { .succeeds() .stdout_is("some_other_file\n"); + scene + .ucmd() + .arg("--hide") + .arg("README*") + .arg("--ignore") + .arg("CONTRIBUTING*") + .arg("-1") + .succeeds() + .stdout_is("some_other_file\n"); + + scene + .ucmd() + .arg("--hide") + .arg("README*") + .arg("--hide") + .arg("CONTRIBUTING*") + .arg("-1") + .succeeds() + .stdout_is("some_other_file\n"); + // Invalid patterns scene .ucmd() @@ -1326,7 +1346,7 @@ fn test_ls_ignore_hide() { scene .ucmd() - .arg("--ignore") + .arg("--hide") .arg("READ[ME") .arg("-1") .succeeds()