use std::env;
use std::ffi::OsStr;
use std::fmt::Write as _;
use std::fs::read_dir;
use std::path::{Path, PathBuf};
use cargo_metadata::MetadataCommand;
use humansize::{file_size_opts, FileSize};
use walkdir::WalkDir;
use crate::library;
use crate::library::Error;
use crate::tables::*;
fn seeing_manifest(path: &Path) -> Option<PathBuf> {
#[allow(clippy::manual_filter_map)]
read_dir(path)
.unwrap()
.filter(Result::is_ok)
.map(|d| d.unwrap().path())
.find(|f| f.file_name() == Some(OsStr::new("Cargo.toml")))
}
pub(crate) fn get_manifest() -> Result<PathBuf, Error> {
let mut cwd: PathBuf = if let Ok(cwd) = env::current_dir() {
cwd
} else {
return Err(Error::NoCWD);
};
let orig_cwd = cwd.clone();
loop {
if let Some(manifest_path) = seeing_manifest(&cwd) {
return Ok(manifest_path);
}
let fs_root_reached = !cwd.pop();
if fs_root_reached {
return Err(Error::NoCargoManifest(orig_cwd));
}
}
}
pub(crate) fn local_subcmd() -> Result<(), Error> {
const MIN_PADDING: usize = 6;
let manifest = get_manifest()?;
let metadata = MetadataCommand::new()
.manifest_path(&manifest)
.no_deps()
.exec()
.unwrap_or_else(|error| {
panic!(
"Failed to parse manifest: '{}'\nError: '{:?}'",
&manifest.display(),
error
)
});
let target_dir = PathBuf::from(metadata.target_directory);
if !target_dir.is_dir() {
return Err(Error::LocalNoTargetDir(target_dir));
}
let dirinfo = library::cumulative_dir_size(&target_dir);
let size_hr = dirinfo.dir_size.file_size(file_size_opts::DECIMAL).unwrap();
let mut stdout = String::new();
let mut lines = Vec::new();
writeln!(stdout, "Project {:?}", metadata.workspace_root.to_string()).unwrap();
if !target_dir.exists() {
stdout.push_str("No target dir found!");
eprintln!("{}", stdout);
}
writeln!(stdout, "Target dir: {}\n", target_dir.display()).unwrap();
lines.push(TableLine::new(0, &"Total Size: ", &size_hr));
let p = &target_dir; let target_dir_debug = p.join("debug");
let target_dir_rls = p.join("rls");
let target_dir_release = p.join("release");
let target_dir_package = p.join("package");
let target_dir_doc = p.join("doc");
let size_debug = library::cumulative_dir_size(&target_dir_debug).dir_size;
if size_debug > 0 {
lines.push(TableLine::new(
0,
&"debug: ".to_string(),
&size_debug.file_size(file_size_opts::DECIMAL).unwrap(),
));
}
let size_rls = library::cumulative_dir_size(&target_dir_rls).dir_size;
if size_rls > 0 {
lines.push(TableLine::new(
0,
&"rls: ".to_string(),
&size_rls.file_size(file_size_opts::DECIMAL).unwrap(),
));
}
let size_release = library::cumulative_dir_size(&target_dir_release).dir_size;
if size_release > 0 {
lines.push(TableLine::new(
0,
&"release: ".to_string(),
&size_release.file_size(file_size_opts::DECIMAL).unwrap(),
));
}
let size_package = library::cumulative_dir_size(&target_dir_package).dir_size;
if size_package > 0 {
lines.push(TableLine::new(
0,
&"package: ".to_string(),
&size_package.file_size(file_size_opts::DECIMAL).unwrap(),
));
}
let size_doc = library::cumulative_dir_size(&target_dir_doc).dir_size;
if size_doc > 0 {
lines.push(TableLine::new(
0,
&"doc: ".to_string(),
&size_doc.file_size(file_size_opts::DECIMAL).unwrap(),
));
}
#[allow(clippy::manual_filter_map)] let size_other: u64 = read_dir(&target_dir)
.unwrap()
.filter_map(Result::ok)
.map(|x| x.path())
.filter(|f| {
!(f.starts_with(&target_dir_debug)
|| f.starts_with(&target_dir_release)
|| f.starts_with(&target_dir_rls)
|| f.starts_with(&target_dir_package)
|| f.starts_with(&target_dir_doc))
})
.flat_map(|f| {
WalkDir::new(f.display().to_string())
.into_iter()
.skip(1)
.map(|d| d.unwrap().into_path())
})
.filter(|f| f.exists())
.map(|f| {
std::fs::metadata(&f)
.unwrap_or_else(|_| panic!("Failed to get metadata of file '{}'", &f.display()))
.len()
})
.sum();
if size_other > 0 {
lines.push(TableLine::new(
0,
&"other: ".to_string(),
&size_other.file_size(file_size_opts::DECIMAL).unwrap(),
));
}
stdout.push_str(&two_row_table(MIN_PADDING, lines, true));
println!("{}", stdout);
Ok(())
}