git-ents.gitmain
⌘K
foforge
lib.rs87 lines · 3.8 KB · rusthistorycomment on this file
1//! `git-ents`: the local root, the CLI-complete milestone
2//! (`docs/development-plan.adoc`, phase 6).
3//!
4//! This crate's one responsibility is composition and porcelain: it wires
5//! the four seams every other crate defines a trait for — `RefStore`
6//! ([`gix_ref_store`]), the object store (gitoxide's own `Find`/`Write`),
7//! `EventSink` ([`ents_receive`]), and `Executor` ([`ents_effect`]) — into
8//! two composition roots ([`root`]), and exposes a subcommand surface
9//! above them. No business logic lives here that a library crate should
10//! own instead: every command module is a thin caller of `ents-gate`,
11//! `ents-receive`, `ents-effect`, `ents-anchor`, or `ents-sync`.
12//!
13//! # Spec coverage
14//!
15//! From `docs/spec/roots.adoc`:
16//!
17//! - `roots.composition`, `roots.local` — [`root::LocalRoot`]: the plain
18//! CLI's composition root (loose-ref `RefStore`, the local odb, a null
19//! `EventSink`, the advisory gate).
20//! - `roots.config-isolation` — every trait implementation is selected in
21//! [`root`] alone; no command module branches on configuration.
22//! - `roots.worktree-update` — [`commands::setup`] sets
23//! `receive.denyCurrentBranch=updateInstead` on the local repository, the
24//! integration-test-harness edge case that spec section names.
25//!
26//! The development plan's phase-6 row additionally doubles this crate as
27//! the single-node hosted root: [`root::HostedRoot`] and [`hook`] wire
28//! loose refs and a real odb behind git's own `receive-pack`, an in-memory
29//! `EventSink` reconciled at boot (`receive.reconstructible`), and a
30//! `SpriteExecutor`. See those modules' own docs for the design this
31//! deployment shape requires — the git-serving-transport case is
32//! deliberately not `roots.hosted` (`git-ents-server`, phase 8, which
33//! replaces the store itself); it is this same crate's wiring, reused,
34//! per the plan's own framing.
35//!
36//! # Examples
37//!
38//! An end-to-end local write: enroll an admin member, then use it to
39//! enroll a second member, mirroring what `git ents members add` does.
40//!
41//! ```
42//! use ents_model::{MemberId, Provenance};
43//! use ents_receive::{Identity, Mode, propose_entity};
44//! use git_ents::mutate::outcome_to_result;
45//! use git_ents::root::LocalRoot;
46//! use git_ents::sign::Signer;
47//! use gix_ref_store::RefStoreRead;
48//!
49//! # let dir = tempfile::tempdir().expect("tempdir");
50//! # gix::init(dir.path()).expect("init");
51//! # let key_path = dir.path().join("id_ed25519");
52//! # {
53//! # use ssh_key::private::{Ed25519Keypair, KeypairData};
54//! # let pair = Ed25519Keypair::from_seed(&[3; 32]);
55//! # let key = ssh_key::PrivateKey::new(KeypairData::from(pair), "t").expect("well-formed");
56//! # key.write_openssh_file(&key_path, ssh_key::LineEnding::LF).expect("write");
57//! # }
58//! let root = LocalRoot::open(dir.path()).expect("opens");
59//! let signer = Signer::load(&key_path).expect("loads");
60//! let actor = gix::actor::Signature {
61//! name: "jdc".into(), email: "jdc@ents.test".into(),
62//! time: gix::date::Time { seconds: 1_000, offset: 0 },
63//! };
64//! let identity = Identity { actor, author: None, sign: &|payload| signer.sign(payload) };
65//!
66//! let member = ents_model::Member::new("jdc", signer.public_openssh(), Provenance::AdminRegistered);
67//! let name = ents_model::namespace::member_ref(&MemberId::new("jdc")).expect("valid");
68//! let outcome = propose_entity(
69//! &root.refs, &root.objects, &root.events, name.clone(), &member,
70//! &identity, "Enroll jdc", root.mode(),
71//! ).expect("evaluates");
72//! outcome_to_result(outcome, None).expect("bootstrap admits the first member");
73//! assert!(root.refs.get(name.as_ref()).expect("reads").is_some());
74//! ```
75
76pub mod cli;
77pub mod commands;
78pub mod compose;
79pub mod error;
80pub mod exe;
81pub mod hook;
82pub mod mutate;
83pub mod package;
84pub mod root;
85pub mod sign;
86
87pub use error::{Error, Result};