use std::env;
use file_engine::{FileEngine, Progress};
#[tokio::main]
async fn main() -> file_engine::Result<()> {
let mut allow_integrity_risk = false;
let mut positional = Vec::new();
for arg in env::args().skip(1) {
if arg == "--allow-integrity-risk" {
allow_integrity_risk = true;
} else {
positional.push(arg);
}
}
let mut positional = positional.into_iter();
let (source, dest) = match (positional.next(), positional.next()) {
(Some(source), Some(dest)) => (source, dest),
_ => {
eprintln!("usage: basic_sync [--allow-integrity-risk] <source> <dest>");
eprintln!();
eprintln!(" --allow-integrity-risk proceed even if the destination filesystem");
eprintln!(" has a known write-integrity risk on this");
eprintln!(" platform (currently: exFAT on macOS)");
std::process::exit(2);
}
};
println!("syncing {source} -> {dest}");
let engine = FileEngine::new();
let mut handle = engine
.sync(&source, &dest)
.allow_filesystem_integrity_risk(allow_integrity_risk)
.start()?;
let mut completed: usize = 0;
while let Some(progress) = tokio_stream::StreamExt::next(handle.progress()).await {
match progress {
Progress::Started {
bytes_total,
entries_total,
} => match bytes_total {
Some(bytes) => println!("started: {entries_total} entries, {bytes} bytes total"),
None => println!("started: {entries_total} entries"),
},
Progress::DirectoriesStarted { total } => println!("creating {total} directories..."),
Progress::EntryStarted { .. } | Progress::DirectoryCompleted { .. } => {}
Progress::EntryCompleted { .. } => {
completed += 1;
if completed.is_multiple_of(200) {
println!(
"...{completed} entries done ({:?} elapsed)",
handle.elapsed()
);
}
}
Progress::EntryFailed { entry } => {
eprintln!("FAILED: {}", entry.relative_path.display());
}
Progress::DirectoryFailed { path } => {
eprintln!("FAILED (creating directory): {}", path.display());
}
_ => {}
}
}
let sync_outcome = handle.await?;
println!();
println!(
"done in {:?} (copy) + {:?} (delete)",
sync_outcome.copy.duration, sync_outcome.delete.duration
);
println!(
"copy phase: succeeded {}, failed {}",
sync_outcome.copy.succeeded.len(),
sync_outcome.copy.failed.len()
);
for (entry, err) in &sync_outcome.copy.failed {
println!(" - {}: {err}", entry.relative_path.display());
}
if let Some(reason) = sync_outcome.copy.stopped_early {
println!(" copy phase stopped early: {reason:?}");
}
println!(
"delete phase: succeeded {}, failed {}",
sync_outcome.delete.succeeded.len(),
sync_outcome.delete.failed.len()
);
for (entry, err) in &sync_outcome.delete.failed {
println!(" - {}: {err}", entry.relative_path.display());
}
Ok(())
}