pitchfork_cli/
state_file.rs1use 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}