dep: rm confy as a dep (#10290)

Co-authored-by: Alexey Shekhirin <a.shekhirin@gmail.com>
This commit is contained in:
Thomas Coratger
2024-08-19 23:37:35 -07:00
committed by GitHub
parent 56e1448dbd
commit cd05a96fee
13 changed files with 187 additions and 49 deletions

29
Cargo.lock generated
View File

@ -1857,18 +1857,6 @@ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "confy"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45b1f4c00870f07dc34adcac82bb6a72cc5aabca8536ba1797e01df51d2ce9a0"
dependencies = [
"directories",
"serde",
"thiserror",
"toml",
]
[[package]] [[package]]
name = "console" name = "console"
version = "0.15.8" version = "0.15.8"
@ -2416,15 +2404,6 @@ dependencies = [
"subtle", "subtle",
] ]
[[package]]
name = "directories"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
dependencies = [
"dirs-sys",
]
[[package]] [[package]]
name = "dirs" name = "dirs"
version = "5.0.1" version = "5.0.1"
@ -6226,7 +6205,6 @@ dependencies = [
"aquamarine", "aquamarine",
"backon", "backon",
"clap", "clap",
"confy",
"discv5", "discv5",
"eyre", "eyre",
"fdlimit", "fdlimit",
@ -6551,7 +6529,6 @@ dependencies = [
"backon", "backon",
"clap", "clap",
"comfy-table", "comfy-table",
"confy",
"crossterm", "crossterm",
"eyre", "eyre",
"fdlimit", "fdlimit",
@ -6658,7 +6635,7 @@ dependencies = [
name = "reth-config" name = "reth-config"
version = "1.0.5" version = "1.0.5"
dependencies = [ dependencies = [
"confy", "eyre",
"humantime-serde", "humantime-serde",
"reth-network-peers", "reth-network-peers",
"reth-network-types", "reth-network-types",
@ -7693,7 +7670,6 @@ name = "reth-node-builder"
version = "1.0.5" version = "1.0.5"
dependencies = [ dependencies = [
"aquamarine", "aquamarine",
"confy",
"eyre", "eyre",
"fdlimit", "fdlimit",
"futures", "futures",
@ -7788,9 +7764,12 @@ dependencies = [
"reth-tracing", "reth-tracing",
"reth-transaction-pool", "reth-transaction-pool",
"secp256k1", "secp256k1",
"serde",
"serde_json", "serde_json",
"shellexpand", "shellexpand",
"tempfile",
"tokio", "tokio",
"toml",
"tracing", "tracing",
"vergen", "vergen",
] ]

View File

@ -527,7 +527,6 @@ secp256k1 = { version = "0.29", default-features = false, features = [
c-kzg = "1.0.0" c-kzg = "1.0.0"
# config # config
confy = "0.6"
toml = "0.8" toml = "0.8"
# misc-testing # misc-testing

View File

@ -83,7 +83,6 @@ tracing.workspace = true
fdlimit.workspace = true fdlimit.workspace = true
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
confy.workspace = true
toml = { workspace = true, features = ["display"] } toml = { workspace = true, features = ["display"] }
# metrics # metrics

View File

@ -58,7 +58,6 @@ secp256k1 = { workspace = true, features = ["global-context", "rand-std", "recov
# io # io
fdlimit.workspace = true fdlimit.workspace = true
confy.workspace = true
toml = { workspace = true, features = ["display"] } toml = { workspace = true, features = ["display"] }
# tui # tui

View File

@ -65,7 +65,8 @@ impl EnvironmentArgs {
} }
let config_path = self.config.clone().unwrap_or_else(|| data_dir.config()); let config_path = self.config.clone().unwrap_or_else(|| data_dir.config());
let mut config: Config = confy::load_path(config_path)
let mut config = Config::from_path(config_path)
.inspect_err( .inspect_err(
|err| warn!(target: "reth::cli", %err, "Failed to load config file, using default"), |err| warn!(target: "reth::cli", %err, "Failed to load config file, using default"),
) )

View File

@ -25,11 +25,12 @@ impl Command {
Config::default() Config::default()
} else { } else {
let path = self.config.clone().unwrap_or_default(); let path = self.config.clone().unwrap_or_default();
// confy will create the file if it doesn't exist; we don't want this // Check if the file exists
if !path.exists() { if !path.exists() {
bail!("Config file does not exist: {}", path.display()); bail!("Config file does not exist: {}", path.display());
} }
confy::load_path::<Config>(&path) // Read the configuration file
Config::from_path(&path)
.wrap_err_with(|| format!("Could not load config file: {}", path.display()))? .wrap_err_with(|| format!("Could not load config file: {}", path.display()))?
}; };
println!("{}", toml::to_string_pretty(&config)?); println!("{}", toml::to_string_pretty(&config)?);

View File

@ -74,13 +74,15 @@ pub enum Subcommands {
// RLPx utilities // RLPx utilities
Rlpx(rlpx::Command), Rlpx(rlpx::Command),
} }
impl Command { impl Command {
/// Execute `p2p` command /// Execute `p2p` command
pub async fn execute(self) -> eyre::Result<()> { pub async fn execute(self) -> eyre::Result<()> {
let data_dir = self.datadir.clone().resolve_datadir(self.chain.chain); let data_dir = self.datadir.clone().resolve_datadir(self.chain.chain);
let config_path = self.config.clone().unwrap_or_else(|| data_dir.config()); let config_path = self.config.clone().unwrap_or_else(|| data_dir.config());
let mut config: Config = confy::load_path(&config_path).unwrap_or_default(); // Load configuration
let mut config = Config::from_path(&config_path).unwrap_or_default();
config.peers.trusted_nodes.extend(self.network.trusted_peers.clone()); config.peers.trusted_nodes.extend(self.network.trusted_peers.clone());

View File

@ -21,9 +21,9 @@ serde.workspace = true
humantime-serde.workspace = true humantime-serde.workspace = true
# toml # toml
confy.workspace = true toml.workspace = true
eyre.workspace = true
[dev-dependencies] [dev-dependencies]
tempfile.workspace = true tempfile.workspace = true
toml.workspace = true
reth-network-peers.workspace = true reth-network-peers.workspace = true

View File

@ -1,11 +1,13 @@
//! Configuration files. //! Configuration files.
use eyre::eyre;
use reth_network_types::{PeersConfig, SessionsConfig}; use reth_network_types::{PeersConfig, SessionsConfig};
use reth_prune_types::PruneModes; use reth_prune_types::PruneModes;
use reth_stages_types::ExecutionStageThresholds; use reth_stages_types::ExecutionStageThresholds;
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
use std::{ use std::{
ffi::OsStr, ffi::OsStr,
fs,
path::{Path, PathBuf}, path::{Path, PathBuf},
time::Duration, time::Duration,
}; };
@ -29,6 +31,31 @@ pub struct Config {
} }
impl Config { impl Config {
/// Load a [`Config`] from a specified path.
///
/// A new configuration file is created with default values if none
/// exists.
pub fn from_path(path: impl AsRef<Path>) -> eyre::Result<Self> {
let path = path.as_ref();
match fs::read_to_string(path) {
Ok(cfg_string) => {
toml::from_str(&cfg_string).map_err(|e| eyre!("Failed to parse TOML: {e}"))
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)
.map_err(|e| eyre!("Failed to create directory: {e}"))?;
}
let cfg = Self::default();
let s = toml::to_string_pretty(&cfg)
.map_err(|e| eyre!("Failed to serialize to TOML: {e}"))?;
fs::write(path, s).map_err(|e| eyre!("Failed to write configuration file: {e}"))?;
Ok(cfg)
}
Err(e) => Err(eyre!("Failed to load configuration: {e}")),
}
}
/// Returns the [`PeersConfig`] for the node. /// Returns the [`PeersConfig`] for the node.
/// ///
/// If a peers file is provided, the basic nodes from the file are added to the configuration. /// If a peers file is provided, the basic nodes from the file are added to the configuration.
@ -48,9 +75,14 @@ impl Config {
return Err(std::io::Error::new( return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput, std::io::ErrorKind::InvalidInput,
format!("reth config file extension must be '{EXTENSION}'"), format!("reth config file extension must be '{EXTENSION}'"),
)) ));
} }
confy::store_path(path, self).map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
std::fs::write(
path,
toml::to_string(self)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))?,
)
} }
/// Sets the pruning configuration. /// Sets the pruning configuration.
@ -384,7 +416,7 @@ where
mod tests { mod tests {
use super::{Config, EXTENSION}; use super::{Config, EXTENSION};
use reth_network_peers::TrustedPeer; use reth_network_peers::TrustedPeer;
use std::{str::FromStr, time::Duration}; use std::{path::Path, str::FromStr, time::Duration};
fn with_tempdir(filename: &str, proc: fn(&std::path::Path)) { fn with_tempdir(filename: &str, proc: fn(&std::path::Path)) {
let temp_dir = tempfile::tempdir().unwrap(); let temp_dir = tempfile::tempdir().unwrap();
@ -395,11 +427,91 @@ mod tests {
temp_dir.close().unwrap() temp_dir.close().unwrap()
} }
/// Run a test function with a temporary config path as fixture.
fn with_config_path(test_fn: fn(&Path)) {
// Create a temporary directory for the config file
let config_dir = tempfile::tempdir().expect("creating test fixture failed");
// Create the config file path
let config_path =
config_dir.path().join("example-app").join("example-config").with_extension("toml");
// Run the test function with the config path
test_fn(&config_path);
config_dir.close().expect("removing test fixture failed");
}
#[test]
fn test_load_path_works() {
with_config_path(|path| {
let config = Config::from_path(path).expect("load_path failed");
assert_eq!(config, Config::default());
})
}
#[test]
fn test_load_path_reads_existing_config() {
with_config_path(|path| {
let config = Config::default();
// Create the parent directory if it doesn't exist
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).expect("Failed to create directories");
}
// Write the config to the file
std::fs::write(path, toml::to_string(&config).unwrap())
.expect("Failed to write config");
// Load the config from the file and compare it
let loaded = Config::from_path(path).expect("load_path failed");
assert_eq!(config, loaded);
})
}
#[test]
fn test_load_path_fails_on_invalid_toml() {
with_config_path(|path| {
let invalid_toml = "invalid toml data";
// Create the parent directory if it doesn't exist
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).expect("Failed to create directories");
}
// Write invalid TOML data to the file
std::fs::write(path, invalid_toml).expect("Failed to write invalid TOML");
// Attempt to load the config should fail
let result = Config::from_path(path);
assert!(result.is_err());
})
}
#[test]
fn test_load_path_creates_directory_if_not_exists() {
with_config_path(|path| {
// Ensure the directory does not exist
let parent = path.parent().unwrap();
assert!(!parent.exists());
// Load the configuration, which should create the directory and a default config file
let config = Config::from_path(path).expect("load_path failed");
assert_eq!(config, Config::default());
// The directory and file should now exist
assert!(parent.exists());
assert!(path.exists());
});
}
#[test] #[test]
fn test_store_config() { fn test_store_config() {
with_tempdir("config-store-test", |config_path| { with_tempdir("config-store-test", |config_path| {
let config = Config::default(); let config = Config::default();
confy::store_path(config_path, config).expect("Failed to store config"); std::fs::write(
config_path,
toml::to_string(&config).expect("Failed to serialize config"),
)
.expect("Failed to write config file");
}) })
} }
@ -415,9 +527,18 @@ mod tests {
fn test_load_config() { fn test_load_config() {
with_tempdir("config-load-test", |config_path| { with_tempdir("config-load-test", |config_path| {
let config = Config::default(); let config = Config::default();
confy::store_path(config_path, &config).unwrap();
let loaded_config: Config = confy::load_path(config_path).unwrap(); // Write the config to a file
std::fs::write(
config_path,
toml::to_string(&config).expect("Failed to serialize config"),
)
.expect("Failed to write config file");
// Load the config from the file
let loaded_config = Config::from_path(config_path).unwrap();
// Compare the loaded config with the original config
assert_eq!(config, loaded_config); assert_eq!(config, loaded_config);
}) })
} }
@ -427,9 +548,18 @@ mod tests {
with_tempdir("config-load-test", |config_path| { with_tempdir("config-load-test", |config_path| {
let mut config = Config::default(); let mut config = Config::default();
config.stages.execution.max_duration = Some(Duration::from_secs(10 * 60)); config.stages.execution.max_duration = Some(Duration::from_secs(10 * 60));
confy::store_path(config_path, &config).unwrap();
let loaded_config: Config = confy::load_path(config_path).unwrap(); // Write the config to a file
std::fs::write(
config_path,
toml::to_string(&config).expect("Failed to serialize config"),
)
.expect("Failed to write config file");
// Load the config from the file
let loaded_config = Config::from_path(config_path).unwrap();
// Compare the loaded config with the original config
assert_eq!(config, loaded_config); assert_eq!(config, loaded_config);
}) })
} }

View File

@ -76,7 +76,6 @@ secp256k1 = { workspace = true, features = [
aquamarine.workspace = true aquamarine.workspace = true
eyre.workspace = true eyre.workspace = true
fdlimit.workspace = true fdlimit.workspace = true
confy.workspace = true
rayon.workspace = true rayon.workspace = true
# tracing # tracing

View File

@ -117,7 +117,7 @@ impl LaunchContext {
pub fn load_toml_config(&self, config: &NodeConfig) -> eyre::Result<reth_config::Config> { pub fn load_toml_config(&self, config: &NodeConfig) -> eyre::Result<reth_config::Config> {
let config_path = config.config.clone().unwrap_or_else(|| self.data_dir.config()); let config_path = config.config.clone().unwrap_or_else(|| self.data_dir.config());
let mut toml_config = confy::load_path::<reth_config::Config>(&config_path) let mut toml_config = reth_config::Config::from_path(&config_path)
.wrap_err_with(|| format!("Could not load config file {config_path:?}"))?; .wrap_err_with(|| format!("Could not load config file {config_path:?}"))?;
Self::save_pruning_config_if_full_node(&mut toml_config, config, &config_path)?; Self::save_pruning_config_if_full_node(&mut toml_config, config, &config_path)?;
@ -970,12 +970,8 @@ mod tests {
) )
.unwrap(); .unwrap();
assert_eq!( let loaded_config = Config::from_path(config_path).unwrap();
reth_config.prune.as_ref().map(|p| p.block_interval),
node_config.prune_config().map(|p| p.block_interval)
);
let loaded_config: Config = confy::load_path(config_path).unwrap();
assert_eq!(reth_config, loaded_config); assert_eq!(reth_config, loaded_config);
}) })
} }

View File

@ -51,6 +51,8 @@ humantime.workspace = true
const_format.workspace = true const_format.workspace = true
rand.workspace = true rand.workspace = true
derive_more.workspace = true derive_more.workspace = true
toml.workspace = true
serde.workspace = true
# io # io
dirs-next = "2.0.0" dirs-next = "2.0.0"
@ -77,6 +79,7 @@ futures.workspace = true
# test vectors generation # test vectors generation
proptest.workspace = true proptest.workspace = true
tokio.workspace = true tokio.workspace = true
tempfile.workspace = true
[features] [features]
optimism = [ optimism = [

View File

@ -8,10 +8,13 @@ use crate::{
dirs::{ChainPath, DataDirPath}, dirs::{ChainPath, DataDirPath},
utils::get_single_header, utils::get_single_header,
}; };
use eyre::eyre;
use reth_chainspec::{ChainSpec, MAINNET}; use reth_chainspec::{ChainSpec, MAINNET};
use reth_config::config::PruneConfig; use reth_config::config::PruneConfig;
use reth_db_api::database::Database; use reth_db_api::database::Database;
use reth_network_p2p::headers::client::HeadersClient; use reth_network_p2p::headers::client::HeadersClient;
use serde::{de::DeserializeOwned, Serialize};
use std::{fs, path::Path};
use reth_primitives::{ use reth_primitives::{
revm_primitives::EnvKzgSettings, BlockHashOrNumber, BlockNumber, Head, SealedHeader, B256, revm_primitives::EnvKzgSettings, BlockHashOrNumber, BlockNumber, Head, SealedHeader, B256,
@ -365,6 +368,33 @@ impl NodeConfig {
pub fn datadir(&self) -> ChainPath<DataDirPath> { pub fn datadir(&self) -> ChainPath<DataDirPath> {
self.datadir.clone().resolve_datadir(self.chain.chain) self.datadir.clone().resolve_datadir(self.chain.chain)
} }
/// Load an application configuration from a specified path.
///
/// A new configuration file is created with default values if none
/// exists.
pub fn load_path<T: Serialize + DeserializeOwned + Default>(
path: impl AsRef<Path>,
) -> eyre::Result<T> {
let path = path.as_ref();
match fs::read_to_string(path) {
Ok(cfg_string) => {
toml::from_str(&cfg_string).map_err(|e| eyre!("Failed to parse TOML: {e}"))
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)
.map_err(|e| eyre!("Failed to create directory: {e}"))?;
}
let cfg = T::default();
let s = toml::to_string_pretty(&cfg)
.map_err(|e| eyre!("Failed to serialize to TOML: {e}"))?;
fs::write(path, s).map_err(|e| eyre!("Failed to write configuration file: {e}"))?;
Ok(cfg)
}
Err(e) => Err(eyre!("Failed to load configuration: {e}")),
}
}
} }
impl Default for NodeConfig { impl Default for NodeConfig {