added rustfmt.toml, ran rustfmt
This commit is contained in:
parent
31acd76c73
commit
b6d340d45c
7 changed files with 94 additions and 74 deletions
4
rusftmt.toml
Normal file
4
rusftmt.toml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
max_width = 120
|
||||||
|
hard_tabs = true
|
||||||
|
tab_spaces = 2
|
||||||
|
newline_style = "Unix"
|
|
@ -1,8 +1,10 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use crate::inspectors::mime_extension_lookup;
|
|
||||||
use mime_guess::Mime;
|
use mime_guess::Mime;
|
||||||
use smartstring::alias::String;
|
use smartstring::alias::String;
|
||||||
|
|
||||||
|
use crate::inspectors::mime_extension_lookup;
|
||||||
|
|
||||||
pub struct Findings {
|
pub struct Findings {
|
||||||
pub file: PathBuf, // TODO: replace with Path???? <'a> and all that
|
pub file: PathBuf, // TODO: replace with Path???? <'a> and all that
|
||||||
pub valid: bool,
|
pub valid: bool,
|
||||||
|
@ -11,7 +13,6 @@ pub struct Findings {
|
||||||
|
|
||||||
impl Findings {
|
impl Findings {
|
||||||
pub fn recommended_extension(&self) -> Option<String> {
|
pub fn recommended_extension(&self) -> Option<String> {
|
||||||
mime_extension_lookup(self.mime.clone())
|
mime_extension_lookup(self.mime.clone()).map(|extensions| extensions[0].to_owned())
|
||||||
.map(|extensions| extensions[0].to_owned())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,9 @@ type Entries = [Result<Findings, (ScanError, PathBuf)>];
|
||||||
|
|
||||||
fn write_pathbuf<W: Write>(f: &mut W, path: &PathBuf) -> io::Result<()> {
|
fn write_pathbuf<W: Write>(f: &mut W, path: &PathBuf) -> io::Result<()> {
|
||||||
match path.to_str() {
|
match path.to_str() {
|
||||||
Some(string) => { write!(f, "{}", escape(string)) }
|
Some(string) => {
|
||||||
|
write!(f, "{}", escape(string))
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
write!(f, "'")?;
|
write!(f, "'")?;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
@ -48,11 +50,7 @@ pub trait Format {
|
||||||
if !finding.valid {
|
if !finding.valid {
|
||||||
// the file's extension is wrong - check for known extension
|
// the file's extension is wrong - check for known extension
|
||||||
if let Some(ext) = finding.recommended_extension() {
|
if let Some(ext) = finding.recommended_extension() {
|
||||||
self.rename(
|
self.rename(f, &finding.file, &finding.file.with_extension(ext.as_str()))?
|
||||||
f,
|
|
||||||
&finding.file,
|
|
||||||
&finding.file.with_extension(ext.as_str()),
|
|
||||||
)?
|
|
||||||
} else {
|
} else {
|
||||||
self.no_known_extension(f, &finding.file)?
|
self.no_known_extension(f, &finding.file)?
|
||||||
}
|
}
|
||||||
|
@ -64,7 +62,7 @@ pub trait Format {
|
||||||
// failed to read the file
|
// failed to read the file
|
||||||
ScanError::File => self.unreadable(f, &error.1)?,
|
ScanError::File => self.unreadable(f, &error.1)?,
|
||||||
// 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 => self.unknown_type(f, &error.1)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +75,9 @@ pub trait Format {
|
||||||
pub struct Script {}
|
pub struct Script {}
|
||||||
|
|
||||||
impl Format for Script {
|
impl Format for Script {
|
||||||
fn new() -> Self { Self {} }
|
fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
|
||||||
fn rename<W: Write>(&self, f: &mut W, from: &PathBuf, to: &PathBuf) -> io::Result<()> {
|
fn rename<W: Write>(&self, f: &mut W, from: &PathBuf, to: &PathBuf) -> io::Result<()> {
|
||||||
// TODO: surely there's a better way...
|
// TODO: surely there's a better way...
|
||||||
|
@ -85,29 +85,33 @@ impl Format for Script {
|
||||||
write_pathbuf(f, from)?;
|
write_pathbuf(f, from)?;
|
||||||
write!(f, " ")?;
|
write!(f, " ")?;
|
||||||
write_pathbuf(f, to)?;
|
write_pathbuf(f, to)?;
|
||||||
writeln!(f, )
|
writeln!(f,)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn no_known_extension<W: Write>(&self, f: &mut W, path: &PathBuf) -> io::Result<()> {
|
fn no_known_extension<W: Write>(&self, f: &mut W, path: &PathBuf) -> io::Result<()> {
|
||||||
write!(f, "echo No known extension for ")?;
|
write!(f, "echo No known extension for ")?;
|
||||||
write_pathbuf(f, path)?;
|
write_pathbuf(f, path)?;
|
||||||
writeln!(f, )
|
writeln!(f,)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unreadable<W: Write>(&self, f: &mut W, path: &PathBuf) -> io::Result<()> {
|
fn unreadable<W: Write>(&self, f: &mut W, path: &PathBuf) -> io::Result<()> {
|
||||||
write!(f, "# Failed to read ")?;
|
write!(f, "# Failed to read ")?;
|
||||||
write_pathbuf(f, path)?;
|
write_pathbuf(f, path)?;
|
||||||
writeln!(f, )
|
writeln!(f,)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unknown_type<W: Write>(&self, f: &mut W, path: &PathBuf) -> io::Result<()> {
|
fn unknown_type<W: Write>(&self, f: &mut W, path: &PathBuf) -> io::Result<()> {
|
||||||
write!(f, "# Failed to detect mime type for ")?;
|
write!(f, "# Failed to detect mime type for ")?;
|
||||||
write_pathbuf(f, path)?;
|
write_pathbuf(f, path)?;
|
||||||
writeln!(f, )
|
writeln!(f,)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header<W: Write>(&self, _: &Entries, f: &mut W) -> io::Result<()> {
|
fn header<W: Write>(&self, _: &Entries, f: &mut W) -> io::Result<()> {
|
||||||
write!(f, "#!/usr/bin/env sh\n\nGenerated by fif {}.\n\n", VERSION.unwrap_or("???"))
|
write!(
|
||||||
|
f,
|
||||||
|
"#!/usr/bin/env sh\n\nGenerated by fif {}.\n\n",
|
||||||
|
VERSION.unwrap_or("???")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn footer<W: Write>(&self, _: &Entries, f: &mut W) -> io::Result<()> {
|
fn footer<W: Write>(&self, _: &Entries, f: &mut W) -> io::Result<()> {
|
||||||
|
|
|
@ -21,7 +21,7 @@ use crate::mimedb::MimeDb;
|
||||||
// at least 265 bytes to identify a tar file.
|
// at least 265 bytes to identify a tar file.
|
||||||
const BUF_SIZE: usize = 512;
|
const BUF_SIZE: usize = 512;
|
||||||
|
|
||||||
pub fn mime_type<T: MimeDb>(db: &T, path: &Path) -> io::Result<Option<Mime>, > {
|
pub fn mime_type<T: MimeDb>(db: &T, path: &Path) -> io::Result<Option<Mime>> {
|
||||||
// attempt to read up to the BUF_SIZE bytes of the file
|
// attempt to read up to the BUF_SIZE bytes of the file
|
||||||
|
|
||||||
let mut buffer = [0; 64];
|
let mut buffer = [0; 64];
|
||||||
|
@ -32,7 +32,6 @@ pub fn mime_type<T: MimeDb>(db: &T, path: &Path) -> io::Result<Option<Mime>, > {
|
||||||
#[allow(clippy::unused_io_amount)]
|
#[allow(clippy::unused_io_amount)]
|
||||||
file.read(&mut buffer)?;
|
file.read(&mut buffer)?;
|
||||||
|
|
||||||
|
|
||||||
let r = db.get_type(&buffer);
|
let r = db.get_type(&buffer);
|
||||||
if r.is_some() {
|
if r.is_some() {
|
||||||
return Ok(r);
|
return Ok(r);
|
||||||
|
@ -61,4 +60,3 @@ cached! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
64
src/main.rs
64
src/main.rs
|
@ -21,7 +21,7 @@ use clap::Clap;
|
||||||
use log::{debug, info, trace, warn};
|
use log::{debug, info, trace, warn};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
#[cfg(feature = "multi-threaded")]
|
#[cfg(feature = "multi-threaded")]
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use smartstring::alias::String;
|
use smartstring::alias::String;
|
||||||
use walkdir::{DirEntry, WalkDir};
|
use walkdir::{DirEntry, WalkDir};
|
||||||
|
|
||||||
|
@ -31,18 +31,18 @@ use crate::mimedb::MimeDb;
|
||||||
use crate::parameters::OutputFormat;
|
use crate::parameters::OutputFormat;
|
||||||
use crate::scanerror::ScanError;
|
use crate::scanerror::ScanError;
|
||||||
|
|
||||||
mod parameters;
|
|
||||||
mod inspectors;
|
|
||||||
mod formats;
|
|
||||||
mod scanerror;
|
|
||||||
mod findings;
|
mod findings;
|
||||||
|
mod formats;
|
||||||
|
mod inspectors;
|
||||||
mod mimedb;
|
mod mimedb;
|
||||||
|
mod parameters;
|
||||||
|
mod scanerror;
|
||||||
|
|
||||||
#[cfg(feature = "infer-backend")]
|
#[cfg(feature = "infer-backend")]
|
||||||
static MIMEDB: OnceCell<mimedb::InferDb> = OnceCell::new();
|
static MIMEDB: OnceCell<mimedb::InferDb> = OnceCell::new();
|
||||||
|
|
||||||
#[cfg(feature = "xdg-mime-backend")]
|
#[cfg(feature = "xdg-mime-backend")]
|
||||||
static MIMEDB: OnceCell<mimedb::XdgDb> = OnceCell::new();
|
static MIMEDB: OnceCell<mimedb::XdgDb> = OnceCell::new();
|
||||||
|
|
||||||
// TODO: test if this actually works on a windows machine
|
// TODO: test if this actually works on a windows machine
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
@ -57,7 +57,10 @@ fn is_hidden(entry: &DirEntry) -> bool {
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
fn is_hidden(entry: &DirEntry) -> bool {
|
fn is_hidden(entry: &DirEntry) -> bool {
|
||||||
entry.file_name().to_str().map_or(false, |f| f.starts_with('.') && f != ".")
|
entry
|
||||||
|
.file_name()
|
||||||
|
.to_str()
|
||||||
|
.map_or(false, |f| f.starts_with('.') && f != ".")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wanted_file(args: ¶meters::Parameters, entry: &DirEntry) -> bool {
|
fn wanted_file(args: ¶meters::Parameters, entry: &DirEntry) -> bool {
|
||||||
|
@ -73,7 +76,9 @@ fn wanted_file(args: ¶meters::Parameters, entry: &DirEntry) -> bool {
|
||||||
|
|
||||||
let ext = extension_from_path(entry.path());
|
let ext = extension_from_path(entry.path());
|
||||||
|
|
||||||
if ext.is_none() { return false; } // don't scan files without extensions. TODO - this should be configurable
|
if ext.is_none() {
|
||||||
|
return false;
|
||||||
|
} // don't scan files without extensions. TODO - this should be configurable
|
||||||
|
|
||||||
if let Some(extensions) = &args.extensions {
|
if let Some(extensions) = &args.extensions {
|
||||||
// if the user has specified a list of extensions to check against, make sure this file ends in one of them.
|
// if the user has specified a list of extensions to check against, make sure this file ends in one of them.
|
||||||
|
@ -117,7 +122,7 @@ fn scan_file(entry: &DirEntry) -> Result<Findings, (ScanError, PathBuf)> {
|
||||||
// there is a known set of extensions for this mimetype, but the file has no extension
|
// there is a known set of extensions for this mimetype, but the file has no extension
|
||||||
Some(_) => false,
|
Some(_) => false,
|
||||||
// there is no known set of extensions for this mimetype -- assume it's correct
|
// there is no known set of extensions for this mimetype -- assume it's correct
|
||||||
None => true
|
None => true,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Findings {
|
Ok(Findings {
|
||||||
|
@ -128,25 +133,25 @@ fn scan_file(entry: &DirEntry) -> Result<Findings, (ScanError, PathBuf)> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scan_from_walkdir(entries: Vec<DirEntry>) -> Vec<Result<Findings, (ScanError, PathBuf)>> {
|
fn scan_from_walkdir(entries: Vec<DirEntry>) -> Vec<Result<Findings, (ScanError, PathBuf)>> {
|
||||||
#[cfg(feature = "multi-threaded")] {
|
#[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.
|
||||||
// this allows each spawned thread to handle 32 files before before closing, rather than creating a new thread for
|
// this allows each spawned thread to handle 32 files before before closing, rather than creating a new thread for
|
||||||
// each file. this leads to a pretty substantial speedup that i'm pretty substantially happy about 0u0
|
// each file. this leads to a pretty substantial speedup that i'm pretty substantially happy about 0u0
|
||||||
entries
|
entries
|
||||||
.par_chunks(32) // split into chunks of 32
|
.par_chunks(32) // split into chunks of 32
|
||||||
.flat_map(|chunk| chunk // return Vec<...> instead of Chunk<Vec<...>>
|
.flat_map(|chunk| {
|
||||||
|
chunk // return Vec<...> instead of Chunk<Vec<...>>
|
||||||
.iter() // iter over the chunk, which is a slice of DirEntry structs
|
.iter() // iter over the chunk, which is a slice of DirEntry structs
|
||||||
.map(|entry| scan_file(entry))
|
.map(|entry| scan_file(entry))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
)
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "multi-threaded"))] {
|
#[cfg(not(feature = "multi-threaded"))]
|
||||||
entries
|
{
|
||||||
.iter()
|
entries.iter().map(|entry: &DirEntry| scan_file(entry)).collect()
|
||||||
.map(|entry: &DirEntry| scan_file(entry))
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,10 +166,16 @@ fn main() {
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
#[cfg(feature = "infer-backend")]
|
#[cfg(feature = "infer-backend")]
|
||||||
MIMEDB.set(mimedb::InferDb::init()).or(Err("Failed to initialise MIMEDB")).unwrap();
|
MIMEDB
|
||||||
|
.set(mimedb::InferDb::init())
|
||||||
|
.or(Err("Failed to initialise MIMEDB"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
#[cfg(feature = "xdg-mime-backend")]
|
#[cfg(feature = "xdg-mime-backend")]
|
||||||
MIMEDB.set(mimedb::XdgDb::init()).or(Err("Failed to initialise MIMEDB")).unwrap();
|
MIMEDB
|
||||||
|
.set(mimedb::XdgDb::init())
|
||||||
|
.or(Err("Failed to initialise MIMEDB"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
debug!("Iterating directory: {:?}", args.dirs);
|
debug!("Iterating directory: {:?}", args.dirs);
|
||||||
|
|
||||||
|
@ -183,21 +194,26 @@ fn main() {
|
||||||
match result {
|
match result {
|
||||||
Ok(r) => {
|
Ok(r) => {
|
||||||
if !r.valid {
|
if !r.valid {
|
||||||
info!("{:?} should have file extension {}", r.file, r.recommended_extension().unwrap())
|
info!(
|
||||||
|
"{:?} should have file extension {}",
|
||||||
|
r.file,
|
||||||
|
r.recommended_extension().unwrap()
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
trace!("{:?} is totally fine", r.file)
|
trace!("{:?} is totally fine", r.file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(f) => warn!("{:#?}: Error 0uo - {}", f.1, f.0)
|
Err(f) => warn!("{:#?}: Error 0uo - {}", f.1, f.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match args.output_format {
|
match args.output_format {
|
||||||
OutputFormat::Script => {
|
OutputFormat::Script => {
|
||||||
let s = Script::new();
|
let s = Script::new();
|
||||||
s.write_all(&results, &mut BufWriter::new(stdout().lock())).expect("failed to output");
|
s.write_all(&results, &mut BufWriter::new(stdout().lock()))
|
||||||
|
.expect("failed to output");
|
||||||
}
|
}
|
||||||
OutputFormat::Text => todo!()
|
OutputFormat::Text => todo!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Done");
|
debug!("Done");
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use mime_guess::Mime;
|
|
||||||
#[cfg(feature = "infer-backend")]
|
#[cfg(feature = "infer-backend")]
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use mime_guess::Mime;
|
||||||
|
|
||||||
pub trait MimeDb {
|
pub trait MimeDb {
|
||||||
fn init() -> Self;
|
fn init() -> Self;
|
||||||
|
@ -9,7 +10,7 @@ pub trait MimeDb {
|
||||||
|
|
||||||
#[cfg(feature = "infer-backend")]
|
#[cfg(feature = "infer-backend")]
|
||||||
pub struct InferDb {
|
pub struct InferDb {
|
||||||
db: infer::Infer
|
db: infer::Infer,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "infer-backend")]
|
#[cfg(feature = "infer-backend")]
|
||||||
|
@ -17,10 +18,7 @@ impl MimeDb for InferDb {
|
||||||
fn init() -> Self {
|
fn init() -> Self {
|
||||||
let mut info = infer::Infer::new();
|
let mut info = infer::Infer::new();
|
||||||
// add a random file type just to make sure adding works and such
|
// add a random file type just to make sure adding works and such
|
||||||
info.add(
|
info.add("image/jpeg2000", ".jp2", |buf| {
|
||||||
"image/jpeg2000",
|
|
||||||
".jp2",
|
|
||||||
|buf| {
|
|
||||||
buf.len() > 23
|
buf.len() > 23
|
||||||
&& buf[0] == 0x00
|
&& buf[0] == 0x00
|
||||||
&& buf[1] == 0x00
|
&& buf[1] == 0x00
|
||||||
|
@ -38,8 +36,7 @@ impl MimeDb for InferDb {
|
||||||
&& buf[21] == 0x70
|
&& buf[21] == 0x70
|
||||||
&& buf[22] == 0x32
|
&& buf[22] == 0x32
|
||||||
&& buf[23] == 0x20
|
&& buf[23] == 0x20
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// unmut
|
// unmut
|
||||||
let info = info;
|
let info = info;
|
||||||
|
@ -48,22 +45,20 @@ impl MimeDb for InferDb {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_type(&self, data: &[u8]) -> Option<Mime> {
|
fn get_type(&self, data: &[u8]) -> Option<Mime> {
|
||||||
self.db
|
self.db.get(data).map(|f| Mime::from_str(f.mime_type()).unwrap())
|
||||||
.get(data)
|
|
||||||
.map(|f| Mime::from_str(f.mime_type()).unwrap())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "xdg-mime-backend")]
|
#[cfg(feature = "xdg-mime-backend")]
|
||||||
pub struct XdgDb {
|
pub struct XdgDb {
|
||||||
db: xdg_mime::SharedMimeInfo
|
db: xdg_mime::SharedMimeInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "xdg-mime-backend")]
|
#[cfg(feature = "xdg-mime-backend")]
|
||||||
impl MimeDb for XdgDb {
|
impl MimeDb for XdgDb {
|
||||||
fn init() -> Self {
|
fn init() -> Self {
|
||||||
Self {
|
Self {
|
||||||
db: xdg_mime::SharedMimeInfo::new()
|
db: xdg_mime::SharedMimeInfo::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,17 @@ use std::fmt::{Display, Formatter, Result};
|
||||||
|
|
||||||
pub enum ScanError {
|
pub enum ScanError {
|
||||||
File,
|
File,
|
||||||
Mime
|
Mime,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ScanError {
|
impl Display for ScanError {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||||
write!(f, "{}",
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
match self {
|
match self {
|
||||||
Self::File => "Couldn't read file",
|
Self::File => "Couldn't read file",
|
||||||
Self::Mime => "Couldn't determine mime type"
|
Self::Mime => "Couldn't determine mime type",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue