added -X
for excluding sets of extensions. -X
is to -E
as -x
is to -e
.
This commit is contained in:
parent
b3ce5d3d46
commit
22f1f280d7
3 changed files with 67 additions and 19 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -4,10 +4,11 @@ Dates are given in YYYY-MM-DD format.
|
||||||
## v0.2
|
## v0.2
|
||||||
### v0.2.14 (2021-xx-yy)
|
### v0.2.14 (2021-xx-yy)
|
||||||
#### Features
|
#### Features
|
||||||
- Added `-x`/`--exclude` flag for excluding file extensions (overrides `-e` or `-E`)
|
- Added `-x`/`--exclude` flag for excluding file extensions (overrides `-e` or `-E` - `-E images -x jpg` scans all image
|
||||||
|
files, except ".jpg" files)
|
||||||
|
- Added `-X`/`--exclude-set` flag for excluding sets of files (like `-E`)
|
||||||
#### Other
|
#### Other
|
||||||
- Publish my fork of ['mime_guess'] as ['new_mime_guess'], allowing it to be used properly with
|
- Published my fork of ['mime_guess'] as ['new_mime_guess'], allowing it to be used properly with
|
||||||
[crates.io](https://crates.io)
|
[crates.io](https://crates.io)
|
||||||
|
|
||||||
### v0.2.13 (2021-04-26)
|
### v0.2.13 (2021-04-26)
|
||||||
|
@ -152,5 +153,5 @@ Initial commit!
|
||||||
[`clap`]: https://crates.io/crates/clap
|
[`clap`]: https://crates.io/crates/clap
|
||||||
[`infer`]: https://crates.io/crates/infer
|
[`infer`]: https://crates.io/crates/infer
|
||||||
[`mime_guess`]: https://crates.io/crates/mime_guess
|
[`mime_guess`]: https://crates.io/crates/mime_guess
|
||||||
[`new_mime_guess`]: https://crates.io/crates/mime_guess
|
[`new_mime_guess`]: https://crates.io/crates/new_mime_guess
|
||||||
[`snailquote`]: https://crates.io/crates/snailquote
|
[`snailquote`]: https://crates.io/crates/snailquote
|
||||||
|
|
|
@ -55,7 +55,9 @@ pub struct Parameters {
|
||||||
#[clap(short = 'x', long, use_delimiter = true, require_delimiter = true)]
|
#[clap(short = 'x', long, use_delimiter = true, require_delimiter = true)]
|
||||||
pub exclude: Option<Vec<StringType>>,
|
pub exclude: Option<Vec<StringType>>,
|
||||||
|
|
||||||
// TODO: -X/--exclude-set - allows you to exclude all extensions in a set, e.g. "-X documents"
|
/// Exclude files using a preset list of extensions.
|
||||||
|
#[clap(short = 'X', long, arg_enum)]
|
||||||
|
pub exclude_set: Option<ExtensionSet>,
|
||||||
|
|
||||||
/// Don't skip hidden files and directories.
|
/// Don't skip hidden files and directories.
|
||||||
/// Even if this flag is not present, fif will still recurse into a hidden root directory - for example, `fif
|
/// Even if this flag is not present, fif will still recurse into a hidden root directory - for example, `fif
|
||||||
|
@ -133,10 +135,26 @@ impl Parameters {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn excluded_extensions(&self) -> Option<Vec<&str>> {
|
pub fn excluded_extensions(&self) -> Option<Vec<&str>> {
|
||||||
self
|
// start with an empty vec
|
||||||
.exclude
|
let mut excluded = vec![];
|
||||||
.as_ref()
|
if let Some(exclude) = self.exclude.as_ref() {
|
||||||
.map(|exclude| exclude.iter().map(|ext| ext.as_str()).collect())
|
// add extensions excluded by `-x`
|
||||||
|
excluded.append(&mut exclude.iter().map(|ext| ext.as_str()).collect());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(exclude_set) = &self.exclude_set {
|
||||||
|
// add extensions excluded by `-X`
|
||||||
|
excluded.append(&mut exclude_set.extensions());
|
||||||
|
}
|
||||||
|
|
||||||
|
if excluded.is_empty() {
|
||||||
|
// no extensions to exclude - return none
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// excluded doesn't sound like a word anymore
|
||||||
|
// tongue twister: enter X-options' excellent extension exclusion
|
||||||
|
Some(excluded)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn get_scan_opts(&self) -> ScanOpts {
|
pub const fn get_scan_opts(&self) -> ScanOpts {
|
||||||
|
|
|
@ -7,10 +7,13 @@ use crate::{extension_from_path, scan_directory, scan_from_walkdir};
|
||||||
|
|
||||||
use mime_guess::mime::{APPLICATION_OCTET_STREAM, APPLICATION_PDF, IMAGE_JPEG, IMAGE_PNG};
|
use mime_guess::mime::{APPLICATION_OCTET_STREAM, APPLICATION_PDF, IMAGE_JPEG, IMAGE_PNG};
|
||||||
use mime_guess::Mime;
|
use mime_guess::Mime;
|
||||||
|
use crate::parameters::Parameters;
|
||||||
|
use clap::Clap;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use crate::parameters::ExtensionSet;
|
||||||
|
|
||||||
const JPEG_BYTES: &[u8] = b"\xFF\xD8\xFF";
|
const JPEG_BYTES: &[u8] = b"\xFF\xD8\xFF";
|
||||||
const PNG_BYTES: &[u8] = b"\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
|
const PNG_BYTES: &[u8] = b"\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
|
||||||
|
@ -167,8 +170,7 @@ fn simple_directory() {
|
||||||
#[test]
|
#[test]
|
||||||
/// Ensure that command line argument parsing works correctly - flags are interpreted, booleans are set, and so on.
|
/// Ensure that command line argument parsing works correctly - flags are interpreted, booleans are set, and so on.
|
||||||
fn argument_parsing() {
|
fn argument_parsing() {
|
||||||
use crate::parameters::{Parameters, ScanOpts};
|
use crate::parameters::ScanOpts;
|
||||||
use clap::Clap;
|
|
||||||
|
|
||||||
// pass `-f`, which enables following symlinks, and `-E images`, which scans files with image extensions
|
// pass `-f`, which enables following symlinks, and `-E images`, which scans files with image extensions
|
||||||
let args: Parameters = Parameters::parse_from(vec!["fif", "-f", "-E", "images"]);
|
let args: Parameters = Parameters::parse_from(vec!["fif", "-f", "-E", "images"]);
|
||||||
|
@ -204,11 +206,8 @@ fn argument_parsing() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
/// Ensure exclude overrides `-e` and `-E`.
|
/// Ensure the `exclude` flag (`-x`) overrides `-e` and `-E`.
|
||||||
fn exclude_overrides() {
|
fn exclude_overrides() {
|
||||||
use crate::parameters::Parameters;
|
|
||||||
use clap::Clap;
|
|
||||||
|
|
||||||
// pass `-E images`, which includes many image extensions, and `-x jpg,png`, which should remove "jpg" and "png" from
|
// pass `-E images`, which includes many image extensions, and `-x jpg,png`, which should remove "jpg" and "png" from
|
||||||
// the extensions list
|
// the extensions list
|
||||||
let args: Parameters = Parameters::parse_from(vec!["fif", "-x", "jpg,png", "-E", "images"]);
|
let args: Parameters = Parameters::parse_from(vec!["fif", "-x", "jpg,png", "-E", "images"]);
|
||||||
|
@ -232,12 +231,42 @@ fn exclude_overrides() {
|
||||||
assert!(extensions.contains(&"jkl"));
|
assert!(extensions.contains(&"jkl"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
/// Ensure the `exclude_set` flag (`-X`) overrides `-e`.
|
||||||
|
fn exclude_set_overrides_includes() {
|
||||||
|
// pass `-e jpg,flac` and `-X images` -- which should produce the equivalent of `-e flag`
|
||||||
|
let args: Parameters = Parameters::parse_from(vec!["fif", "-e", "jpg,flac", "-X", "images"]);
|
||||||
|
let extensions = args.extensions();
|
||||||
|
assert!(extensions.is_some(), "Extensions should be set!");
|
||||||
|
let mut extensions = extensions.unwrap().into_iter();
|
||||||
|
|
||||||
|
assert_eq!(extensions.next(), Some("flac"), "Extensions should contain flac!");
|
||||||
|
assert_eq!(extensions.next(), None, "Too many extensions!");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
/// Ensure the `exclude_set` flag (`-X`) overrides `-E`.
|
||||||
|
fn exclude_set_overrides_include_set() {
|
||||||
|
// pass `-E media` and `-X images` -- which should produce the equivalent of `-E audio,videos`
|
||||||
|
let args: Parameters = Parameters::parse_from(vec!["fif", "-E", "media", "-X", "images"]);
|
||||||
|
let extensions = args.extensions();
|
||||||
|
assert!(extensions.is_some(), "Extensions should be set!");
|
||||||
|
let extensions = extensions.unwrap();
|
||||||
|
|
||||||
|
// ensure all of audio and video's extensions are here
|
||||||
|
for &ext in ExtensionSet::Audio.extensions().iter().chain(ExtensionSet::Videos.extensions().iter()) {
|
||||||
|
assert!(extensions.contains(&ext), "Extensions should contain {}!", ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure all of images' extensions are excluded
|
||||||
|
for ext in ExtensionSet::Images.extensions() {
|
||||||
|
assert!(!extensions.contains(&ext), "Extensions should not contain {}!", ext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
/// Ensure that badly formed command line arguments are rejected.
|
/// Ensure that badly formed command line arguments are rejected.
|
||||||
fn rejects_bad_args() {
|
fn rejects_bad_args() {
|
||||||
use crate::parameters::Parameters;
|
|
||||||
|
|
||||||
use clap::Clap;
|
|
||||||
let tests = [
|
let tests = [
|
||||||
// Non-existent flags:
|
// Non-existent flags:
|
||||||
vec!["fif", "-abcdefghijklmnopqrstuvwxyz"],
|
vec!["fif", "-abcdefghijklmnopqrstuvwxyz"],
|
||||||
|
|
Loading…
Reference in a new issue