use std::sync::Arc;
use crate::control::ControlStore;
use crate::doc::{impl_doc, DocRef, ShardedMap};
use crate::error::Result;
use crate::sandbox::RepoRef;
pub const POLICY_REF: &str = "refs/gunnar/policy";
#[derive(Default, Clone, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct PolicyDoc {
#[serde(default)]
repos: ShardedMap<String>,
}
impl_doc!(PolicyDoc { repos });
#[derive(Clone, Debug)]
pub struct PolicyStore {
doc: DocRef<PolicyDoc>,
}
impl PolicyStore {
pub fn new(store: Arc<dyn ControlStore>) -> Result<Self> {
Ok(PolicyStore {
doc: DocRef::new(store, POLICY_REF)?,
})
}
pub fn ref_name(&self) -> &str {
self.doc.ref_name()
}
pub fn history(&self) -> Result<Vec<crate::control::DocVersion>> {
self.doc.history()
}
pub fn get(&self, repo: &RepoRef) -> Result<Option<String>> {
self.doc.load()?.repos.get(&repo.key())
}
pub fn set(&self, repo: &RepoRef, document: &str) -> Result<()> {
if document.trim().is_empty() {
return Err(crate::error::Error::InvalidInput {
what: "policy document",
reason: "empty; use `remove` to delete a repository's policy".to_owned(),
});
}
let key = repo.key();
let document = document.to_owned();
self.doc.update(|doc| {
doc.repos.insert(key.clone(), document.clone())?;
Ok(())
})
}
pub fn remove(&self, repo: &RepoRef) -> Result<bool> {
let key = repo.key();
self.doc.update(|doc| Ok(doc.repos.remove(&key)?.is_some()))
}
}