omni_dev/data/
amendments.rs1use anyhow::{Context, Result};
4use serde::{Deserialize, Serialize};
5use std::fs;
6use std::path::Path;
7
8#[derive(Debug, Serialize, Deserialize)]
10pub struct AmendmentFile {
11 pub amendments: Vec<Amendment>,
13}
14
15#[derive(Debug, Serialize, Deserialize)]
17pub struct Amendment {
18 pub commit: String,
20 pub message: String,
22}
23
24impl AmendmentFile {
25 pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
27 let content = fs::read_to_string(&path).with_context(|| {
28 format!("Failed to read amendment file: {}", path.as_ref().display())
29 })?;
30
31 let amendment_file: AmendmentFile =
32 serde_yaml::from_str(&content).context("Failed to parse YAML amendment file")?;
33
34 amendment_file.validate()?;
35
36 Ok(amendment_file)
37 }
38
39 pub fn validate(&self) -> Result<()> {
41 if self.amendments.is_empty() {
42 anyhow::bail!("Amendment file must contain at least one amendment");
43 }
44
45 for (i, amendment) in self.amendments.iter().enumerate() {
46 amendment
47 .validate()
48 .with_context(|| format!("Invalid amendment at index {}", i))?;
49 }
50
51 Ok(())
52 }
53
54 pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
56 let yaml_content =
57 serde_yaml::to_string(self).context("Failed to serialize amendments to YAML")?;
58
59 fs::write(&path, yaml_content).with_context(|| {
60 format!(
61 "Failed to write amendment file: {}",
62 path.as_ref().display()
63 )
64 })?;
65
66 Ok(())
67 }
68}
69
70impl Amendment {
71 pub fn new(commit: String, message: String) -> Self {
73 Self { commit, message }
74 }
75
76 pub fn validate(&self) -> Result<()> {
78 if self.commit.len() != 40 {
80 anyhow::bail!(
81 "Commit hash must be exactly 40 characters long, got: {}",
82 self.commit.len()
83 );
84 }
85
86 if !self.commit.chars().all(|c| c.is_ascii_hexdigit()) {
87 anyhow::bail!("Commit hash must contain only hexadecimal characters");
88 }
89
90 if !self
91 .commit
92 .chars()
93 .all(|c| c.is_ascii_lowercase() || c.is_ascii_digit())
94 {
95 anyhow::bail!("Commit hash must be lowercase");
96 }
97
98 if self.message.trim().is_empty() {
100 anyhow::bail!("Commit message cannot be empty");
101 }
102
103 Ok(())
104 }
105}