refactor: derive CLI Set REF/NOUN/load/store from the storage traits
commit
d89c4carefactor: derive CLI Set REF/NOUN/load/store from the storage traits
Set now applies directly to a MapDocument + Component item (Check) instead of a separate marker type, and its REF/NOUN/load/store default to the items own trait impls, so the checks Set impl shrinks to just empty_listing/key/value.
refactor: implement Set for Check directly, dropping the Checks marker Assisted-by: Claude:claude-sonnet-5
Reviews
No reviews of this commit yet — record a verdict below.
Start a review
crates/git-ents/src/main.rs
@@ -23,6 +23,7 @@
use git_comment::{COMMENTS_NS, Comment};
use git_ents::account::{self, Account};
use git_ents::checks::{self, CHECKS_REF, Check};
+use git_ents::component::{self, Component, MapDocument};
use git_ents::members::{self, MEMBER_NS, Member, Trust, member_ref};
use git_ents::revocations::{self, REVOKED_REF, Revocation};
@@ -343,14 +344,14 @@
fn run_checks(action: ChecksAction, remote: &str) -> Result<(), String> {
match action {
- ChecksAction::List => list::<Checks>(remote),
+ ChecksAction::List => list::<Check>(remote),
ChecksAction::Add {
name,
command,
image,
depends,
} => add_check(name, command, image, depends, remote),
- ChecksAction::Remove { name } => remove::<Checks>(&name, remote),
+ ChecksAction::Remove { name } => remove::<Check>(&name, remote),
ChecksAction::Debug => checks_debug(remote),
ChecksAction::Runs => checks_runs(remote),
}
@@ -585,45 +586,38 @@
/// A `refs/meta/*` set the porcelain manages uniformly: a named ref synced from
/// and pushed to a remote, holding entries the CLI lists and removes from. The
/// check set runs through this; the member set is decomposed across
-/// `refs/meta/member/*` and handled on its own. A set differs only in its item
-/// type, what the messages call an entry, and how a row presents; the thin
-/// [`load`](Set::load)/[`store`](Set::store) keep each on its own typed module.
-trait Set {
- /// The set's item type.
- type Item;
- /// The ref the set lives on.
- const REF: &'static str;
- /// The singular noun used in messages ("member", "check").
- const NOUN: &'static str;
-
- /// The set's items.
- fn load(repo: &Path) -> Result<Vec<Self::Item>, String>;
- /// Replace the set with `items`.
- fn store(repo: &Path, items: &[Self::Item]) -> Result<(), String>;
+/// `refs/meta/member/*` and handled on its own, and the revocation set's CLI
+/// needs more than these four methods (fingerprint validation, a
+/// lock-yourself-out confirmation) so it stays bespoke too. `REF`, `NOUN`,
+/// and the default [`load`](Set::load)/[`store`](Set::store) come from the
+/// item's own [`MapDocument`]/[`Component`] impls, so a `Set` impl needs only
+/// say how an entry lists and what its key is.
+trait Set: MapDocument + Component {
/// The line printed when the set is empty on `remote`.
fn empty_listing(remote: &str) -> String;
/// An item's key — its identity for removal and the left list column.
- fn key(item: &Self::Item) -> String;
+ fn key(item: &Self) -> String;
/// The right list column for an item.
- fn value(item: &Self::Item) -> String;
+ fn value(item: &Self) -> String;
+
+ /// The set's items.
+ fn load(repo: &Path) -> Result<Vec<Self>, String> {
+ component::load_map(&git_store::Store::open(repo).map_err(|error| error.to_string())?)
+ .map_err(|error| error.to_string())
+ }
+
+ /// Replace the set with `items`.
+ fn store(repo: &Path, items: &[Self]) -> Result<(), String> {
+ component::store_map(
+ &git_store::Store::open(repo).map_err(|error| error.to_string())?,
+ items,
+ &format!("Update {}", Self::PLURAL),
+ )
+ .map_err(|error| error.to_string())
+ }
}
-/// The configured check set at `refs/meta/checks`.
-struct Checks;
-
-impl Set for Checks {
- type Item = Check;
- const REF: &'static str = CHECKS_REF;
- const NOUN: &'static str = "check";
-
- fn load(repo: &Path) -> Result<Vec<Check>, String> {
- checks::load(repo).map_err(|error| error.to_string())
- }
-
- fn store(repo: &Path, items: &[Check]) -> Result<(), String> {
- checks::store(repo, items).map_err(|error| error.to_string())
- }
-
+impl Set for Check {
fn empty_listing(remote: &str) -> String {
format!("no checks configured on {remote}")
}
@@ -676,7 +670,7 @@
let expected = sync(remote, S::REF)?;
let before = S::load(&repo)?;
let count = before.len();
- let after: Vec<S::Item> = before
+ let after: Vec<S> = before
.into_iter()
.filter(|item| S::key(item) != key)
.collect();