new option for scanning extensionless files, nicer #[cfg]s, -s no longer skips hidden root dir...
This commit is contained in:
parent
4412161193
commit
8a152d4118
6 changed files with 47 additions and 18 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -168,7 +168,7 @@ checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fif"
|
name = "fif"
|
||||||
version = "0.2.7"
|
version = "0.2.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cached",
|
"cached",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "fif"
|
name = "fif"
|
||||||
description = "A command-line tool for detecting and optionally correcting files with incorrect extensions."
|
description = "A command-line tool for detecting and optionally correcting files with incorrect extensions."
|
||||||
version = "0.2.7"
|
version = "0.2.8"
|
||||||
authors = ["Lynnesbian <lynne@bune.city>"]
|
authors = ["Lynnesbian <lynne@bune.city>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
|
@ -35,7 +35,7 @@ rayon = { version = "1.5.0", optional = true }
|
||||||
exitcode = "1.1.2"
|
exitcode = "1.1.2"
|
||||||
cfg-if = "1.0.0"
|
cfg-if = "1.0.0"
|
||||||
|
|
||||||
[target.'cfg(any(unix, target_os="redox"))'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
xdg-mime = "0.3"
|
xdg-mime = "0.3"
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
|
|
30
src/main.rs
30
src/main.rs
|
@ -29,7 +29,7 @@ use walkdir::{DirEntry, WalkDir};
|
||||||
use crate::findings::Findings;
|
use crate::findings::Findings;
|
||||||
use crate::formats::{Format, Script};
|
use crate::formats::{Format, Script};
|
||||||
use crate::mime_db::MimeDb;
|
use crate::mime_db::MimeDb;
|
||||||
use crate::parameters::OutputFormat;
|
use crate::parameters::{OutputFormat, ScanOpts};
|
||||||
use crate::scan_error::ScanError;
|
use crate::scan_error::ScanError;
|
||||||
use env_logger::Env;
|
use env_logger::Env;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
@ -46,7 +46,7 @@ mod scan_error;
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(any(all(not(unix), not(feature = "xdg-mime-backend")), all(unix, feature = "infer-backend")))] {
|
if #[cfg(any(all(unix, feature = "infer-backend"), all(not(unix), not(feature = "xdg-mime-backend"))))] {
|
||||||
/// A [OnceCell] holding an instance of [mime_db::MimeDb].
|
/// A [OnceCell] holding an instance of [mime_db::MimeDb].
|
||||||
static MIMEDB: OnceCell<mime_db::InferDb> = OnceCell::new();
|
static MIMEDB: OnceCell<mime_db::InferDb> = OnceCell::new();
|
||||||
/// The backend being used; either "Infer" or "XDG-Mime".
|
/// The backend being used; either "Infer" or "XDG-Mime".
|
||||||
|
@ -80,7 +80,7 @@ fn main() {
|
||||||
|
|
||||||
debug!("Checking files with extensions: {:?}", extensions);
|
debug!("Checking files with extensions: {:?}", extensions);
|
||||||
|
|
||||||
let entries = scan_directory(&args.dirs, &extensions, args.scan_hidden);
|
let entries = scan_directory(&args.dirs, &extensions, &args.get_scan_opts());
|
||||||
|
|
||||||
if entries.is_none() {
|
if entries.is_none() {
|
||||||
// no need to log anything for fatal errors - fif will already have printed something obvious like
|
// no need to log anything for fatal errors - fif will already have printed something obvious like
|
||||||
|
@ -161,9 +161,15 @@ cfg_if! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if a file matches the given criteria.
|
/// Returns `true` if a file matches the given criteria. This means checking whether the file's extension appears in
|
||||||
fn wanted_file(scan_hidden: bool, exts: &[&str], entry: &DirEntry) -> bool {
|
/// `exts`, potentially skipping over hidden files, and so on.
|
||||||
if !scan_hidden && is_hidden(entry) {
|
fn wanted_file(entry: &DirEntry, exts: &[&str], scan_opts: &ScanOpts) -> bool {
|
||||||
|
if entry.depth() == 0 {
|
||||||
|
// the root directory should always be scanned.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !scan_opts.hidden && is_hidden(entry) {
|
||||||
// skip hidden files and directories. this check is performed first because it's very lightweight.
|
// skip hidden files and directories. this check is performed first because it's very lightweight.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -175,9 +181,10 @@ fn wanted_file(scan_hidden: bool, exts: &[&str], entry: &DirEntry) -> bool {
|
||||||
|
|
||||||
let ext = extension_from_path(entry.path());
|
let ext = extension_from_path(entry.path());
|
||||||
|
|
||||||
if ext.is_none() {
|
if ext.is_none() && !scan_opts.extensionless {
|
||||||
|
// don't scan files without extensions.
|
||||||
return false;
|
return false;
|
||||||
} // don't scan files without extensions. TODO - this should be configurable
|
}
|
||||||
|
|
||||||
exts.contains(&ext.unwrap().to_lowercase().as_str())
|
exts.contains(&ext.unwrap().to_lowercase().as_str())
|
||||||
}
|
}
|
||||||
|
@ -186,6 +193,7 @@ fn wanted_file(scan_hidden: bool, exts: &[&str], entry: &DirEntry) -> bool {
|
||||||
///
|
///
|
||||||
/// The extension is currently [converted to a lossy string](std::ffi::OsStr::to_string_lossy), although it will
|
/// The extension is currently [converted to a lossy string](std::ffi::OsStr::to_string_lossy), although it will
|
||||||
/// (eventually) in future return an OsStr instead.
|
/// (eventually) in future return an OsStr instead.
|
||||||
|
// TODO: ↑
|
||||||
fn extension_from_path(path: &Path) -> Option<String> {
|
fn extension_from_path(path: &Path) -> Option<String> {
|
||||||
path.extension(). // Get the path's extension
|
path.extension(). // Get the path's extension
|
||||||
map(|e| String::from(e.to_string_lossy())) // Convert from OsStr to String
|
map(|e| String::from(e.to_string_lossy())) // Convert from OsStr to String
|
||||||
|
@ -258,11 +266,11 @@ fn scan_from_walkdir(entries: &[DirEntry]) -> Vec<Result<Findings, ScanError>> {
|
||||||
|
|
||||||
/// Scans a given directory with [WalkDir], filters with [wanted_file], checks for errors, and returns a vector of
|
/// Scans a given directory with [WalkDir], filters with [wanted_file], checks for errors, and returns a vector of
|
||||||
/// [DirEntry]s.
|
/// [DirEntry]s.
|
||||||
fn scan_directory(dirs: &PathBuf, exts: &Vec<&str>, scan_hidden: bool) -> Option<Vec<DirEntry>> {
|
fn scan_directory(dirs: &PathBuf, exts: &Vec<&str>, scan_opts: &ScanOpts) -> Option<Vec<DirEntry>> {
|
||||||
let stepper = WalkDir::new(dirs).into_iter();
|
let stepper = WalkDir::new(dirs).into_iter();
|
||||||
let mut probably_fatal_error = false;
|
let mut probably_fatal_error = false;
|
||||||
let entries: Vec<DirEntry> = stepper
|
let entries: Vec<DirEntry> = stepper
|
||||||
.filter_entry(|e| wanted_file(scan_hidden, exts, e)) // filter out unwanted files
|
.filter_entry(|e| wanted_file(e, exts, scan_opts)) // filter out unwanted files
|
||||||
.filter_map(|e| {
|
.filter_map(|e| {
|
||||||
if let Err(err) = &e {
|
if let Err(err) = &e {
|
||||||
debug!("uh oh spaghettio!! {:#?}", e);
|
debug!("uh oh spaghettio!! {:#?}", e);
|
||||||
|
@ -299,7 +307,7 @@ fn scan_directory(dirs: &PathBuf, exts: &Vec<&str>, scan_hidden: bool) -> Option
|
||||||
/// Initialises [MIMEDB] with a value dependent on the current backend.
|
/// Initialises [MIMEDB] with a value dependent on the current backend.
|
||||||
fn init_db() {
|
fn init_db() {
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(any(all(not(unix), not(feature = "xdg-mime-backend")), all(unix, feature = "infer-backend")))] {
|
if #[cfg(any(all(unix, feature = "infer-backend"), all(not(unix), not(feature = "xdg-mime-backend"))))] {
|
||||||
MIMEDB
|
MIMEDB
|
||||||
.set(mime_db::InferDb::init())
|
.set(mime_db::InferDb::init())
|
||||||
.or(Err("Failed to initialise Infer backend!"))
|
.or(Err("Failed to initialise Infer backend!"))
|
||||||
|
|
|
@ -9,7 +9,7 @@ pub trait MimeDb {
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(any(all(not(target_os = "linux"), not(feature = "xdg-mime-backend")), all(target_os = "linux", feature = "infer-backend")))] {
|
if #[cfg(any(all(unix, feature = "infer-backend"), all(not(unix), not(feature = "xdg-mime-backend"))))] {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
pub struct InferDb {
|
pub struct InferDb {
|
||||||
|
|
|
@ -47,6 +47,10 @@ pub struct Parameters {
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
pub scan_hidden: bool,
|
pub scan_hidden: bool,
|
||||||
|
|
||||||
|
/// Scan files without extensions
|
||||||
|
#[clap(short = 'S', long)]
|
||||||
|
pub scan_extensionless: bool,
|
||||||
|
|
||||||
/// Output format to use
|
/// Output format to use
|
||||||
#[clap(short, long, default_value = "script", arg_enum)]
|
#[clap(short, long, default_value = "script", arg_enum)]
|
||||||
pub output_format: OutputFormat,
|
pub output_format: OutputFormat,
|
||||||
|
@ -57,6 +61,14 @@ pub struct Parameters {
|
||||||
pub dirs: PathBuf,
|
pub dirs: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Further options relating to scanning.
|
||||||
|
pub struct ScanOpts {
|
||||||
|
/// Whether hidden files and directories should be scanned.
|
||||||
|
pub hidden: bool,
|
||||||
|
/// Whether files without extensions should be scanned.
|
||||||
|
pub extensionless: bool
|
||||||
|
}
|
||||||
|
|
||||||
impl Parameters {
|
impl Parameters {
|
||||||
pub fn extensions(&self) -> Vec<&str> {
|
pub fn extensions(&self) -> Vec<&str> {
|
||||||
if let Some(exts) = &self.exts {
|
if let Some(exts) = &self.exts {
|
||||||
|
@ -70,4 +82,8 @@ impl Parameters {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_scan_opts(&self) -> ScanOpts {
|
||||||
|
ScanOpts { hidden: self.scan_hidden, extensionless: self.scan_extensionless }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::inspectors::mime_extension_lookup;
|
||||||
use crate::mime_db::*;
|
use crate::mime_db::*;
|
||||||
use crate::{extension_from_path, init_db, scan_directory, scan_from_walkdir};
|
use crate::{extension_from_path, init_db, scan_directory, scan_from_walkdir};
|
||||||
|
|
||||||
use crate::parameters::Parameters;
|
use crate::parameters::{Parameters, ScanOpts};
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
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;
|
||||||
|
@ -16,7 +16,7 @@ const PDF_BYTES: &[u8] = b"%PDF-";
|
||||||
const ZIP_BYTES: &[u8] = b"PK\x03\x04";
|
const ZIP_BYTES: &[u8] = b"PK\x03\x04";
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(any(all(not(target_os = "linux"), not(feature = "xdg-mime-backend")), all(target_os = "linux", feature = "infer-backend")))] {
|
if #[cfg(any(all(unix, feature = "infer-backend"), all(not(unix), not(feature = "xdg-mime-backend"))))] {
|
||||||
fn get_mime_db() -> InferDb {
|
fn get_mime_db() -> InferDb {
|
||||||
InferDb::init()
|
InferDb::init()
|
||||||
}
|
}
|
||||||
|
@ -95,10 +95,15 @@ fn simple_directory() {
|
||||||
drop(file);
|
drop(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let scan_opts = ScanOpts{
|
||||||
|
hidden: true,
|
||||||
|
extensionless: false
|
||||||
|
};
|
||||||
|
|
||||||
let entries = scan_directory(
|
let entries = scan_directory(
|
||||||
&dir.path().to_path_buf(),
|
&dir.path().to_path_buf(),
|
||||||
&vec!["jpg", "jpeg", "png", "pdf", "zip"],
|
&vec!["jpg", "jpeg", "png", "pdf", "zip"],
|
||||||
true,
|
&scan_opts,
|
||||||
)
|
)
|
||||||
.expect("Directory scan failed.");
|
.expect("Directory scan failed.");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue