Skip to content

Commit

Permalink
feat(config): config files are now kdl-based
Browse files Browse the repository at this point in the history
Fixes: #153
  • Loading branch information
zkat committed Apr 3, 2023
1 parent 868a42b commit 09e81bd
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 32 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/oro-config/Cargo.toml
Expand Up @@ -12,7 +12,8 @@ rust-version = "1.67.1"

[dependencies]
clap = { workspace = true, features = ["string"] }
config = { workspace = true, features = ["toml"] }
config = { workspace = true, default-features = false }
kdl = { workspace = true }
miette = { workspace = true }
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
Expand Down
13 changes: 13 additions & 0 deletions crates/oro-config/src/error.rs
@@ -0,0 +1,13 @@
use miette::Diagnostic;
use thiserror::Error;

#[derive(Debug, Error, Diagnostic)]
pub enum OroConfigError {
#[error(transparent)]
#[diagnostic(code(config::error))]
ConfigError(#[from] config::ConfigError),

#[error(transparent)]
#[diagnostic(code(config::error))]
ConfigParseError(#[from] Box<dyn std::error::Error + Send + Sync>),
}
63 changes: 63 additions & 0 deletions crates/oro-config/src/kdl_source.rs
@@ -0,0 +1,63 @@
use config::{ConfigError, FileStoredFormat, Format, Map, Source, Value, ValueKind};
use kdl::{KdlDocument, KdlValue};

#[derive(Clone, Debug)]
pub(crate) struct KdlSource(KdlDocument);

impl Source for KdlSource {
fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
Box::new(self.clone())
}

fn collect(&self) -> Result<Map<String, Value>, ConfigError> {
let mut map = Map::new();
for node in self.0.nodes() {
let key = node.name().to_string();
if let Some(value) = node.get(0) {
let value = Value::new(
Some(&if let Some(str) = value.as_string() {
str.to_owned()
} else {
value.to_string()
}),
value_kind(value),
);
map.insert(key, value);
}
}
Ok(map)
}
}

#[derive(Clone, Debug)]
pub(crate) struct KdlFormat;

impl Format for KdlFormat {
fn parse(
&self,
_uri: Option<&String>,
text: &str,
) -> Result<Map<String, Value>, Box<dyn std::error::Error + Send + Sync>> {
Ok(KdlSource(text.parse()?).collect()?)
}
}

impl FileStoredFormat for KdlFormat {
fn file_extensions(&self) -> &'static [&'static str] {
&["kdl"]
}
}

fn value_kind(value: &KdlValue) -> ValueKind {
if let Some(str) = value.as_string() {
ValueKind::String(str.into())
} else if let Some(num) = value.as_i64() {
ValueKind::I64(num)
} else if let Some(float) = value.as_f64() {
ValueKind::Float(float)
} else if let Some(boolean) = value.as_bool() {
ValueKind::Boolean(boolean)
} else {
ValueKind::Nil
}
}
44 changes: 14 additions & 30 deletions crates/oro-config/src/lib.rs
Expand Up @@ -2,14 +2,20 @@

use std::{
collections::{HashMap, HashSet},
path::PathBuf, ffi::OsString,
ffi::OsString,
path::PathBuf,
};

pub use clap::{ArgMatches, Command};
pub use config::Config as OroConfig;
use config::{builder::DefaultState, ConfigBuilder, ConfigError, Environment, File};
use miette::{Diagnostic, Result};
use thiserror::Error;
use config::{builder::DefaultState, ConfigBuilder, Environment, File};
use kdl_source::KdlFormat;
use miette::Result;

use error::OroConfigError;

mod error;
mod kdl_source;

pub trait OroConfigLayerExt {
fn with_negations(self) -> Self;
Expand Down Expand Up @@ -70,17 +76,6 @@ impl OroConfigLayerExt for Command {
}
}

#[derive(Debug, Error, Diagnostic)]
pub enum OroConfigError {
#[error(transparent)]
#[diagnostic(code(config::error))]
ConfigError(#[from] ConfigError),

#[error(transparent)]
#[diagnostic(code(config::error))]
ConfigParseError(#[from] Box<dyn std::error::Error + Send + Sync>),
}

#[derive(Debug, Clone)]
pub struct OroConfigOptions {
builder: ConfigBuilder<DefaultState>,
Expand Down Expand Up @@ -137,27 +132,16 @@ impl OroConfigOptions {
if self.global {
if let Some(config_file) = self.global_config_file {
let path = config_file.display().to_string();
builder = builder.add_source(File::with_name(&path[..]).required(false));
builder = builder.add_source(File::new(&path, KdlFormat).required(false));
}
}
if self.env {
builder = builder.add_source(Environment::with_prefix("oro_config"));
}
if let Some(root) = self.pkg_root {
builder = builder
.add_source(
File::with_name(&root.join("ororc").display().to_string()).required(false),
)
.add_source(
File::with_name(&root.join(".ororc").display().to_string()).required(false),
)
.add_source(
File::with_name(&root.join("ororc.toml").display().to_string()).required(false),
)
.add_source(
File::with_name(&root.join(".ororc.toml").display().to_string())
.required(false),
);
builder = builder.add_source(
File::new(&root.join("oro.kdl").display().to_string(), KdlFormat).required(false),
);
}
Ok(builder.build().map_err(OroConfigError::ConfigError)?)
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Expand Up @@ -269,7 +269,7 @@ impl Orogene {
cfg_builder.global_config_file(Some(file.clone())).load()?
} else {
cfg_builder
.global_config_file(dirs.map(|d| d.config_dir().to_owned().join("ororc.toml")))
.global_config_file(dirs.map(|d| d.config_dir().to_owned().join("oro.kdl")))
.pkg_root(Some(self.root.clone()))
.load()?
};
Expand Down

0 comments on commit 09e81bd

Please sign in to comment.