diff options
author | Nick Mathewson <nickm@torproject.org> | 2024-03-13 18:52:39 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2024-03-13 18:52:39 +0000 |
commit | 6b120ec2117b8b0dfb5f0daa1746ec532cf3ad3a (patch) | |
tree | 29d14abc31afd46fe92fc1b869aa66dc1c94f988 | |
parent | dc3605c605b42a46450b39eec3f676a88cf4359f (diff) | |
parent | db912ae774dc378f78d7ad14b814f879c69a8f41 (diff) | |
download | arti-6b120ec2117b8b0dfb5f0daa1746ec532cf3ad3a.tar.gz arti-6b120ec2117b8b0dfb5f0daa1746ec532cf3ad3a.zip |
Merge branch 'encapsulate_config_rs' into 'main'
Encapsulate usage of config-rs inside tor-config.
See merge request tpo/core/arti!2040
-rw-r--r-- | Cargo.lock | 3 | ||||
-rw-r--r-- | crates/arti-client/src/config.rs | 4 | ||||
-rw-r--r-- | crates/arti-testing/Cargo.toml | 4 | ||||
-rw-r--r-- | crates/arti/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/arti/src/cfg.rs | 26 | ||||
-rw-r--r-- | crates/arti/src/reload_cfg.rs | 1 | ||||
-rw-r--r-- | crates/tor-config/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/tor-config/README.md | 2 | ||||
-rw-r--r-- | crates/tor-config/semver.md | 5 | ||||
-rw-r--r-- | crates/tor-config/src/err.rs | 17 | ||||
-rw-r--r-- | crates/tor-config/src/lib.rs | 39 | ||||
-rw-r--r-- | crates/tor-config/src/list_builder.rs | 8 | ||||
-rw-r--r-- | crates/tor-config/src/load.rs | 62 | ||||
-rw-r--r-- | crates/tor-config/src/path.rs | 14 | ||||
-rw-r--r-- | crates/tor-config/src/sources.rs | 72 | ||||
-rw-r--r-- | crates/tor-ptmgr/Cargo.toml | 4 | ||||
-rw-r--r-- | crates/tor-ptmgr/src/ipc.rs | 2 |
17 files changed, 159 insertions, 106 deletions
diff --git a/Cargo.lock b/Cargo.lock index 650abfa7b..206a1b080 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -204,7 +204,6 @@ dependencies = [ "backtrace", "cfg-if", "clap", - "config", "derive_builder_fork_arti", "derive_more", "educe", @@ -388,7 +387,6 @@ dependencies = [ "async-trait", "cfg-if", "clap", - "config", "futures", "pin-project", "rand", @@ -5803,6 +5801,7 @@ dependencies = [ "derive_builder_fork_arti", "fs-mistrust", "futures", + "itertools 0.12.1", "serde", "thiserror", "tokio", diff --git a/crates/arti-client/src/config.rs b/crates/arti-client/src/config.rs index dc09ce49a..d82d6e7c3 100644 --- a/crates/arti-client/src/config.rs +++ b/crates/arti-client/src/config.rs @@ -924,8 +924,8 @@ mod test { // here, so we'll just make sure it does _something_ plausible. let dflt = default_config_files().unwrap(); - assert!(dflt[0].as_path().ends_with("arti.toml")); - assert!(dflt[1].as_path().ends_with("arti.d")); + assert!(dflt[0].as_path().unwrap().ends_with("arti.toml")); + assert!(dflt[1].as_path().unwrap().ends_with("arti.d")); assert_eq!(dflt.len(), 2); } diff --git a/crates/arti-testing/Cargo.toml b/crates/arti-testing/Cargo.toml index 92eb68981..da9ef33c0 100644 --- a/crates/arti-testing/Cargo.toml +++ b/crates/arti-testing/Cargo.toml @@ -21,7 +21,8 @@ full = [ "tor-dirmgr/full", "tor-error/full", "tor-netdoc/full", - "tor-rtcompat/full", "tor-basic-utils/full", + "tor-rtcompat/full", + "tor-basic-utils/full", ] [dependencies] @@ -31,7 +32,6 @@ arti-client = { package = "arti-client", path = "../arti-client", version = "0.1 async-trait = "0.1.54" cfg-if = "1.0.0" clap = { version = "4.3.24", features = ["wrap_help"] } -config = { version = "0.14.0", default-features = false } futures = "0.3.14" pin-project = "1" rand = "0.8" diff --git a/crates/arti/Cargo.toml b/crates/arti/Cargo.toml index 1f742de9c..80f1270d1 100644 --- a/crates/arti/Cargo.toml +++ b/crates/arti/Cargo.toml @@ -100,7 +100,6 @@ async-ctrlc = { version = "1.2.0", optional = true } backtrace = "0.3.68" cfg-if = "1.0.0" clap = { version = "4.3.24", features = ["string", "wrap_help"] } -config = { version = "0.14.0", default-features = false, features = ["toml"] } derive_builder = { version = "0.11", package = "derive_builder_fork_arti" } educe = "0.4.6" fs-mistrust = { path = "../fs-mistrust", version = "0.7.7" } diff --git a/crates/arti/src/cfg.rs b/crates/arti/src/cfg.rs index 1d77072a9..f87a7251f 100644 --- a/crates/arti/src/cfg.rs +++ b/crates/arti/src/cfg.rs @@ -601,7 +601,9 @@ mod test { fn default_config() { use InExample::*; - let empty_config = config::Config::builder().build().unwrap(); + let empty_config = tor_config::ConfigurationSources::new_empty() + .load() + .unwrap(); let empty_config: ArtiCombinedConfig = tor_config::resolve(empty_config).unwrap(); let default = (ArtiConfig::default(), TorClientConfig::default()); @@ -662,10 +664,14 @@ mod test { } let parses_to_defaults = |example: &str, which: WhichExample, uncommented: bool| { - let cfg = config::Config::builder() - .add_source(config::File::from_str(example, config::FileFormat::Toml)) - .build() - .unwrap(); + let cfg = { + let mut sources = tor_config::ConfigurationSources::new_empty(); + sources.push_source( + tor_config::ConfigurationSource::from_verbatim(example.to_string()), + tor_config::sources::MustRead::MustRead, + ); + sources.load().unwrap() + }; // This tests that the example settings do not *contradict* the defaults. let results: ResolutionResults<ArtiCombinedConfig> = @@ -1242,11 +1248,15 @@ example config file {which:?}, uncommented={uncommented:?} /// Make a TOML document of this section and parse it as a complete configuration. /// Panic if the section cannot be parsed. - fn parse(&self) -> config::Config { + fn parse(&self) -> tor_config::ConfigurationTree { let s = self.build_string(); eprintln!("parsing\n --\n{}\n --", &s); - let c: toml::Value = toml::from_str(&s).expect(&s); - config::Config::try_from(&c).expect(&s) + let mut sources = tor_config::ConfigurationSources::new_empty(); + sources.push_source( + tor_config::ConfigurationSource::from_verbatim(s.to_string()), + tor_config::sources::MustRead::MustRead, + ); + sources.load().expect(&s) } fn resolve<R: tor_config::load::Resolvable>(&self) -> Result<R, ConfigResolveError> { diff --git a/crates/arti/src/reload_cfg.rs b/crates/arti/src/reload_cfg.rs index 0a664dc8c..41b0638e7 100644 --- a/crates/arti/src/reload_cfg.rs +++ b/crates/arti/src/reload_cfg.rs @@ -322,6 +322,7 @@ impl FileWatcherBuilder { match source { ConfigurationSource::Dir(dir) => self.watch_dir(dir)?, ConfigurationSource::File(file) => self.watch_file(file)?, + ConfigurationSource::Verbatim(_) => {} } } Ok(sources) diff --git a/crates/tor-config/Cargo.toml b/crates/tor-config/Cargo.toml index 680a5e7aa..14c2c2805 100644 --- a/crates/tor-config/Cargo.toml +++ b/crates/tor-config/Cargo.toml @@ -51,7 +51,6 @@ tracing = "0.1.36" void = "1" [dev-dependencies] -config = { version = "0.14.0", default-features = false, features = ["toml"] } dirs = "5.0.0" rmp-serde = "1" serde_json = "1.0.50" diff --git a/crates/tor-config/README.md b/crates/tor-config/README.md index 48a254243..cdea6d420 100644 --- a/crates/tor-config/README.md +++ b/crates/tor-config/README.md @@ -25,7 +25,7 @@ works as follows: 2. [`ConfigurationSources::load`] actually *reads* all of these sources, parses them (eg, as TOML files), - and returns a [`config::Config`]. + and returns a [`ConfigurationTree`]. This is a tree-structured dynamically typed data structure, mirroring the input configuration structure, largely unvalidated, and containing everything in the input config sources. diff --git a/crates/tor-config/semver.md b/crates/tor-config/semver.md new file mode 100644 index 000000000..1c39155ce --- /dev/null +++ b/crates/tor-config/semver.md @@ -0,0 +1,5 @@ +BREAKING: Several re-exported macro dependencies are now hidden. +BREAKING: ConfigurationSource can now be Verbatim +BREAKING: ConfigurationSource::as_path() has a new return type; AsRef<Path> is gone. +BREAKING: config::Config is no longer exposed. + diff --git a/crates/tor-config/src/err.rs b/crates/tor-config/src/err.rs index a3a23b4e8..993b240b2 100644 --- a/crates/tor-config/src/err.rs +++ b/crates/tor-config/src/err.rs @@ -130,12 +130,16 @@ impl HasKind for ReconfigureError { } } -/// Wrapper for [`config::ConfigError`] with a more helpful error message. +/// Wrapper for an error type from our underlying configuration library. #[derive(Debug, Clone)] pub struct ConfigError(Arc<config::ConfigError>); -impl From<config::ConfigError> for ConfigError { - fn from(err: config::ConfigError) -> Self { +impl ConfigError { + /// Wrap `err` as a ConfigError. + /// + /// This is not a From implementation, since we don't want to expose our + /// underlying configuration library. + pub(crate) fn from_cfg_err(err: config::ConfigError) -> Self { ConfigError(Arc::new(err)) } } @@ -157,13 +161,6 @@ impl std::error::Error for ConfigError { } } -impl ConfigError { - /// Return the inner [`config::ConfigError`] that this is wrapping. - pub fn inner(&self) -> &config::ConfigError { - self.0.as_ref() - } -} - #[cfg(test)] mod test { // @@ begin test lint list maintained by maint/add_warning @@ diff --git a/crates/tor-config/src/lib.rs b/crates/tor-config/src/lib.rs index d6e340a0c..6c29fd541 100644 --- a/crates/tor-config/src/lib.rs +++ b/crates/tor-config/src/lib.rs @@ -51,28 +51,49 @@ mod mut_cfg; mod path; pub mod sources; +#[doc(hidden)] +pub mod deps { + pub use config; + pub use educe; + pub use itertools::Itertools; + pub use paste::paste; + pub use serde; + pub use tor_basic_utils::macro_first_nonempty; +} + pub use cmdline::CmdLine; -pub use config as config_crate; -pub use educe; pub use err::{ConfigBuildError, ConfigError, ReconfigureError}; pub use flatten::{Flatten, Flattenable}; -pub use itertools::Itertools; pub use list_builder::{MultilineListBuilder, MultilineListBuilderError}; pub use load::{resolve, resolve_ignore_warnings, resolve_return_results}; pub use misc::*; pub use mut_cfg::MutCfg; -pub use paste::paste; pub use path::{CfgPath, CfgPathError}; -pub use serde; pub use sources::{ConfigurationSource, ConfigurationSources}; -pub use tor_basic_utils::macro_first_nonempty; +use itertools::Itertools; #[doc(hidden)] pub use derive_adhoc; #[doc(hidden)] pub use flatten::flattenable_extract_fields; +/// A set of configuration fields, represented as a set of nested K=V +/// mappings. +/// +/// (This is a wrapper for an underlying type provided by the library that +/// actually does our configuration.) +#[derive(Clone, Debug)] +pub struct ConfigurationTree(config::Config); + +#[cfg(test)] +impl ConfigurationTree { + #[cfg(test)] + pub(crate) fn get_string(&self, key: &str) -> Result<String, crate::ConfigError> { + self.0.get_string(key).map_err(ConfigError::from_cfg_err) + } +} + /// Rules for reconfiguring a running Arti instance. #[derive(Debug, Clone, Copy, Eq, PartialEq)] #[non_exhaustive] @@ -315,7 +336,7 @@ where /// * `impl Default for $Config` /// * `impl Builder for $ConfigBuilder` /// * a self-test that the `Default` impl actually works -/// * a test that the `Builder` can be deserialized from an empty [`config::Config`], +/// * a test that the `Builder` can be deserialized from an empty [`ConfigurationTree`], /// and then built, and that the result is the same as the ordinary default. // // The implementation munches fake "trait bounds" (`: !Deserialize + !Wombat ...`) off the RHS. @@ -383,7 +404,7 @@ macro_rules! impl_standard_builder { @ ( $($Builder :ident)? ) ( $($default :ident)? ) ( $($try_deserialize:ident)? ) $Config:ty : $(+)? - } => { $crate::paste!{ + } => { $crate::deps::paste!{ impl $Config { /// Returns a fresh, default, builder pub fn builder() -> [< $Config Builder >] { @@ -420,7 +441,7 @@ macro_rules! impl_standard_builder { if let Some(def) = def { $( // expands iff there was $try_deserialize, which is always try_deserialize - let empty_config = $crate::config_crate::Config::builder().build().unwrap(); + let empty_config = $crate::deps::config::Config::builder().build().unwrap(); let builder: [< $Config Builder >] = empty_config.$try_deserialize().unwrap(); let from_empty = builder.build().unwrap(); assert_eq!(def, from_empty); diff --git a/crates/tor-config/src/list_builder.rs b/crates/tor-config/src/list_builder.rs index 1db8727b1..51570642c 100644 --- a/crates/tor-config/src/list_builder.rs +++ b/crates/tor-config/src/list_builder.rs @@ -225,8 +225,8 @@ macro_rules! define_list_builder_helper { $( item_build: $item_build:expr; )? $(#[ serde $serde_attrs:tt ] )+ } => { - #[derive($crate::educe::Educe, Clone, Debug)] - #[derive($crate::serde::Serialize, $crate::serde::Deserialize)] + #[derive($crate::deps::educe::Educe, Clone, Debug)] + #[derive($crate::deps::serde::Serialize, $crate::deps::serde::Deserialize)] #[educe(Default)] $(#[ serde $serde_attrs ])+ $(#[ $docs_and_attrs ])* @@ -263,7 +263,7 @@ macro_rules! define_list_builder_helper { let $things = $things .iter() .map( - $crate::macro_first_nonempty!{ + $crate::deps::macro_first_nonempty!{ [ $( $item_build )? ], [ |item| item.build() ], } @@ -356,7 +356,7 @@ macro_rules! define_list_builder_accessors { )* } } => { - impl $OuterBuilder { $( $crate::paste!{ + impl $OuterBuilder { $( $crate::deps::paste!{ /// Access the being-built list (resolving default) /// /// If the field has not yet been set or accessed, the default list will be diff --git a/crates/tor-config/src/load.rs b/crates/tor-config/src/load.rs index 2ad34a925..506cb8384 100644 --- a/crates/tor-config/src/load.rs +++ b/crates/tor-config/src/load.rs @@ -1,8 +1,8 @@ -//! Processing a config::Config into a validated configuration +//! Processing a `ConfigurationTree` into a validated configuration //! //! This module, and particularly [`resolve`], takes care of: //! -//! * Deserializing a [`config::Config`] into various `FooConfigBuilder` +//! * Deserializing a [`ConfigurationTree`] into various `FooConfigBuilder` //! * Calling the `build()` methods to get various `FooConfig`. //! * Reporting unrecognised configuration keys //! (eg to help the user detect misspellings). @@ -21,7 +21,7 @@ //! //! * [`impl TopLevel`](TopLevel) for your *top level* structures (only). //! -//! * Call [`resolve`] (or one of its variants) with a `config::Config`, +//! * Call [`resolve`] (or one of its variants) with a `ConfigurationTree`, //! to obtain your top-level configuration(s). //! //! # Example @@ -33,7 +33,7 @@ //! for additional configuration settings for the added features. //! * Establishes some configuration sources //! (the trivial empty `ConfigSources`, to avoid clutter in the example) -//! * Reads those sources into a single configuration taxonomy [`config::Config`]. +//! * Reads those sources into a single configuration taxonomy [`ConfigurationTree`]. //! * Processes that configuration into a 3-tuple of configuration //! structs for the three components, namely: //! - `TorClientConfig`, the configuration for the `arti_client` crate's `TorClient` @@ -96,7 +96,7 @@ use serde::de::DeserializeOwned; use thiserror::Error; use tracing::warn; -use crate::ConfigBuildError; +use crate::{ConfigBuildError, ConfigurationTree}; /// Error resolving a configuration (during deserialize, or build) #[derive(Error, Debug)] @@ -111,12 +111,6 @@ pub enum ConfigResolveError { Build(#[from] ConfigBuildError), } -impl From<config::ConfigError> for ConfigResolveError { - fn from(err: config::ConfigError) -> Self { - crate::ConfigError::from(err).into() - } -} - /// A type that can be built from a builder via a build method pub trait Builder { /// The type that this builder constructs @@ -230,7 +224,7 @@ define_for_tuples! { A - B C D E } /// You don't want to try to obtain one. pub struct ResolveContext { /// The input - input: config::Config, + input: ConfigurationTree, /// Paths unrecognized by all deserializations /// @@ -303,7 +297,7 @@ enum PathEntry { /// /// Inner function used by all the `resolve_*` family fn resolve_inner<T>( - input: config::Config, + input: ConfigurationTree, want_disfavoured: bool, ) -> Result<ResolutionResults<T>, ConfigResolveError> where @@ -314,7 +308,7 @@ where if want_disfavoured { T::enumerate_deprecated_keys(&mut |l: &[&str]| { for key in l { - match input.get(key) { + match input.0.get(key) { Err(_) => {} Ok(serde::de::IgnoredAny) => { deprecated.insert(key); @@ -373,7 +367,7 @@ where /// /// For an example, see the /// [`tor_config::load` module-level documentation](self). -pub fn resolve<T>(input: config::Config) -> Result<T, ConfigResolveError> +pub fn resolve<T>(input: ConfigurationTree) -> Result<T, ConfigResolveError> where T: Resolvable, { @@ -393,7 +387,7 @@ where /// Deserialize and build overall configuration, reporting unrecognized keys in the return value pub fn resolve_return_results<T>( - input: config::Config, + input: ConfigurationTree, ) -> Result<ResolutionResults<T>, ConfigResolveError> where T: Resolvable, @@ -416,7 +410,7 @@ pub struct ResolutionResults<T> { } /// Deserialize and build overall configuration, silently ignoring unrecognized config keys -pub fn resolve_ignore_warnings<T>(input: config::Config) -> Result<T, ConfigResolveError> +pub fn resolve_ignore_warnings<T>(input: ConfigurationTree) -> Result<T, ConfigResolveError> where T: Resolvable, { @@ -436,13 +430,13 @@ where // That is how this tracking is disabled when we want it to be. let want_unrecognized = !input.unrecognized.is_empty(); let ret = if !want_unrecognized { - deser.try_deserialize() + deser.0.try_deserialize() } else { let mut nign = BTreeSet::new(); let mut recorder = |path: serde_ignored::Path<'_>| { nign.insert(copy_path(&path)); }; - let deser = serde_ignored::Deserializer::new(deser, &mut recorder); + let deser = serde_ignored::Deserializer::new(deser.0, &mut recorder); let ret = serde::Deserialize::deserialize(deser); if ret.is_err() { // If we got an error, the config might only have been partially processed, @@ -452,7 +446,7 @@ where input.unrecognized.intersect_with(nign); ret }; - ret? + ret.map_err(crate::ConfigError::from_cfg_err)? }; let built = builder.build()?; Ok(built) @@ -784,12 +778,14 @@ mod test { a = "hi" old = true "#; - let source = config::File::from_str(test_data, config::FileFormat::Toml); - - let cfg = config::Config::builder() - .add_source(source) - .build() - .unwrap(); + let cfg = { + let mut sources = crate::ConfigurationSources::new_empty(); + sources.push_source( + crate::ConfigurationSource::from_verbatim(test_data.to_string()), + crate::sources::MustRead::MustRead, + ); + sources.load().unwrap() + }; let _: (TestConfigA, TestConfigB) = resolve_ignore_warnings(cfg.clone()).unwrap(); @@ -836,11 +832,15 @@ mod test { // suppress a dead-code warning. let _b = TestConfigC::builder(); - let source = config::File::from_str(test_data, config::FileFormat::Toml); - let cfg = config::Config::builder() - .add_source(source) - .build() - .unwrap(); + let cfg = { + let mut sources = crate::ConfigurationSources::new_empty(); + sources.push_source( + crate::ConfigurationSource::from_verbatim(test_data.to_string()), + crate::sources::MustRead::MustRead, + ); + sources.load().unwrap() + }; + { // First try "A", then "C". let res1: Result<ResolutionResults<(TestConfigA, TestConfigC)>, _> = diff --git a/crates/tor-config/src/path.rs b/crates/tor-config/src/path.rs index aa7cc6f2f..476d04ae2 100644 --- a/crates/tor-config/src/path.rs +++ b/crates/tor-config/src/path.rs @@ -405,13 +405,15 @@ mod test_serde { } fn deser_toml_cfg(toml: &str) -> CfgPath { dbg!(toml); - let cfg = config::File::from_str(toml, config::FileFormat::Toml); - let cfg = config::Config::builder() - .add_source(cfg) - .build() - .expect("parse toml failed"); + let mut sources = crate::ConfigurationSources::new_empty(); + sources.push_source( + crate::ConfigurationSource::from_verbatim(toml.to_string()), + crate::sources::MustRead::MustRead, + ); + let cfg = sources.load().unwrap(); + dbg!(&cfg); - let TestConfigFile { p } = cfg.try_deserialize().expect("deser cfg failed"); + let TestConfigFile { p } = cfg.0.try_deserialize().expect("deser cfg failed"); p } diff --git a/crates/tor-config/src/sources.rs b/crates/tor-config/src/sources.rs index 00a64a623..687952bfa 100644 --- a/crates/tor-config/src/sources.rs +++ b/crates/tor-config/src/sources.rs @@ -2,7 +2,8 @@ //! //! This module provides [`ConfigurationSources`]. //! -//! This layer brings together the functionality of [`config::File`], +//! This layer brings together the functionality of +//! our underlying configuration library, //! [`fs_mistrust`] and [`tor_config::cmdline`](crate::cmdline). //! //! A `ConfigurationSources` records a set of filenames of TOML files, @@ -12,7 +13,7 @@ //! Usually, call [`ConfigurationSources::from_cmdline`], //! perhaps [`set_mistrust`](ConfigurationSources::set_mistrust), //! and finally [`load`](ConfigurationSources::load). -//! The resulting [`config::Config`] can then be deserialized. +//! The resulting [`ConfigurationTree`] can then be deserialized. //! //! If you want to watch for config file changes, //! use [`ConfigurationSources::scan()`], @@ -23,12 +24,12 @@ //! which is necessary to avoid possibly missing changes.) use std::ffi::OsString; -use std::{fs, io}; +use std::{fs, io, sync::Arc}; use void::ResultVoidExt as _; use crate::err::ConfigError; -use crate::CmdLine; +use crate::{CmdLine, ConfigurationTree}; /// The synchronous configuration builder type we use. /// @@ -68,13 +69,16 @@ pub enum MustRead { /// You can make one out of a `PathBuf`, examining its syntax like `arti` does, /// using `ConfigurationSource::from_path`. #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] -#[allow(clippy::exhaustive_enums)] // Callers will need to understand this +#[allow(clippy::exhaustive_enums)] pub enum ConfigurationSource { /// A plain file File(PathBuf), /// A directory Dir(PathBuf), + + /// A verbatim TOML file + Verbatim(Arc<String>), } impl ConfigurationSource { @@ -94,17 +98,17 @@ impl ConfigurationSource { } } - /// Return a reference to the inner `Path` - pub fn as_path(&self) -> &Path { - self.as_ref() + /// Use the provided text as verbatim TOML, as if it had been read from disk. + pub fn from_verbatim(text: String) -> ConfigurationSource { + Self::Verbatim(Arc::new(text)) } -} -impl AsRef<PathBuf> for ConfigurationSource { - fn as_ref(&self) -> &PathBuf { + /// Return a reference to the inner `Path`, if there is one. + pub fn as_path(&self) -> Option<&Path> { use ConfigurationSource as CS; match self { - CS::File(p) | CS::Dir(p) => p, + CS::File(p) | CS::Dir(p) => Some(p), + CS::Verbatim(_) => None, } } } @@ -248,11 +252,11 @@ impl ConfigurationSources { &self.mistrust } - /// Scan for files and load the configuration into a new [`config::Config`]. + /// Scan for files and load the configuration into a new [`ConfigurationTree`]. /// /// This is a convenience method for [`scan()`](Self::scan) /// followed by [`files.load`]. - pub fn load(&self) -> Result<config::Config, ConfigError> { + pub fn load(&self) -> Result<ConfigurationTree, ConfigError> { let files = self.scan()?; files.load() } @@ -270,12 +274,13 @@ impl ConfigurationSources { if e.kind() == io::ErrorKind::NotFound && !required { Result::<_, crate::ConfigError>::Ok(()) } else { - Err(config::ConfigError::Message(format!( - "unable to access config path: {:?}: {}", - &source.as_path(), - e + Err(crate::ConfigError::from_cfg_err( + config::ConfigError::Message(format!( + "unable to access config path: {:?}: {}", + &source.as_path(), + e + )), )) - .into()) } }; @@ -319,7 +324,7 @@ impl ConfigurationSources { must_read: MustRead::TolerateAbsence, })); } - CS::File(_) => { + CS::File(_) | CS::Verbatim(_) => { out.push(FoundConfigFile { source: source.clone(), must_read, @@ -354,6 +359,11 @@ impl FoundConfigFiles<'_> { let file = match source { CS::File(file) => file, CS::Dir(_) => continue, + CS::Verbatim(text) => { + builder = + builder.add_source(config::File::from_str(&text, config::FileFormat::Toml)); + continue; + } }; match self @@ -383,11 +393,13 @@ impl FoundConfigFiles<'_> { Ok(builder) } - /// Load the configuration into a new [`config::Config`]. - pub fn load(self) -> Result<config::Config, ConfigError> { + /// Load the configuration into a new [`ConfigurationTree`]. + pub fn load(self) -> Result<ConfigurationTree, ConfigError> { let mut builder = config::Config::builder(); builder = self.add_sources(builder)?; - Ok(builder.build()?) + Ok(ConfigurationTree( + builder.build().map_err(ConfigError::from_cfg_err)?, + )) } } @@ -422,7 +434,7 @@ fn foreign_err<E>(err: E) -> crate::ConfigError where E: Into<Box<dyn std::error::Error + Send + Sync>>, { - crate::ConfigError::from(config::ConfigError::Foreign(err.into())) + crate::ConfigError::from_cfg_err(config::ConfigError::Foreign(err.into())) } #[cfg(test)] @@ -474,7 +486,7 @@ friends = 4242 fn load_nodefaults<P: AsRef<Path>>( files: &[(P, MustRead)], opts: &[String], - ) -> Result<config::Config, crate::ConfigError> { + ) -> Result<ConfigurationTree, crate::ConfigError> { sources_nodefaults(files, opts).load() } @@ -527,7 +539,13 @@ world = \"nonsense\" assert_eq!( found .iter() - .map(|p| p.as_path().strip_prefix(&td).unwrap().to_str().unwrap()) + .map(|p| p + .as_path() + .unwrap() + .strip_prefix(&td) + .unwrap() + .to_str() + .unwrap()) .collect_vec(), &["1.toml", "extra.d", "extra.d/2.toml"] ); @@ -571,7 +589,7 @@ world = \"nonsense\" let files: Vec<_> = sources .files .iter() - .map(|file| file.0.as_ref().to_str().unwrap()) + .map(|file| file.0.as_path().unwrap().to_str().unwrap()) .collect(); assert_eq!(files, vec!["/family/yor.toml", "/family/anya.toml"]); assert_eq!(sources.files[0].1, MustRead::MustRead); diff --git a/crates/tor-ptmgr/Cargo.toml b/crates/tor-ptmgr/Cargo.toml index a51f50337..9d6361ca5 100644 --- a/crates/tor-ptmgr/Cargo.toml +++ b/crates/tor-ptmgr/Cargo.toml @@ -22,7 +22,8 @@ full = [ "tor-error/full", "tor-linkspec/full", "tor-rtcompat/full", - "tor-socksproto/full", "tor-async-utils/full", + "tor-socksproto/full", + "tor-async-utils/full", ] experimental = ["experimental-api"] @@ -34,6 +35,7 @@ async-trait = "0.1.54" derive_builder = { version = "0.11.2", package = "derive_builder_fork_arti" } fs-mistrust = { version = "0.7.7", path = "../fs-mistrust" } futures = "0.3.14" +itertools = "0.12.0" serde = { version = "1.0.103", features = ["derive"] } thiserror = "1" tor-async-utils = { version = "0.1.5", path = "../tor-async-utils" } diff --git a/crates/tor-ptmgr/src/ipc.rs b/crates/tor-ptmgr/src/ipc.rs index cd65fb19c..50e15b1b0 100644 --- a/crates/tor-ptmgr/src/ipc.rs +++ b/crates/tor-ptmgr/src/ipc.rs @@ -9,6 +9,7 @@ use crate::err::PtError; use futures::channel::mpsc; use futures::channel::mpsc::Receiver; use futures::StreamExt; +use itertools::Itertools; use std::borrow::Cow; use std::collections::HashMap; use std::ffi::OsString; @@ -21,7 +22,6 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use std::{io, thread}; use tor_basic_utils::PathExt as _; -use tor_config::Itertools; use tor_error::{internal, warn_report}; use tor_linkspec::PtTransportName; use tor_rtcompat::{Runtime, SleepProviderExt}; |