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.
195 lines
4.9 KiB
195 lines
4.9 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;
|
|
|
|
#[macro_use] 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;
|
|
|
|
/// Install things and get other things
|
|
fn install() -> eyre::Result<(progress::logging::Level,)>
|
|
{
|
|
let logv = std::env::var("RUST_LOG");
|
|
color_eyre::install()?;
|
|
|
|
let lv = match logv {
|
|
Ok(log) if log.trim().len() !=0 => log.parse().unwrap_or_else(|e| {
|
|
let def = Default::default();
|
|
eprintln!("Failed to parse logging level, using default `{:?}`: {}", def, e);
|
|
def
|
|
}),
|
|
_ => Default::default(),
|
|
};
|
|
|
|
Ok((lv,))
|
|
}
|
|
|
|
/// 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);
|
|
let mut progress = state.progress().clone();
|
|
let task_id_fut = progress.send_command(progress::CommandKind::AddTask(file.clone())).await?;
|
|
let mut logger= state.logger_output();
|
|
let res = if !path.exists() {
|
|
error!(yield logger => "{:?} does not exist, skipping", path);
|
|
Ok(())
|
|
} else {
|
|
info!(logger => "{:?} Processing", path);
|
|
delete::process(state, &mut logger, path).await
|
|
.wrap_err(eyre!("Processing failed"))
|
|
.with_section(move || file.header("Root path was"))
|
|
};
|
|
progress.send_command_and_detach(progress::CommandKind::Bump(1)).await?;
|
|
progress.send_command_and_wait(progress::CommandKind::
|
|
RemoveTask(task_id_fut.await?
|
|
.map(|x| x.downcast()
|
|
.ok()
|
|
.map(|x| *x))
|
|
.flatten()
|
|
.unwrap())).await?;
|
|
|
|
res
|
|
}
|
|
|
|
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::*;
|
|
let (log_level,) = 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 = {
|
|
use progress::logging;
|
|
let mut logger = logging::Logger::new(progress,
|
|
log_level);
|
|
|
|
let state = Arc::new(state::State::new(validate_config(config::Config::default()).await
|
|
.wrap_err(eyre!("Failed to validate config"))?,
|
|
logger.clone()));
|
|
info!(yield logger => "Validated config OK");
|
|
state
|
|
};
|
|
|
|
if {
|
|
let (sz, pro) = args::process(|file| {
|
|
let state = Arc::clone(&state);
|
|
use futures::future::TryFutureExt;
|
|
process(state, file).inspect_err(|err| eprintln!("{:?}", err))
|
|
});
|
|
state.progress().clone().send_command_and_wait(progress::CommandKind::BumpHigh(sz as isize)).await?;
|
|
pro
|
|
}.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
|
|
})
|
|
}
|