lade_sdk/
lib.rs

1use std::{
2    collections::HashMap,
3    path::{Path, PathBuf},
4};
5
6use anyhow::{bail, Ok, Result};
7use futures::future::try_join_all;
8use once_cell::sync::Lazy;
9use providers::Provider;
10use regex::Regex;
11
12type Hydration = HashMap<String, String>;
13
14mod providers;
15
16pub struct Hydrater {
17    providers: Vec<Box<dyn Provider + Send>>,
18}
19
20impl Hydrater {
21    fn new() -> Self {
22        Self {
23            providers: providers::providers(),
24        }
25    }
26    fn add(&mut self, value: String) -> Result<()> {
27        for provider in self.providers.iter_mut() {
28            if provider.add(value.clone()).is_ok() {
29                return Ok(());
30            }
31        }
32        bail!("No provider found")
33    }
34    async fn resolve(&self, cwd: &Path) -> Result<Hydration> {
35        Ok(try_join_all(self.providers.iter().map(|p| p.resolve(cwd)))
36            .await?
37            .into_iter()
38            .flatten()
39            .collect())
40    }
41}
42
43pub async fn hydrate(
44    env: HashMap<String, String>,
45    cwd: PathBuf,
46) -> Result<HashMap<String, String>> {
47    let mut hydrater = Hydrater::new();
48    for value_or_uri in env.values() {
49        hydrater.add(value_or_uri.clone())?
50    }
51
52    let hydration = hydrater.resolve(&cwd).await?;
53
54    let mut ret: HashMap<String, String> = HashMap::default();
55    for (key, value_or_uri) in env.iter() {
56        ret.insert(
57            key.clone(),
58            hydration
59                .get(value_or_uri)
60                .unwrap_or_else(|| {
61                    panic!(
62                        "Cannot find {} in {}",
63                        value_or_uri,
64                        hydration
65                            .keys()
66                            .cloned()
67                            .collect::<Vec<String>>()
68                            .join(", ")
69                    )
70                })
71                .clone(),
72        );
73    }
74
75    Ok(ret)
76}
77
78pub async fn hydrate_one(value: String, cwd: &Path) -> Result<String> {
79    let mut hydrater = Hydrater::new();
80    hydrater.add(value.clone())?;
81    let hydration = hydrater.resolve(cwd).await?;
82    let hydrated = hydration.get(&value).unwrap().to_owned();
83    Ok(hydrated)
84}
85
86static VAR: Lazy<Regex> = Lazy::new(|| Regex::new(r"(\$\{?(\w+)\}?)").unwrap());
87
88pub fn resolve(
89    kvs: &HashMap<String, String>,
90    existing_vars: &HashMap<String, String>,
91) -> Result<HashMap<String, String>> {
92    kvs.iter()
93        .map(|(key, value)| resolve_one(value, existing_vars).map(|v| (key.clone(), v)))
94        .collect()
95}
96
97pub fn resolve_one(value: &str, existing_vars: &HashMap<String, String>) -> Result<String> {
98    Ok(VAR.captures_iter(value).fold(value.to_string(), |agg, c| {
99        agg.replace(&c[1], existing_vars.get(&c[2]).unwrap_or(&"".to_string()))
100    }))
101}