add cli override for any configuration item
Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
parent
4e975887cf
commit
c423a83656
8 changed files with 68 additions and 14 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -708,6 +708,7 @@ dependencies = [
|
||||||
"tikv-jemallocator",
|
"tikv-jemallocator",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-metrics",
|
"tokio-metrics",
|
||||||
|
"toml",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
|
|
@ -35,6 +35,11 @@ version = "0.2.8"
|
||||||
version = "0.20"
|
version = "0.20"
|
||||||
features = ["features"]
|
features = ["features"]
|
||||||
|
|
||||||
|
[workspace.dependencies.toml]
|
||||||
|
version = "0.8.14"
|
||||||
|
default-features = false
|
||||||
|
features = ["parse"]
|
||||||
|
|
||||||
[workspace.dependencies.sanitize-filename]
|
[workspace.dependencies.sanitize-filename]
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,7 @@ tikv-jemalloc-sys.optional = true
|
||||||
tikv-jemalloc-sys.workspace = true
|
tikv-jemalloc-sys.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
tokio-metrics.workspace = true
|
tokio-metrics.workspace = true
|
||||||
|
toml.workspace = true
|
||||||
tracing-core.workspace = true
|
tracing-core.workspace = true
|
||||||
tracing-subscriber.workspace = true
|
tracing-subscriber.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
|
|
|
@ -9,10 +9,8 @@ use either::{
|
||||||
Either,
|
Either,
|
||||||
Either::{Left, Right},
|
Either::{Left, Right},
|
||||||
};
|
};
|
||||||
use figment::{
|
use figment::providers::{Env, Format, Toml};
|
||||||
providers::{Env, Format, Toml},
|
pub use figment::{value::Value as FigmentValue, Figment};
|
||||||
Figment,
|
|
||||||
};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use regex::RegexSet;
|
use regex::RegexSet;
|
||||||
use ruma::{
|
use ruma::{
|
||||||
|
@ -408,8 +406,8 @@ const DEPRECATED_KEYS: &[&str; 9] = &[
|
||||||
];
|
];
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
/// Initialize config
|
/// Pre-initialize config
|
||||||
pub fn new(path: &Option<PathBuf>) -> Result<Self> {
|
pub fn load(path: &Option<PathBuf>) -> Result<Figment> {
|
||||||
let raw_config = if let Some(config_file_env) = Env::var("CONDUIT_CONFIG") {
|
let raw_config = if let Some(config_file_env) = Env::var("CONDUIT_CONFIG") {
|
||||||
Figment::new()
|
Figment::new()
|
||||||
.merge(Toml::file(config_file_env).nested())
|
.merge(Toml::file(config_file_env).nested())
|
||||||
|
@ -431,13 +429,18 @@ impl Config {
|
||||||
.merge(Env::prefixed("CONDUWUIT_").global().split("__"))
|
.merge(Env::prefixed("CONDUWUIT_").global().split("__"))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Ok(raw_config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finalize config
|
||||||
|
pub fn new(raw_config: &Figment) -> Result<Self> {
|
||||||
let config = match raw_config.extract::<Self>() {
|
let config = match raw_config.extract::<Self>() {
|
||||||
Err(e) => return Err!("There was a problem with your configuration file: {e}"),
|
Err(e) => return Err!("There was a problem with your configuration file: {e}"),
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
};
|
};
|
||||||
|
|
||||||
// don't start if we're listening on both UNIX sockets and TCP at same time
|
// don't start if we're listening on both UNIX sockets and TCP at same time
|
||||||
check::is_dual_listening(&raw_config)?;
|
check::is_dual_listening(raw_config)?;
|
||||||
|
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,12 @@ pub enum Error {
|
||||||
HttpHeader(#[from] http::header::InvalidHeaderValue),
|
HttpHeader(#[from] http::header::InvalidHeaderValue),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
CargoToml(#[from] cargo_toml::Error),
|
CargoToml(#[from] cargo_toml::Error),
|
||||||
|
#[error("{0}")]
|
||||||
|
FigmentError(#[from] figment::error::Error),
|
||||||
|
#[error("{0}")]
|
||||||
|
TomlSerError(#[from] toml::ser::Error),
|
||||||
|
#[error("{0}")]
|
||||||
|
TomlDeError(#[from] toml::de::Error),
|
||||||
|
|
||||||
// ruma
|
// ruma
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
|
|
|
@ -10,6 +10,7 @@ pub mod pdu;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
pub use ::toml;
|
||||||
pub use config::Config;
|
pub use config::Config;
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use info::{rustc_flags_capture, version, version::version};
|
pub use info::{rustc_flags_capture, version, version::version};
|
||||||
|
|
|
@ -3,16 +3,24 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use conduit::{Config, Result};
|
use conduit::{
|
||||||
|
config::{Figment, FigmentValue},
|
||||||
|
err, toml, Err, Result,
|
||||||
|
};
|
||||||
|
|
||||||
/// Commandline arguments
|
/// Commandline arguments
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[clap(version = conduit::version(), about, long_about = None)]
|
#[clap(version = conduit::version(), about, long_about = None)]
|
||||||
pub(crate) struct Args {
|
pub(crate) struct Args {
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
/// Optional argument to the path of a conduwuit config TOML file
|
/// Path to the config TOML file (optional)
|
||||||
pub(crate) config: Option<PathBuf>,
|
pub(crate) config: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Override a configuration variable using TOML 'key=value' syntax
|
||||||
|
#[arg(long, short('O'))]
|
||||||
|
pub(crate) option: Vec<String>,
|
||||||
|
|
||||||
|
#[cfg(feature = "console")]
|
||||||
/// Activate admin command console automatically after startup.
|
/// Activate admin command console automatically after startup.
|
||||||
#[arg(long, num_args(0))]
|
#[arg(long, num_args(0))]
|
||||||
pub(crate) console: bool,
|
pub(crate) console: bool,
|
||||||
|
@ -23,10 +31,38 @@ pub(crate) struct Args {
|
||||||
pub(super) fn parse() -> Args { Args::parse() }
|
pub(super) fn parse() -> Args { Args::parse() }
|
||||||
|
|
||||||
/// Synthesize any command line options with configuration file options.
|
/// Synthesize any command line options with configuration file options.
|
||||||
pub(crate) fn update(config: &mut Config, args: &Args) -> Result<()> {
|
pub(crate) fn update(mut config: Figment, args: &Args) -> Result<Figment> {
|
||||||
|
#[cfg(feature = "console")]
|
||||||
// Indicate the admin console should be spawned automatically if the
|
// Indicate the admin console should be spawned automatically if the
|
||||||
// configuration file hasn't already.
|
// configuration file hasn't already.
|
||||||
config.admin_console_automatic |= args.console;
|
if args.console {
|
||||||
|
config = config.join(("admin_console_automatic", true));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
// All other individual overrides can go last in case we have options which
|
||||||
|
// set multiple conf items at once and the user still needs granular overrides.
|
||||||
|
for option in &args.option {
|
||||||
|
let (key, val) = option
|
||||||
|
.split_once('=')
|
||||||
|
.ok_or_else(|| err!("Missing '=' in -O/--option: {option:?}"))?;
|
||||||
|
|
||||||
|
if key.is_empty() {
|
||||||
|
return Err!("Missing key= in -O/--option: {option:?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if val.is_empty() {
|
||||||
|
return Err!("Missing =val in -O/--option: {option:?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The value has to pass for what would appear as a line in the TOML file.
|
||||||
|
let val = toml::from_str::<FigmentValue>(option)?;
|
||||||
|
let FigmentValue::Dict(_, val) = val else {
|
||||||
|
panic!("Unexpected Figment Value: {val:#?}");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Figment::merge() overrides existing
|
||||||
|
config = config.merge((key, val[key].clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,9 @@ pub(crate) struct Server {
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
pub(crate) fn build(args: &Args, runtime: Option<&runtime::Handle>) -> Result<Arc<Self>, Error> {
|
pub(crate) fn build(args: &Args, runtime: Option<&runtime::Handle>) -> Result<Arc<Self>, Error> {
|
||||||
let mut config = Config::new(&args.config)?;
|
let raw_config = Config::load(&args.config)?;
|
||||||
crate::clap::update(&mut config, args)?;
|
let raw_config = crate::clap::update(raw_config, args)?;
|
||||||
|
let config = Config::new(&raw_config)?;
|
||||||
|
|
||||||
#[cfg(feature = "sentry_telemetry")]
|
#[cfg(feature = "sentry_telemetry")]
|
||||||
let sentry_guard = crate::sentry::init(&config);
|
let sentry_guard = crate::sentry::init(&config);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue