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

perf: support FigmentProviders settings #7812

Merged
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
171 changes: 103 additions & 68 deletions crates/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,86 @@ impl Config {
Ok(config)
}

/// Returns the populated [Figment] using the requested [FigmentProviders] preset.
///
/// This will merge various providers, such as env,toml,remappings into the figment.
pub fn to_figment(self, providers: FigmentProviders) -> Figment {
let mut c = self;
let profile = Config::selected_profile();
let mut figment = Figment::default().merge(DappHardhatDirProvider(&c.__root.0));

// merge global foundry.toml file
if let Some(global_toml) = Config::foundry_dir_toml().filter(|p| p.exists()) {
figment = Config::merge_toml_provider(
figment,
TomlFileProvider::new(None, global_toml).cached(),
profile.clone(),
);
}
// merge local foundry.toml file
figment = Config::merge_toml_provider(
figment,
TomlFileProvider::new(Some("FOUNDRY_CONFIG"), c.__root.0.join(Config::FILE_NAME))
.cached(),
profile.clone(),
);

// merge environment variables
figment = figment
.merge(
Env::prefixed("DAPP_")
.ignore(&["REMAPPINGS", "LIBRARIES", "FFI", "FS_PERMISSIONS"])
.global(),
)
.merge(
Env::prefixed("DAPP_TEST_")
.ignore(&["CACHE", "FUZZ_RUNS", "DEPTH", "FFI", "FS_PERMISSIONS"])
.global(),
)
.merge(DappEnvCompatProvider)
.merge(EtherscanEnvProvider::default())
.merge(
Env::prefixed("FOUNDRY_")
.ignore(&["PROFILE", "REMAPPINGS", "LIBRARIES", "FFI", "FS_PERMISSIONS"])
.map(|key| {
let key = key.as_str();
if Config::STANDALONE_SECTIONS.iter().any(|section| {
key.starts_with(&format!("{}_", section.to_ascii_uppercase()))
}) {
key.replacen('_', ".", 1).into()
} else {
key.into()
}
})
.global(),
)
.select(profile.clone());

// only resolve remappings if all providers are requested
if providers.is_all() {
// we try to merge remappings after we've merged all other providers, this prevents
// redundant fs lookups to determine the default remappings that are eventually updated
// by other providers, like the toml file
let remappings = RemappingsProvider {
auto_detect_remappings: figment
.extract_inner::<bool>("auto_detect_remappings")
.unwrap_or(true),
lib_paths: figment
.extract_inner::<Vec<PathBuf>>("libs")
.map(Cow::Owned)
.unwrap_or_else(|_| Cow::Borrowed(&c.libs)),
root: &c.__root.0,
remappings: figment.extract_inner::<Vec<Remapping>>("remappings"),
};
figment = figment.merge(remappings);
}

// normalize defaults
figment = c.normalize_defaults(figment);

Figment::from(c).merge(figment).select(profile)
}

/// The config supports relative paths and tracks the root path separately see
/// `Config::with_root`
///
Expand Down Expand Up @@ -1643,77 +1723,32 @@ impl Config {
}

impl From<Config> for Figment {
fn from(mut c: Config) -> Figment {
let profile = Config::selected_profile();
let mut figment = Figment::default().merge(DappHardhatDirProvider(&c.__root.0));

// merge global foundry.toml file
if let Some(global_toml) = Config::foundry_dir_toml().filter(|p| p.exists()) {
figment = Config::merge_toml_provider(
figment,
TomlFileProvider::new(None, global_toml).cached(),
profile.clone(),
);
}
// merge local foundry.toml file
figment = Config::merge_toml_provider(
figment,
TomlFileProvider::new(Some("FOUNDRY_CONFIG"), c.__root.0.join(Config::FILE_NAME))
.cached(),
profile.clone(),
);

// merge environment variables
figment = figment
.merge(
Env::prefixed("DAPP_")
.ignore(&["REMAPPINGS", "LIBRARIES", "FFI", "FS_PERMISSIONS"])
.global(),
)
.merge(
Env::prefixed("DAPP_TEST_")
.ignore(&["CACHE", "FUZZ_RUNS", "DEPTH", "FFI", "FS_PERMISSIONS"])
.global(),
)
.merge(DappEnvCompatProvider)
.merge(EtherscanEnvProvider::default())
.merge(
Env::prefixed("FOUNDRY_")
.ignore(&["PROFILE", "REMAPPINGS", "LIBRARIES", "FFI", "FS_PERMISSIONS"])
.map(|key| {
let key = key.as_str();
if Config::STANDALONE_SECTIONS.iter().any(|section| {
key.starts_with(&format!("{}_", section.to_ascii_uppercase()))
}) {
key.replacen('_', ".", 1).into()
} else {
key.into()
}
})
.global(),
)
.select(profile.clone());
fn from(c: Config) -> Figment {
c.to_figment(FigmentProviders::All)
}
}

// we try to merge remappings after we've merged all other providers, this prevents
// redundant fs lookups to determine the default remappings that are eventually updated by
// other providers, like the toml file
let remappings = RemappingsProvider {
auto_detect_remappings: figment
.extract_inner::<bool>("auto_detect_remappings")
.unwrap_or(true),
lib_paths: figment
.extract_inner::<Vec<PathBuf>>("libs")
.map(Cow::Owned)
.unwrap_or_else(|_| Cow::Borrowed(&c.libs)),
root: &c.__root.0,
remappings: figment.extract_inner::<Vec<Remapping>>("remappings"),
};
let merge = figment.merge(remappings);
/// Determines what providers should be used when loading the [Figment] for a [Config]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FigmentProviders {
/// Include all providers
#[default]
All,
/// Only include necessary providers that are useful for cast commands
///
/// This will exclude more expensive providers such as remappings
Cast,
}

// normalize defaults
let merge = c.normalize_defaults(merge);
impl FigmentProviders {
/// Returns true if all providers should be included
pub const fn is_all(&self) -> bool {
matches!(self, Self::All)
}

Figment::from(c).merge(merge).select(profile)
/// Returns true if this is the cast preset
pub const fn is_cast(&self) -> bool {
matches!(self, Self::Cast)
}
}

Expand Down
6 changes: 5 additions & 1 deletion crates/config/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,16 @@ macro_rules! merge_impl_figment_convert {
}

/// A macro to implement converters from a type to [`Config`] and [`figment::Figment`]
///
/// Via [Config::to_figment](crate::Config::to_figment) and the
/// [Cast](crate::FigmentProviders::Cast) profile.
#[macro_export]
macro_rules! impl_figment_convert_cast {
($name:ty) => {
impl<'a> From<&'a $name> for $crate::figment::Figment {
fn from(args: &'a $name) -> Self {
$crate::Config::figment_with_root($crate::find_project_root_path(None).unwrap())
$crate::Config::with_root($crate::find_project_root_path(None).unwrap())
.to_figment($crate::FigmentProviders::Cast)
.merge(args)
}
}
Expand Down
Loading