blob: 4f40f3cb26ba10b19b119daa294ddb8dfeb3965b [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
crate::mapping::{postprocess, preprocess, replace_regex as replace},
anyhow::anyhow,
lazy_static::lazy_static,
regex::Regex,
serde_json::Value,
std::env,
};
fn check(value: &String, regex: &Regex) -> bool {
// First verify all environment variables exist.
// If one does not exist, return none.
for caps in regex.captures_iter(&value) {
// Skip the first one since that'll be the whole string.
for cap in caps.iter().skip(1) {
if let Some(c) = cap {
let var = c.as_str();
if let Err(_) = env::var(var) {
return false;
}
}
}
}
true
}
pub(crate) fn env_var(value: Value) -> Option<Value> {
lazy_static! {
static ref REGEX: Regex = Regex::new(r"\$([A-Z][A-Z0-9_]*)").unwrap();
}
let env_string = preprocess(&value);
if let Some(ref e) = env_string {
if !check(e, &*REGEX) {
return None;
}
}
env_string
.as_ref()
.map(|s| replace(s, &*REGEX, |v| env::var(v).map_err(|_| anyhow!(""))))
.map(postprocess)
.or(Some(value))
}
////////////////////////////////////////////////////////////////////////////////
// tests
#[cfg(test)]
mod test {
use super::*;
fn setup_test(env_vars: Vec<(&'static str, &'static str)>) -> Box<dyn FnOnce() -> ()> {
env_vars.iter().for_each(|(var, val)| env::set_var(var, val));
Box::new(move || {
env_vars.iter().for_each(|(var, _)| env::remove_var(var));
})
}
#[test]
fn test_env_var_mapper() {
let cleanup: Box<dyn FnOnce() -> ()> =
setup_test(vec![("FFX_TEST_ENV_VAR_MAPPER", "test")]);
let test = Value::String("$FFX_TEST_ENV_VAR_MAPPER".to_string());
assert_eq!(env_var(test), Some(Value::String("test".to_string())));
cleanup();
}
#[test]
fn test_env_var_mapper_multiple() {
let cleanup: Box<dyn FnOnce() -> ()> =
setup_test(vec![("FFX_TEST_ENV_VAR_MAPPER_MULTIPLE", "test")]);
let test = Value::String(
"$FFX_TEST_ENV_VAR_MAPPER_MULTIPLE/$FFX_TEST_ENV_VAR_MAPPER_MULTIPLE".to_string(),
);
assert_eq!(env_var(test), Some(Value::String(format!("{}/{}", "test", "test"))));
cleanup();
}
#[test]
fn test_env_var_mapper_returns_none() {
let test = Value::String("$ENVIRONMENT_VARIABLE_THAT_DOES_NOT_EXIST".to_string());
assert_eq!(env_var(test), None);
}
#[test]
fn test_env_var_mapper_multiple_returns_none_if_one_does_not_exist() {
let cleanup: Box<dyn FnOnce() -> ()> =
setup_test(vec![("FFX_TEST_ENV_VAR_EXISTS", "test")]);
let test = Value::String("$HOME/$ENVIRONMENT_VARIABLE_THAT_DOES_NOT_EXIST".to_string());
assert_eq!(env_var(test), None);
cleanup();
}
#[test]
fn test_env_var_mapper_escapes_dollar_sign() {
let test = Value::String("$$HOME".to_string());
assert_eq!(env_var(test), Some(Value::String("$HOME".to_string())));
}
#[test]
fn test_env_var_returns_value_if_not_string() {
let test = Value::Bool(false);
assert_eq!(env_var(test), Some(Value::Bool(false)));
}
}