Skip to content

Commit

Permalink
perf: support FigmentProviders settings (#7812)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattsse authored Apr 30, 2024
1 parent a6e7fe0 commit ba399ae
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 69 deletions.
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 @@ -1658,77 +1738,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

0 comments on commit ba399ae

Please sign in to comment.