Skip to main content

git_psect/
state.rs

1use std::path::Path;
2
3use serde::{Deserialize, Serialize};
4
5use crate::error::Error;
6
7#[derive(Debug, Serialize, Deserialize)]
8pub struct State {
9    pub meta: Meta,
10    pub priors: Priors,
11    #[serde(default)]
12    pub old_revisions: Vec<String>,
13    #[serde(default)]
14    pub new_revisions: Vec<String>,
15    #[serde(default)]
16    pub samples: Vec<Sample>,
17}
18
19#[derive(Debug, Serialize, Deserialize)]
20pub struct Meta {
21    pub tool_version: String,
22    pub started_at: String,
23}
24
25#[derive(Debug, Default, Serialize, Deserialize)]
26pub struct Priors {
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub old_pass_rate: Option<f64>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub new_pass_rate: Option<f64>,
31}
32
33#[derive(Debug, Serialize, Deserialize)]
34pub struct Sample {
35    pub revision: String,
36    pub outcome: bool,
37    pub recorded_at: String,
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub comment: Option<String>,
40}
41
42pub fn read(state_dir: &Path) -> Result<State, Error> {
43    let path = state_dir.join("state.toml");
44    if !path.exists() {
45        return Err(Error::Validation(
46            "no psect session — run 'git psect start' first".into(),
47        ));
48    }
49    let contents = std::fs::read_to_string(path)?;
50    Ok(toml::from_str(&contents)?)
51}
52
53pub fn write(state_dir: &Path, state: &State) -> Result<(), Error> {
54    std::fs::create_dir_all(state_dir)?;
55    let tmp = state_dir.join("state.toml.tmp");
56    std::fs::write(&tmp, toml::to_string_pretty(state)?)?;
57    std::fs::rename(&tmp, state_dir.join("state.toml"))?;
58    Ok(())
59}