pitchfork_cli/
state_file.rs1use crate::daemon::Daemon;
2use crate::{env, Result};
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).expect("Error reading state file")
32 });
33 &STATE_FILE
34 }
35
36 pub fn read<P: AsRef<Path>>(path: P) -> Result<Self> {
37 let path = path.as_ref();
38 if !path.exists() {
39 return Ok(Self::new(path.to_path_buf()));
40 }
41 let _lock = xx::fslock::get(path, false)?;
42 let raw = xx::file::read_to_string(path).unwrap_or_else(|e| {
43 warn!("Error reading state file {:?}: {}", path, e);
44 String::new()
45 });
46 let mut state_file: Self = toml::from_str(&raw).unwrap_or_else(|e| {
47 warn!("Error parsing state file {:?}: {}", path, e);
48 Self::new(path.to_path_buf())
49 });
50 state_file.path = path.to_path_buf();
51 for (name, daemon) in state_file.daemons.iter_mut() {
52 daemon.id = name.clone();
53 }
54 Ok(state_file)
55 }
56
57 pub fn write(&self) -> Result<()> {
58 let _lock = xx::fslock::get(&self.path, false)?;
59 let raw = toml::to_string(self).into_diagnostic()?;
60 xx::file::write(&self.path, raw)?;
61 Ok(())
62 }
63}