diff --git a/Cargo.lock b/Cargo.lock index 188dea9b7..a6c23c9bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 [[package]] name = "Inflector" @@ -868,19 +869,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -[[package]] -name = "globset" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - [[package]] name = "half" version = "1.8.2" @@ -2603,7 +2591,7 @@ dependencies = [ "atty", "chrono", "clap", - "globset", + "glob", "lazy_static", "lscolors", "number_prefix", diff --git a/src/uu/ls/Cargo.toml b/src/uu/ls/Cargo.toml index 4eff804e0..099a79e00 100644 --- a/src/uu/ls/Cargo.toml +++ b/src/uu/ls/Cargo.toml @@ -21,7 +21,7 @@ unicode-width = "0.1.8" number_prefix = "0.4" term_grid = "0.1.5" termsize = "0.1.6" -globset = "0.4.6" +glob = "0.3.0" lscolors = { version = "0.7.1", features = ["ansi_term"] } uucore = { version = ">=0.0.8", package = "uucore", path = "../../uucore", features = ["entries", "fs"] } uucore_procs = { version=">=0.0.7", package = "uucore_procs", path = "../../uucore_procs" } diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 32707da36..356e4c0f5 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -16,7 +16,7 @@ extern crate lazy_static; mod quoting_style; use clap::{crate_version, App, Arg}; -use globset::{self, Glob, GlobSet, GlobSetBuilder}; +use glob::Pattern; use lscolors::LsColors; use number_prefix::NumberPrefix; use once_cell::unsync::OnceCell; @@ -233,7 +233,7 @@ struct Config { recursive: bool, reverse: bool, dereference: Dereference, - ignore_patterns: GlobSet, + ignore_patterns: Vec, size_format: SizeFormat, directory: bool, time: Time, @@ -547,16 +547,18 @@ impl Config { } else { TimeStyle::Locale }; - let mut ignore_patterns = GlobSetBuilder::new(); + + let mut ignore_patterns: Vec = Vec::new(); + if options.is_present(options::IGNORE_BACKUPS) { - ignore_patterns.add(Glob::new("*~").unwrap()); - ignore_patterns.add(Glob::new(".*~").unwrap()); + ignore_patterns.push(Pattern::new("*~").unwrap()); + ignore_patterns.push(Pattern::new(".*~").unwrap()); } for pattern in options.values_of(options::IGNORE).into_iter().flatten() { - match Glob::new(pattern) { + match Pattern::new(pattern) { Ok(p) => { - ignore_patterns.add(p); + ignore_patterns.push(p); } Err(_) => show_warning!("Invalid pattern for ignore: {}", pattern.quote()), } @@ -564,21 +566,15 @@ impl Config { if files == Files::Normal { for pattern in options.values_of(options::HIDE).into_iter().flatten() { - match Glob::new(pattern) { + match Pattern::new(pattern) { Ok(p) => { - ignore_patterns.add(p); + ignore_patterns.push(p); } Err(_) => show_warning!("Invalid pattern for hide: {}", pattern.quote()), } } } - if files == Files::Normal { - ignore_patterns.add(Glob::new(".*").unwrap()); - } - - let ignore_patterns = ignore_patterns.build().unwrap(); - let dereference = if options.is_present(options::dereference::ALL) { Dereference::All } else if options.is_present(options::dereference::ARGS) { @@ -1372,26 +1368,39 @@ fn sort_entries(entries: &mut Vec, config: &Config) { } } -#[cfg(windows)] fn is_hidden(file_path: &DirEntry) -> bool { - let path = file_path.path(); - let metadata = fs::metadata(&path).unwrap_or_else(|_| fs::symlink_metadata(&path).unwrap()); - let attr = metadata.file_attributes(); - (attr & 0x2) > 0 + #[cfg(windows)] + { + let path = file_path.path(); + let metadata = fs::metadata(&path).unwrap_or_else(|_| fs::symlink_metadata(&path).unwrap()); + let attr = metadata.file_attributes(); + (attr & 0x2) > 0 + } + #[cfg(unix)] + { + file_path + .file_name() + .to_str() + .map(|res| res.starts_with('.')) + .unwrap_or(false) + } } fn should_display(entry: &DirEntry, config: &Config) -> bool { - let ffi_name = entry.file_name(); - - // For unix, the hidden files are already included in the ignore pattern - #[cfg(windows)] - { - if config.files == Files::Normal && is_hidden(entry) { - return false; - } + // check if hidden + if config.files == Files::Normal && is_hidden(entry) { + return false; } - !config.ignore_patterns.is_match(&ffi_name) + // check if explicitly ignored + for pattern in &config.ignore_patterns { + if pattern.matches(entry.file_name().to_str().unwrap()) { + return false; + }; + continue; + } + // else default to display + true } fn enter_directory(dir: &PathData, config: &Config, out: &mut BufWriter) { @@ -1412,8 +1421,16 @@ fn enter_directory(dir: &PathData, config: &Config, out: &mut BufWriter) let mut temp: Vec<_> = crash_if_err!(1, fs::read_dir(&dir.p_buf)) .map(|res| crash_if_err!(1, res)) - .filter(|e| should_display(e, config)) - .map(|e| PathData::new(DirEntry::path(&e), Some(e.file_type()), None, config, false)) + .filter(|res| should_display(res, config)) + .map(|res| { + PathData::new( + DirEntry::path(&res), + Some(res.file_type()), + None, + config, + false, + ) + }) .collect(); sort_entries(&mut temp, config); diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 56711d6e0..b3234ce54 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -40,6 +40,35 @@ fn test_ls_i() { } #[test] +fn test_ls_walk_glob() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch(".test-1"); + at.mkdir("some-dir"); + at.touch( + Path::new("some-dir") + .join("test-2~") + .as_os_str() + .to_str() + .unwrap(), + ); + + #[allow(clippy::trivial_regex)] + let re_pwd = Regex::new(r"^\.\n").unwrap(); + + scene + .ucmd() + .arg("-1") + .arg("--ignore-backups") + .arg("some-dir") + .succeeds() + .stdout_does_not_contain("test-2~") + .stdout_does_not_contain("..") + .stdout_does_not_match(&re_pwd); +} + +#[test] +#[cfg(unix)] fn test_ls_a() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; @@ -1903,6 +1932,7 @@ fn test_ls_ignore_hide() { } #[test] +#[cfg(unix)] fn test_ls_ignore_backups() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures;