radicle: Split out `SignRepository` trait
This new trait is used when only signing refs is needed, and not general write access to a repository. We also implement `ReadRepository` and `SignRepository` for `DraftStore`.
This commit is contained in:
parent
ff7e9ded17
commit
4634913b66
|
|
@ -27,7 +27,7 @@ use radicle::profile;
|
|||
use radicle::profile::Home;
|
||||
use radicle::profile::Profile;
|
||||
use radicle::rad;
|
||||
use radicle::storage::{ReadRepository, ReadStorage as _, WriteRepository};
|
||||
use radicle::storage::{ReadRepository, ReadStorage as _, SignRepository as _};
|
||||
use radicle::test::fixtures;
|
||||
use radicle::Storage;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ use radicle::crypto::{PublicKey, Signer};
|
|||
use radicle::node;
|
||||
use radicle::node::{Handle, NodeId};
|
||||
use radicle::prelude::Id;
|
||||
use radicle::storage;
|
||||
use radicle::storage::git::cob::object::ParseObjectId;
|
||||
use radicle::storage::git::transport::local::Url;
|
||||
use radicle::storage::WriteRepository;
|
||||
use radicle::storage::{self, ReadRepository};
|
||||
use radicle::storage::{ReadRepository, SignRepository as _, WriteRepository};
|
||||
use radicle::Profile;
|
||||
use radicle::{git, rad};
|
||||
use radicle_cli::terminal as cli;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
use std::path::Path;
|
||||
|
||||
use radicle::{node::Handle, storage::ReadStorage, storage::WriteRepository};
|
||||
use radicle::{
|
||||
node::Handle,
|
||||
storage::{ReadStorage, SignRepository, WriteRepository},
|
||||
};
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let cwd = Path::new(".").canonicalize()?;
|
||||
|
|
|
|||
|
|
@ -1152,7 +1152,7 @@ pub struct PatchMut<'a, 'g, R> {
|
|||
|
||||
impl<'a, 'g, R> PatchMut<'a, 'g, R>
|
||||
where
|
||||
R: WriteRepository + cob::Store,
|
||||
R: ReadRepository + SignRepository + cob::Store,
|
||||
{
|
||||
pub fn new(
|
||||
id: ObjectId,
|
||||
|
|
@ -1392,7 +1392,7 @@ impl<'a, R> Deref for Patches<'a, R> {
|
|||
|
||||
impl<'a, R> Patches<'a, R>
|
||||
where
|
||||
R: WriteRepository + cob::Store,
|
||||
R: ReadRepository + cob::Store,
|
||||
{
|
||||
/// Open an patches store.
|
||||
pub fn open(repository: &'a R) -> Result<Self, store::Error> {
|
||||
|
|
@ -1401,6 +1401,74 @@ where
|
|||
Ok(Self { raw })
|
||||
}
|
||||
|
||||
/// Patches count by state.
|
||||
pub fn counts(&self) -> Result<PatchCounts, store::Error> {
|
||||
let all = self.all()?;
|
||||
let state_groups =
|
||||
all.filter_map(|s| s.ok())
|
||||
.fold(PatchCounts::default(), |mut state, (_, p, _)| {
|
||||
match p.state() {
|
||||
State::Draft => state.draft += 1,
|
||||
State::Open { .. } => state.open += 1,
|
||||
State::Archived => state.archived += 1,
|
||||
State::Merged { .. } => state.merged += 1,
|
||||
}
|
||||
state
|
||||
});
|
||||
|
||||
Ok(state_groups)
|
||||
}
|
||||
|
||||
/// Find the `Patch` containing the given `Revision`.
|
||||
pub fn find_by_revision(
|
||||
&self,
|
||||
id: &RevisionId,
|
||||
) -> Result<Option<(PatchId, Patch, Revision)>, Error> {
|
||||
// Revision may be the patch's first, making it have the same ID.
|
||||
let p_id = ObjectId::from(id);
|
||||
if let Some(p) = self.get(&p_id)? {
|
||||
return Ok(p.revision(id).map(|r| (p_id, p.clone(), r.clone())));
|
||||
}
|
||||
|
||||
let result = self
|
||||
.all()?
|
||||
.filter_map(|result| result.ok())
|
||||
.find_map(|(p_id, p, _)| p.revision(id).map(|r| (p_id, p.clone(), r.clone())));
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Get a patch.
|
||||
pub fn get(&self, id: &ObjectId) -> Result<Option<Patch>, store::Error> {
|
||||
self.raw.get(id).map(|r| r.map(|(p, _)| p))
|
||||
}
|
||||
|
||||
/// Get proposed patches.
|
||||
pub fn proposed(
|
||||
&self,
|
||||
) -> Result<impl Iterator<Item = (PatchId, Patch, clock::Lamport)> + '_, Error> {
|
||||
let all = self.all()?;
|
||||
|
||||
Ok(all
|
||||
.into_iter()
|
||||
.filter_map(|result| result.ok())
|
||||
.filter(|(_, p, _)| p.is_open()))
|
||||
}
|
||||
|
||||
/// Get patches proposed by the given key.
|
||||
pub fn proposed_by<'b>(
|
||||
&'b self,
|
||||
who: &'b Did,
|
||||
) -> Result<impl Iterator<Item = (PatchId, Patch, clock::Lamport)> + '_, Error> {
|
||||
Ok(self
|
||||
.proposed()?
|
||||
.filter(move |(_, p, _)| p.author().id() == who))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R> Patches<'a, R>
|
||||
where
|
||||
R: ReadRepository + SignRepository + cob::Store,
|
||||
{
|
||||
/// Open a new patch.
|
||||
pub fn create<'g, G: Signer>(
|
||||
&'g mut self,
|
||||
|
|
@ -1447,47 +1515,6 @@ where
|
|||
)
|
||||
}
|
||||
|
||||
/// Patches count by state.
|
||||
pub fn counts(&self) -> Result<PatchCounts, store::Error> {
|
||||
let all = self.all()?;
|
||||
let state_groups =
|
||||
all.filter_map(|s| s.ok())
|
||||
.fold(PatchCounts::default(), |mut state, (_, p, _)| {
|
||||
match p.state() {
|
||||
State::Draft => state.draft += 1,
|
||||
State::Open { .. } => state.open += 1,
|
||||
State::Archived => state.archived += 1,
|
||||
State::Merged { .. } => state.merged += 1,
|
||||
}
|
||||
state
|
||||
});
|
||||
|
||||
Ok(state_groups)
|
||||
}
|
||||
|
||||
/// Find the `Patch` containing the given `Revision`.
|
||||
pub fn find_by_revision(
|
||||
&self,
|
||||
id: &RevisionId,
|
||||
) -> Result<Option<(PatchId, Patch, Revision)>, Error> {
|
||||
// Revision may be the patch's first, making it have the same ID.
|
||||
let p_id = ObjectId::from(id);
|
||||
if let Some(p) = self.get(&p_id)? {
|
||||
return Ok(p.revision(id).map(|r| (p_id, p.clone(), r.clone())));
|
||||
}
|
||||
|
||||
let result = self
|
||||
.all()?
|
||||
.filter_map(|result| result.ok())
|
||||
.find_map(|(p_id, p, _)| p.revision(id).map(|r| (p_id, p.clone(), r.clone())));
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Get a patch.
|
||||
pub fn get(&self, id: &ObjectId) -> Result<Option<Patch>, store::Error> {
|
||||
self.raw.get(id).map(|r| r.map(|(p, _)| p))
|
||||
}
|
||||
|
||||
/// Get a patch mutably.
|
||||
pub fn get_mut<'g>(&'g mut self, id: &ObjectId) -> Result<PatchMut<'a, 'g, R>, store::Error> {
|
||||
let (patch, clock) = self
|
||||
|
|
@ -1503,28 +1530,6 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
/// Get proposed patches.
|
||||
pub fn proposed(
|
||||
&self,
|
||||
) -> Result<impl Iterator<Item = (PatchId, Patch, clock::Lamport)> + 'a, Error> {
|
||||
let all = self.all()?;
|
||||
|
||||
Ok(all
|
||||
.into_iter()
|
||||
.filter_map(|result| result.ok())
|
||||
.filter(|(_, p, _)| p.is_open()))
|
||||
}
|
||||
|
||||
/// Get patches proposed by the given key.
|
||||
pub fn proposed_by<'b>(
|
||||
&'b self,
|
||||
who: &'b Did,
|
||||
) -> Result<impl Iterator<Item = (PatchId, Patch, clock::Lamport)> + '_, Error> {
|
||||
Ok(self
|
||||
.proposed()?
|
||||
.filter(move |(_, p, _)| p.author().id() == who))
|
||||
}
|
||||
|
||||
/// Create a patch. This is an internal function used by `create` and `draft`.
|
||||
fn _create<'g, G: Signer>(
|
||||
&'g mut self,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use crate::cob::{ActorId, Create, EntryId, History, ObjectId, TypeName, Update,
|
|||
use crate::git;
|
||||
use crate::prelude::*;
|
||||
use crate::storage::git as storage;
|
||||
use crate::storage::SignRepository;
|
||||
use crate::{cob, identity};
|
||||
|
||||
/// History type for standard radicle COBs.
|
||||
|
|
@ -155,7 +156,7 @@ impl<'a, T, R: ReadRepository> Store<'a, T, R> {
|
|||
|
||||
impl<'a, T, R> Store<'a, T, R>
|
||||
where
|
||||
R: WriteRepository + cob::Store,
|
||||
R: ReadRepository + SignRepository + cob::Store,
|
||||
T: FromHistory,
|
||||
T::Action: Serialize,
|
||||
{
|
||||
|
|
@ -220,6 +221,34 @@ where
|
|||
Ok((*cob.id(), object, clock))
|
||||
}
|
||||
|
||||
/// Remove an object.
|
||||
pub fn remove<G: Signer>(&self, id: &ObjectId, signer: &G) -> Result<(), Error> {
|
||||
let name = git::refs::storage::cob(signer.public_key(), T::type_name(), id);
|
||||
match self
|
||||
.repo
|
||||
.reference_oid(signer.public_key(), &name.strip_namespace())
|
||||
{
|
||||
Ok(_) => {
|
||||
cob::remove(self.repo, signer.public_key(), T::type_name(), id)?;
|
||||
self.repo.sign_refs(signer).map_err(Error::SignRefs)?;
|
||||
Ok(())
|
||||
}
|
||||
Err(git::Error::NotFound(_)) => Ok(()),
|
||||
Err(git::Error::Git(err)) if err.code() == git::raw::ErrorCode::NotFound => Ok(()),
|
||||
Err(err) => Err(Error::RefLookup {
|
||||
name: name.to_ref_string(),
|
||||
err,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, R> Store<'a, T, R>
|
||||
where
|
||||
R: ReadRepository + cob::Store,
|
||||
T: FromHistory,
|
||||
T::Action: Serialize,
|
||||
{
|
||||
/// Get an object.
|
||||
pub fn get(&self, id: &ObjectId) -> Result<Option<(T, Lamport)>, Error> {
|
||||
let cob = cob::get(self.repo, T::type_name(), id)?;
|
||||
|
|
@ -259,27 +288,6 @@ where
|
|||
|
||||
Ok(raw.len())
|
||||
}
|
||||
|
||||
/// Remove an object.
|
||||
pub fn remove<G: Signer>(&self, id: &ObjectId, signer: &G) -> Result<(), Error> {
|
||||
let name = git::refs::storage::cob(signer.public_key(), T::type_name(), id);
|
||||
match self
|
||||
.repo
|
||||
.reference_oid(signer.public_key(), &name.strip_namespace())
|
||||
{
|
||||
Ok(_) => {
|
||||
cob::remove(self.repo, signer.public_key(), T::type_name(), id)?;
|
||||
self.repo.sign_refs(signer).map_err(Error::SignRefs)?;
|
||||
Ok(())
|
||||
}
|
||||
Err(git::Error::NotFound(_)) => Ok(()),
|
||||
Err(git::Error::Git(err)) if err.code() == git::raw::ErrorCode::NotFound => Ok(()),
|
||||
Err(err) => Err(Error::RefLookup {
|
||||
name: name.to_ref_string(),
|
||||
err,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows operations to be batched atomically.
|
||||
|
|
@ -310,7 +318,7 @@ impl<T: FromHistory> Transaction<T> {
|
|||
where
|
||||
G: Signer,
|
||||
F: FnOnce(&mut Self) -> Result<(), Error>,
|
||||
R: WriteRepository + cob::Store,
|
||||
R: ReadRepository + SignRepository + cob::Store,
|
||||
T::Action: Serialize + Clone,
|
||||
{
|
||||
let actor = *signer.public_key();
|
||||
|
|
@ -350,7 +358,7 @@ impl<T: FromHistory> Transaction<T> {
|
|||
signer: &G,
|
||||
) -> Result<(Vec<cob::Op<T::Action>>, Lamport, EntryId), Error>
|
||||
where
|
||||
R: WriteRepository + cob::Store,
|
||||
R: ReadRepository + SignRepository + cob::Store,
|
||||
T::Action: Serialize + Clone,
|
||||
{
|
||||
let actions = NonEmpty::from_vec(self.actions)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ pub mod prelude {
|
|||
pub use identity::{project::Project, Did, Doc, Id};
|
||||
pub use node::{Alias, NodeId, Timestamp};
|
||||
pub use profile::Profile;
|
||||
pub use storage::{BranchName, ReadRepository, ReadStorage, WriteRepository, WriteStorage};
|
||||
pub use storage::{
|
||||
BranchName, ReadRepository, ReadStorage, SignRepository, WriteRepository, WriteStorage,
|
||||
};
|
||||
}
|
||||
|
||||
pub mod env {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use crate::identity::{doc, IdentityError};
|
|||
use crate::storage::git::transport;
|
||||
use crate::storage::git::Repository;
|
||||
use crate::storage::refs::SignedRefs;
|
||||
use crate::storage::{BranchName, ReadRepository as _, RemoteId};
|
||||
use crate::storage::{BranchName, ReadRepository as _, RemoteId, SignRepository as _};
|
||||
use crate::storage::{WriteRepository, WriteStorage};
|
||||
use crate::{identity, storage};
|
||||
|
||||
|
|
|
|||
|
|
@ -450,18 +450,22 @@ pub trait ReadRepository: Sized {
|
|||
}
|
||||
|
||||
/// Allows read-write access to a repository.
|
||||
pub trait WriteRepository: ReadRepository {
|
||||
pub trait WriteRepository: ReadRepository + SignRepository {
|
||||
/// Set the repository head to the canonical branch.
|
||||
/// This computes the head based on the delegate set.
|
||||
fn set_head(&self) -> Result<Oid, IdentityError>;
|
||||
/// Set the repository 'rad/id' to the canonical commit, agreed by quorum.
|
||||
fn set_identity_head(&self) -> Result<Oid, IdentityError>;
|
||||
/// Sign the repository's refs under the `refs/rad/sigrefs` branch.
|
||||
fn sign_refs<G: Signer>(&self, signer: &G) -> Result<SignedRefs<Verified>, Error>;
|
||||
/// Get the underlying git repository.
|
||||
fn raw(&self) -> &git2::Repository;
|
||||
}
|
||||
|
||||
/// Allows signing refs.
|
||||
pub trait SignRepository {
|
||||
/// Sign the repository's refs under the `refs/rad/sigrefs` branch.
|
||||
fn sign_refs<G: Signer>(&self, signer: &G) -> Result<SignedRefs<Verified>, Error>;
|
||||
}
|
||||
|
||||
impl<T, S> ReadStorage for T
|
||||
where
|
||||
T: Deref<Target = S>,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ use crate::identity::{Identity, IdentityError, Project};
|
|||
use crate::storage::refs;
|
||||
use crate::storage::refs::{Refs, SignedRefs};
|
||||
use crate::storage::{
|
||||
Inventory, ReadRepository, ReadStorage, Remote, Remotes, WriteRepository, WriteStorage,
|
||||
Inventory, ReadRepository, ReadStorage, Remote, Remotes, SignRepository, WriteRepository,
|
||||
WriteStorage,
|
||||
};
|
||||
|
||||
pub use crate::git::*;
|
||||
|
|
@ -628,6 +629,12 @@ impl WriteRepository for Repository {
|
|||
Ok(head)
|
||||
}
|
||||
|
||||
fn raw(&self) -> &git2::Repository {
|
||||
&self.backend
|
||||
}
|
||||
}
|
||||
|
||||
impl SignRepository for Repository {
|
||||
fn sign_refs<G: Signer>(&self, signer: &G) -> Result<SignedRefs<Verified>, Error> {
|
||||
let remote = signer.public_key();
|
||||
let refs = self.references_of(remote)?;
|
||||
|
|
@ -637,10 +644,6 @@ impl WriteRepository for Repository {
|
|||
|
||||
Ok(signed)
|
||||
}
|
||||
|
||||
fn raw(&self) -> &git2::Repository {
|
||||
&self.backend
|
||||
}
|
||||
}
|
||||
|
||||
pub mod trailers {
|
||||
|
|
@ -703,7 +706,7 @@ mod tests {
|
|||
use super::*;
|
||||
use crate::git;
|
||||
use crate::storage::refs::SIGREFS_BRANCH;
|
||||
use crate::storage::{ReadRepository, ReadStorage, WriteRepository};
|
||||
use crate::storage::{ReadRepository, ReadStorage};
|
||||
use crate::test::arbitrary;
|
||||
use crate::test::fixtures;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,18 @@ use std::collections::BTreeMap;
|
|||
use cob::object::Objects;
|
||||
use radicle_cob as cob;
|
||||
use radicle_cob::change;
|
||||
use storage::SignRepository;
|
||||
|
||||
use crate::git;
|
||||
use crate::storage;
|
||||
use crate::storage::Error;
|
||||
use crate::storage::ReadRepository;
|
||||
use crate::storage::{
|
||||
git::{Remote, Remotes, VerifyError},
|
||||
ReadRepository, Verified,
|
||||
};
|
||||
use crate::{
|
||||
git, identity,
|
||||
identity::{doc::DocError, IdentityError},
|
||||
};
|
||||
|
||||
pub use crate::git::*;
|
||||
pub use cob::*;
|
||||
|
|
@ -165,14 +173,24 @@ impl cob::object::Storage for Repository {
|
|||
}
|
||||
|
||||
/// Stores draft collaborative objects.
|
||||
pub struct DraftStore {
|
||||
///
|
||||
// This storage backend for COBs stores changes in a `draft/cobs/*` namespace,
|
||||
// which allows for some of the features needed for code review. For
|
||||
// example, users can draft comments and later decide to publish them.
|
||||
pub struct DraftStore<'a> {
|
||||
remote: RemoteId,
|
||||
repo: Repository,
|
||||
repo: &'a Repository,
|
||||
}
|
||||
|
||||
impl cob::Store for DraftStore {}
|
||||
impl<'a> DraftStore<'a> {
|
||||
pub fn new(remote: RemoteId, repo: &'a Repository) -> Self {
|
||||
Self { remote, repo }
|
||||
}
|
||||
}
|
||||
|
||||
impl change::Storage for DraftStore {
|
||||
impl<'a> cob::Store for DraftStore<'a> {}
|
||||
|
||||
impl<'a> change::Storage for DraftStore<'a> {
|
||||
type StoreError = <git2::Repository as change::Storage>::StoreError;
|
||||
type LoadError = <git2::Repository as change::Storage>::LoadError;
|
||||
|
||||
|
|
@ -202,7 +220,125 @@ impl change::Storage for DraftStore {
|
|||
}
|
||||
}
|
||||
|
||||
impl cob::object::Storage for DraftStore {
|
||||
impl<'a> SignRepository for DraftStore<'a> {
|
||||
fn sign_refs<G: crypto::Signer>(
|
||||
&self,
|
||||
signer: &G,
|
||||
) -> Result<storage::refs::SignedRefs<Verified>, Error> {
|
||||
self.repo.sign_refs(signer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ReadRepository for DraftStore<'a> {
|
||||
fn id(&self) -> identity::Id {
|
||||
self.repo.id()
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> Result<bool, git2::Error> {
|
||||
self.repo.is_empty()
|
||||
}
|
||||
|
||||
fn head(&self) -> Result<(fmt::Qualified, Oid), identity::IdentityError> {
|
||||
self.repo.head()
|
||||
}
|
||||
|
||||
fn canonical_head(&self) -> Result<(fmt::Qualified, Oid), identity::IdentityError> {
|
||||
self.repo.canonical_head()
|
||||
}
|
||||
|
||||
fn validate_remote(
|
||||
&self,
|
||||
remote: &Remote<Verified>,
|
||||
) -> Result<Vec<fmt::RefString>, VerifyError> {
|
||||
self.repo.validate_remote(remote)
|
||||
}
|
||||
|
||||
fn path(&self) -> &std::path::Path {
|
||||
self.repo.path()
|
||||
}
|
||||
|
||||
fn remote(&self, id: &RemoteId) -> Result<Remote<Verified>, storage::refs::Error> {
|
||||
self.repo.remote(id)
|
||||
}
|
||||
|
||||
fn remotes(&self) -> Result<Remotes<Verified>, storage::refs::Error> {
|
||||
ReadRepository::remotes(self.repo)
|
||||
}
|
||||
|
||||
fn commit(&self, oid: Oid) -> Result<git2::Commit, git_ext::Error> {
|
||||
self.repo.commit(oid)
|
||||
}
|
||||
|
||||
fn revwalk(&self, head: Oid) -> Result<git2::Revwalk, git2::Error> {
|
||||
self.repo.revwalk(head)
|
||||
}
|
||||
|
||||
fn is_ancestor_of(&self, ancestor: Oid, head: Oid) -> Result<bool, git_ext::Error> {
|
||||
self.repo.is_ancestor_of(ancestor, head)
|
||||
}
|
||||
|
||||
fn blob_at<'b>(
|
||||
&'b self,
|
||||
oid: git_ext::Oid,
|
||||
path: &'b std::path::Path,
|
||||
) -> Result<git2::Blob<'b>, git_ext::Error> {
|
||||
self.repo.blob_at(oid, path)
|
||||
}
|
||||
|
||||
fn reference(
|
||||
&self,
|
||||
remote: &RemoteId,
|
||||
reference: &git::Qualified,
|
||||
) -> Result<git2::Reference, git_ext::Error> {
|
||||
self.repo.reference(remote, reference)
|
||||
}
|
||||
|
||||
fn reference_oid(
|
||||
&self,
|
||||
remote: &RemoteId,
|
||||
reference: &git::Qualified,
|
||||
) -> Result<git_ext::Oid, git_ext::Error> {
|
||||
self.repo.reference_oid(remote, reference)
|
||||
}
|
||||
|
||||
fn references_of(&self, remote: &RemoteId) -> Result<crate::storage::refs::Refs, Error> {
|
||||
self.repo.references_of(remote)
|
||||
}
|
||||
|
||||
fn references_glob(
|
||||
&self,
|
||||
pattern: &git::PatternStr,
|
||||
) -> Result<Vec<(fmt::Qualified, Oid)>, git::ext::Error> {
|
||||
self.repo.references_glob(pattern)
|
||||
}
|
||||
|
||||
fn identity_doc(
|
||||
&self,
|
||||
) -> Result<(Oid, crate::identity::Doc<crate::crypto::Unverified>), IdentityError> {
|
||||
self.repo.identity_doc()
|
||||
}
|
||||
|
||||
fn identity_doc_at(
|
||||
&self,
|
||||
head: Oid,
|
||||
) -> Result<crate::identity::Doc<crate::crypto::Unverified>, DocError> {
|
||||
self.repo.identity_doc_at(head)
|
||||
}
|
||||
|
||||
fn identity_head(&self) -> Result<Oid, IdentityError> {
|
||||
self.repo.identity_head()
|
||||
}
|
||||
|
||||
fn canonical_identity_head(&self) -> Result<Oid, IdentityError> {
|
||||
self.repo.canonical_identity_head()
|
||||
}
|
||||
|
||||
fn merge_base(&self, left: &Oid, right: &Oid) -> Result<Oid, git::ext::Error> {
|
||||
self.repo.merge_base(left, right)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> cob::object::Storage for DraftStore<'a> {
|
||||
type ObjectsError = ObjectsError;
|
||||
type TypesError = git::ext::Error;
|
||||
type UpdateError = git2::Error;
|
||||
|
|
@ -276,6 +412,6 @@ impl cob::object::Storage for DraftStore {
|
|||
git::refs::storage::draft::cob(identifier, typename, object_id).as_str(),
|
||||
)?;
|
||||
|
||||
reference.delete().map_err(Self::RemoveError::from)
|
||||
reference.delete()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -248,14 +248,16 @@ impl WriteRepository for MockRepository {
|
|||
todo!()
|
||||
}
|
||||
|
||||
fn set_identity_head(&self) -> Result<Oid, IdentityError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl SignRepository for MockRepository {
|
||||
fn sign_refs<G: Signer>(
|
||||
&self,
|
||||
_signer: &G,
|
||||
) -> Result<crate::storage::refs::SignedRefs<Verified>, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_identity_head(&self) -> Result<Oid, IdentityError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue