Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions crates/runtime-factors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,15 @@ pub struct TriggerAppArgs {

/// Variable(s) to be passed to the app
///
/// A single key-value pair can be passed as `key=value`. Alternatively, the
/// path to a JSON or TOML file may be given as `@file.json` or
/// A single key-value pair can be passed as `key=value`, or `key=@file` to
/// read the value from a text file. Alternatively, any number of key-value
/// pairs may be passed via a JSON or TOML file using the syntax `@file.json` or
/// `@file.toml`.
///
/// This option may be repeated. If the same key is specified multiple times
/// the last value will be used.
#[clap(long, value_parser = clap::value_parser!(VariableSource),
value_name = "KEY=VALUE | @FILE.json | @FILE.toml")]
value_name = "KEY=VALUE | KEY=@FILE | @FILE.json | @FILE.toml")]
pub variable: Vec<VariableSource>,

/// Cache variables to avoid reading files twice
Expand Down
38 changes: 37 additions & 1 deletion crates/variables-static/src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,25 @@ use std::{collections::HashMap, path::PathBuf, str::FromStr};

#[derive(Clone, Debug)]
pub enum VariableSource {
/// The value of the given variable name is the given string
Literal(String, String),
/// The value of the given variable name is the content of the given file (as a string)
FileContent(String, PathBuf),
/// The file contains a map of variable names to (string) values
JsonFile(PathBuf),
/// The file contains a map of variable names to (string) values
TomlFile(PathBuf),
}

impl VariableSource {
pub fn get_variables(&self) -> anyhow::Result<HashMap<String, String>> {
match self {
VariableSource::Literal(key, val) => Ok([(key.to_string(), val.to_string())].into()),
VariableSource::FileContent(key, path) => {
let val = std::fs::read_to_string(path)
.with_context(|| format!("Failed to read {}.", quoted_path(path)))?;
Ok([(key.to_string(), val)].into())
}
VariableSource::JsonFile(path) => {
let json_bytes = std::fs::read(path)
.with_context(|| format!("Failed to read {}.", quoted_path(path)))?;
Expand Down Expand Up @@ -43,7 +53,14 @@ impl FromStr for VariableSource {
_ => bail!("variable files must end in .json or .toml"),
}
} else if let Some((key, val)) = s.split_once('=') {
Ok(VariableSource::Literal(key.to_string(), val.to_string()))
if let Some(path) = val.strip_prefix('@') {
Ok(VariableSource::FileContent(
key.to_string(),
PathBuf::from(path),
))
} else {
Ok(VariableSource::Literal(key.to_string(), val.to_string()))
}
} else {
bail!("variables must be in the form 'key=value' or '@file'")
}
Expand All @@ -66,6 +83,14 @@ mod tests {
Ok(other) => panic!("wrong variant {other:?}"),
Err(err) => panic!("{err:?}"),
}
match "[email protected]".parse() {
Ok(VariableSource::FileContent(key, path)) => {
assert_eq!(key, "k");
assert_eq!(path, PathBuf::from("v.txt"));
}
Ok(other) => panic!("wrong variant {other:?}"),
Err(err) => panic!("{err:?}"),
}
match "@file.json".parse() {
Ok(VariableSource::JsonFile(_)) => {}
Ok(other) => panic!("wrong variant {other:?}"),
Expand Down Expand Up @@ -93,6 +118,17 @@ mod tests {
assert_eq!(vars["k"], "v");
}

#[test]
fn file_content_get_variables() {
let mut file = tempfile::NamedTempFile::with_suffix(".txt").unwrap();
file.write_all(br#"sausage time!"#).unwrap();
let path = file.into_temp_path();
let vars = VariableSource::FileContent("k".to_string(), path.to_path_buf())
.get_variables()
.unwrap();
assert_eq!(vars["k"], "sausage time!");
}

#[test]
fn json_get_variables() {
let mut json_file = tempfile::NamedTempFile::with_suffix(".json").unwrap();
Expand Down