Merge pull request #2458 from dcampbell24/display-for-clean
Display what is removed from mdbook clean.
This commit is contained in:
commit
dff5ac64e5
1 changed files with 84 additions and 5 deletions
|
|
@ -2,8 +2,9 @@ use super::command_prelude::*;
|
|||
use crate::get_book_dir;
|
||||
use anyhow::Context;
|
||||
use mdbook::MDBook;
|
||||
use std::fs;
|
||||
use std::mem::take;
|
||||
use std::path::PathBuf;
|
||||
use std::{fmt, fs};
|
||||
|
||||
// Create clap subcommand arguments
|
||||
pub fn make_subcommand() -> Command {
|
||||
|
|
@ -23,10 +24,88 @@ pub fn execute(args: &ArgMatches) -> mdbook::errors::Result<()> {
|
|||
None => book.root.join(&book.config.build.build_dir),
|
||||
};
|
||||
|
||||
if dir_to_remove.exists() {
|
||||
fs::remove_dir_all(&dir_to_remove)
|
||||
.with_context(|| "Unable to remove the build directory")?;
|
||||
}
|
||||
let removed = Clean::new(&dir_to_remove)?;
|
||||
println!("{removed}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Formats a number of bytes into a human readable SI-prefixed size.
|
||||
/// Returns a tuple of `(quantity, units)`.
|
||||
pub fn human_readable_bytes(bytes: u64) -> (f32, &'static str) {
|
||||
static UNITS: [&str; 7] = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"];
|
||||
let bytes = bytes as f32;
|
||||
let i = ((bytes.log2() / 10.0) as usize).min(UNITS.len() - 1);
|
||||
(bytes / 1024_f32.powi(i as i32), UNITS[i])
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Clean {
|
||||
num_files_removed: u64,
|
||||
num_dirs_removed: u64,
|
||||
total_bytes_removed: u64,
|
||||
}
|
||||
|
||||
impl Clean {
|
||||
fn new(dir: &PathBuf) -> mdbook::errors::Result<Clean> {
|
||||
let mut files = vec![dir.clone()];
|
||||
let mut children = Vec::new();
|
||||
let mut num_files_removed = 0;
|
||||
let mut num_dirs_removed = 0;
|
||||
let mut total_bytes_removed = 0;
|
||||
|
||||
if dir.exists() {
|
||||
while !files.is_empty() {
|
||||
for file in files {
|
||||
if let Ok(meta) = file.metadata() {
|
||||
// Note: This can over-count bytes removed for hard-linked
|
||||
// files. It also under-counts since it only counts the exact
|
||||
// byte sizes and not the block sizes.
|
||||
total_bytes_removed += meta.len();
|
||||
}
|
||||
if file.is_file() {
|
||||
num_files_removed += 1;
|
||||
} else if file.is_dir() {
|
||||
num_dirs_removed += 1;
|
||||
for entry in fs::read_dir(file)? {
|
||||
children.push(entry?.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
files = take(&mut children);
|
||||
}
|
||||
fs::remove_dir_all(&dir).with_context(|| "Unable to remove the build directory")?;
|
||||
}
|
||||
|
||||
Ok(Clean {
|
||||
num_files_removed,
|
||||
num_dirs_removed,
|
||||
total_bytes_removed,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Clean {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Removed ")?;
|
||||
match (self.num_files_removed, self.num_dirs_removed) {
|
||||
(0, 0) => write!(f, "0 files")?,
|
||||
(0, 1) => write!(f, "1 directory")?,
|
||||
(0, 2..) => write!(f, "{} directories", self.num_dirs_removed)?,
|
||||
(1, _) => write!(f, "1 file")?,
|
||||
(2.., _) => write!(f, "{} files", self.num_files_removed)?,
|
||||
}
|
||||
|
||||
if self.total_bytes_removed == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
// Don't show a fractional number of bytes.
|
||||
if self.total_bytes_removed < 1024 {
|
||||
write!(f, ", {}B total", self.total_bytes_removed)
|
||||
} else {
|
||||
let (bytes, unit) = human_readable_bytes(self.total_bytes_removed);
|
||||
write!(f, ", {bytes:.2}{unit} total")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue