69 lines
2.1 KiB
Rust
69 lines
2.1 KiB
Rust
use std::{collections::{HashMap, HashSet}, error::Error, os::unix::prelude::MetadataExt, path::PathBuf};
|
|
|
|
use clap::Parser;
|
|
use walkdir::WalkDir;
|
|
|
|
type StdError<T> = Result<T, Box<dyn Error>>;
|
|
|
|
#[derive(Parser)]
|
|
#[clap(author, version, about)]
|
|
struct Cli {
|
|
/// Source directory
|
|
#[clap(value_parser)]
|
|
source: PathBuf,
|
|
/// Destination directory
|
|
#[clap(value_parser)]
|
|
destination: PathBuf,
|
|
// /// Be more verbose
|
|
// #[clap(short, long, value_parser)]
|
|
// verbose: bool,
|
|
}
|
|
|
|
// Map from (filesize, filename) to full file path relative to root
|
|
#[derive(Default)]
|
|
struct FileMap(HashMap<(u64, String), String>);
|
|
|
|
impl FileMap {
|
|
fn new(path: &PathBuf) -> StdError<Self> {
|
|
let mut fm = Self::default();
|
|
for entry in WalkDir::new(path).into_iter().filter_entry(|e| {
|
|
!e.file_name()
|
|
.to_str()
|
|
.map(|s| s.starts_with('.'))
|
|
.unwrap_or(false)
|
|
}) {
|
|
let entry = entry?;
|
|
let meta = &entry.metadata()?;
|
|
if meta.is_dir() {
|
|
continue;
|
|
}
|
|
let fname = entry.file_name().to_str().unwrap().to_owned();
|
|
let fpath = entry.path().to_str().unwrap().to_owned();
|
|
if let Some(old) = fm.0.insert((meta.size(), fname.clone()), fpath.clone()) {
|
|
return Err(format!("Duplicate filesize/filename detected: {}, clashes with {}!", old, fpath).into());
|
|
}
|
|
}
|
|
Ok(fm)
|
|
}
|
|
}
|
|
|
|
fn main() -> StdError<()> {
|
|
let cli = Cli::parse();
|
|
let source = FileMap::new(&cli.source)?;
|
|
let source_set: HashSet<_> = source.0.keys().collect();
|
|
eprintln!("{} files in source", source.0.len());
|
|
let dest = FileMap::new(&cli.destination)?;
|
|
let dest_set = dest.0.keys().collect();
|
|
eprintln!("{} files in destination", dest.0.len());
|
|
let mut diffs: Vec<_> = source_set.difference(&dest_set).map(|d| source.0[d].clone()).collect();
|
|
diffs.sort();
|
|
if !diffs.is_empty() {
|
|
eprintln!("Files present in source but not dest:");
|
|
for diff in diffs {
|
|
eprintln!("{}", diff);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|