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.
dirstat/src/main.rs

157 lines
4.4 KiB

#![feature(never_type)]
#![allow(dead_code)]
#[macro_use] extern crate pin_project;
#[macro_use] extern crate lazy_static;
#[cfg(feature="inspect")] use serde::{Serialize, Deserialize};
#[cfg(feature="jemalloc")]
use jemallocator::Jemalloc;
#[cfg(feature="jemalloc")]
#[global_allocator]
static GLOBAL: Jemalloc = Jemalloc;
use std::convert::{TryFrom, TryInto};
use color_eyre::{
eyre::{
self,
eyre,
WrapErr as _,
},
Help as _,
SectionExt as _,
};
#[macro_use] mod ext;
pub use ext::prelude::*;
mod bytes;
mod data;
mod config;
mod state;
mod arg;
mod work;
#[cfg(feature="inspect")] mod serial;
#[cfg(feature="defer-drop")] mod defer_drop;
async fn normal(cfg: config::Config) -> eyre::Result<()>
{
let state = state::State::new(cfg
.validate()
.wrap_err(eyre!("Invalid config"))
.with_suggestion(|| "Try running `--help`")?);
let (graph, cfg) = tokio::select!{
x = work::work_on_all(state) => {x}
_ = tokio::signal::ctrl_c() => {
return Err(eyre!("Interrupt signalled, exiting"));
}
};
let cfg = cfg.make_global();
let graph = tokio::task::spawn_blocking(move || {
cfg_println!(Verbose; cfg, "Computing hierarchy...");
let mut graph = graph.into_hierarchical();
cfg_println!(Verbose; cfg, "Computing sizes...");
graph.compute_recursive_sizes();
graph
}).await.expect("Failed to compute hierarchy from graph");
#[cfg(debug_assertions)] cfg_eprintln!(Verbose; cfg, "{:?}", graph);
cfg_println!(Quiet; cfg, "Max size file: {:?}", graph.path_max_size_for(data::FsKind::File));
cfg_println!(Quiet; cfg, "Max size dir: {:?}", graph.path_max_size_for(data::FsKind::Directory));
cfg_println!(Quiet; cfg, "Max size all: {:?}", graph.path_max_size());
#[cfg(feature="inspect")]
match cfg.serialise_output.as_ref().map(|ser_out| {
type BoxedWrite = Box<dyn tokio::io::AsyncWrite + Unpin>;
use futures::FutureExt;
use config::OutputSerialisationMode;
match ser_out {
OutputSerialisationMode::File(output_file) => {
use tokio::fs::OpenOptions;
(async move {
let stream = OpenOptions::new()
.write(true)
.truncate(true)
.create(true)
.open(output_file).await
.wrap_err(eyre!("Failed to open file for writing"))
.with_section(|| format!("{:?}", output_file).header("File was"))?;
Ok::<BoxedWrite, eyre::Report>(Box::new(stream))
}.boxed(), None)
},
OutputSerialisationMode::Stdout => (async move { Ok::<BoxedWrite, _>(Box::new(tokio::io::stdout())) }.boxed(), None),
#[cfg(feature="prealloc")] OutputSerialisationMode::PreallocFile(output_file) => {
(async move {
Ok::<BoxedWrite, _>(Box::new(tokio::io::sink())) // we use a sink as a shim stream since it will never be used when tuple item `.1` is Some()
}.boxed(), Some(output_file))
},
}
}) {
// We use tuple item `.1` here to indicate if we're in normal write mode.
// None -> normal
// Some(path) -> prealloc
Some((stream_fut, None)) => {
let stream = stream_fut.await?;
serial::write_async(stream, &graph, serial::compress::No).await
.wrap_err(eyre!("Failed to serialise graph to stream"))?;
},
#[cfg(feature="prealloc")] Some((_task_fut, Some(output_file))) => {
use tokio::fs::OpenOptions;
let file = OpenOptions::new()
.write(true)
.read(true) //needed for map I think?
.truncate(true)
.create(true)
.open(&output_file).await
.wrap_err(eyre!("Failed to open file for mapping"))
.with_section(|| format!("{:?}", output_file).header("File was"))?;
let mut file = file.into_std().await;
tokio::task::spawn_blocking(move || {
serial::write_sync_map(&mut file, &graph)
}).await.wrap_err(eyre!("Prealloc panicked while dumping"))
.with_section(|| format!("{:?}", output_file).header("File was"))?
.wrap_err(eyre!("Prealloc failed to dump graph to file"))
.with_section(|| format!("{:?}", output_file).header("File was"))?;
},
_ => (),
}
Ok(())
}
async fn parse_mode() -> eyre::Result<()>
{
match arg::parse_args().wrap_err(eyre!("Failed to parse args"))?
{
arg::Mode::Normal(cfg) => {
normal(cfg).await
},
arg::Mode::Help => arg::help(),
}
}
#[tokio::main]
async fn main() -> eyre::Result<()> {
color_eyre::install()?;
parse_mode().await
.wrap_err(eyre!("Fatal error"))?;
/* let max_size = graph.directories().map(|x| x.size()).max();
println!("Max size: {:?}", max_size);*/
//println!("{:?}", graph);
Ok(())
}