Skip to content

Commit

Permalink
metaconfig 4
Browse files Browse the repository at this point in the history
  • Loading branch information
anmenaga committed Oct 18, 2024
1 parent de57c5d commit c9396e4
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 41 deletions.
5 changes: 5 additions & 0 deletions dsc/default_settings.v1.dsc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,10 @@
"allow_env_override": true,
"append_env_path": true,
"directories": []
},
"tracing": {
"level": "WARN",
"format": "Default",
"allow_override": true
}
}
5 changes: 5 additions & 0 deletions dsc/settings.dsc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,10 @@
"allow_env_override": true,
"append_env_path": true,
"directories": []
},
"tracing": {
"level": "WARN",
"format": "Default",
"allow_override": true
}
}
7 changes: 4 additions & 3 deletions dsc/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use clap::{Parser, Subcommand, ValueEnum};
use clap_complete::Shell;
use dsc_lib::dscresources::command_resource::TraceLevel;
use serde::Deserialize;

#[derive(Debug, Clone, PartialEq, Eq, ValueEnum)]
pub enum OutputFormat {
Expand All @@ -12,7 +13,7 @@ pub enum OutputFormat {
Yaml,
}

#[derive(Debug, Clone, PartialEq, Eq, ValueEnum)]
#[derive(Debug, Clone, PartialEq, Eq, ValueEnum, Deserialize)]
pub enum TraceFormat {
Default,
Plaintext,
Expand All @@ -29,8 +30,8 @@ pub struct Args {
pub subcommand: SubCommand,
#[clap(short = 'l', long, help = "Trace level to use", value_enum)]
pub trace_level: Option<TraceLevel>,
#[clap(short = 'f', long, help = "Trace format to use", value_enum, default_value = "default")]
pub trace_format: TraceFormat,
#[clap(short = 'f', long, help = "Trace format to use", value_enum)]
pub trace_format: Option<TraceFormat>,
}

#[derive(Debug, PartialEq, Eq, Subcommand)]
Expand Down
2 changes: 1 addition & 1 deletion dsc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn main() {

let args = Args::parse();

util::enable_tracing(&args.trace_level, &args.trace_format);
util::enable_tracing(args.trace_level, args.trace_format);

debug!("Running dsc {}", env!("CARGO_PKG_VERSION"));

Expand Down
96 changes: 75 additions & 21 deletions dsc/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ use dsc_lib::{
}, resource_manifest::ResourceManifest
},
util::parse_input_to_json,
util::get_setting,
};
use jsonschema::JSONSchema;
use path_absolutize::Absolutize;
use schemars::{schema_for, schema::RootSchema};
use serde::Deserialize;
use serde_json::Value;
use std::collections::HashMap;
use std::env;
Expand Down Expand Up @@ -55,6 +57,23 @@ pub const EXIT_DSC_RESOURCE_NOT_FOUND: i32 = 7;
pub const DSC_CONFIG_ROOT: &str = "DSC_CONFIG_ROOT";
pub const DSC_TRACE_LEVEL: &str = "DSC_TRACE_LEVEL";

#[derive(Deserialize)]
pub struct TracingSetting {
level: TraceLevel,
format: TraceFormat,
allow_override: bool
}

impl Default for TracingSetting {
fn default() -> TracingSetting {
TracingSetting {
level: TraceLevel::Warn,
format: TraceFormat::Default,
allow_override: true,
}
}
}

/// Get string representation of JSON value.
///
/// # Arguments
Expand Down Expand Up @@ -268,46 +287,81 @@ pub fn write_output(json: &str, format: &Option<OutputFormat>) {
}
}

pub fn enable_tracing(trace_level: &Option<TraceLevel>, trace_format: &TraceFormat) {
let tracing_level = match trace_level {
Some(level) => level,
None => {
// use DSC_TRACE_LEVEL env var if set
match env::var(DSC_TRACE_LEVEL) {
Ok(level) => {
match level.to_ascii_uppercase().as_str() {
"ERROR" => &TraceLevel::Error,
"WARN" => &TraceLevel::Warn,
"INFO" => &TraceLevel::Info,
"DEBUG" => &TraceLevel::Debug,
"TRACE" => &TraceLevel::Trace,
_ => {
warn!("Invalid DSC_TRACE_LEVEL value '{level}', defaulting to 'warn'");
&TraceLevel::Warn
},
}
pub fn enable_tracing(trace_level_arg: Option<TraceLevel>, trace_format_arg: Option<TraceFormat>) {

let mut policy_is_used = false;
let mut tracing_setting = TracingSetting::default();

// read setting/policy from files
if let Ok(v) = get_setting("tracing") {
if v.policy != serde_json::Value::Null {
match serde_json::from_value::<TracingSetting>(v.policy) {
Ok(v) => {
tracing_setting = v;
policy_is_used = true;
},
Err(_) => &TraceLevel::Warn,
Err(e) => { println!("{}", format!("{e}")); }
}
} else if v.setting != serde_json::Value::Null {
match serde_json::from_value::<TracingSetting>(v.setting) {
Ok(v) => {
tracing_setting = v;
},
Err(e) => { println!("{}", format!("{e}")); }
}
}
} else {
println!("Could not read 'tracing' setting");
}

// override with DSC_TRACE_LEVEL env var if permitted
if tracing_setting.allow_override {
match env::var(DSC_TRACE_LEVEL) {
Ok(level) => {
tracing_setting.level = match level.to_ascii_uppercase().as_str() {
"ERROR" => TraceLevel::Error,
"WARN" => TraceLevel::Warn,
"INFO" => TraceLevel::Info,
"DEBUG" => TraceLevel::Debug,
"TRACE" => TraceLevel::Trace,
_ => {
warn!("Invalid DSC_TRACE_LEVEL value '{level}', defaulting to 'warn'");
TraceLevel::Warn
}
}
},
Err(_) => {},
}
}

// command-line args override setting value, but not policy
if !policy_is_used {
if let Some(v) = trace_level_arg {
tracing_setting.level = v.clone();
};
if let Some(v) = trace_format_arg {
tracing_setting.format = v.clone();
};
};

let tracing_level = match tracing_level {
// convert to 'tracing' crate type
let tracing_level = match tracing_setting.level {
TraceLevel::Error => Level::ERROR,
TraceLevel::Warn => Level::WARN,
TraceLevel::Info => Level::INFO,
TraceLevel::Debug => Level::DEBUG,
TraceLevel::Trace => Level::TRACE,
};

// enable tracing
let filter = EnvFilter::try_from_default_env()
.or_else(|_| EnvFilter::try_new("warning"))
.unwrap_or_default()
.add_directive(tracing_level.into());
let indicatif_layer = IndicatifLayer::new();
let layer = tracing_subscriber::fmt::Layer::default().with_writer(indicatif_layer.get_stderr_writer());
let with_source = tracing_level == Level::DEBUG || tracing_level == Level::TRACE;
let fmt = match trace_format {
let fmt = match tracing_setting.format {
TraceFormat::Default => {
layer
.with_ansi(true)
Expand Down
31 changes: 24 additions & 7 deletions dsc_lib/src/discovery/command_discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,38 @@ impl CommandDiscovery {
fn get_resource_path_setting() -> Result<ResourcePathSetting, DscError>
{
if let Ok(v) = get_setting("resource_path") {
if let Ok(resource_path_setting) = serde_json::from_value(v) {
return Ok(resource_path_setting);
// if there is a policy value defined - use it; otherwise use setting value
if v.policy != serde_json::Value::Null {
match serde_json::from_value::<ResourcePathSetting>(v.policy) {
Ok(v) => {
return Ok(v);
},
Err(e) => { return Err(DscError::Operation(format!("{}", e))); }
}
} else if v.setting != serde_json::Value::Null {
match serde_json::from_value::<ResourcePathSetting>(v.setting) {
Ok(v) => {
return Ok(v);
},
Err(e) => { return Err(DscError::Operation(format!("{}", e))); }
}
}
}

Err(DscError::Operation("Could not read resource_path setting".to_string()))
Err(DscError::Operation("Could not read 'resource_path' setting".to_string()))
}

fn get_resource_paths() -> Result<Vec<PathBuf>, DscError>
{
let mut resource_path_setting = ResourcePathSetting::default();
if let Ok(v) = Self::get_resource_path_setting() {
resource_path_setting = v;
} else {
debug!("Could not read resource_path setting");

match Self::get_resource_path_setting() {
Ok(v) => {
resource_path_setting = v;
},
Err(e) => {
debug!("{e}");
}
}

let mut using_custom_path = false;
Expand Down
32 changes: 23 additions & 9 deletions dsc_lib/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ use std::path::Path;
use std::env;
use tracing::debug;

pub struct DscSettingValue {
pub setting: serde_json::Value,
pub policy: serde_json::Value,
}

impl Default for DscSettingValue {
fn default() -> DscSettingValue {
DscSettingValue {
setting: serde_json::Value::Null,
policy: serde_json::Value::Null,
}
}
}

/// Return JSON string whether the input is JSON or YAML
///
/// # Arguments
Expand Down Expand Up @@ -53,30 +67,29 @@ pub fn parse_input_to_json(value: &str) -> Result<String, DscError> {
/// # Errors
///
/// Will return `Err` if could not find requested setting.
pub fn get_setting(value_name: &str) -> Result<serde_json::Value, DscError> {
pub fn get_setting(value_name: &str) -> Result<DscSettingValue, DscError> {

const SETTINGS_FILE_NAME: &str = "settings.dsc.json";
// Note that default settings file name has a version that is specific to this version of dsc
const DEFAULT_SETTINGS_FILE_NAME: &str = "default_settings.v1.dsc.json";

let mut result:serde_json::Value = serde_json::Value::Null;
let mut result: DscSettingValue = DscSettingValue::default();
let mut settings_file_path : PathBuf;

if let Some(exe_home) = env::current_exe()?.parent() {

// First, get setting from the default settings file
settings_file_path = exe_home.join(DEFAULT_SETTINGS_FILE_NAME);
if let Ok(v) = load_value_from_json(&settings_file_path, value_name) {
result = v;
result.setting = v;
debug!("Found setting '{}' in {}", &value_name, settings_file_path.to_string_lossy());
} else {
debug!("Did not find setting '{}' in {}", &value_name, settings_file_path.to_string_lossy());
}

// Second, get setting from the active settings file overwriting previous value
// Second, get setting from the active settings file overwriting previous value
settings_file_path = exe_home.join(SETTINGS_FILE_NAME);
if let Ok(v) = load_value_from_json(&settings_file_path, value_name) {
result = v;
result.setting = v;
debug!("Found setting '{}' in {}", &value_name, settings_file_path.to_string_lossy());
} else {
debug!("Did not find setting '{}' in {}", &value_name, settings_file_path.to_string_lossy());
Expand All @@ -85,16 +98,17 @@ pub fn get_setting(value_name: &str) -> Result<serde_json::Value, DscError> {
debug!("Can't get dsc executable path");
}

// Third, get setting from the policy settings file overwriting previous value
// Third, get setting from the policy
settings_file_path = PathBuf::from(get_settings_policy_file_path());
if let Ok(v) = load_value_from_json(&settings_file_path, value_name) {
result = v;
result.policy = v;
debug!("Found setting '{}' in {}", &value_name, settings_file_path.to_string_lossy());
} else {
debug!("Did not find setting '{}' in {}", &value_name, settings_file_path.to_string_lossy());
}

if result == serde_json::Value::Null {
if (result.setting == serde_json::Value::Null) &&
(result.policy == serde_json::Value::Null) {
return Err(DscError::NotSupported(format!("Could not find '{value_name}' in settings").to_string()));
}

Expand Down

0 comments on commit c9396e4

Please sign in to comment.