diff --git a/Cargo.toml b/Cargo.toml index 5c6de47..22a08bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,10 @@ authors = ["Lynnesbian "] edition = "2018" license = "GPL-3.0-or-later" rust-version = "1.43.0" # cached requires 1.42.0 +repository = "https://git.bune.city/lynnesbian/fif" +readme = "README.md" +keywords = ["mime", "mimetype", "utilities", "tools"] +categories = ["command-line-utilities"] #resolver = "2" #license-file = "LICENSE" diff --git a/README.md b/README.md new file mode 100644 index 0000000..12d99dd --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +fif +=== +A command-line tool for detecting and optionally correcting files with incorrect extensions. + +## Installation +```bash +cargo install --locked fif +``` + +## Usage + +```bash +fif --help +``` \ No newline at end of file diff --git a/src/extensionset.rs b/src/extensionset.rs index 17c7cef..01e2db4 100644 --- a/src/extensionset.rs +++ b/src/extensionset.rs @@ -13,21 +13,16 @@ pub enum ExtensionSet { impl ExtensionSet { pub fn extensions(&self) -> Vec<&str> { match self { - Self::Images => vec![ - "png", "jpg", "jpeg", "webp", "raw", "gif", "apng", "tga", "bmp", "tif", "tiff", "heif", "avif", "jp2", "mng", - "svg", - ], - Self::Videos => vec![ - "webm", "mp4", "mkv", "mov", "avi", "m4v", "wmv", "bik", "ogv", "qt", "3gp", "3g2", "divx", - ], - Self::Audio => vec![ - "ogg", "oga", "opus", "mp3", "m4a", "aac", "flac", "ape", "midi", "mid", "alac", "wav", "aiff", "aa3", "at3", - ], - Self::Documents => vec![ + Self::Images => mime_guess::get_mime_extensions_str("image/*"), + Self::Videos => mime_guess::get_mime_extensions_str("video/*"), + Self::Audio => mime_guess::get_mime_extensions_str("audio/*"), + Self::Documents => Some(&[ "doc", "docx", "ppt", "pptx", "xls", "xlsx", "csv", "tsv", "pdf", "odt", "ods", "odp", - ], - Self::Archives => vec!["zip", "tar", "gz", "zst", "xz", "rar", "7z", "bz", "bz2"], + ][..]), + // many compressed file types follow the name scheme "application/x.+compressed.*" - maybe this can be used + // somehow to extract extensions for compressed files from mime_guess? + Self::Archives => Some(&["zip", "tar", "gz", "zst", "xz", "rar", "7z", "bz", "bz2"][..]), _ => todo!(), - } + }.unwrap().to_vec() } } diff --git a/src/formats.rs b/src/formats.rs index 3f05570..c66074d 100644 --- a/src/formats.rs +++ b/src/formats.rs @@ -16,7 +16,7 @@ enum Writable<'a> { String(&'a str), Path(&'a PathBuf), Space, - Newline + Newline, } // the lifetime of a lifetime @@ -40,19 +40,16 @@ fn smart_write(f: &mut W, writeables: &[Writable]) -> io::Result<()> { Writable::Newline => writeln!(f, )?, Writable::String(s) => write!(f, "{}", s)?, Writable::Path(path) => { - match path.to_str() { - Some(string) => { - write!(f, "{}", escape(string))? - } - None => { - write!(f, "'''")?; - #[cfg(unix)] + if let Some(string) = path.to_str() { + write!(f, "{}", escape(string))? + } else { + write!(f, "'''")?; + #[cfg(unix)] f.write_all(&*path.as_os_str().as_bytes())?; - #[cfg(windows)] - write!(f, "{}", path.as_os_str().to_string_lossy())?; // TODO: implement bonked strings for windows - // f.write_all(&*path.as_os_str().encode_wide().collect::>())?; - write!(f, "'''")? - } + #[cfg(windows)] + write!(f, "{}", path.as_os_str().to_string_lossy())?; // TODO: implement bonked strings for windows + // f.write_all(&*path.as_os_str().encode_wide().collect::>())?; + write!(f, "'''")? } } } diff --git a/src/main.rs b/src/main.rs index 993b284..657800d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -117,10 +117,8 @@ fn scan_file(entry: &DirEntry) -> Result { let valid = match known_exts { // there is a known set of extensions for this mimetype, and the file has an extension Some(e) if entry_ext.is_some() => e.contains(&entry_ext.unwrap().to_lowercase().into()), - // there is a known set of extensions for this mimetype, but the file has no extension - Some(_) => false, - // there is no known set of extensions for this mimetype :( - None => false, + // either this file has no extension, or there is no known set of extensions for this mimetype :( + Some(_) | None => false, }; Ok(Findings { @@ -130,7 +128,7 @@ fn scan_file(entry: &DirEntry) -> Result { }) } -fn scan_from_walkdir(entries: Vec) -> Vec> { +fn scan_from_walkdir(entries: &[DirEntry]) -> Vec> { #[cfg(feature = "multi-threaded")] { // rather than using a standard par_iter, split the entries into chunks of 32 first. @@ -232,7 +230,7 @@ fn main() { trace!("Found {} items to check", entries.len()); - let results: Vec<_> = scan_from_walkdir(entries) + let results: Vec<_> = scan_from_walkdir(&entries) .into_iter() .filter( |result| result.is_err() || !result.as_ref().unwrap().valid,