added rustfmt.toml, ran rustfmt

This commit is contained in:
Lynne Megido 2021-02-18 19:48:38 +10:00
parent 31acd76c73
commit b6d340d45c
Signed by: lynnesbian
GPG Key ID: F0A184B5213D9F90
7 changed files with 94 additions and 74 deletions

4
rusftmt.toml Normal file
View File

@ -0,0 +1,4 @@
max_width = 120
hard_tabs = true
tab_spaces = 2
newline_style = "Unix"

View File

@ -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())
} }
} }

View File

@ -16,13 +16,15 @@ 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)]
f.write_all(&*path.as_os_str().as_bytes())?; f.write_all(&*path.as_os_str().as_bytes())?;
#[cfg(windows)] #[cfg(windows)]
f.write_all(&*path.as_os_str().encode_wide().collect())?; // TODO: TEST THIS f.write_all(&*path.as_os_str().encode_wide().collect())?; // TODO: TEST THIS
write!(f, "'") write!(f, "'")
} }
} }
@ -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,32 +85,36 @@ 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<()> {
writeln!(f, "\necho Done.") writeln!(f, "\necho Done.")
} }
} }

View File

@ -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];
@ -30,8 +30,7 @@ pub fn mime_type<T: MimeDb>(db: &T, path: &Path) -> io::Result<Option<Mime>, > {
// this lint can be ignored: it's okay if the file isn't long enough to fill the buffer, as we only care about the // this lint can be ignored: it's okay if the file isn't long enough to fill the buffer, as we only care about the
// first few bytes for the purpose of mime sniffing // first few bytes for the purpose of mime sniffing
#[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() {
@ -61,4 +60,3 @@ cached! {
} }
} }
} }

View File

@ -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)]
@ -50,14 +50,17 @@ fn is_hidden(entry: &DirEntry) -> bool {
use std::os::windows::prelude::*; use std::os::windows::prelude::*;
std::fs::metadata(entry) // try to get metadata for file std::fs::metadata(entry) // try to get metadata for file
.map_or( .map_or(
false, // if getting metadata/attributes fails, assume it's not hidden false, // if getting metadata/attributes fails, assume it's not hidden
|f| f.file_attributes() & 0x2 > 0, // flag for hidden - https://docs.microsoft.com/windows/win32/fileio/file-attribute-constants |f| f.file_attributes() & 0x2 > 0, // flag for hidden - https://docs.microsoft.com/windows/win32/fileio/file-attribute-constants
) )
} }
#[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: &parameters::Parameters, entry: &DirEntry) -> bool { fn wanted_file(args: &parameters::Parameters, entry: &DirEntry) -> bool {
@ -73,7 +76,9 @@ fn wanted_file(args: &parameters::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| {
.iter() // iter over the chunk, which is a slice of DirEntry structs chunk // return Vec<...> instead of Chunk<Vec<...>>
.map(|entry| scan_file(entry)) .iter() // iter over the chunk, which is a slice of DirEntry structs
.collect::<Vec<_>>() .map(|entry| scan_file(entry))
) .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");

View File

@ -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,11 +18,8 @@ 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", buf.len() > 23
".jp2",
|buf| {
buf.len() > 23
&& buf[0] == 0x00 && buf[0] == 0x00
&& buf[1] == 0x00 && buf[1] == 0x00
&& buf[2] == 0x00 && buf[2] == 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,26 +45,24 @@ 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(),
} }
} }
fn get_type(&self, data: &[u8]) -> Option<Mime> { fn get_type(&self, data: &[u8]) -> Option<Mime> {
self.db.get_mime_type_for_data(&data).map(|m| m.0) self.db.get_mime_type_for_data(&data).map(|m| m.0)
} }
} }

View File

@ -2,16 +2,18 @@ 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!(
match self { f,
Self::File => "Couldn't read file", "{}",
Self::Mime => "Couldn't determine mime type" match self {
} Self::File => "Couldn't read file",
Self::Mime => "Couldn't determine mime type",
}
) )
} }
} }