You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
videl/src/main.rs

161 lines
3.7 KiB

#![cfg_attr(nightly, feature(never_type))]
#![cfg_attr(nightly, feature(drain_filter))]
#![allow(dead_code)]
#[macro_use] extern crate log;
use cfg_if::cfg_if;
use lazy_static::lazy_static;
//use futures::prelude::*;
use tokio::prelude::*;
use futures::{
Future,
};
#[allow(unused_imports)]
use color_eyre::{
eyre::{
self,
eyre,
WrapErr as _,
},
SectionExt as _, Help as _,
};
use std::{
sync::Arc,
};
mod ext;
use ext::*;
mod util;
mod dedup;
mod resolve;
mod database;
mod args;
mod config;
mod progress;
mod state;
mod delete;
mod restore;
cfg_if!{
if #[cfg(nightly)] {
type Never = !;
} else {
type Never = std::convert::Infallible;
}
}
type Pointer = *const Never;
fn install() -> eyre::Result<()>
{
pretty_env_logger::init();
color_eyre::install()?;
Ok(())
}
/// Currently a mock impl for process
async fn process_mock(state: Arc<state::State>, file: String)
{
let config = state.config();
let _g = state.lock().await;
println!(" -> {:?}", file);
let dbdir = resolve::mangle_path(&config, &file);
println!("Database path for this file {:?}", dbdir);
println!("Demangle: {:?}", resolve::demangle_path(&dbdir).await
.wrap_err(eyre!("Failed to demangle path"))
.with_section(|| dbdir.to_string_lossy().into_owned().header("Path was"))
.with_section(|| config.base_dir.clone().to_string_lossy().into_owned().header("The videl database root directory is"))
.with_suggestion(|| "Are you sure this database location is correct"));
}
async fn process(state: Arc<state::State>, file: String) -> eyre::Result<()>
{
let path = std::path::Path::new(&file);
if !path.exists() {
error!("{:?} does not exist, skipping", path);
} else {
info!("{:?} Processing", path);
delete::process(state, path).await
.wrap_err(eyre!("Processing failed"))
.with_section(move || file.header("Root path was"))?;
}
Ok(())
}
async fn validate_config(config: config::Config) -> eyre::Result<config::Config>
{
config.validate().await
.with_section(|| format!("{:#?}", config).header("Config was"))
.with_suggestion(|| "Are you sure the base directory is a valid pathspec?")
.with_suggestion(|| "Are you sure the base directory is not already occupied by a non-directory?")
.with_suggestion(|| format!("Are you sure we have read-write access to {:?}?", config.base_dir))?;
Ok(config)
}
async fn begin() -> eyre::Result<i32>
{
use futures::prelude::*;
install()?;
{
let (progress, progress_join) = {
let bar = termprogress::progress::Bar::new(50);
let (p, join) = progress::host(bar);
(p, join.map(|bar| match bar {
Ok(bar) => {
bar.complete();
Ok(())
},
Err(panic) => {
println!();
Err(panic)
},
}))
};
let state = Arc::new(state::State::new(validate_config(config::Config::default()).await
.wrap_err(eyre!("Failed to validate config"))?,
progress));
info!("Validated config OK");
if args::process(|file| {
let state = Arc::clone(&state);
use futures::future::TryFutureExt;
process(state, file).inspect_err(|err| eprintln!("{:?}", err))
}).await
.wrap_err(eyre!("One or more child workers failed to complete successfully"))?
.len() == 0
{
args::usage();
}
//Cleanup deferred in new `async` block to drop `state` before this block is ran.
async move {
progress_join.await?;
Ok::<_, eyre::Report>(0)
}.map(|res| res.wrap_err(eyre!("Cleanup failed")))
}.await
}
#[tokio::main]
async fn main() -> eyre::Result<()>
{
std::process::exit(match begin().await {
Ok(0) => return Ok(()),
Err(err) => {
eprintln!("\nexited with error: {}", err);
return Err(err)
.wrap_err(eyre!("Fatal error"));
},
Ok(v) => v
})
}