Skip to content

Commit

Permalink
Add flag to load options from yaml/json files
Browse files Browse the repository at this point in the history
Additionally, refactor the way that options and requests are loaded
to use a consistent method of layering and de-duplication.

Signed-off-by: Ryan Bottriell <[email protected]>
  • Loading branch information
rydrman committed Oct 5, 2022
1 parent 59cbb4f commit 4ca9a81
Showing 1 changed file with 29 additions and 32 deletions.
61 changes: 29 additions & 32 deletions crates/spk-cli/common/src/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
// https://github.com/imageworks/spk

use std::collections::HashMap;
use std::str::FromStr;
use std::sync::Arc;

Expand All @@ -12,7 +11,7 @@ use colored::Colorize;
use solve::{DecisionFormatter, DecisionFormatterBuilder};
use spk_schema::foundation::ident_build::Build;
use spk_schema::foundation::ident_component::Component;
use spk_schema::foundation::name::{OptName, OptNameBuf};
use spk_schema::foundation::name::OptName;
use spk_schema::foundation::option_map::{host_options, OptionMap};
use spk_schema::foundation::spec_ops::{Named, RecipeOps};
use spk_schema::foundation::version::CompatRule;
Expand Down Expand Up @@ -166,9 +165,16 @@ pub struct Options {
/// an equals sign or colon (--opt name=value --opt other:value).
/// Additionally, many options can be specified at once in yaml
/// or json format (--opt '{name: value, other: value}').
///
/// Options can also be given in a file via the --options-file/-f flag. If
/// given, --opt will supercede anything in the options file(s).
#[clap(long = "opt", short)]
pub options: Vec<String>,

/// Specify build/resolve options from a json or yaml file (see --opt/-o)
#[clap(long)]
pub options_file: Vec<std::path::PathBuf>,

/// Do not add the default options for the current host system
#[clap(long)]
pub no_host: bool,
Expand All @@ -181,23 +187,20 @@ impl Options {
false => host_options().context("Failed to compute options for current host")?,
};

for req in self.get_var_requests()? {
opts.insert(req.var, req.value);
for filename in self.options_file.iter() {
let reader =
std::fs::File::open(filename).context(format!("Failed to open: {filename:?}"))?;
let options: OptionMap = serde_yaml::from_reader(reader)
.context(format!("Failed to parse as option mapping: {filename:?}"))?;
opts.extend(options);
}

Ok(opts)
}

pub fn get_var_requests(&self) -> Result<Vec<VarRequest>> {
let mut requests = Vec::with_capacity(self.options.len());
for pair in self.options.iter() {
let pair = pair.trim();
if pair.starts_with('{') {
let given: HashMap<OptNameBuf, String> = serde_yaml::from_str(pair)
let given: OptionMap = serde_yaml::from_str(pair)
.context("--opt value looked like yaml, but could not be parsed")?;
for (name, value) in given.into_iter() {
requests.push(VarRequest::new_with_value(name, value));
}
opts.extend(given);
continue;
}

Expand All @@ -209,9 +212,19 @@ impl Options {
})
.and_then(|(name, value)| Ok((OptName::new(name)?, value)))?;

requests.push(VarRequest::new_with_value(name, value));
opts.insert(name.to_owned(), value.to_string());
}
Ok(requests)

Ok(opts)
}

pub fn get_var_requests(&self) -> Result<Vec<VarRequest>> {
Ok(self
.get_options()?
.into_iter()
.filter(|(_name, value)| !value.is_empty())
.map(|(name, value)| VarRequest::new_with_value(name, value))
.collect())
}
}

Expand Down Expand Up @@ -282,23 +295,7 @@ impl Requests {
S: AsRef<str>,
{
let mut out = Vec::<Request>::new();
let var_requests = options.get_var_requests()?;
let mut options = match options.no_host {
true => OptionMap::default(),
false => host_options()?,
};
// Insert var_requests, which includes requests specified on the command-line,
// into the map so that they can override values provided by host_options().
for req in var_requests {
options.insert(req.var, req.value);
}

for (name, value) in options.iter() {
if !value.is_empty() {
out.push(VarRequest::new_with_value(name.clone(), value).into());
}
}

let options = options.get_options()?;
for r in requests.into_iter() {
let r = r.as_ref();
if r.contains('@') {
Expand Down

0 comments on commit 4ca9a81

Please sign in to comment.