Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 90 additions & 24 deletions crates/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
use std::{
borrow::Cow,
collections::BTreeMap,
fs,
fs, io,
path::{Path, PathBuf},
str::FromStr,
};
Expand Down Expand Up @@ -1269,7 +1269,9 @@ impl Config {
let project = builder.build(self.compiler()?)?;

if self.force {
self.cleanup(&project)?;
// Warnings are intentionally dropped here because `sh_warn!` is a circular
// dependency. Callers that need warnings should call `cleanup()` directly.
let _ = self.cleanup(&project);
}

Ok(project)
Expand Down Expand Up @@ -1298,21 +1300,40 @@ impl Config {
}

/// Cleans the project.
///
/// Returns a list of warning messages for any non-fatal cleanup failures. Cleanup is
/// best-effort: all steps are attempted even if some fail.
pub fn cleanup<C: Compiler, T: ArtifactOutput<CompilerContract = C::CompilerContract>>(
&self,
project: &Project<C, T>,
) -> Result<(), SolcError> {
project.cleanup()?;
) -> Result<Vec<String>, SolcError> {
let mut warnings = Vec::new();

if let Err(err) = project.cleanup() {
warnings.push(format!("failed to clean project artifacts: {err}"));
}

// Remove last test run failures file.
let _ = fs::remove_file(&self.test_failures_file);
if let Err(err) = fs::remove_file(&self.test_failures_file)
&& err.kind() != io::ErrorKind::NotFound
{
warnings.push(format!(
"failed to remove test failures file {}: {err}",
self.test_failures_file.display()
));
}

// Remove fuzz and invariant cache directories.
let remove_test_dir = |test_dir: &Option<PathBuf>| {
let mut remove_test_dir = |test_dir: &Option<PathBuf>| {
if let Some(test_dir) = test_dir {
let path = project.root().join(test_dir);
if path.exists() {
let _ = fs::remove_dir_all(&path);
if let Err(err) = fs::remove_dir_all(&path)
&& err.kind() != io::ErrorKind::NotFound
{
warnings.push(format!(
"failed to remove test cache directory {}: {err}",
path.display()
));
}
}
};
Expand All @@ -1321,7 +1342,7 @@ impl Config {
remove_test_dir(&self.invariant.corpus.corpus_dir);
remove_test_dir(&self.invariant.failure_persist_dir);

Ok(())
Ok(warnings)
}

/// Ensures that the configured version is installed if explicitly set
Expand Down Expand Up @@ -2154,63 +2175,108 @@ impl Config {
}

/// Clears the foundry cache.
pub fn clean_foundry_cache() -> eyre::Result<()> {
///
/// Returns warnings for any non-fatal deletion failures.
pub fn clean_foundry_cache() -> eyre::Result<Vec<String>> {
if let Some(cache_dir) = Self::foundry_cache_dir() {
let path = cache_dir.as_path();
let _ = fs::remove_dir_all(path);
if let Err(err) = fs::remove_dir_all(path)
&& err.kind() != io::ErrorKind::NotFound
{
return Ok(vec![format!(
"failed to remove foundry cache at {}: {err}",
path.display()
)]);
}
} else {
eyre::bail!("failed to get foundry_cache_dir");
}

Ok(())
Ok(vec![])
}

/// Clears the foundry cache for `chain`.
pub fn clean_foundry_chain_cache(chain: Chain) -> eyre::Result<()> {
///
/// Returns warnings for any non-fatal deletion failures.
pub fn clean_foundry_chain_cache(chain: Chain) -> eyre::Result<Vec<String>> {
if let Some(cache_dir) = Self::foundry_chain_cache_dir(chain) {
let path = cache_dir.as_path();
let _ = fs::remove_dir_all(path);
if let Err(err) = fs::remove_dir_all(path)
&& err.kind() != io::ErrorKind::NotFound
{
return Ok(vec![format!(
"failed to remove foundry cache for chain {chain} at {}: {err}",
path.display()
)]);
}
} else {
eyre::bail!("failed to get foundry_chain_cache_dir");
}

Ok(())
Ok(vec![])
}

/// Clears the foundry cache for `chain` and `block`.
pub fn clean_foundry_block_cache(chain: Chain, block: u64) -> eyre::Result<()> {
///
/// Returns warnings for any non-fatal deletion failures.
pub fn clean_foundry_block_cache(chain: Chain, block: u64) -> eyre::Result<Vec<String>> {
if let Some(cache_dir) = Self::foundry_block_cache_dir(chain, block) {
let path = cache_dir.as_path();
let _ = fs::remove_dir_all(path);
if let Err(err) = fs::remove_dir_all(path)
&& err.kind() != io::ErrorKind::NotFound
{
return Ok(vec![format!(
"failed to remove foundry cache for chain {chain} block {block} at {}: {err}",
path.display()
)]);
}
} else {
eyre::bail!("failed to get foundry_block_cache_dir");
}

Ok(())
Ok(vec![])
}

/// Clears the foundry etherscan cache.
pub fn clean_foundry_etherscan_cache() -> eyre::Result<()> {
///
/// Returns warnings for any non-fatal deletion failures.
pub fn clean_foundry_etherscan_cache() -> eyre::Result<Vec<String>> {
if let Some(cache_dir) = Self::foundry_etherscan_cache_dir() {
let path = cache_dir.as_path();
let _ = fs::remove_dir_all(path);
if let Err(err) = fs::remove_dir_all(path)
&& err.kind() != io::ErrorKind::NotFound
{
return Ok(vec![format!(
"failed to remove foundry etherscan cache at {}: {err}",
path.display()
)]);
}
} else {
eyre::bail!("failed to get foundry_etherscan_cache_dir");
}

Ok(())
Ok(vec![])
}

/// Clears the foundry etherscan cache for `chain`.
pub fn clean_foundry_etherscan_chain_cache(chain: Chain) -> eyre::Result<()> {
///
/// Returns warnings for any non-fatal deletion failures.
pub fn clean_foundry_etherscan_chain_cache(chain: Chain) -> eyre::Result<Vec<String>> {
if let Some(cache_dir) = Self::foundry_etherscan_chain_cache_dir(chain) {
let path = cache_dir.as_path();
let _ = fs::remove_dir_all(path);
if let Err(err) = fs::remove_dir_all(path)
&& err.kind() != io::ErrorKind::NotFound
{
return Ok(vec![format!(
"failed to remove foundry etherscan cache for chain {chain} at {}: {err}",
path.display()
)]);
}
} else {
eyre::bail!("failed to get foundry_etherscan_cache_dir for chain: {}", chain);
}

Ok(())
Ok(vec![])
}

/// List the data in the foundry cache.
Expand Down
6 changes: 4 additions & 2 deletions crates/forge/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use clap::{CommandFactory, Parser};
use clap_complete::generate;
use eyre::Result;
use foundry_cli::utils;
use foundry_common::shell;
use foundry_common::{sh_warn, shell};
use foundry_evm::inspectors::cheatcodes::{ForgeContext, set_execution_context};

/// Run the `forge` command line interface.
Expand Down Expand Up @@ -99,7 +99,9 @@ pub fn run_command(args: Forge) -> Result<()> {
ForgeSubcommand::Clean { root } => {
let config = utils::load_config_with_root(root.as_deref())?;
let project = config.project()?;
config.cleanup(&project)?;
for warning in config.cleanup(&project)? {
let _ = sh_warn!("{warning}");
}
Ok(())
}
ForgeSubcommand::Snapshot(cmd) => {
Expand Down
21 changes: 16 additions & 5 deletions crates/forge/src/cmd/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use clap::{
builder::{PossibleValuesParser, TypedValueParser},
};
use eyre::Result;
use foundry_common::sh_warn;
use foundry_config::{Chain, Config, NamedChain, cache};
use std::{ffi::OsStr, str::FromStr};
use strum::VariantNames;
Expand Down Expand Up @@ -63,10 +64,13 @@ impl CleanArgs {
clean_chain_cache(chain, blocks.clone(), etherscan)?
}
ChainOrAll::All => {
if etherscan {
Config::clean_foundry_etherscan_cache()?;
let warnings = if etherscan {
Config::clean_foundry_etherscan_cache()?
} else {
Config::clean_foundry_cache()?
};
for warning in warnings {
let _ = sh_warn!("{warning}");
}
}
}
Expand Down Expand Up @@ -128,17 +132,24 @@ impl FromStr for ChainOrAll {

fn clean_chain_cache(chain: impl Into<Chain>, blocks: Vec<u64>, etherscan: bool) -> Result<()> {
let chain = chain.into();
let mut warnings = Vec::new();
if blocks.is_empty() {
Config::clean_foundry_etherscan_chain_cache(chain)?;
warnings.extend(Config::clean_foundry_etherscan_chain_cache(chain)?);
if etherscan {
for warning in warnings {
let _ = sh_warn!("{warning}");
}
return Ok(());
}
Config::clean_foundry_chain_cache(chain)?;
warnings.extend(Config::clean_foundry_chain_cache(chain)?);
} else {
for block in blocks {
Config::clean_foundry_block_cache(chain, block)?;
warnings.extend(Config::clean_foundry_block_cache(chain, block)?);
}
}
for warning in warnings {
let _ = sh_warn!("{warning}");
}
Ok(())
}

Expand Down
Loading