lade-sdk 0.1.0

Load automatically env variables from different sources.
Documentation
use std::collections::HashMap;

use anyhow::{bail, Ok, Result};
use async_process::{Command, Stdio};
use async_trait::async_trait;
use futures::AsyncWriteExt;

use log::{debug, info};
use url::Url;

use crate::Hydration;

use super::Provider;

#[derive(Default)]
pub struct OnePassword {
    urls: Vec<Url>,
}

impl OnePassword {
    pub fn new() -> Self {
        Default::default()
    }
}

#[async_trait]
impl Provider for OnePassword {
    fn add(&mut self, value: String) -> Result<()> {
        match Url::parse(&value) {
            std::result::Result::Ok(url) if url.scheme() == "op" => {
                self.urls.push(url);
                Ok(())
            }
            _ => bail!("Not a onepassword scheme"),
        }
    }
    async fn resolve(&self) -> Result<Hydration> {
        let vars = self
            .urls
            .iter()
            .enumerate()
            .map(|(idx, u)| (idx.to_string(), u.to_string()))
            .collect::<HashMap<_, _>>();

        if vars.is_empty() {
            return Ok(HashMap::new());
        }

        let json = serde_json::to_string(&vars)?;

        let f = async move {
            let cmd = &["op", "inject"];
            info!("{}", cmd.join(" "));
            let mut child = Command::new(cmd[0])
                .args(&cmd[1..])
                .stdout(Stdio::piped())
                .stdin(Stdio::piped())
                .spawn()?;

            debug!("stdin: {:?}", json);

            let mut stdin = child.stdin.take().expect("Failed to open stdin");
            stdin.write_all(json.as_bytes()).await?;
            drop(stdin);

            let loaded = serde_json::from_slice::<Hydration>(&child.output().await?.stdout)?;

            let hydration = vars
                .into_iter()
                .map(|(key, var)| (var, loaded.get(&key).expect("Variable not found").clone()))
                .collect::<Hydration>();

            debug!("hydration: {:?}", hydration);
            Ok(hydration)
        };

        Ok(f.await?)
    }
}