pitchfork_cli/
state_file.rs

1use crate::daemon::Daemon;
2use crate::{Result, env};
3use miette::IntoDiagnostic;
4use once_cell::sync::Lazy;
5use std::collections::{BTreeMap, BTreeSet};
6use std::fmt::Debug;
7use std::path::{Path, PathBuf};
8
9#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
10pub struct StateFile {
11    pub daemons: BTreeMap<String, Daemon>,
12    pub disabled: BTreeSet<String>,
13    pub shell_dirs: BTreeMap<String, PathBuf>,
14    #[serde(skip)]
15    pub(crate) path: PathBuf,
16}
17
18impl StateFile {
19    pub fn new(path: PathBuf) -> Self {
20        Self {
21            daemons: Default::default(),
22            disabled: Default::default(),
23            shell_dirs: Default::default(),
24            path,
25        }
26    }
27
28    pub fn get() -> &'static Self {
29        static STATE_FILE: Lazy<StateFile> = Lazy::new(|| {
30            let path = &*env::PITCHFORK_STATE_FILE;
31            StateFile::read(path).unwrap_or_else(|e| {
32                warn!("Could not read state file: {e}, starting fresh");
33                StateFile::new(path.to_path_buf())
34            })
35        });
36        &STATE_FILE
37    }
38
39    pub fn read<P: AsRef<Path>>(path: P) -> Result<Self> {
40        let path = path.as_ref();
41        if !path.exists() {
42            return Ok(Self::new(path.to_path_buf()));
43        }
44        let _lock = xx::fslock::get(path, false)?;
45        let raw = xx::file::read_to_string(path).unwrap_or_else(|e| {
46            warn!("Error reading state file {:?}: {}", path, e);
47            String::new()
48        });
49        let mut state_file: Self = toml::from_str(&raw).unwrap_or_else(|e| {
50            warn!("Error parsing state file {:?}: {}", path, e);
51            Self::new(path.to_path_buf())
52        });
53        state_file.path = path.to_path_buf();
54        for (name, daemon) in state_file.daemons.iter_mut() {
55            daemon.id = name.clone();
56        }
57        Ok(state_file)
58    }
59
60    pub fn write(&self) -> Result<()> {
61        let _lock = xx::fslock::get(&self.path, false)?;
62        let raw = toml::to_string(self).into_diagnostic()?;
63        xx::file::write(&self.path, raw)?;
64        Ok(())
65    }
66}