use std::fs::DirBuilder;
use std::{collections::HashMap, panic::UnwindSafe};
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use crate::ioutil;
pub mod paths {
use std::path::{Path, PathBuf};
use lazy_static::lazy_static;
lazy_static! {
static ref KUBIE_DATA_DIR: PathBuf = {
let base_data_dir = dirs::data_local_dir().expect("Could not get local data dir");
base_data_dir.join("kubie")
};
static ref KUBIE_STATE_PATH: PathBuf = KUBIE_DATA_DIR.join("state.json");
static ref KUBIE_STATE_LOCK_PATH: PathBuf = KUBIE_DATA_DIR.join(".state.json.lock");
}
#[inline]
pub fn data_dir() -> &'static Path {
&*KUBIE_DATA_DIR
}
#[inline]
pub fn state() -> &'static Path {
&*KUBIE_STATE_PATH
}
#[inline]
pub fn state_lock() -> &'static Path {
&*KUBIE_STATE_LOCK_PATH
}
}
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct State {
pub namespace_history: HashMap<String, Option<String>>,
}
impl State {
pub fn load() -> Result<State> {
Self::access(|state| Ok(state))
}
pub fn modify<F: FnOnce(&mut State) -> Result<()> + UnwindSafe>(func: F) -> Result<()> {
Self::access(|mut state| {
func(&mut state)?;
state.save()?;
Ok(())
})
}
fn access<R, F: FnOnce(State) -> Result<R> + UnwindSafe>(func: F) -> Result<R> {
DirBuilder::new()
.recursive(true)
.create(paths::data_dir())
.with_context(|| format!("Could not create data dir: {}", paths::data_dir().display()))?;
ioutil::file_lock(paths::state_lock(), || {
State::read_and_parse()
.with_context(|| format!("Could not load state file: {}", paths::state().display()))
.and_then(func)
})
}
fn read_and_parse() -> Result<State> {
if !paths::state().exists() {
return Ok(State::default());
}
ioutil::read_json(paths::state())
.with_context(|| format!("Failed to read state from '{}'", paths::state().display()))
}
fn save(&self) -> Result<()> {
ioutil::write_json(paths::state(), self)
.with_context(|| format!("Failed to write state to '{}'", paths::state().display()))
}
}