mirror of
https://github.com/denoland/deno.git
synced 2024-12-29 02:29:06 -05:00
98 lines
2.4 KiB
Rust
98 lines
2.4 KiB
Rust
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||
|
|
||
|
use deno_core::anyhow::Context;
|
||
|
use deno_core::error::AnyError;
|
||
|
use std::path::Path;
|
||
|
|
||
|
use crate::cache::DenoDir;
|
||
|
use crate::colors;
|
||
|
use crate::display;
|
||
|
use crate::util::progress_bar::ProgressBar;
|
||
|
use crate::util::progress_bar::ProgressBarStyle;
|
||
|
use crate::util::progress_bar::ProgressMessagePrompt;
|
||
|
use crate::util::progress_bar::UpdateGuard;
|
||
|
|
||
|
struct CleanState {
|
||
|
files_removed: u64,
|
||
|
dirs_removed: u64,
|
||
|
bytes_removed: u64,
|
||
|
progress_guard: UpdateGuard,
|
||
|
}
|
||
|
|
||
|
impl CleanState {
|
||
|
fn update_progress(&self) {
|
||
|
self
|
||
|
.progress_guard
|
||
|
.set_position(self.files_removed + self.dirs_removed);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn clean() -> Result<(), AnyError> {
|
||
|
let deno_dir = DenoDir::new(None)?;
|
||
|
if deno_dir.root.exists() {
|
||
|
let no_of_files = walkdir::WalkDir::new(&deno_dir.root).into_iter().count();
|
||
|
let progress_bar = ProgressBar::new(ProgressBarStyle::ProgressBars);
|
||
|
let progress_guard =
|
||
|
progress_bar.update_with_prompt(ProgressMessagePrompt::Cleaning, "");
|
||
|
|
||
|
let mut state = CleanState {
|
||
|
files_removed: 0,
|
||
|
dirs_removed: 0,
|
||
|
bytes_removed: 0,
|
||
|
progress_guard,
|
||
|
};
|
||
|
state
|
||
|
.progress_guard
|
||
|
.set_total_size(no_of_files.try_into().unwrap());
|
||
|
|
||
|
rm_rf(&mut state, &deno_dir.root)?;
|
||
|
|
||
|
// Drop the guard so that progress bar disappears.
|
||
|
drop(state.progress_guard);
|
||
|
|
||
|
log::info!(
|
||
|
"{} {} {}",
|
||
|
colors::green("Removed"),
|
||
|
deno_dir.root.display(),
|
||
|
colors::gray(&format!(
|
||
|
"({} files, {})",
|
||
|
state.files_removed + state.dirs_removed,
|
||
|
display::human_size(state.bytes_removed as f64)
|
||
|
))
|
||
|
);
|
||
|
}
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
fn rm_rf(state: &mut CleanState, path: &Path) -> Result<(), AnyError> {
|
||
|
for entry in walkdir::WalkDir::new(path).contents_first(true) {
|
||
|
let entry = entry?;
|
||
|
|
||
|
if entry.file_type().is_dir() {
|
||
|
state.dirs_removed += 1;
|
||
|
state.update_progress();
|
||
|
std::fs::remove_dir_all(entry.path())?;
|
||
|
} else {
|
||
|
remove_file(state, entry.path(), entry.metadata().ok())?;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
fn remove_file(
|
||
|
state: &mut CleanState,
|
||
|
path: &Path,
|
||
|
meta: Option<std::fs::Metadata>,
|
||
|
) -> Result<(), AnyError> {
|
||
|
if let Some(meta) = meta {
|
||
|
state.bytes_removed += meta.len();
|
||
|
}
|
||
|
state.files_removed += 1;
|
||
|
state.update_progress();
|
||
|
std::fs::remove_file(path)
|
||
|
.with_context(|| format!("Failed to remove file: {}", path.display()))?;
|
||
|
Ok(())
|
||
|
}
|