feat: display size of each file and total removed size

This commit is contained in:
Arthur Pinheiro 2025-03-12 16:52:03 +01:00
parent 266a00d983
commit 6825d63aaa
3 changed files with 64 additions and 14 deletions

7
Cargo.lock generated
View File

@ -136,6 +136,12 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
[[package]]
name = "bytesize"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3c8f83209414aacf0eeae3cf730b18d6981697fba62f200fcfb92b9f082acba"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -634,6 +640,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"async-trait",
"bytesize",
"clap",
"env_logger",
"goblin",

View File

@ -23,3 +23,4 @@ nix = { version = "0.29", features = ["fs"] }
petgraph = { version = "0.7" }
tokio = { version = "1", features = ["full"] }
walkdir = { version = "2" }
bytesize = { version = "2.0" }

View File

@ -10,10 +10,11 @@ use crate::{
};
use anyhow::{Error, Result};
use async_trait::async_trait;
use bytesize::ByteSize;
use dso::DsoCleaner;
use list::ListCleaner;
use nix::libc::EXDEV;
use std::{collections::HashMap, io, path::Path};
use std::{collections::HashMap, fmt, io, ops::AddAssign, path::Path};
use tokio::{sync::mpsc, task::JoinSet};
use walkdir::{DirEntry, WalkDir};
@ -26,8 +27,22 @@ pub trait Cleaner {
) -> Result<()>;
}
struct FileSize(u64);
impl fmt::Display for FileSize {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", ByteSize(self.0))
}
}
impl AddAssign for FileSize {
fn add_assign(&mut self, rhs: Self) {
self.0.add_assign(rhs.0);
}
}
type Cleaners = Vec<Box<dyn Cleaner + Send>>;
type RemovalFn = Box<dyn Fn(&Path) -> io::Result<()>>;
type RemovalFn = Box<dyn Fn(&Path) -> io::Result<FileSize>>;
pub struct Runner {
cleaners: Cleaners,
@ -129,6 +144,8 @@ impl Runner {
async fn final_decision(removal_fn: RemovalFn, mut output_rx: mpsc::Receiver<Decision>) {
let mut final_decisions = HashMap::new();
let mut total_removed_size = FileSize(0);
while let Some(input_decision) = output_rx.recv().await {
if input_decision.action == Action::Undecided {
continue;
@ -147,28 +164,38 @@ impl Runner {
for (file, action) in final_decisions {
if action == Action::Remove {
if let Err(err) = (removal_fn)(&file) {
log::error!("{}: {}", file.display(), err);
}
let removed_size = match (removal_fn)(&file) {
Ok(size) => size,
Err(err) => {
log::error!("{}: {}", file.display(), err);
FileSize(0)
}
};
total_removed_size += removed_size;
}
}
log::info!("Total space removed: {}", total_removed_size);
}
fn new_removal_fn(args: &Args) -> RemovalFn {
if let Some(dest) = args.split_to.clone() {
if args.dry_run {
Box::new(move |path| {
let size = Self::get_file_size(path)?;
log::info!(
"(dry-run) would move {} to {}",
"(dry-run) would move {} to {} ({})",
path.display(),
dest.display()
dest.display(),
size
);
Ok(())
Ok(size)
})
} else {
Box::new(move |path| {
log::info!("moving {} to {}", path.display(), dest.display());
Self::move_preserve(&path, &dest)
let size = Self::get_file_size(path)?;
log::info!("moving {} to {} ({})", path.display(), dest.display(), size);
Self::move_preserve(&path, &dest)?;
Ok(size)
})
}
} else {
@ -179,18 +206,33 @@ impl Runner {
} else {
"regular file"
};
log::info!("(dry-run) would remove {} {}", ty, path.display());
Ok(())
let size = Self::get_file_size(path)?;
log::info!("(dry-run) would remove {} {} ({})", ty, path.display(), size);
Ok(size)
})
} else {
Box::new(move |path| {
log::info!("removing {}", path.display());
std::fs::remove_file(&path)
let size = Self::get_file_size(path)?;
log::info!("removing {} ({})", path.display(), size);
std::fs::remove_file(&path)?;
Ok(size)
})
}
}
}
fn get_file_size(file: &Path) -> io::Result<FileSize> {
let lstat = nix::sys::stat::lstat(file);
let size = match lstat {
Err(err) => {
log::error!("failed to get metadata from: {}, {}", file.display(), err);
FileSize(0)
},
Ok(lstat) => FileSize(lstat.st_size as u64)
};
Ok(size)
}
fn move_preserve(src: &Path, dest: &Path) -> io::Result<()> {
assert!(src.is_relative());
let abs_dest = dest.join(src);