Compare commits
3 commits
c270383e6f
...
4412161193
Author | SHA1 | Date | |
---|---|---|---|
4412161193 | |||
5907309689 | |||
32da919f81 |
9 changed files with 53 additions and 34 deletions
|
@ -14,6 +14,9 @@ exclude = [".idea/", "Cross.toml", "*.sh", "*.py", ".drone.yml"]
|
||||||
#resolver = "2"
|
#resolver = "2"
|
||||||
#license-file = "LICENSE"
|
#license-file = "LICENSE"
|
||||||
|
|
||||||
|
[badges]
|
||||||
|
maintenance = { status = "experimental" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["multi-threaded"]
|
default = ["multi-threaded"]
|
||||||
multi-threaded = ["rayon"]
|
multi-threaded = ["rayon"]
|
||||||
|
|
|
@ -7,14 +7,14 @@ use std::path::PathBuf;
|
||||||
|
|
||||||
use snailquote::escape;
|
use snailquote::escape;
|
||||||
|
|
||||||
use crate::scanerror::ScanError;
|
use crate::scan_error::ScanError;
|
||||||
use crate::{Findings, BACKEND};
|
use crate::{Findings, BACKEND};
|
||||||
|
|
||||||
/// The current version of fif, as defined in Cargo.toml.
|
/// The current version of fif, as defined in Cargo.toml.
|
||||||
const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");
|
const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
type Entries = [Result<Findings, (ScanError, PathBuf)>];
|
type Entries = [Result<Findings, ScanError>];
|
||||||
|
|
||||||
enum Writable<'a> {
|
enum Writable<'a> {
|
||||||
String(&'a str),
|
String(&'a str),
|
||||||
|
@ -86,11 +86,11 @@ pub trait Format {
|
||||||
|
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
// something went wrong 0uo
|
// something went wrong 0uo
|
||||||
match error.0 {
|
match error {
|
||||||
// failed to read the file
|
// failed to read the file
|
||||||
ScanError::File => self.unreadable(f, &error.1)?,
|
ScanError::File(path) => self.unreadable(f, path)?,
|
||||||
// file was read successfully, but we couldn't determine a mimetype
|
// file was read successfully, but we couldn't determine a mimetype
|
||||||
ScanError::Mime => self.unknown_type(f, &error.1)?,
|
ScanError::Mime(path) => self.unknown_type(f, path)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use cached::cached;
|
||||||
use mime_guess::Mime;
|
use mime_guess::Mime;
|
||||||
use smartstring::alias::String;
|
use smartstring::alias::String;
|
||||||
|
|
||||||
use crate::mimedb::MimeDb;
|
use crate::mime_db::MimeDb;
|
||||||
|
|
||||||
/// The number of bytes to read initially.
|
/// The number of bytes to read initially.
|
||||||
///
|
///
|
||||||
|
|
34
src/main.rs
34
src/main.rs
|
@ -28,32 +28,32 @@ use walkdir::{DirEntry, WalkDir};
|
||||||
|
|
||||||
use crate::findings::Findings;
|
use crate::findings::Findings;
|
||||||
use crate::formats::{Format, Script};
|
use crate::formats::{Format, Script};
|
||||||
use crate::mimedb::MimeDb;
|
use crate::mime_db::MimeDb;
|
||||||
use crate::parameters::OutputFormat;
|
use crate::parameters::OutputFormat;
|
||||||
use crate::scanerror::ScanError;
|
use crate::scan_error::ScanError;
|
||||||
use env_logger::Env;
|
use env_logger::Env;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
mod extensionset;
|
mod extension_set;
|
||||||
mod findings;
|
mod findings;
|
||||||
mod formats;
|
mod formats;
|
||||||
mod inspectors;
|
mod inspectors;
|
||||||
mod mimedb;
|
mod mime_db;
|
||||||
mod parameters;
|
mod parameters;
|
||||||
mod scanerror;
|
mod scan_error;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
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(not(unix), not(feature = "xdg-mime-backend")), all(unix, feature = "infer-backend")))] {
|
||||||
/// A [OnceCell] holding an instance of [mimedb::MimeDb].
|
/// A [OnceCell] holding an instance of [mime_db::MimeDb].
|
||||||
static MIMEDB: OnceCell<mimedb::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".
|
||||||
const BACKEND: &str = "Infer";
|
const BACKEND: &str = "Infer";
|
||||||
} else {
|
} else {
|
||||||
/// A [OnceCell] holding an instance of [mimedb::MimeDb].
|
/// A [OnceCell] holding an instance of [mime_db::MimeDb].
|
||||||
static MIMEDB: OnceCell<mimedb::XdgDb> = OnceCell::new();
|
static MIMEDB: OnceCell<mime_db::XdgDb> = OnceCell::new();
|
||||||
/// The backend being used; either "Infer" or "XDG-Mime".
|
/// The backend being used; either "Infer" or "XDG-Mime".
|
||||||
const BACKEND: &str = "XDG-Mime";
|
const BACKEND: &str = "XDG-Mime";
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ fn main() {
|
||||||
r.recommended_extension().unwrap_or_else(|| "???".into())
|
r.recommended_extension().unwrap_or_else(|| "???".into())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Err(f) => warn!("{:#?}: Error 0uo - {}", f.1, f.0),
|
Err(f) => warn!("Error 0uo - {}", f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,26 +191,26 @@ fn extension_from_path(path: &Path) -> Option<String> {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inspects the given entry, returning a [Findings] on success and a tuple of [ScanError] and [PathBuf] on failure.
|
/// Inspects the given entry, returning a [Findings] on success and a [ScanError] on failure.
|
||||||
///
|
///
|
||||||
/// In the event of an IO error, the returned ScanError will be of type [ScanError::File]. Otherwise, a
|
/// In the event of an IO error, the returned ScanError will be of type [ScanError::File]. Otherwise, a
|
||||||
/// [ScanError::Mime] will be returned, meaning that the file was scanned successfully, but a mimetype could not be
|
/// [ScanError::Mime] will be returned, meaning that the file was scanned successfully, but a mimetype could not be
|
||||||
/// determined.
|
/// determined.
|
||||||
fn scan_file(entry: &DirEntry) -> Result<Findings, (ScanError, PathBuf)> {
|
fn scan_file(entry: &DirEntry) -> Result<Findings, ScanError> {
|
||||||
// try to determine mimetype for this entry
|
// try to determine mimetype for this entry
|
||||||
let result = inspectors::mime_type(MIMEDB.get().unwrap(), entry.path());
|
let result = inspectors::mime_type(MIMEDB.get().unwrap(), entry.path());
|
||||||
|
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
// an error occurred while trying to read the file
|
// an error occurred while trying to read the file
|
||||||
// error!("{}: {}", entry.path().to_string_lossy(), error);
|
// error!("{}: {}", entry.path().to_string_lossy(), error);
|
||||||
return Err((ScanError::File, entry.path().to_path_buf()));
|
return Err(ScanError::File(entry.path().to_path_buf()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = result.unwrap();
|
let result = result.unwrap();
|
||||||
if result.is_none() {
|
if result.is_none() {
|
||||||
// the file was read successfully, but we were unable to determine its mimetype
|
// the file was read successfully, but we were unable to determine its mimetype
|
||||||
// warn!("Couldn't determine mimetype for {}", entry.path().to_string_lossy());
|
// warn!("Couldn't determine mimetype for {}", entry.path().to_string_lossy());
|
||||||
return Err((ScanError::Mime, entry.path().to_path_buf()));
|
return Err(ScanError::Mime(entry.path().to_path_buf()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = result.unwrap();
|
let result = result.unwrap();
|
||||||
|
@ -235,7 +235,7 @@ fn scan_file(entry: &DirEntry) -> Result<Findings, (ScanError, PathBuf)> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes a slice of [DirEntry]s and calls [scan_file] on each one, returning the results in a vector.
|
/// Takes a slice of [DirEntry]s and calls [scan_file] on each one, returning the results in a vector.
|
||||||
fn scan_from_walkdir(entries: &[DirEntry]) -> Vec<Result<Findings, (ScanError, PathBuf)>> {
|
fn scan_from_walkdir(entries: &[DirEntry]) -> Vec<Result<Findings, ScanError>> {
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "multi-threaded")] {
|
if #[cfg(feature = "multi-threaded")] {
|
||||||
// rather than using a standard par_iter, split the entries into chunks of 32 first.
|
// rather than using a standard par_iter, split the entries into chunks of 32 first.
|
||||||
|
@ -301,12 +301,12 @@ 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(not(unix), not(feature = "xdg-mime-backend")), all(unix, feature = "infer-backend")))] {
|
||||||
MIMEDB
|
MIMEDB
|
||||||
.set(mimedb::InferDb::init())
|
.set(mime_db::InferDb::init())
|
||||||
.or(Err("Failed to initialise Infer backend!"))
|
.or(Err("Failed to initialise Infer backend!"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
MIMEDB
|
MIMEDB
|
||||||
.set(mimedb::XdgDb::init())
|
.set(mime_db::XdgDb::init())
|
||||||
.or(Err("Failed to initialise XDG Mime backend!"))
|
.or(Err("Failed to initialise XDG Mime backend!"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,20 +2,32 @@
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::extensionset::ExtensionSet;
|
use crate::extension_set::ExtensionSet;
|
||||||
use clap::{Clap};
|
use clap::{Clap, AppSettings};
|
||||||
use smartstring::{LazyCompact, SmartString};
|
use smartstring::{LazyCompact, SmartString};
|
||||||
|
|
||||||
#[derive(Clap, PartialEq, Debug)]
|
#[derive(Clap, PartialEq, Debug)]
|
||||||
pub enum OutputFormat {
|
pub enum OutputFormat {
|
||||||
|
/// A Bourne shell compatible script.
|
||||||
Script,
|
Script,
|
||||||
|
/// Plain text.
|
||||||
Text,
|
Text,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: convert this to macro style?: https://docs.rs/clap/3.0.0-beta.2/clap/index.html#using-macros
|
// TODO: convert this to macro style?: https://docs.rs/clap/3.0.0-beta.2/clap/index.html#using-macros
|
||||||
|
|
||||||
#[derive(Clap, Debug)]
|
#[derive(Clap, Debug)]
|
||||||
#[clap(version = option_env!("CARGO_PKG_VERSION").unwrap_or("???"))]
|
#[clap(
|
||||||
|
version = option_env!("CARGO_PKG_VERSION").unwrap_or("???"),
|
||||||
|
author = option_env!("CARGO_PKG_AUTHORS").unwrap_or("Lynnesbian"),
|
||||||
|
about = option_env!("CARGO_PKG_DESCRIPTION").unwrap_or("File Info Fixer"),
|
||||||
|
before_help = "Copyright © 2021 Lynnesbian under the GPL3 (or later) License.",
|
||||||
|
before_long_help = "Copyright © 2021 Lynnesbian\n\
|
||||||
|
This program is free software: you can redistribute it and/or modify \
|
||||||
|
it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 \
|
||||||
|
of the License, or (at your option) any later version.",
|
||||||
|
setting(AppSettings::ColoredHelp)
|
||||||
|
)]
|
||||||
pub struct Parameters {
|
pub struct Parameters {
|
||||||
/// Only examine files with these extensions (Comma-separated list)
|
/// Only examine files with these extensions (Comma-separated list)
|
||||||
#[clap(
|
#[clap(
|
||||||
|
@ -27,7 +39,7 @@ pub struct Parameters {
|
||||||
)]
|
)]
|
||||||
pub exts: Option<Vec<SmartString<LazyCompact>>>,
|
pub exts: Option<Vec<SmartString<LazyCompact>>>,
|
||||||
|
|
||||||
/// write good docs 0uo
|
/// Use a preset list of extensions as the search filter
|
||||||
#[clap(short = 'E', long, arg_enum, required_unless_present = "exts")]
|
#[clap(short = 'E', long, arg_enum, required_unless_present = "exts")]
|
||||||
pub ext_set: Option<ExtensionSet>,
|
pub ext_set: Option<ExtensionSet>,
|
||||||
|
|
||||||
|
@ -35,7 +47,7 @@ pub struct Parameters {
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
pub scan_hidden: bool,
|
pub scan_hidden: bool,
|
||||||
|
|
||||||
/// Output format to use. See "--help formats" for more information.
|
/// 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,
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,25 @@
|
||||||
use std::fmt::{Display, Formatter, Result};
|
use std::fmt::{Display, Formatter, Result};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ScanError {
|
pub enum ScanError {
|
||||||
/// Something went wrong while trying to read the given file.
|
/// Something went wrong while trying to read the given file.
|
||||||
File,
|
File(PathBuf),
|
||||||
/// Failed to determine the mimetype of the given file.
|
/// Failed to determine the mimetype of the given file.
|
||||||
Mime,
|
Mime(PathBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ScanError {
|
impl Display for ScanError {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}",
|
"Couldn't {} file: {}",
|
||||||
match self {
|
match self {
|
||||||
Self::File => "Couldn't read file",
|
Self::File(_) => "read",
|
||||||
Self::Mime => "Couldn't determine mime type",
|
Self::Mime(_) => "determine mime type of",
|
||||||
|
},
|
||||||
|
match self {
|
||||||
|
Self::File(f) | Self::Mime(f) => f.to_string_lossy(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::inspectors::mime_extension_lookup;
|
use crate::inspectors::mime_extension_lookup;
|
||||||
use crate::mimedb::*;
|
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;
|
||||||
|
|
Loading…
Reference in a new issue