use std::fmt;
use std::fmt::Write as _;
use std::fs;
use std::path::{Path, PathBuf};
use crate::cache::caches::{Cache, RegistrySuperCache};
use crate::cache::*;
use crate::dirsizes::DirSizes;
use humansize::{file_size_opts, FileSize};
use rayon::iter::*;
use walkdir::WalkDir;
pub(crate) type CargoCacheResult<T, E> = Result<T, E>;
pub(crate) trait ErrorHandling<T, E: std::fmt::Display> {
fn unwrap_or_fatal_error(self) -> T;
fn exit_or_fatal_error(self);
}
impl<T, E: std::fmt::Display> ErrorHandling<T, E> for CargoCacheResult<T, E> {
fn unwrap_or_fatal_error(self) -> T {
match self {
Ok(t) => t,
Err(e) => {
eprintln!("{}", e);
std::process::exit(1);
}
}
}
fn exit_or_fatal_error(self) {
match self {
Ok(_) => {
std::process::exit(0);
}
Err(e) => {
eprintln!("{}", e);
std::process::exit(1);
}
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct DirInfo {
pub(crate) dir_size: u64,
#[allow(unused)] pub(crate) file_number: u64,
}
#[derive(Debug, Clone)]
pub(crate) struct CargoCachePaths {
pub(crate) cargo_home: PathBuf,
pub(crate) bin_dir: PathBuf,
pub(crate) registry: PathBuf,
pub(crate) registry_pkg_cache: PathBuf,
pub(crate) registry_sources: PathBuf,
pub(crate) registry_index: PathBuf,
pub(crate) git_repos_bare: PathBuf,
pub(crate) git_checkouts: PathBuf,
}
#[derive(Debug)]
pub(crate) enum Error {
GitRepoNotOpened(PathBuf),
GitRepoDirNotFound(PathBuf),
GitGCFailed(PathBuf, std::io::Error),
GitPackRefsFailed(PathBuf, std::io::Error),
GitReflogFailed(PathBuf, std::io::Error),
GitFsckFailed(PathBuf, std::io::Error),
GitRepackFailed(PathBuf, std::io::Error),
GitNotInstalled,
MalformedPackageName(String),
GetCargoHomeFailed,
CargoHomeNotDirectory(PathBuf),
InvalidDeletableDirs(String),
RemoveDirNoArg,
NoCWD,
NoCargoManifest(PathBuf),
QueryRegexFailedParsing(String),
GitGCFile(PathBuf),
LocalNoTargetDir(PathBuf),
DateParseFailure(String, String),
UnparsableManifest(PathBuf, cargo_metadata::Error),
NoSccacheDir,
NoRustupHome,
TrimLimitUnitParseFailure(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let valid_deletable_dirs =
"git-db,git-repos,registry-sources,registry-crate-cache,registry-index,registry,all";
match &self {
Self::GitRepoNotOpened(path) => {
write!(f, "Failed to open git repository at \"{}\"", path.display())
}
Self::GitRepoDirNotFound(path) => {
write!(f, "Git repo \"{}\" not found", path.display())
}
Self::GitGCFailed(path, error) => write!(
f,
"Failed to git gc repository \"{}\":\n{:?}",
path.display(),
error
),
Self::GitPackRefsFailed(path, error) => write!(
f,
"Failed to git pack-refs repository \"{}\":\n{:?}",
path.display(),
error
),
Self::GitReflogFailed(path, error) => write!(
f,
"Failed to git reflog repository \"{}\":\n{:?}",
path.display(),
error
),
Self::GitFsckFailed(path, error) => write!(
f,
"Failed to git fsck repository \"{}\":\n{:?}",
path.display(),
error
),
Self::GitRepackFailed(path, error) => write!(
f,
"Failed to git repack repository \"{}\":\n{:?}",
path.display(),
error
),
Self::GitNotInstalled => write!(f, "Could not find 'git' binary. Is 'git' installed?",),
Self::MalformedPackageName(pkgname) => {
write!(f, "Error: \"{}\" is not a valid package name", pkgname)
}
Self::GetCargoHomeFailed => write!(f, "Failed to get CARGO_HOME!"),
Self::CargoHomeNotDirectory(path) => write!(
f,
"CARGO_HOME \"{}\" is not an existing directory!",
path.display()
),
Self::InvalidDeletableDirs(dirs) => write!(
f,
"\"{}\" are not valid removable directories! Chose one or several from {}",
dirs, valid_deletable_dirs
),
Self::RemoveDirNoArg => write!(
f,
"No argument passed to \"--remove-dir\"! Chose one or several from {}",
valid_deletable_dirs
),
Self::NoCWD => write!(f, "Failed to find current working directory!",),
Self::NoCargoManifest(dir) => write!(
f,
"Failed to Cargo.toml manifest in {} or downwards.",
dir.display()
),
Self::QueryRegexFailedParsing(regex) => {
write!(f, "Failed to parse regular expression \"{}\"", regex)
}
Self::GitGCFile(path) => write!(
f,
"Tried to \"git gc\" a file instead of a directory: \"{}\"",
path.display()
),
Self::LocalNoTargetDir(path) => write!(
f,
"error: \"local\" subcommand tried to read \"target\" \
directory that does not exist: \"{}\"",
path.display()
),
Self::DateParseFailure(date, error) => {
write!(f, "ERROR failed to parse {} as date {}", date, error)
}
Self::UnparsableManifest(path, error) => write!(
f,
"Failed to parse Cargo.toml at '{}': '{:?}'",
path.display(),
error
),
Self::NoSccacheDir => {
write!(f,
"Could not find sccache cache directory at ~/.cache/sccache or ${{SCCACHE_DIR}}")
}
Self::NoRustupHome => write!(f, "Failed to determine rustup home directory"),
Self::TrimLimitUnitParseFailure(limit) => write!(
f,
"Failed to parse limit: \"{}\". \
Should be of the form 123X where X is one of B,K,M,G or T.",
limit
),
}
}
}
impl CargoCachePaths {
pub(crate) fn default() -> Result<Self, Error> {
let cargo_home = if let Ok(cargo_home) = home::cargo_home() {
cargo_home
} else {
return Err(Error::GetCargoHomeFailed);
};
if !cargo_home.is_dir() {
return Err(Error::CargoHomeNotDirectory(cargo_home));
}
let bin = cargo_home.join("bin");
let registry = cargo_home.join("registry");
let registry_index = registry.join("index");
let reg_cache = registry.join("cache");
let reg_src = registry.join("src");
let git_repos_bare = cargo_home.join("git").join("db");
let git_checkouts = cargo_home.join("git").join("checkouts");
Ok(Self {
cargo_home,
bin_dir: bin,
registry,
registry_index,
registry_pkg_cache: reg_cache,
registry_sources: reg_src,
git_repos_bare,
git_checkouts,
})
}
}
impl std::fmt::Display for CargoCachePaths {
fn fmt(&self, f: &'_ mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(
f,
"\ncargo home: {}",
&self.cargo_home.display()
)?;
writeln!(f, "binaries directory: {}", &self.bin_dir.display())?;
writeln!(
f,
"registry directory: {}",
&self.registry.display()
)?;
writeln!(
f,
"registry index: {}",
&self.registry_index.display()
)?;
writeln!(
f,
"crate source archives: {}",
&self.registry_pkg_cache.display()
)?;
writeln!(
f,
"unpacked crate sources: {}",
&self.registry_sources.display()
)?;
writeln!(
f,
"bare git repos: {}",
&self.git_repos_bare.display()
)?;
writeln!(
f,
"git repo checkouts: {}",
&self.git_checkouts.display()
)?;
Ok(())
}
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub(crate) enum RemovableGroup {
All,
GitDB,
GitRepos,
RegistrySources,
RegistryCrateCache,
RegistryIndex,
Registry,
}
impl std::str::FromStr for RemovableGroup {
type Err = String;
fn from_str(s: &str) -> Result<Self, String> {
match s {
"all" => Ok(RemovableGroup::All),
"git-db" => Ok(RemovableGroup::GitDB),
"git-repos" => Ok(RemovableGroup::GitRepos),
"registry-sources" => Ok(RemovableGroup::RegistrySources),
"registry-crate-cache" => Ok(RemovableGroup::RegistryCrateCache),
"registry-index" => Ok(RemovableGroup::RegistryIndex),
"registry" => Ok(RemovableGroup::Registry),
other => Err(other.to_string()),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub(crate) enum Component {
GitDB, GitRepos, RegistrySources, RegistryCrateCache, RegistryIndex, }
pub(crate) fn components_from_groups(input: Option<&str>) -> Result<Vec<Component>, Error> {
let input_string = if let Some(value) = input {
value
} else {
return Err(Error::RemoveDirNoArg);
};
#[allow(clippy::type_complexity)]
let (dirs, errors): (
Vec<Result<RemovableGroup, String>>,
Vec<Result<RemovableGroup, String>>,
) = input_string
.split(',')
.map(str::parse)
.partition(Result::is_ok);
if !errors.is_empty() {
let invalid_dirs = errors
.into_iter()
.map(|e| e.err().unwrap())
.collect::<Vec<String>>();
let inv_dirs_joined = invalid_dirs.join(" ");
let inv_dirs_trimmed = inv_dirs_joined.trim();
return Err(Error::InvalidDeletableDirs(inv_dirs_trimmed.to_string()));
}
let dirs = dirs.into_iter().map(|d| d.ok().unwrap());
let mut mapped_dirs = Vec::new();
dirs.for_each(|dir| match dir {
RemovableGroup::All => {
mapped_dirs.extend(
vec![
Component::GitDB,
Component::GitRepos,
Component::RegistrySources,
Component::RegistryCrateCache,
Component::RegistryIndex,
],
);
}
RemovableGroup::GitDB => {
mapped_dirs.extend(vec![Component::GitDB, Component::GitRepos]);
}
RemovableGroup::GitRepos => {
mapped_dirs.push(Component::GitRepos);
}
RemovableGroup::RegistrySources => {
mapped_dirs.push(Component::RegistrySources);
}
RemovableGroup::RegistryCrateCache => {
mapped_dirs.extend(vec![
Component::RegistrySources,
Component::RegistryCrateCache,
]);
}
RemovableGroup::RegistryIndex => {
mapped_dirs.push(Component::RegistryIndex);
}
RemovableGroup::Registry => mapped_dirs.extend(vec![
Component::RegistrySources,
Component::RegistryCrateCache,
]),
});
mapped_dirs.sort();
mapped_dirs.dedup();
Ok(mapped_dirs)
}
pub(crate) fn size_of_path(path: &Path) -> u64 {
if path.is_dir() {
cumulative_dir_size(path).dir_size
} else {
fs::metadata(path)
.unwrap_or_else(|_| panic!("Failed to get metadata of file '{}'", &path.display()))
.len()
}
}
pub(crate) fn cumulative_dir_size(dir: &Path) -> DirInfo {
if !dir.is_dir() {
return DirInfo {
dir_size: 0,
file_number: 0,
};
}
let walkdir_start = dir.display().to_string();
let dir_size = WalkDir::new(&walkdir_start)
.into_iter()
.map(|e| e.unwrap().path().to_owned())
.filter(|f| f.exists()) .collect::<Vec<_>>() .par_iter()
.filter(|f| f.exists()) .map(|f| {
fs::metadata(f)
.unwrap_or_else(|_| panic!("Failed to get metadata of file '{}'", &f.display()))
.len()
})
.sum();
let file_number = if walkdir_start.contains("registry") {
WalkDir::new(&walkdir_start)
.max_depth(2)
.min_depth(2)
.into_iter()
.count()
} else {
fs::read_dir(dir).unwrap().count()
} as u64;
DirInfo {
dir_size,
file_number,
}
}
pub(crate) fn get_info(c: &CargoCachePaths, s: &DirSizes<'_>) -> String {
let mut strn = String::with_capacity(1500);
if let Ok(cache_path) = std::env::var("CARGO_HOME") {
writeln!(
strn,
"${{CARGO_HOME}} env var set to '{}', using that!",
cache_path
)
.unwrap();
} else {
writeln!(
strn,
"Default cache dir found: '{}', using that!",
c.cargo_home.display()
)
.unwrap();
};
strn.push('\n');
writeln!(
strn,
"Total cache size: {}\n",
s.total_size().file_size(file_size_opts::DECIMAL).unwrap()
)
.unwrap();
strn.push_str(&c.bin_dir.display().to_string());
strn.push('\n');
writeln!(
strn,
"\t{} binaries installed in binary directory, total size: {}",
s.numb_bins(),
s.total_bin_size()
.file_size(file_size_opts::DECIMAL)
.unwrap()
)
.unwrap();
strn.push_str("\tThese are the binaries installed via 'cargo install'.\n");
strn.push_str("\tUse 'cargo uninstall' to remove binaries if needed.\n");
strn.push('\n');
strn.push_str(&c.registry.display().to_string());
strn.push('\n');
writeln!(
strn,
"\tRegistry root dir, size: {}",
s.total_reg_size()
.file_size(file_size_opts::DECIMAL)
.unwrap()
)
.unwrap();
strn.push_str("\tCrate registries are stored here.\n");
strn.push('\n');
strn.push_str(&c.registry_index.display().to_string());
strn.push('\n');
writeln!(
strn,
"\tRegistry index, size: {}",
s.total_reg_index_size()
.file_size(file_size_opts::DECIMAL)
.unwrap()
)
.unwrap();
strn.push_str("\tA git repo holding information on what crates are available.\n");
strn.push_str("\tWill be recloned as needed.\n");
strn.push('\n');
strn.push_str(&c.registry_pkg_cache.display().to_string());
strn.push('\n');
writeln!(
strn,
"\tCrate source package archive, size: {}",
s.total_reg_cache_size()
.file_size(file_size_opts::DECIMAL)
.unwrap()
)
.unwrap();
strn.push_str("\tCrates source packages of the registries are downloaded into this folder.\n");
strn.push_str("\tThey will be redownloaded as needed.\n");
strn.push('\n');
strn.push_str(&c.registry_sources.display().to_string());
strn.push('\n');
writeln!(
strn,
"\tCrate sources, size: {}",
s.total_reg_src_size()
.file_size(file_size_opts::DECIMAL)
.unwrap()
)
.unwrap();
strn.push_str("\tSource archives are extracted into this dir.\n");
strn.push_str("\tThey will be reextracted from the package archive as needed.\n");
strn.push('\n');
strn.push_str(&c.git_repos_bare.display().to_string());
strn.push('\n');
writeln!(
strn,
"\tGit database, size: {}",
s.total_git_repos_bare_size()
.file_size(file_size_opts::DECIMAL)
.unwrap()
)
.unwrap();
strn.push_str("\tBare repos of git dependencies are stored here.\n");
strn.push_str("\tRemoved git repositories will be recloned as needed.\n");
strn.push('\n');
strn.push_str(&c.git_checkouts.display().to_string());
strn.push('\n');
writeln!(
strn,
"\tGit repo checkouts, size: {}",
s.total_git_chk_size()
.file_size(file_size_opts::DECIMAL)
.unwrap()
)
.unwrap();
strn.push_str("\tSpecific commits of the bare repos will be checked out into here.\n");
strn.push_str("\tGit checkouts will be rechecked-out from repo database as needed.");
strn
}
pub(crate) fn size_diff_format(
size_before: u64,
size_after: u64,
display_size_before: bool,
) -> String {
#[allow(clippy::cast_possible_wrap)]
let size_diff: i64 = size_after as i64 - size_before as i64;
let sign = if size_diff > 0 { "+" } else { "" };
let size_after_human_readable = size_after.file_size(file_size_opts::DECIMAL).unwrap();
let humansize_opts = file_size_opts::FileSizeOpts {
allow_negative: true,
..file_size_opts::DECIMAL
};
let size_diff_human_readable = size_diff.file_size(humansize_opts).unwrap();
let size_before_human_readabel = size_before.file_size(file_size_opts::DECIMAL).unwrap();
#[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)]
let perc: f32 =
(((size_after as f64 / size_before as f64) * f64::from(100)) - f64::from(100)) as f32;
let percentage: f32 = ((perc * f32::from(100_i8)).trunc()) / (f32::from(100_u8));
if size_before == size_after {
if display_size_before {
format!(
"{} => {}",
size_before_human_readabel, size_after_human_readable
)
} else {
size_after_human_readable
}
} else if display_size_before {
format!(
"{} => {} ({}{}, {}%)",
size_before_human_readabel,
size_after_human_readable,
sign,
size_diff_human_readable,
percentage
)
} else {
format!(
"{} ({}{}, {}%)",
size_after_human_readable, sign, size_diff_human_readable, percentage
)
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn print_size_changed_summary(
previous_total_size: u64,
cargo_cache: &CargoCachePaths,
bin_cache: &mut bin::BinaryCache,
checkouts_cache: &mut git_checkouts::GitCheckoutCache,
bare_repos_cache: &mut git_bare_repos::GitRepoCache,
registry_pkgs_cache: &mut registry_pkg_cache::RegistryPkgCaches,
registry_index_caches: &mut registry_index::RegistryIndicesCache,
registry_sources_caches: &mut registry_sources::RegistrySourceCaches,
) {
bin_cache.invalidate();
checkouts_cache.invalidate();
bare_repos_cache.invalidate();
registry_pkgs_cache.invalidate();
registry_index_caches.invalidate();
registry_sources_caches.invalidate();
let cache_size_new = DirSizes::new(
bin_cache,
checkouts_cache,
bare_repos_cache,
registry_pkgs_cache,
registry_index_caches,
registry_sources_caches,
cargo_cache,
)
.total_size();
let size_old_human_readable = previous_total_size
.file_size(file_size_opts::DECIMAL)
.unwrap();
println!(
"\nSize changed from {} to {}",
size_old_human_readable,
size_diff_format(previous_total_size, cache_size_new, false)
);
}
#[cfg(test)]
mod libtests {
use super::*;
use pretty_assertions::assert_eq;
use regex::Regex;
use std::env;
use crate::test_helpers::assert_path_end;
impl CargoCachePaths {
pub(crate) fn new(dir: PathBuf) -> Result<Self, Error> {
if !dir.is_dir() {
return Err(Error::CargoHomeNotDirectory(dir));
}
let cargo_home = dir;
let bin = cargo_home.join("bin");
let registry = cargo_home.join("registry");
let registry_index = registry.join("index");
let reg_cache = registry.join("cache");
let reg_src = registry.join("src");
let git = cargo_home.join("git");
let git_repos_bare = git.join("db");
let git_checkouts = git.join("checkouts");
Ok(Self {
cargo_home,
bin_dir: bin,
registry,
registry_index,
registry_pkg_cache: reg_cache,
registry_sources: reg_src,
git_repos_bare,
git_checkouts,
})
}
}
#[allow(non_snake_case)]
#[test]
fn test_DirInfo() {
let x = DirInfo {
dir_size: 10,
file_number: 20,
};
assert_eq!(x.dir_size, 10);
assert_eq!(x.file_number, 20);
}
#[allow(non_snake_case)]
#[test]
fn test_CargoCachePaths_gen() {
let dir_paths = CargoCachePaths::new(env::temp_dir());
assert!(dir_paths.is_ok(), "dir paths: {:?}", dir_paths);
}
#[allow(non_snake_case)]
#[test]
fn test_CargoCachePaths_paths() {
let target_dir = cargo_metadata::MetadataCommand::new()
.exec()
.unwrap()
.target_directory;
let mut cargo_home = PathBuf::from(target_dir);
cargo_home.push("cargo_home_cargo_cache_paths");
let CH_string = format!("{}", cargo_home.display());
assert_path_end(
&cargo_home,
&["cargo-cache", "target", "cargo_home_cargo_cache_paths"],
);
if !std::path::PathBuf::from(&CH_string).is_dir() {
std::fs::DirBuilder::new().create(&CH_string).unwrap();
}
assert!(fs::metadata(&CH_string).unwrap().is_dir());
assert!(std::path::PathBuf::from(&CH_string).is_dir());
let ccp = CargoCachePaths::new(PathBuf::from(CH_string)).unwrap();
assert_path_end(&ccp.cargo_home, &["cargo_home_cargo_cache_paths"]);
assert_path_end(&ccp.bin_dir, &["cargo_home_cargo_cache_paths", "bin"]);
assert_path_end(&ccp.registry, &["cargo_home_cargo_cache_paths", "registry"]);
assert_path_end(
&ccp.registry_index,
&["cargo_home_cargo_cache_paths", "registry", "index"],
);
assert_path_end(
&ccp.registry_pkg_cache,
&["cargo_home_cargo_cache_paths", "registry", "cache"],
);
assert_path_end(
&ccp.registry_sources,
&["cargo_home_cargo_cache_paths", "registry", "src"],
);
assert_path_end(
&ccp.git_repos_bare,
&["cargo_home_cargo_cache_paths", "git", "db"],
);
assert_path_end(
&ccp.git_checkouts,
&["cargo_home_cargo_cache_paths", "git", "checkouts"],
);
}
#[allow(non_snake_case)]
#[test]
fn test_CargoCachePaths_print() {
let target_dir = cargo_metadata::MetadataCommand::new()
.exec()
.unwrap()
.target_directory;
let mut cargo_home = PathBuf::from(target_dir);
cargo_home.push("cargo_home_cargo_cache_paths_print");
let CH_string = format!("{}", cargo_home.display());
assert_path_end(
&cargo_home,
&[
"cargo-cache",
"target",
"cargo_home_cargo_cache_paths_print",
],
);
if !std::path::PathBuf::from(&CH_string).exists() {
std::fs::DirBuilder::new().create(&CH_string).unwrap();
}
assert!(fs::metadata(&CH_string).unwrap().is_dir());
assert!(std::path::PathBuf::from(&CH_string).is_dir());
let ccp = CargoCachePaths::new(PathBuf::from(CH_string)).unwrap();
let output = ccp.to_string();
let mut iter = output.lines().skip(1);
let cargo_home2 = iter.next().unwrap();
assert!(
Regex::new(if cfg!(windows) {
r"cargo home:.*\\cargo_home_cargo_cache_paths_print"
} else {
r"cargo home:.*/cargo_home_cargo_cache_paths_print"
})
.unwrap()
.is_match(cargo_home2),
"cargo home: \"{:?}\"",
cargo_home
);
let bins = iter.next().unwrap();
assert!(Regex::new(if cfg!(windows) {
r"binaries directory:.*\\cargo_home_cargo_cache_paths_print\\bin"
} else {
r"binaries directory:.*/cargo_home_cargo_cache_paths_print/bin"
})
.unwrap()
.is_match(bins));
let registry = iter.next().unwrap();
assert!(Regex::new(if cfg!(windows) {
r"registry directory:.*\\cargo_home_cargo_cache_paths_print\\registry"
} else {
r"registry directory:.*/cargo_home_cargo_cache_paths_print/registry"
})
.unwrap()
.is_match(registry));
let registry_index = iter.next().unwrap();
assert!(Regex::new(if cfg!(windows) {
r"registry index:.*\\cargo_home_cargo_cache_paths_print\\registry\\index"
} else {
r"registry index:.*/cargo_home_cargo_cache_paths_print/registry/index"
})
.unwrap()
.is_match(registry_index));
let crate_archives = iter.next().unwrap();
assert!(Regex::new(if cfg!(windows) {
r"crate source archives:.*\\cargo_home_cargo_cache_paths_print\\registry\\cache"
} else {
r"crate source archives:.*/cargo_home_cargo_cache_paths_print/registry/cache"
})
.unwrap()
.is_match(crate_archives));
let crate_sources = iter.next().unwrap();
assert!(Regex::new(if cfg!(windows) {
r"unpacked crate sources:.*\\cargo_home_cargo_cache_paths_print\\registry\\src"
} else {
r"unpacked crate sources:.*/cargo_home_cargo_cache_paths_print/registry/src"
})
.unwrap()
.is_match(crate_sources));
let bare_repos = iter.next().unwrap();
assert!(Regex::new(if cfg!(windows) {
r"bare git repos:.*\\cargo_home_cargo_cache_paths_print\\git\\db"
} else {
r"bare git repos:.*/cargo_home_cargo_cache_paths_print/git/db"
})
.unwrap()
.is_match(bare_repos));
let git_repo_checkouts = iter.next().unwrap();
assert!(Regex::new(if cfg!(windows) {
r"git repo checkouts.*\\cargo_home_cargo_cache_paths_print\\git\\checkouts"
} else {
r"git repo checkouts.*/cargo_home_cargo_cache_paths_print/git/checkouts"
})
.unwrap()
.is_match(git_repo_checkouts));
let last = iter.next();
assert!(last.is_none(), "found another directory?!: '{:?}'", last);
}
}
#[cfg(all(test, feature = "bench"))]
mod benchmarks {
use super::*;
use crate::test::black_box;
use crate::test::Bencher;
use crate::test_helpers::assert_path_end;
#[allow(non_snake_case)]
#[bench]
fn bench_CargoCachePaths_new(b: &mut Bencher) {
let mut target_dir = std::env::current_dir().unwrap();
target_dir.push("target");
let mut cargo_home = target_dir;
cargo_home.push("cargo_home_bench_new");
let CH_string = format!("{}", cargo_home.display());
assert_path_end(
&cargo_home,
&["cargo-cache", "target", "cargo_home_bench_new"],
);
if !std::path::PathBuf::from(&CH_string).is_dir() {
std::fs::DirBuilder::new().create(&CH_string).unwrap();
}
assert!(fs::metadata(&CH_string).unwrap().is_dir());
assert!(std::path::PathBuf::from(&CH_string).is_dir());
#[allow(unused_must_use)]
b.iter(|| {
let x = CargoCachePaths::new(PathBuf::from(&CH_string));
black_box(x);
});
}
#[allow(non_snake_case)]
#[bench]
fn bench_CargoCachePaths_print(b: &mut Bencher) {
let mut target_dir = std::env::current_dir().unwrap();
target_dir.push("target");
let mut cargo_home = target_dir;
cargo_home.push("cargo_home_bench_print");
let CH_string = format!("{}", cargo_home.display());
assert_path_end(
&cargo_home,
&["cargo-cache", "target", "cargo_home_bench_print"],
);
if !std::path::PathBuf::from(&CH_string).is_dir() {
std::fs::DirBuilder::new().create(&CH_string).unwrap();
}
assert!(fs::metadata(&CH_string).unwrap().is_dir());
assert!(std::path::PathBuf::from(&CH_string).is_dir());
let ccp = CargoCachePaths::new(PathBuf::from(CH_string)).unwrap();
#[allow(unused_must_use)]
b.iter(|| {
let x = ccp.to_string();
let _ = black_box(x);
});
}
}