Implement multiple suffixes extension support with tests (#214)

This commit is contained in:
Martin Larralde 2018-02-06 15:10:15 +01:00 committed by David Peter
parent b1bb60ebb9
commit 86fe9977e8
4 changed files with 71 additions and 5 deletions

View file

@ -25,6 +25,7 @@ mod app;
mod exec; mod exec;
mod internal; mod internal;
mod output; mod output;
mod utils;
mod walk; mod walk;
#[cfg(windows)] #[cfg(windows)]
@ -152,7 +153,7 @@ fn main() {
.collect(), .collect(),
}, },
extensions: matches.values_of("extension").map(|exts| { extensions: matches.values_of("extension").map(|exts| {
exts.map(|e| e.trim_left_matches('.').to_lowercase()) exts.map(|e| String::from(".") + &e.trim_left_matches('.'))
.collect() .collect()
}), }),
command, command,

45
src/utils.rs Normal file
View file

@ -0,0 +1,45 @@
// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::path::Path;
use std::iter::Iterator;
/// Determine if an os string ends with any of the given extensions (case insensitive).
pub fn path_has_any_extension<'a, I>(path: &Path, exts: I) -> bool
where
I: 'a + Iterator<Item = &'a String> + Clone,
{
// TODO: remove these two lines when we drop support for Rust version < 1.23.
#[allow(unused_imports)]
use std::ascii::AsciiExt;
if let Some(ref name) = path.file_name() {
if let Some(ref name_str) = name.to_str() {
exts.clone().any(|x| {
let mut it = name_str.chars().rev();
if x.chars()
.rev()
.zip(&mut it)
.all(|(a, b)| a.eq_ignore_ascii_case(&b))
{
match it.next() {
Some('/') | None => false,
_ => true,
}
} else {
false
}
})
} else {
false
}
} else {
false
}
}

View file

@ -11,6 +11,7 @@ extern crate ctrlc;
use exec; use exec;
use fshelper; use fshelper;
use internal::{error, FdOptions, EXITCODE_SIGINT, MAX_BUFFER_LENGTH}; use internal::{error, FdOptions, EXITCODE_SIGINT, MAX_BUFFER_LENGTH};
use utils::path_has_any_extension;
use output; use output;
use std::process; use std::process;
@ -214,10 +215,7 @@ pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<FdOptions>) {
// Filter out unwanted extensions. // Filter out unwanted extensions.
if let Some(ref filter_exts) = config.extensions { if let Some(ref filter_exts) = config.extensions {
let entry_ext = entry_path if !path_has_any_extension(entry_path, filter_exts.iter()) {
.extension()
.map(|e| e.to_string_lossy().to_lowercase());
if entry_ext.map_or(true, |ext| !filter_exts.contains(&ext)) {
return ignore::WalkState::Continue; return ignore::WalkState::Continue;
} }
} }

View file

@ -530,6 +530,28 @@ fn test_extension() {
te.assert_output(&["--extension", ".foo", "a"], "a.foo"); te.assert_output(&["--extension", ".foo", "a"], "a.foo");
te.assert_output(&["--extension", "foo2"], "one/two/C.Foo2"); te.assert_output(&["--extension", "foo2"], "one/two/C.Foo2");
let te2 = TestEnv::new(&[], &["spam.bar.baz", "egg.bar.baz", "yolk.bar.baz.sig"]);
te2.assert_output(
&["--extension", ".bar.baz"],
"spam.bar.baz
egg.bar.baz",
);
te2.assert_output(&["--extension", "sig"], "yolk.bar.baz.sig");
te2.assert_output(&["--extension", "bar.baz.sig"], "yolk.bar.baz.sig");
let te3 = TestEnv::new(&[], &["latin1.e\u{301}xt", "smiley.☻"]);
te3.assert_output(&["--extension", ""], "smiley.☻");
te3.assert_output(&["--extension", ".e\u{301}xt"], "latin1.e\u{301}xt");
let te4 = TestEnv::new(&[], &[".hidden", "test.hidden"]);
te4.assert_output(&["--hidden", "--extension", ".hidden"], "test.hidden");
} }
/// Symlinks misc /// Symlinks misc