use crate::config::Config;
use crate::load::{find_clause_json, find_rfc_json};
use crate::model::{AdrEntry, ClauseSpec, GuardEntry, RfcSpec, WorkItemEntry};
use crate::parse::{
load_adrs, load_guards, load_work_items, write_adr, write_guard, write_work_item,
};
use crate::write::{WriteOp, read_clause, read_rfc, write_clause, write_rfc};
use std::path::PathBuf;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct JsonDoc<T> {
pub path: PathBuf,
pub data: T,
}
#[allow(dead_code)]
pub trait JsonAdapter {
type Data;
fn load(config: &Config, id: &str) -> anyhow::Result<JsonDoc<Self::Data>>;
fn write(config: &Config, doc: &JsonDoc<Self::Data>, op: WriteOp) -> anyhow::Result<()>;
}
#[allow(dead_code)]
pub trait TomlAdapter {
type Entry;
fn load(config: &Config, id: &str) -> anyhow::Result<Self::Entry>;
fn write(config: &Config, entry: &Self::Entry, op: WriteOp) -> anyhow::Result<()>;
}
pub struct RfcJsonAdapter;
impl JsonAdapter for RfcJsonAdapter {
type Data = RfcSpec;
fn load(config: &Config, id: &str) -> anyhow::Result<JsonDoc<Self::Data>> {
let path =
find_rfc_json(config, id).ok_or_else(|| anyhow::anyhow!("RFC not found: {id}"))?;
let data = read_rfc(config, &path)?;
Ok(JsonDoc { path, data })
}
fn write(config: &Config, doc: &JsonDoc<Self::Data>, op: WriteOp) -> anyhow::Result<()> {
write_rfc(
&doc.path,
&doc.data,
op,
Some(&config.display_path(&doc.path)),
)
}
}
pub struct ClauseJsonAdapter;
impl JsonAdapter for ClauseJsonAdapter {
type Data = ClauseSpec;
fn load(config: &Config, id: &str) -> anyhow::Result<JsonDoc<Self::Data>> {
let path = find_clause_json(config, id)
.ok_or_else(|| anyhow::anyhow!("Clause not found: {id}"))?;
let data = read_clause(config, &path)?;
Ok(JsonDoc { path, data })
}
fn write(config: &Config, doc: &JsonDoc<Self::Data>, op: WriteOp) -> anyhow::Result<()> {
write_clause(
&doc.path,
&doc.data,
op,
Some(&config.display_path(&doc.path)),
)
}
}
pub struct AdrTomlAdapter;
impl TomlAdapter for AdrTomlAdapter {
type Entry = AdrEntry;
fn load(config: &Config, id: &str) -> anyhow::Result<Self::Entry> {
load_adrs(config)?
.into_iter()
.find(|a| a.spec.govctl.id == id)
.ok_or_else(|| anyhow::anyhow!("ADR not found: {id}"))
}
fn write(config: &Config, entry: &Self::Entry, op: WriteOp) -> anyhow::Result<()> {
write_adr(
&entry.path,
&entry.spec,
op,
Some(&config.display_path(&entry.path)),
)
.map_err(Into::into)
}
}
pub struct WorkTomlAdapter;
impl TomlAdapter for WorkTomlAdapter {
type Entry = WorkItemEntry;
fn load(config: &Config, id: &str) -> anyhow::Result<Self::Entry> {
load_work_items(config)?
.into_iter()
.find(|w| w.spec.govctl.id == id || w.path.to_string_lossy().contains(id))
.ok_or_else(|| anyhow::anyhow!("Work item not found: {id}"))
}
fn write(config: &Config, entry: &Self::Entry, op: WriteOp) -> anyhow::Result<()> {
write_work_item(
&entry.path,
&entry.spec,
op,
Some(&config.display_path(&entry.path)),
)
.map_err(Into::into)
}
}
pub struct GuardTomlAdapter;
impl TomlAdapter for GuardTomlAdapter {
type Entry = GuardEntry;
fn load(config: &Config, id: &str) -> anyhow::Result<Self::Entry> {
load_guards(config)
.map_err(|d| anyhow::anyhow!("{}", d.message))?
.into_iter()
.find(|g| g.spec.govctl.id == id)
.ok_or_else(|| anyhow::anyhow!("Guard not found: {id}"))
}
fn write(config: &Config, entry: &Self::Entry, op: WriteOp) -> anyhow::Result<()> {
write_guard(
&entry.path,
&entry.spec,
op,
Some(&config.display_path(&entry.path)),
)
.map_err(Into::into)
}
}