new option for scanning extensionless files, nicer #[cfg]s, -s no longer skips hidden root dir...
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing

This commit is contained in:
Lynne Megido 2021-03-03 01:12:29 +10:00
parent 4412161193
commit 8a152d4118
Signed by: lynnesbian
GPG Key ID: F0A184B5213D9F90
6 changed files with 47 additions and 18 deletions

2
Cargo.lock generated
View File

@ -168,7 +168,7 @@ checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193"
[[package]]
name = "fif"
version = "0.2.7"
version = "0.2.8"
dependencies = [
"cached",
"cfg-if",

View File

@ -1,7 +1,7 @@
[package]
name = "fif"
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>"]
edition = "2018"
license = "GPL-3.0-or-later"
@ -35,7 +35,7 @@ rayon = { version = "1.5.0", optional = true }
exitcode = "1.1.2"
cfg-if = "1.0.0"
[target.'cfg(any(unix, target_os="redox"))'.dependencies]
[target.'cfg(unix)'.dependencies]
xdg-mime = "0.3"
[patch.crates-io]

View File

@ -29,7 +29,7 @@ use walkdir::{DirEntry, WalkDir};
use crate::findings::Findings;
use crate::formats::{Format, Script};
use crate::mime_db::MimeDb;
use crate::parameters::OutputFormat;
use crate::parameters::{OutputFormat, ScanOpts};
use crate::scan_error::ScanError;
use env_logger::Env;
use std::process::exit;
@ -46,7 +46,7 @@ mod scan_error;
mod tests;
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].
static MIMEDB: OnceCell<mime_db::InferDb> = OnceCell::new();
/// The backend being used; either "Infer" or "XDG-Mime".
@ -80,7 +80,7 @@ fn main() {
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() {
// 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.
fn wanted_file(scan_hidden: bool, exts: &[&str], entry: &DirEntry) -> bool {
if !scan_hidden && is_hidden(entry) {
/// Returns `true` if a file matches the given criteria. This means checking whether the file's extension appears in
/// `exts`, potentially skipping over hidden files, and so on.
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.
return false;
}
@ -175,9 +181,10 @@ fn wanted_file(scan_hidden: bool, exts: &[&str], entry: &DirEntry) -> bool {
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;
} // don't scan files without extensions. TODO - this should be configurable
}
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
/// (eventually) in future return an OsStr instead.
// TODO: ↑
fn extension_from_path(path: &Path) -> Option<String> {
path.extension(). // Get the path's extension
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
/// [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 mut probably_fatal_error = false;
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| {
if let Err(err) = &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.
fn init_db() {
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
.set(mime_db::InferDb::init())
.or(Err("Failed to initialise Infer backend!"))

View File

@ -9,7 +9,7 @@ pub trait MimeDb {
}
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;
pub struct InferDb {

View File

@ -47,6 +47,10 @@ pub struct Parameters {
#[clap(short, long)]
pub scan_hidden: bool,
/// Scan files without extensions
#[clap(short = 'S', long)]
pub scan_extensionless: bool,
/// Output format to use
#[clap(short, long, default_value = "script", arg_enum)]
pub output_format: OutputFormat,
@ -57,6 +61,14 @@ pub struct Parameters {
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 {
pub fn extensions(&self) -> Vec<&str> {
if let Some(exts) = &self.exts {
@ -70,4 +82,8 @@ impl Parameters {
unreachable!()
}
}
pub fn get_scan_opts(&self) -> ScanOpts {
ScanOpts { hidden: self.scan_hidden, extensionless: self.scan_extensionless }
}
}

View File

@ -2,7 +2,7 @@ use crate::inspectors::mime_extension_lookup;
use crate::mime_db::*;
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 mime_guess::mime::{APPLICATION_OCTET_STREAM, APPLICATION_PDF, IMAGE_JPEG, IMAGE_PNG};
use mime_guess::Mime;
@ -16,7 +16,7 @@ const PDF_BYTES: &[u8] = b"%PDF-";
const ZIP_BYTES: &[u8] = b"PK\x03\x04";
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 {
InferDb::init()
}
@ -95,10 +95,15 @@ fn simple_directory() {
drop(file);
}
let scan_opts = ScanOpts{
hidden: true,
extensionless: false
};
let entries = scan_directory(
&dir.path().to_path_buf(),
&vec!["jpg", "jpeg", "png", "pdf", "zip"],
true,
&scan_opts,
)
.expect("Directory scan failed.");