diff --git a/radicle-cli/src/commands/assign.rs b/radicle-cli/src/commands/assign.rs index f0a698fb..a0e00ef2 100644 --- a/radicle-cli/src/commands/assign.rs +++ b/radicle-cli/src/commands/assign.rs @@ -83,7 +83,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { let signer = term::signer(&profile)?; let storage = &profile.storage; let (_, id) = radicle::rad::cwd()?; - let repo = storage.repository(id)?; + let repo = storage.repository_mut(id)?; let mut issues = issue::Issues::open(*signer.public_key(), &repo)?; let mut issue = issues.get_mut(&options.id).map_err(|err| match err { diff --git a/radicle-cli/src/commands/checkout.rs b/radicle-cli/src/commands/checkout.rs index 74e7823d..b9f2f46a 100644 --- a/radicle-cli/src/commands/checkout.rs +++ b/radicle-cli/src/commands/checkout.rs @@ -7,7 +7,6 @@ use anyhow::Context as _; use radicle::prelude::*; use radicle::storage::git::transport; use radicle::storage::RemoteId; -use radicle::storage::WriteStorage; use crate::project; use crate::terminal as term; diff --git a/radicle-cli/src/commands/clone.rs b/radicle-cli/src/commands/clone.rs index ee00fa9c..b439db68 100644 --- a/radicle-cli/src/commands/clone.rs +++ b/radicle-cli/src/commands/clone.rs @@ -15,7 +15,6 @@ use radicle::prelude::*; use radicle::rad; use radicle::storage; use radicle::storage::git::{ProjectError, Storage}; -use radicle::storage::WriteStorage; use crate::commands::rad_checkout as checkout; use crate::project; diff --git a/radicle-cli/src/commands/comment.rs b/radicle-cli/src/commands/comment.rs index 74df76fa..fff7e10b 100644 --- a/radicle-cli/src/commands/comment.rs +++ b/radicle-cli/src/commands/comment.rs @@ -10,7 +10,6 @@ use radicle::cob::store; use radicle::cob::thread; use radicle::prelude::*; use radicle::storage; -use radicle::storage::WriteStorage; use crate::terminal as term; use crate::terminal::args::{Args, Error, Help}; diff --git a/radicle-cli/src/commands/delegate/add.rs b/radicle-cli/src/commands/delegate/add.rs index 9e963625..8d75a9cb 100644 --- a/radicle-cli/src/commands/delegate/add.rs +++ b/radicle-cli/src/commands/delegate/add.rs @@ -19,7 +19,7 @@ where .get(&profile.public_key, id)? .context("No project with such ID exists")?; - let repo = storage.repository(id)?; + let repo = storage.repository_mut(id)?; if !project.is_delegate(me) { return Err(anyhow::anyhow!( diff --git a/radicle-cli/src/commands/delegate/remove.rs b/radicle-cli/src/commands/delegate/remove.rs index 840edc5c..8f815e16 100644 --- a/radicle-cli/src/commands/delegate/remove.rs +++ b/radicle-cli/src/commands/delegate/remove.rs @@ -19,7 +19,7 @@ where .get(&profile.public_key, id)? .context("No project with such ID exists")?; - let repo = storage.repository(id)?; + let repo = storage.repository_mut(id)?; if !project.is_delegate(me) { return Err(anyhow::anyhow!( diff --git a/radicle-cli/src/commands/edit.rs b/radicle-cli/src/commands/edit.rs index 20cbfec8..c7ad5a40 100644 --- a/radicle-cli/src/commands/edit.rs +++ b/radicle-cli/src/commands/edit.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use anyhow::{anyhow, Context as _}; use radicle::identity::Id; -use radicle::storage::{ReadStorage, WriteRepository, WriteStorage}; +use radicle::storage::{ReadStorage, WriteRepository}; use crate::terminal as term; use crate::terminal::args::{Args, Error, Help}; diff --git a/radicle-cli/src/commands/id.rs b/radicle-cli/src/commands/id.rs index e7bcf14a..d3b7091c 100644 --- a/radicle-cli/src/commands/id.rs +++ b/radicle-cli/src/commands/id.rs @@ -5,7 +5,7 @@ use radicle::cob::identity::{self, Proposal, ProposalId, Proposals, Revision, Re use radicle::git::Oid; use radicle::identity::Identity; use radicle::prelude::Doc; -use radicle::storage::WriteStorage as _; +use radicle::storage::ReadStorage as _; use radicle_crypto::{PublicKey, Verified}; use crate::terminal::args::{Args, Error, Help}; diff --git a/radicle-cli/src/commands/inspect.rs b/radicle-cli/src/commands/inspect.rs index d3658081..f2cd3e56 100644 --- a/radicle-cli/src/commands/inspect.rs +++ b/radicle-cli/src/commands/inspect.rs @@ -11,7 +11,7 @@ use json_color::{Color, Colorizer}; use radicle::crypto::Unverified; use radicle::identity::Untrusted; use radicle::identity::{Doc, Id}; -use radicle::storage::{ReadRepository, ReadStorage, WriteStorage}; +use radicle::storage::{ReadRepository, ReadStorage}; use crate::terminal as term; use crate::terminal::args::{Args, Error, Help}; diff --git a/radicle-cli/src/commands/issue.rs b/radicle-cli/src/commands/issue.rs index d8ea4875..f4870515 100644 --- a/radicle-cli/src/commands/issue.rs +++ b/radicle-cli/src/commands/issue.rs @@ -198,7 +198,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { let signer = term::signer(&profile)?; let storage = &profile.storage; let (_, id) = radicle::rad::cwd()?; - let repo = storage.repository(id)?; + let repo = storage.repository_mut(id)?; let mut issues = Issues::open(*signer.public_key(), &repo)?; match options.op { diff --git a/radicle-cli/src/commands/ls.rs b/radicle-cli/src/commands/ls.rs index 8fbe6484..21626647 100644 --- a/radicle-cli/src/commands/ls.rs +++ b/radicle-cli/src/commands/ls.rs @@ -3,7 +3,7 @@ use std::ffi::OsString; use crate::terminal as term; use crate::terminal::args::{Args, Error, Help}; -use radicle::storage::{ReadRepository, WriteStorage}; +use radicle::storage::{ReadRepository, ReadStorage}; pub const HELP: Help = Help { name: "ls", diff --git a/radicle-cli/src/commands/track.rs b/radicle-cli/src/commands/track.rs index 613c46f8..61e0a989 100644 --- a/radicle-cli/src/commands/track.rs +++ b/radicle-cli/src/commands/track.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use anyhow::{anyhow, Context as _}; use radicle::node::{Handle, NodeId}; -use radicle::storage::WriteStorage; +use radicle::storage::ReadStorage; use crate::terminal as term; use crate::terminal::args::{Args, Error, Help}; diff --git a/radicle-cli/src/commands/unassign.rs b/radicle-cli/src/commands/unassign.rs index e5f10b01..5529ab04 100644 --- a/radicle-cli/src/commands/unassign.rs +++ b/radicle-cli/src/commands/unassign.rs @@ -83,7 +83,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { let signer = term::signer(&profile)?; let storage = &profile.storage; let (_, id) = radicle::rad::cwd()?; - let repo = storage.repository(id)?; + let repo = storage.repository_mut(id)?; let mut issues = issue::Issues::open(*signer.public_key(), &repo)?; let mut issue = issues.get_mut(&options.id).map_err(|err| match err { diff --git a/radicle-cli/src/commands/untrack.rs b/radicle-cli/src/commands/untrack.rs index 4cd3c31b..e5ba3fb3 100644 --- a/radicle-cli/src/commands/untrack.rs +++ b/radicle-cli/src/commands/untrack.rs @@ -5,7 +5,7 @@ use anyhow::{anyhow, Context as _}; use radicle::identity::Id; use radicle::node::Handle; use radicle::prelude::*; -use radicle::storage::WriteStorage; +use radicle::storage::ReadStorage; use crate::terminal as term; use crate::terminal::args::{Args, Error, Help}; diff --git a/radicle-cli/tests/commands.rs b/radicle-cli/tests/commands.rs index f3680c0c..303959ac 100644 --- a/radicle-cli/tests/commands.rs +++ b/radicle-cli/tests/commands.rs @@ -6,7 +6,7 @@ use std::{thread, time}; use radicle::git; use radicle::prelude::Id; use radicle::profile::Home; -use radicle::storage::{ReadRepository, WriteStorage}; +use radicle::storage::{ReadRepository, ReadStorage}; use radicle::test::fixtures; use radicle_cli_test::TestFormula; diff --git a/radicle-httpd/src/api.rs b/radicle-httpd/src/api.rs index 91027b31..e0b6433b 100644 --- a/radicle-httpd/src/api.rs +++ b/radicle-httpd/src/api.rs @@ -14,7 +14,7 @@ use tower_http::cors::{self, CorsLayer}; use radicle::cob::issue::Issues; use radicle::identity::Id; -use radicle::storage::{ReadRepository, WriteStorage}; +use radicle::storage::{ReadRepository, ReadStorage}; use radicle::Profile; mod auth; diff --git a/radicle-httpd/src/api/test.rs b/radicle-httpd/src/api/test.rs index 06e29df1..19179425 100644 --- a/radicle-httpd/src/api/test.rs +++ b/radicle-httpd/src/api/test.rs @@ -13,7 +13,7 @@ use tower::ServiceExt; use radicle::cob::issue::Issues; use radicle::cob::patch::{MergeTarget, Patches}; use radicle::git::raw as git2; -use radicle::storage::WriteStorage; +use radicle::storage::ReadStorage; use radicle_cli::commands::rad_init; use radicle_crypto::ssh::keystore::MemorySigner; use radicle_crypto::Signer; diff --git a/radicle-httpd/src/api/v1/delegates.rs b/radicle-httpd/src/api/v1/delegates.rs index e8b3d09d..8ae6a256 100644 --- a/radicle-httpd/src/api/v1/delegates.rs +++ b/radicle-httpd/src/api/v1/delegates.rs @@ -5,7 +5,7 @@ use axum::{Json, Router}; use radicle::cob::issue::Issues; use radicle::identity::Did; -use radicle::storage::{ReadRepository, WriteStorage}; +use radicle::storage::{ReadRepository, ReadStorage}; use crate::api::axum_extra::{Path, Query}; use crate::api::error::Error; diff --git a/radicle-httpd/src/api/v1/projects.rs b/radicle-httpd/src/api/v1/projects.rs index a012c311..9bd91f8d 100644 --- a/radicle-httpd/src/api/v1/projects.rs +++ b/radicle-httpd/src/api/v1/projects.rs @@ -17,7 +17,7 @@ use radicle::cob::patch::Patches; use radicle::cob::{thread, ActorId, Tag}; use radicle::identity::Id; use radicle::node::NodeId; -use radicle::storage::{git::paths, ReadRepository, WriteStorage}; +use radicle::storage::{git::paths, ReadRepository, ReadStorage}; use radicle_surf::{Glob, Oid, Repository}; use crate::api::axum_extra::{Path, Query}; diff --git a/radicle-node/src/service/message.rs b/radicle-node/src/service/message.rs index 9d2dbff5..31cc74de 100644 --- a/radicle-node/src/service/message.rs +++ b/radicle-node/src/service/message.rs @@ -10,7 +10,7 @@ use crate::service::filter::Filter; use crate::service::{NodeId, Timestamp}; use crate::storage; use crate::storage::refs::SignedRefs; -use crate::storage::{ReadRepository, WriteStorage}; +use crate::storage::{ReadRepository, ReadStorage}; use crate::wire; /// Maximum number of addresses which can be announced to other nodes. @@ -154,8 +154,14 @@ pub struct RefsAnnouncement { impl RefsAnnouncement { /// Check if this announcement is "fresh", meaning if it contains refs we do not have. - pub fn is_fresh(&self, storage: S) -> Result { - let repo = storage.repository(self.rid)?; + pub fn is_fresh(&self, storage: S) -> Result { + let repo = match storage.repository(self.rid) { + // If the repo doesn't exist, we consider this announcement "fresh", since we + // obviously don't have the refs. + Err(e) if e.is_not_found() => return Ok(true), + Err(e) => return Err(e), + Ok(r) => r, + }; for (remote_id, theirs) in self.refs.iter() { if let Ok(ours) = repo.remote(remote_id) { diff --git a/radicle-node/src/test/simulator.rs b/radicle-node/src/test/simulator.rs index 91bff090..c64826fb 100644 --- a/radicle-node/src/test/simulator.rs +++ b/radicle-node/src/test/simulator.rs @@ -411,7 +411,11 @@ impl Simulation { Input::Fetched(f, result) => { let result = Rc::try_unwrap(result).unwrap(); if f.initiated { - let mut repo = p.storage().repository(f.rid).unwrap(); + let mut repo = match p.storage().repository_mut(f.rid) { + Ok(repo) => repo, + Err(e) if e.is_not_found() => p.storage().create(f.rid).unwrap(), + Err(e) => panic!("Failed to open repository: {e}"), + }; fetch(&mut repo, &f.remote, f.namespaces.clone()).unwrap(); } p.fetched(f, result); diff --git a/radicle-node/src/tests/e2e.rs b/radicle-node/src/tests/e2e.rs index ae3997fb..fb048fc5 100644 --- a/radicle-node/src/tests/e2e.rs +++ b/radicle-node/src/tests/e2e.rs @@ -2,7 +2,7 @@ use std::{thread, time}; use radicle::crypto::Signer; use radicle::node::{FetchResult, Handle as _}; -use radicle::storage::{ReadRepository, WriteStorage}; +use radicle::storage::{ReadRepository, ReadStorage}; use radicle::{assert_matches, rad}; use crate::service; diff --git a/radicle-node/src/worker.rs b/radicle-node/src/worker.rs index 3d477dcc..8602a7ce 100644 --- a/radicle-node/src/worker.rs +++ b/radicle-node/src/worker.rs @@ -166,7 +166,11 @@ impl Worker { fetch: &Fetch, tunnel: &mut Tunnel>, ) -> Result, FetchError> { - let repo = self.storage.repository(fetch.rid)?; + let repo = match self.storage.repository_mut(fetch.rid) { + Ok(r) => Ok(r), + Err(e) if e.is_not_found() => self.storage.create(fetch.rid), + Err(e) => Err(e), + }?; let tunnel_addr = tunnel.local_addr()?; let mut cmd = process::Command::new("git"); cmd.current_dir(repo.path()) diff --git a/radicle-remote-helper/src/lib.rs b/radicle-remote-helper/src/lib.rs index 780330c5..09d2d7a9 100644 --- a/radicle-remote-helper/src/lib.rs +++ b/radicle-remote-helper/src/lib.rs @@ -55,7 +55,7 @@ pub fn run(profile: radicle::Profile) -> Result<(), Box anyhow::Result<()> { let cwd = Path::new(".").canonicalize()?; diff --git a/radicle/src/identity.rs b/radicle/src/identity.rs index f560855c..fe7f3e1d 100644 --- a/radicle/src/identity.rs +++ b/radicle/src/identity.rs @@ -154,7 +154,7 @@ mod test { use crate::crypto::PublicKey; use crate::rad; use crate::storage::git::Storage; - use crate::storage::{ReadStorage, WriteRepository, WriteStorage}; + use crate::storage::{ReadStorage, WriteRepository}; use crate::test::fixtures; use super::did::Did; diff --git a/radicle/src/identity/doc.rs b/radicle/src/identity/doc.rs index fed53a4a..1ddfefe0 100644 --- a/radicle/src/identity/doc.rs +++ b/radicle/src/identity/doc.rs @@ -371,7 +371,7 @@ mod test { use crate::rad; use crate::storage::git::transport; use crate::storage::git::Storage; - use crate::storage::WriteStorage; + use crate::storage::WriteStorage as _; use crate::test::arbitrary; use crate::test::fixtures; @@ -414,7 +414,7 @@ mod test { let storage = Storage::open(tempdir.path().join("storage")).unwrap(); let remote = arbitrary::gen::(1); let proj = arbitrary::gen::(1); - let repo = storage.repository(proj).unwrap(); + let repo = storage.create(proj).unwrap(); let oid = git2::Oid::from_str("2d52a53ce5e4f141148a5f770cfd3ead2d6a45b8").unwrap(); let err = Doc::::head(&remote, &repo).unwrap_err(); diff --git a/radicle/src/rad.rs b/radicle/src/rad.rs index dfe43ab3..cffd5d14 100644 --- a/radicle/src/rad.rs +++ b/radicle/src/rad.rs @@ -14,7 +14,8 @@ use crate::identity::project::Project; use crate::storage::git::transport; use crate::storage::git::{ProjectError, Repository, Storage}; use crate::storage::refs::SignedRefs; -use crate::storage::{BranchName, ReadRepository as _, RemoteId, WriteRepository as _}; +use crate::storage::WriteRepository; +use crate::storage::{BranchName, ReadRepository as _, RemoteId}; use crate::{identity, storage}; /// Name of the radicle storage remote. @@ -129,7 +130,7 @@ pub fn fork_remote( .get(remote, proj)? .ok_or(ForkError::NotFound(proj))?; let project = doc.project()?; - let repository = storage.repository(proj)?; + let repository = storage.repository_mut(proj)?; let raw = repository.raw(); let remote_head = raw.refname_to_id(&git::refs::storage::branch( @@ -162,7 +163,7 @@ pub fn fork( storage: &S, ) -> Result<(), ForkError> { let me = signer.public_key(); - let repository = storage.repository(proj)?; + let repository = storage.repository_mut(proj)?; // TODO: We should get the id branch pointer from a stored canonical reference. let (canonical_id, _) = repository.identity_doc()?; let (canonical_branch, canonical_head) = repository.head()?; @@ -302,7 +303,7 @@ mod tests { use crate::identity::Did; use crate::storage::git::transport; use crate::storage::git::Storage; - use crate::storage::{ReadStorage, WriteStorage}; + use crate::storage::ReadStorage; use crate::test::fixtures; use super::*; diff --git a/radicle/src/storage.rs b/radicle/src/storage.rs index b21fdab5..918005e5 100644 --- a/radicle/src/storage.rs +++ b/radicle/src/storage.rs @@ -70,6 +70,18 @@ pub enum Error { Io(#[from] io::Error), } +impl Error { + /// Whether this error is caused by something not being found. + pub fn is_not_found(&self) -> bool { + match self { + Self::Io(e) if e.kind() == io::ErrorKind::NotFound => true, + Self::Git(e) if git::is_not_found_err(e) => true, + Self::Doc(e) if e.is_not_found() => true, + _ => false, + } + } +} + /// Fetch error. #[derive(Error, Debug)] #[allow(clippy::large_enum_variant)] @@ -246,6 +258,8 @@ impl Remote { /// Read-only operations on a storage instance. pub trait ReadStorage { + type Repository: ReadRepository; + /// Get the storage base path. fn path(&self) -> &Path; /// Get an identity document of a repository under a given remote. @@ -258,13 +272,18 @@ pub trait ReadStorage { fn contains(&self, rid: &Id) -> Result; /// Get the inventory of repositories hosted under this storage. fn inventory(&self) -> Result; + /// Open or create a read-only repository. + fn repository(&self, rid: Id) -> Result; } /// Allows access to individual storage repositories. pub trait WriteStorage: ReadStorage { - type Repository: WriteRepository; + type RepositoryMut: WriteRepository; - fn repository(&self, proj: Id) -> Result; + /// Open a read-write repository. + fn repository_mut(&self, rid: Id) -> Result; + /// Create a read-write repository. + fn create(&self, rid: Id) -> Result; } /// Allows read-only access to a repository. @@ -355,6 +374,8 @@ where T: Deref, S: ReadStorage + 'static, { + type Repository = S::Repository; + fn path(&self) -> &Path { self.deref().path() } @@ -374,6 +395,10 @@ where ) -> Result>, ProjectError> { self.deref().get(remote, proj) } + + fn repository(&self, rid: Id) -> Result { + self.deref().repository(rid) + } } impl WriteStorage for T @@ -381,10 +406,14 @@ where T: Deref, S: WriteStorage + 'static, { - type Repository = S::Repository; + type RepositoryMut = S::RepositoryMut; - fn repository(&self, proj: Id) -> Result { - self.deref().repository(proj) + fn repository_mut(&self, rid: Id) -> Result { + self.deref().repository_mut(rid) + } + + fn create(&self, rid: Id) -> Result { + self.deref().create(rid) } } diff --git a/radicle/src/storage/git.rs b/radicle/src/storage/git.rs index 9d9a5695..5b8d7217 100644 --- a/radicle/src/storage/git.rs +++ b/radicle/src/storage/git.rs @@ -95,6 +95,8 @@ pub struct Storage { } impl ReadStorage for Storage { + type Repository = Repository; + fn path(&self) -> &Path { self.path.as_path() } @@ -108,29 +110,39 @@ impl ReadStorage for Storage { } fn get(&self, remote: &RemoteId, proj: Id) -> Result>, ProjectError> { - // TODO: Don't create a repo here if it doesn't exist? - // Perhaps for checking we could have a `contains` method? - match self.repository(proj)?.identity_of(remote) { + let repo = match self.repository(proj) { + Ok(doc) => doc, + Err(e) if e.is_not_found() => return Ok(None), + Err(e) => return Err(e.into()), + }; + match repo.identity_of(remote) { Ok(doc) => Ok(Some(doc)), - - Err(err) if err.is_not_found() => Ok(None), - Err(err) => Err(err), + Err(e) if e.is_not_found() => Ok(None), + Err(e) => Err(e), } } fn inventory(&self) -> Result { self.repositories() } -} - -impl WriteStorage for Storage { - type Repository = Repository; fn repository(&self, rid: Id) -> Result { Repository::open(paths::repository(self, &rid), rid) } } +impl WriteStorage for Storage { + type RepositoryMut = Repository; + + fn repository_mut(&self, rid: Id) -> Result { + Repository::open(paths::repository(self, &rid), rid) + } + + fn create(&self, rid: Id) -> Result { + Repository::create(paths::repository(self, &rid), rid) + } +} + impl Storage { // TODO: Return a better error when not found. pub fn open>(path: P) -> Result { @@ -207,27 +219,27 @@ pub enum VerifyError { } impl Repository { + /// Open an existing repository. pub fn open>(path: P, id: Id) -> Result { - let backend = match git2::Repository::open_bare(path.as_ref()) { - Err(e) if ext::is_not_found_err(&e) => { - let backend = git2::Repository::init_opts( - &path, - git2::RepositoryInitOptions::new() - .bare(true) - .no_reinit(true) - .external_template(false), - )?; - let mut config = backend.config()?; + let backend = git2::Repository::open_bare(path.as_ref())?; - // TODO: Get ahold of user name and/or key. - config.set_str("user.name", "radicle")?; - config.set_str("user.email", "radicle@localhost")?; + Ok(Self { id, backend }) + } - Ok(backend) - } - Ok(repo) => Ok(repo), - Err(e) => Err(e), - }?; + /// Create a new repository. + pub fn create>(path: P, id: Id) -> Result { + let backend = git2::Repository::init_opts( + &path, + git2::RepositoryInitOptions::new() + .bare(true) + .no_reinit(true) + .external_template(false), + )?; + let mut config = backend.config()?; + + // TODO: Get ahold of user name and/or key. + config.set_str("user.name", "radicle")?; + config.set_str("user.email", "radicle@localhost")?; Ok(Self { id, backend }) } @@ -241,7 +253,7 @@ impl Repository { ) -> Result<(Self, git::Oid), Error> { let (doc_oid, doc) = doc.encode()?; let id = Id::from(doc_oid); - let repo = Self::open(paths::repository(storage, &id), id)?; + let repo = Self::create(paths::repository(storage, &id), id)?; let oid = Doc::init( doc.as_slice(), remote, @@ -730,7 +742,7 @@ mod tests { let storage = Storage::open(tmp.path()).unwrap(); let proj_id = arbitrary::gen::(1); let alice = *signer.public_key(); - let project = storage.repository(proj_id).unwrap(); + let project = storage.create(proj_id).unwrap(); let backend = &project.backend; let sig = git2::Signature::now(&alice.to_string(), "anonymous@radicle.xyz").unwrap(); let head = git::initial_commit(backend, &sig).unwrap(); diff --git a/radicle/src/test/storage.rs b/radicle/src/test/storage.rs index f212631e..6c3a92f2 100644 --- a/radicle/src/test/storage.rs +++ b/radicle/src/test/storage.rs @@ -32,6 +32,8 @@ impl MockStorage { } impl ReadStorage for MockStorage { + type Repository = MockRepository; + fn path(&self) -> &Path { self.path.as_path() } @@ -51,12 +53,20 @@ impl ReadStorage for MockStorage { fn inventory(&self) -> Result { Ok(self.inventory.keys().cloned().collect::>()) } + + fn repository(&self, _proj: Id) -> Result { + Ok(MockRepository {}) + } } impl WriteStorage for MockStorage { - type Repository = MockRepository; + type RepositoryMut = MockRepository; - fn repository(&self, _proj: Id) -> Result { + fn repository_mut(&self, _rid: Id) -> Result { + Ok(MockRepository {}) + } + + fn create(&self, _rid: Id) -> Result { Ok(MockRepository {}) } }