2016-10-30 14:43:33 +00:00
|
|
|
|
use glob;
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
2017-06-27 00:13:50 +00:00
|
|
|
|
use fs::DotFilter;
|
2017-07-24 07:34:50 +00:00
|
|
|
|
use fs::filter::{FileFilter, SortField, SortCase, IgnorePatterns};
|
2017-07-26 16:48:18 +00:00
|
|
|
|
|
|
|
|
|
use options::{flags, Misfire};
|
2017-08-05 18:11:00 +00:00
|
|
|
|
use options::parser::MatchedFlags;
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl FileFilter {
|
|
|
|
|
|
|
|
|
|
/// Determines the set of file filter options to use, based on the user’s
|
|
|
|
|
/// command-line arguments.
|
2017-08-05 18:11:00 +00:00
|
|
|
|
pub fn deduce(matches: &MatchedFlags) -> Result<FileFilter, Misfire> {
|
2016-04-17 19:38:37 +00:00
|
|
|
|
Ok(FileFilter {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
list_dirs_first: matches.has(&flags::DIRS_FIRST),
|
|
|
|
|
reverse: matches.has(&flags::REVERSE),
|
2017-03-26 16:35:50 +00:00
|
|
|
|
sort_field: SortField::deduce(matches)?,
|
2017-06-29 11:07:46 +00:00
|
|
|
|
dot_filter: DotFilter::deduce(matches)?,
|
2017-03-26 16:35:50 +00:00
|
|
|
|
ignore_patterns: IgnorePatterns::deduce(matches)?,
|
2016-04-17 19:38:37 +00:00
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Default for SortField {
|
|
|
|
|
fn default() -> SortField {
|
|
|
|
|
SortField::Name(SortCase::Sensitive)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-26 19:45:01 +00:00
|
|
|
|
const SORTS: &[&str] = &[ "name", "Name", "size", "extension",
|
|
|
|
|
"Extension", "modified", "accessed",
|
|
|
|
|
"created", "inode", "type", "none" ];
|
|
|
|
|
|
2016-04-17 19:38:37 +00:00
|
|
|
|
impl SortField {
|
|
|
|
|
|
|
|
|
|
/// Determine the sort field to use, based on the presence of a “sort”
|
|
|
|
|
/// argument. This will return `Err` if the option is there, but does not
|
|
|
|
|
/// correspond to a valid field.
|
2017-08-05 18:11:00 +00:00
|
|
|
|
fn deduce(matches: &MatchedFlags) -> Result<SortField, Misfire> {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
let word = match matches.get(&flags::SORT) {
|
|
|
|
|
Some(w) => w,
|
|
|
|
|
None => return Ok(SortField::default()),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if word == "name" || word == "filename" {
|
|
|
|
|
Ok(SortField::Name(SortCase::Sensitive))
|
|
|
|
|
}
|
|
|
|
|
else if word == "Name" || word == "Filename" {
|
|
|
|
|
Ok(SortField::Name(SortCase::Insensitive))
|
|
|
|
|
}
|
|
|
|
|
else if word == "size" || word == "filesize" {
|
|
|
|
|
Ok(SortField::Size)
|
|
|
|
|
}
|
|
|
|
|
else if word == "ext" || word == "extension" {
|
|
|
|
|
Ok(SortField::Extension(SortCase::Sensitive))
|
|
|
|
|
}
|
|
|
|
|
else if word == "Ext" || word == "Extension" {
|
|
|
|
|
Ok(SortField::Extension(SortCase::Insensitive))
|
|
|
|
|
}
|
|
|
|
|
else if word == "mod" || word == "modified" {
|
|
|
|
|
Ok(SortField::ModifiedDate)
|
|
|
|
|
}
|
|
|
|
|
else if word == "acc" || word == "accessed" {
|
|
|
|
|
Ok(SortField::AccessedDate)
|
|
|
|
|
}
|
|
|
|
|
else if word == "cr" || word == "created" {
|
|
|
|
|
Ok(SortField::CreatedDate)
|
|
|
|
|
}
|
|
|
|
|
else if word == "inode" {
|
|
|
|
|
Ok(SortField::FileInode)
|
|
|
|
|
}
|
|
|
|
|
else if word == "type" {
|
|
|
|
|
Ok(SortField::FileType)
|
|
|
|
|
}
|
|
|
|
|
else if word == "none" {
|
|
|
|
|
Ok(SortField::Unsorted)
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
Err(Misfire::bad_argument(&flags::SORT, word, SORTS))
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-30 14:43:33 +00:00
|
|
|
|
|
|
|
|
|
|
2017-06-26 22:28:10 +00:00
|
|
|
|
impl DotFilter {
|
2017-08-05 18:11:00 +00:00
|
|
|
|
pub fn deduce(matches: &MatchedFlags) -> Result<DotFilter, Misfire> {
|
2017-07-26 20:14:05 +00:00
|
|
|
|
match matches.count(&flags::ALL) {
|
|
|
|
|
0 => Ok(DotFilter::JustFiles),
|
|
|
|
|
1 => Ok(DotFilter::Dotfiles),
|
|
|
|
|
_ => if matches.has(&flags::TREE) { Err(Misfire::TreeAllAll) }
|
|
|
|
|
else { Ok(DotFilter::DotfilesAndDots) }
|
2017-06-26 22:48:55 +00:00
|
|
|
|
}
|
2017-06-26 22:28:10 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-10-30 14:43:33 +00:00
|
|
|
|
impl IgnorePatterns {
|
2017-07-24 07:34:50 +00:00
|
|
|
|
|
2016-10-30 14:43:33 +00:00
|
|
|
|
/// Determines the set of file filter options to use, based on the user’s
|
|
|
|
|
/// command-line arguments.
|
2017-08-05 18:11:00 +00:00
|
|
|
|
pub fn deduce(matches: &MatchedFlags) -> Result<IgnorePatterns, Misfire> {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
let patterns = match matches.get(&flags::IGNORE_GLOB) {
|
2016-10-30 14:43:33 +00:00
|
|
|
|
None => Ok(Vec::new()),
|
2017-07-26 16:48:18 +00:00
|
|
|
|
Some(is) => is.to_string_lossy().split('|').map(|a| glob::Pattern::new(a)).collect(),
|
|
|
|
|
}?;
|
2016-10-30 14:43:33 +00:00
|
|
|
|
|
2017-07-26 16:48:18 +00:00
|
|
|
|
// TODO: is to_string_lossy really the best way to handle
|
|
|
|
|
// invalid UTF-8 there?
|
|
|
|
|
|
|
|
|
|
Ok(IgnorePatterns { patterns })
|
2016-10-30 14:43:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-07-26 19:45:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod test {
|
|
|
|
|
use super::*;
|
|
|
|
|
use std::ffi::OsString;
|
|
|
|
|
use options::flags;
|
|
|
|
|
|
|
|
|
|
pub fn os(input: &'static str) -> OsString {
|
|
|
|
|
let mut os = OsString::new();
|
|
|
|
|
os.push(input);
|
|
|
|
|
os
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! test {
|
|
|
|
|
($name:ident: $type:ident <- $inputs:expr => $result:expr) => {
|
|
|
|
|
#[test]
|
|
|
|
|
fn $name() {
|
2017-08-05 16:46:38 +00:00
|
|
|
|
use options::parser::{Args, Arg};
|
2017-07-26 19:45:01 +00:00
|
|
|
|
use std::ffi::OsString;
|
|
|
|
|
|
2017-07-26 20:29:49 +00:00
|
|
|
|
static TEST_ARGS: &[&Arg] = &[ &flags::SORT, &flags::ALL, &flags::TREE, &flags::IGNORE_GLOB ];
|
2017-07-26 19:45:01 +00:00
|
|
|
|
|
|
|
|
|
let bits = $inputs.as_ref().into_iter().map(|&o| os(o)).collect::<Vec<OsString>>();
|
2017-08-05 16:46:38 +00:00
|
|
|
|
let results = Args(TEST_ARGS).parse(bits.iter());
|
2017-08-05 18:11:00 +00:00
|
|
|
|
assert_eq!($type::deduce(&results.unwrap().flags), $result);
|
2017-07-26 19:45:01 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mod sort_fields {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
// Default behaviour
|
|
|
|
|
test!(empty: SortField <- [] => Ok(SortField::default()));
|
|
|
|
|
|
|
|
|
|
// Sort field arguments
|
|
|
|
|
test!(one_arg: SortField <- ["--sort=cr"] => Ok(SortField::CreatedDate));
|
|
|
|
|
test!(one_long: SortField <- ["--sort=size"] => Ok(SortField::Size));
|
|
|
|
|
test!(one_short: SortField <- ["-saccessed"] => Ok(SortField::AccessedDate));
|
|
|
|
|
test!(lowercase: SortField <- ["--sort", "name"] => Ok(SortField::Name(SortCase::Sensitive)));
|
|
|
|
|
test!(uppercase: SortField <- ["--sort", "Name"] => Ok(SortField::Name(SortCase::Insensitive)));
|
|
|
|
|
|
|
|
|
|
// Errors
|
|
|
|
|
test!(error: SortField <- ["--sort=colour"] => Err(Misfire::bad_argument(&flags::SORT, &os("colour"), super::SORTS)));
|
|
|
|
|
|
|
|
|
|
// Overriding
|
|
|
|
|
test!(overridden: SortField <- ["--sort=cr", "--sort", "mod"] => Ok(SortField::ModifiedDate));
|
|
|
|
|
test!(overridden_2: SortField <- ["--sort", "none", "--sort=Extension"] => Ok(SortField::Extension(SortCase::Insensitive)));
|
|
|
|
|
}
|
2017-07-26 20:01:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mod dot_filters {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
// Default behaviour
|
|
|
|
|
test!(empty: DotFilter <- [] => Ok(DotFilter::JustFiles));
|
|
|
|
|
|
|
|
|
|
// --all
|
|
|
|
|
test!(all: DotFilter <- ["--all"] => Ok(DotFilter::Dotfiles));
|
|
|
|
|
test!(all_all: DotFilter <- ["--all", "-a"] => Ok(DotFilter::DotfilesAndDots));
|
|
|
|
|
test!(all_all_2: DotFilter <- ["-aa"] => Ok(DotFilter::DotfilesAndDots));
|
|
|
|
|
|
|
|
|
|
// --all and --tree
|
2017-07-26 20:14:05 +00:00
|
|
|
|
test!(tree_a: DotFilter <- ["-Ta"] => Ok(DotFilter::Dotfiles));
|
|
|
|
|
test!(tree_aa: DotFilter <- ["-Taa"] => Err(Misfire::TreeAllAll));
|
2017-07-26 20:01:22 +00:00
|
|
|
|
}
|
2017-07-26 20:29:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mod ignore_patternses {
|
|
|
|
|
use super::*;
|
|
|
|
|
use glob;
|
|
|
|
|
|
|
|
|
|
fn pat(string: &'static str) -> glob::Pattern {
|
|
|
|
|
glob::Pattern::new(string).unwrap()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Various numbers of globs
|
|
|
|
|
test!(none: IgnorePatterns <- [] => Ok(IgnorePatterns { patterns: vec![] }));
|
|
|
|
|
test!(one: IgnorePatterns <- ["--ignore-glob", "*.ogg"] => Ok(IgnorePatterns { patterns: vec![ pat("*.ogg") ] }));
|
|
|
|
|
test!(two: IgnorePatterns <- ["--ignore-glob=*.ogg|*.MP3"] => Ok(IgnorePatterns { patterns: vec![ pat("*.ogg"), pat("*.MP3") ] }));
|
|
|
|
|
test!(loads: IgnorePatterns <- ["-I*|?|.|*"] => Ok(IgnorePatterns { patterns: vec![ pat("*"), pat("?"), pat("."), pat("*") ] }));
|
|
|
|
|
}
|
2017-07-26 19:45:01 +00:00
|
|
|
|
}
|