use crate::error::ConfigError;
use super::Layer;
use super::file::FileSource;
use super::overrides::parse_override_value;
use super::path::try_normalize_external_path;
mod claim;
mod layer;
use self::layer::ArgsLayerState;
#[derive(Debug, Clone)]
pub struct ArgsSource {
args: Vec<String>,
}
impl ArgsSource {
#[must_use]
pub fn from_env() -> Self {
Self::from_args(std::env::args())
}
#[must_use]
pub fn from_args<I, S>(iter: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
Self {
args: iter.into_iter().map(Into::into).collect(),
}
}
}
#[derive(Debug, Clone)]
pub(super) struct ParsedArgs {
pub(super) profile: Option<String>,
pub(super) files: Vec<FileSource>,
pub(super) layer: Option<Layer>,
}
pub(super) fn parse_args(source: ArgsSource) -> Result<ParsedArgs, ConfigError> {
let mut args = source.args.into_iter();
let mut files = Vec::new();
let mut profile = None;
let mut layer = ArgsLayerState::new();
while let Some(arg) = args.next() {
if let Some(value) = arg.strip_prefix("--config=") {
files.push(FileSource::new(value));
continue;
}
if arg == "--config" {
let value = args.next().ok_or_else(|| ConfigError::MissingArgValue {
flag: "--config".to_owned(),
})?;
files.push(FileSource::new(value));
continue;
}
if let Some(value) = arg.strip_prefix("--profile=") {
profile = Some(value.to_owned());
continue;
}
if arg == "--profile" {
profile = Some(args.next().ok_or_else(|| ConfigError::MissingArgValue {
flag: "--profile".to_owned(),
})?);
continue;
}
let set_value = if let Some(value) = arg.strip_prefix("--set=") {
Some(value.to_owned())
} else if arg == "--set" {
Some(args.next().ok_or_else(|| ConfigError::MissingArgValue {
flag: "--set".to_owned(),
})?)
} else {
None
};
let Some(set_value) = set_value else {
continue;
};
let (raw_path, raw_value) =
set_value
.split_once('=')
.ok_or_else(|| ConfigError::InvalidArg {
arg: set_value.clone(),
message: "expected key=value".to_owned(),
})?;
let path =
try_normalize_external_path(raw_path).map_err(|message| ConfigError::InvalidArg {
arg: format!("--set {raw_path}={raw_value}"),
message,
})?;
if path.is_empty() {
return Err(ConfigError::InvalidArg {
arg: set_value,
message: "configuration path cannot be empty".to_owned(),
});
}
let parsed =
parse_override_value(raw_value).map_err(|message| ConfigError::InvalidArg {
arg: format!("--set {path}={raw_value}"),
message,
})?;
let arg_trace_name = format!("--set {raw_path}={raw_value}");
layer.insert_override(
&arg_trace_name,
&path,
parsed,
format!("--set {path}={raw_value}"),
)?;
}
Ok(ParsedArgs {
profile,
files,
layer: layer.into_layer(),
})
}