orcs 0.0.8

Microservices monorepo orchestration tool
Documentation
use super::Store;
use crate::{Error, Project};
use std::collections::HashMap;
use std::fs::{create_dir_all, File};
use std::io::prelude::*;
use std::path::Path;
use std::sync::Arc;
use tracing::{debug, instrument};

const STORE_FOLDER: &str = ".store";
const STORE_VALUE_FILE: &str = "store.json";

pub struct Local {
    project: Arc<Project>,
    store: HashMap<String, String>,
    changed: bool,
}

impl Store for Local {
    #[instrument(skip(project))]
    fn from_project(project: Arc<Project>) -> Result<Self, Error> {
        debug!("Load local parameter store");
        let store_path = Path::new(&project.path).join(STORE_FOLDER);

        // New local store
        let store = if store_path.is_dir() && store_path.join(STORE_VALUE_FILE).is_file() {
            let store_reader = File::open(store_path.join(STORE_VALUE_FILE))?;
            serde_json::from_reader(store_reader)?
        } else {
            create_dir_all(store_path)?;
            Default::default()
        };

        // Load the local store
        Ok(Self {
            project,
            store,
            changed: false,
        })
    }

    fn get(&self, name: &str) -> Result<String, Error> {
        match self.store.get(name) {
            Some(data) => Ok(data.clone()),
            None => Err(Error::GetParameterError(
                "parameter does not exist",
                name.to_string(),
            )),
        }
    }

    fn get_bytes(&self, name: &str) -> Result<Vec<u8>, Error> {
        let param_path = Path::new(&self.project.path)
            .join(STORE_FOLDER)
            .join(format!("{}.store", name));
        let param_reader = File::open(param_path)?;
        let data = param_reader
            .bytes()
            .collect::<Result<Vec<u8>, std::io::Error>>()?;
        Ok(data)
    }

    fn set(&mut self, name: &str, value: &str) -> Result<(), Error> {
        self.store.insert(name.to_string(), value.to_string());
        self.changed = true;
        Ok(())
    }

    fn set_bytes(&mut self, name: &str, value: &[u8]) -> Result<(), Error> {
        let param_path = Path::new(&self.project.path)
            .join(STORE_FOLDER)
            .join(format!("{}.store", name));
        let mut param_writer = File::create(param_path)?;
        param_writer.write_all(value)?;
        Ok(())
    }
}
impl Local {
    fn flush(&mut self) -> Result<(), Error> {
        if self.changed {
            let store_path = Path::new(&self.project.path).join(STORE_FOLDER);
            let store_writer = File::create(store_path.join(STORE_VALUE_FILE))?;
            serde_json::to_writer(store_writer, &self.store)?;
            self.changed = false;
        }

        Ok(())
    }
}

impl Drop for Local {
    fn drop(&mut self) {
        self.flush().unwrap();
    }
}