Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(foundry-ignore-compile): read from ignore file and filter out al… #1

Open
wants to merge 4 commits into
base: feature/foundry-ignore-compile
Choose a base branch
from
Open
Changes from 2 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
97 changes: 66 additions & 31 deletions crates/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use figment::{
value::{Dict, Map, Value},
Error, Figment, Metadata, Profile, Provider,
};
use filter::GlobMatcher;
use filter::{GlobMatcher, SkipBuildFilter};
use foundry_compilers::{
artifacts::{
output_selection::{ContractOutputSelection, OutputSelection},
Expand Down Expand Up @@ -44,7 +44,8 @@ use serde::{Deserialize, Serialize, Serializer};
use std::{
borrow::Cow,
collections::HashMap,
fs,
fs::{self, File},
io::{self, BufRead},
path::{Path, PathBuf},
str::FromStr,
};
Expand Down Expand Up @@ -834,6 +835,21 @@ impl Config {
.set_build_info(!no_artifacts && self.build_info)
.set_no_artifacts(no_artifacts);

let foundry_ignored_paths: Vec<String> = self.get_ignore_paths()?;

if foundry_ignored_paths.is_empty() {
println!("No ignored paths found");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer use warning here

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
println!("No ignored paths found");
println!("No skipped paths found in .foundryignore");

}

let ignore_pattern: Vec<GlobMatcher> = foundry_ignored_paths
.iter()
.filter_map(|path| GlobMatcher::from_str(path).ok())
.collect();

let ignore_filter: SkipBuildFilters =
SkipBuildFilters::new(ignore_pattern.clone(), self.root.0.clone());
builder = builder.sparse_output(ignore_filter);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Group these lines in to a fn

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
builder = builder.sparse_output(ignore_filter);
builder = builder.sparse_output(ignore_filter);


if !self.skip.is_empty() {
let filter = SkipBuildFilters::new(self.skip.clone(), self.root.0.clone());
builder = builder.sparse_output(filter);
Expand Down Expand Up @@ -886,7 +902,7 @@ impl Config {
if self.offline {
return Err(SolcError::msg(format!(
"can't install missing solc {version} in offline mode"
)))
)));
}
Solc::blocking_install(version)?
}
Expand All @@ -896,12 +912,12 @@ impl Config {
return Err(SolcError::msg(format!(
"`solc` {} does not exist",
solc.display()
)))
)));
}
Solc::new(solc)?
}
};
return Ok(Some(solc))
return Ok(Some(solc));
}

Ok(None)
Expand All @@ -919,16 +935,16 @@ impl Config {
/// `auto_detect_solc`
pub fn is_auto_detect(&self) -> bool {
if self.solc.is_some() {
return false
return false;
}
self.auto_detect_solc
}

/// Whether caching should be enabled for the given chain id
pub fn enable_caching(&self, endpoint: &str, chain_id: impl Into<u64>) -> bool {
!self.no_storage_caching &&
self.rpc_storage_caching.enable_for_chain_id(chain_id.into()) &&
self.rpc_storage_caching.enable_for_endpoint(endpoint)
!self.no_storage_caching
&& self.rpc_storage_caching.enable_for_chain_id(chain_id.into())
&& self.rpc_storage_caching.enable_for_endpoint(endpoint)
}

/// Returns the `ProjectPathsConfig` sub set of the config.
Expand Down Expand Up @@ -978,7 +994,7 @@ impl Config {
pub fn vyper_compiler(&self) -> Result<Option<Vyper>, SolcError> {
// Only instantiate Vyper if there are any Vyper files in the project.
if self.project_paths::<VyperLanguage>().input_files_iter().next().is_none() {
return Ok(None)
return Ok(None);
}
let vyper = if let Some(path) = &self.vyper.path {
Some(Vyper::new(path)?)
Expand Down Expand Up @@ -1063,6 +1079,25 @@ impl Config {
}
}

pub fn get_ignore_paths(&self) -> Result<Vec<String>, SolcError> {
let path = Path::new("foundry.ignore");
if !path.exists() {
return Ok(Vec::new());
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return more clear error, to differentiate "file not found", and "file not contains items"

let file = File::open(&path).unwrap();
let reader = io::BufReader::new(file);
let mut entries: Vec<String> = Vec::new();
for line in reader.lines() {
let line = line.map_err(|e| SolcError::msg(format!("Failed to read line: {}", e)))?;
let trimmed = line.trim();
if !trimmed.is_empty() && !trimmed.starts_with('#') {
entries.push(trimmed.to_string());
}
}

Ok(entries)
}

/// Resolves the given alias to a matching rpc url
///
/// Returns:
Expand Down Expand Up @@ -1160,7 +1195,7 @@ impl Config {
) -> Result<Option<ResolvedEtherscanConfig>, EtherscanConfigError> {
if let Some(maybe_alias) = self.etherscan_api_key.as_ref().or(self.eth_rpc_url.as_ref()) {
if self.etherscan.contains_key(maybe_alias) {
return self.etherscan.clone().resolved().remove(maybe_alias).transpose()
return self.etherscan.clone().resolved().remove(maybe_alias).transpose();
}
}

Expand All @@ -1174,7 +1209,7 @@ impl Config {
// we update the key, because if an etherscan_api_key is set, it should take
// precedence over the entry, since this is usually set via env var or CLI args.
config.key.clone_from(key);
return Ok(Some(config))
return Ok(Some(config));
}
(Ok(config), None) => return Ok(Some(config)),
(Err(err), None) => return Err(err),
Expand All @@ -1187,7 +1222,7 @@ impl Config {
// etherscan fallback via API key
if let Some(key) = self.etherscan_api_key.as_ref() {
let chain = chain.or(self.chain).unwrap_or_default();
return Ok(ResolvedEtherscanConfig::create(key, chain))
return Ok(ResolvedEtherscanConfig::create(key, chain));
}

Ok(None)
Expand Down Expand Up @@ -1471,7 +1506,7 @@ impl Config {
{
let file_path = self.get_config_path();
if !file_path.exists() {
return Ok(())
return Ok(());
}
let contents = fs::read_to_string(&file_path)?;
let mut doc = contents.parse::<toml_edit::DocumentMut>()?;
Expand Down Expand Up @@ -1633,14 +1668,14 @@ impl Config {
return match path.is_file() {
true => Some(path.to_path_buf()),
false => None,
}
};
}
let cwd = std::env::current_dir().ok()?;
let mut cwd = cwd.as_path();
loop {
let file_path = cwd.join(path);
if file_path.is_file() {
return Some(file_path)
return Some(file_path);
}
cwd = cwd.parent()?;
}
Expand Down Expand Up @@ -1714,7 +1749,7 @@ impl Config {
if let Some(cache_dir) = Self::foundry_rpc_cache_dir() {
let mut cache = Cache { chains: vec![] };
if !cache_dir.exists() {
return Ok(cache)
return Ok(cache);
}
if let Ok(entries) = cache_dir.as_path().read_dir() {
for entry in entries.flatten().filter(|x| x.path().is_dir()) {
Expand Down Expand Up @@ -1758,19 +1793,19 @@ impl Config {
fn get_cached_blocks(chain_path: &Path) -> eyre::Result<Vec<(String, u64)>> {
let mut blocks = vec![];
if !chain_path.exists() {
return Ok(blocks)
return Ok(blocks);
}
for block in chain_path.read_dir()?.flatten() {
let file_type = block.file_type()?;
let file_name = block.file_name();
let filepath = if file_type.is_dir() {
block.path().join("storage.json")
} else if file_type.is_file() &&
file_name.to_string_lossy().chars().all(char::is_numeric)
} else if file_type.is_file()
&& file_name.to_string_lossy().chars().all(char::is_numeric)
{
block.path()
} else {
continue
continue;
};
blocks.push((file_name.to_string_lossy().into_owned(), fs::metadata(filepath)?.len()));
}
Expand All @@ -1780,7 +1815,7 @@ impl Config {
/// The path provided to this function should point to the etherscan cache for a chain.
fn get_cached_block_explorer_data(chain_path: &Path) -> eyre::Result<u64> {
if !chain_path.exists() {
return Ok(0)
return Ok(0);
}

fn dir_size_recursive(mut dir: fs::ReadDir) -> eyre::Result<u64> {
Expand Down Expand Up @@ -1956,7 +1991,7 @@ pub(crate) mod from_opt_glob {
{
let s: Option<String> = Option::deserialize(deserializer)?;
if let Some(s) = s {
return Ok(Some(globset::Glob::new(&s).map_err(serde::de::Error::custom)?))
return Ok(Some(globset::Glob::new(&s).map_err(serde::de::Error::custom)?));
}
Ok(None)
}
Expand Down Expand Up @@ -2238,7 +2273,7 @@ impl TomlFileProvider {
if let Some(file) = self.env_val() {
let path = Path::new(&file);
if !path.exists() {
return true
return true;
}
}
false
Expand All @@ -2258,7 +2293,7 @@ impl TomlFileProvider {
"Config file `{}` set in env var `{}` does not exist",
file,
self.env_var.unwrap()
)))
)));
}
Toml::file(file)
} else {
Expand Down Expand Up @@ -2302,7 +2337,7 @@ impl<P: Provider> Provider for ForcedSnakeCaseData<P> {
if Config::STANDALONE_SECTIONS.contains(&profile.as_ref()) {
// don't force snake case for keys in standalone sections
map.insert(profile, dict);
continue
continue;
}
map.insert(profile, dict.into_iter().map(|(k, v)| (k.to_snake_case(), v)).collect());
}
Expand Down Expand Up @@ -2442,7 +2477,7 @@ impl Provider for DappEnvCompatProvider {
if val > 1 {
return Err(
format!("Invalid $DAPP_BUILD_OPTIMIZE value `{val}`, expected 0 or 1").into()
)
);
}
dict.insert("optimizer".to_string(), (val == 1).into());
}
Expand Down Expand Up @@ -2508,7 +2543,7 @@ impl<P: Provider> Provider for RenameProfileProvider<P> {
fn data(&self) -> Result<Map<Profile, Dict>, Error> {
let mut data = self.provider.data()?;
if let Some(data) = data.remove(&self.from) {
return Ok(Map::from([(self.to.clone(), data)]))
return Ok(Map::from([(self.to.clone(), data)]));
}
Ok(Default::default())
}
Expand Down Expand Up @@ -2554,7 +2589,7 @@ impl<P: Provider> Provider for UnwrapProfileProvider<P> {
for (profile_str, profile_val) in profiles {
let profile = Profile::new(&profile_str);
if profile != self.profile {
continue
continue;
}
match profile_val {
Value::Dict(_, dict) => return Ok(profile.collect(dict)),
Expand All @@ -2565,7 +2600,7 @@ impl<P: Provider> Provider for UnwrapProfileProvider<P> {
));
err.metadata = Some(self.provider.metadata());
err.profile = Some(self.profile.clone());
return Err(err)
return Err(err);
}
}
}
Expand Down Expand Up @@ -2677,7 +2712,7 @@ impl<P: Provider> Provider for OptionalStrictProfileProvider<P> {
// provider and can't map the metadata to the error. Therefor we return the root error
// if this error originated in the provider's data.
if let Err(root_err) = self.provider.data() {
return root_err
return root_err;
}
err
})
Expand Down