Make `ReadStorage` more usable
Previously, we were not able to access a `ReadRepository` instance through `ReadStorage`. With this change, we are able to.
This commit is contained in:
parent
89fcc6de1c
commit
950fae209d
|
|
@ -83,7 +83,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let signer = term::signer(&profile)?;
|
let signer = term::signer(&profile)?;
|
||||||
let storage = &profile.storage;
|
let storage = &profile.storage;
|
||||||
let (_, id) = radicle::rad::cwd()?;
|
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 issues = issue::Issues::open(*signer.public_key(), &repo)?;
|
||||||
|
|
||||||
let mut issue = issues.get_mut(&options.id).map_err(|err| match err {
|
let mut issue = issues.get_mut(&options.id).map_err(|err| match err {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ use anyhow::Context as _;
|
||||||
use radicle::prelude::*;
|
use radicle::prelude::*;
|
||||||
use radicle::storage::git::transport;
|
use radicle::storage::git::transport;
|
||||||
use radicle::storage::RemoteId;
|
use radicle::storage::RemoteId;
|
||||||
use radicle::storage::WriteStorage;
|
|
||||||
|
|
||||||
use crate::project;
|
use crate::project;
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ use radicle::prelude::*;
|
||||||
use radicle::rad;
|
use radicle::rad;
|
||||||
use radicle::storage;
|
use radicle::storage;
|
||||||
use radicle::storage::git::{ProjectError, Storage};
|
use radicle::storage::git::{ProjectError, Storage};
|
||||||
use radicle::storage::WriteStorage;
|
|
||||||
|
|
||||||
use crate::commands::rad_checkout as checkout;
|
use crate::commands::rad_checkout as checkout;
|
||||||
use crate::project;
|
use crate::project;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ use radicle::cob::store;
|
||||||
use radicle::cob::thread;
|
use radicle::cob::thread;
|
||||||
use radicle::prelude::*;
|
use radicle::prelude::*;
|
||||||
use radicle::storage;
|
use radicle::storage;
|
||||||
use radicle::storage::WriteStorage;
|
|
||||||
|
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
use crate::terminal::args::{Args, Error, Help};
|
use crate::terminal::args::{Args, Error, Help};
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ where
|
||||||
.get(&profile.public_key, id)?
|
.get(&profile.public_key, id)?
|
||||||
.context("No project with such ID exists")?;
|
.context("No project with such ID exists")?;
|
||||||
|
|
||||||
let repo = storage.repository(id)?;
|
let repo = storage.repository_mut(id)?;
|
||||||
|
|
||||||
if !project.is_delegate(me) {
|
if !project.is_delegate(me) {
|
||||||
return Err(anyhow::anyhow!(
|
return Err(anyhow::anyhow!(
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ where
|
||||||
.get(&profile.public_key, id)?
|
.get(&profile.public_key, id)?
|
||||||
.context("No project with such ID exists")?;
|
.context("No project with such ID exists")?;
|
||||||
|
|
||||||
let repo = storage.repository(id)?;
|
let repo = storage.repository_mut(id)?;
|
||||||
|
|
||||||
if !project.is_delegate(me) {
|
if !project.is_delegate(me) {
|
||||||
return Err(anyhow::anyhow!(
|
return Err(anyhow::anyhow!(
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use std::str::FromStr;
|
||||||
use anyhow::{anyhow, Context as _};
|
use anyhow::{anyhow, Context as _};
|
||||||
|
|
||||||
use radicle::identity::Id;
|
use radicle::identity::Id;
|
||||||
use radicle::storage::{ReadStorage, WriteRepository, WriteStorage};
|
use radicle::storage::{ReadStorage, WriteRepository};
|
||||||
|
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
use crate::terminal::args::{Args, Error, Help};
|
use crate::terminal::args::{Args, Error, Help};
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use radicle::cob::identity::{self, Proposal, ProposalId, Proposals, Revision, Re
|
||||||
use radicle::git::Oid;
|
use radicle::git::Oid;
|
||||||
use radicle::identity::Identity;
|
use radicle::identity::Identity;
|
||||||
use radicle::prelude::Doc;
|
use radicle::prelude::Doc;
|
||||||
use radicle::storage::WriteStorage as _;
|
use radicle::storage::ReadStorage as _;
|
||||||
use radicle_crypto::{PublicKey, Verified};
|
use radicle_crypto::{PublicKey, Verified};
|
||||||
|
|
||||||
use crate::terminal::args::{Args, Error, Help};
|
use crate::terminal::args::{Args, Error, Help};
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use json_color::{Color, Colorizer};
|
||||||
use radicle::crypto::Unverified;
|
use radicle::crypto::Unverified;
|
||||||
use radicle::identity::Untrusted;
|
use radicle::identity::Untrusted;
|
||||||
use radicle::identity::{Doc, Id};
|
use radicle::identity::{Doc, Id};
|
||||||
use radicle::storage::{ReadRepository, ReadStorage, WriteStorage};
|
use radicle::storage::{ReadRepository, ReadStorage};
|
||||||
|
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
use crate::terminal::args::{Args, Error, Help};
|
use crate::terminal::args::{Args, Error, Help};
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let signer = term::signer(&profile)?;
|
let signer = term::signer(&profile)?;
|
||||||
let storage = &profile.storage;
|
let storage = &profile.storage;
|
||||||
let (_, id) = radicle::rad::cwd()?;
|
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)?;
|
let mut issues = Issues::open(*signer.public_key(), &repo)?;
|
||||||
|
|
||||||
match options.op {
|
match options.op {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::ffi::OsString;
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
use crate::terminal::args::{Args, Error, Help};
|
use crate::terminal::args::{Args, Error, Help};
|
||||||
|
|
||||||
use radicle::storage::{ReadRepository, WriteStorage};
|
use radicle::storage::{ReadRepository, ReadStorage};
|
||||||
|
|
||||||
pub const HELP: Help = Help {
|
pub const HELP: Help = Help {
|
||||||
name: "ls",
|
name: "ls",
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use std::str::FromStr;
|
||||||
use anyhow::{anyhow, Context as _};
|
use anyhow::{anyhow, Context as _};
|
||||||
|
|
||||||
use radicle::node::{Handle, NodeId};
|
use radicle::node::{Handle, NodeId};
|
||||||
use radicle::storage::WriteStorage;
|
use radicle::storage::ReadStorage;
|
||||||
|
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
use crate::terminal::args::{Args, Error, Help};
|
use crate::terminal::args::{Args, Error, Help};
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let signer = term::signer(&profile)?;
|
let signer = term::signer(&profile)?;
|
||||||
let storage = &profile.storage;
|
let storage = &profile.storage;
|
||||||
let (_, id) = radicle::rad::cwd()?;
|
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 issues = issue::Issues::open(*signer.public_key(), &repo)?;
|
||||||
|
|
||||||
let mut issue = issues.get_mut(&options.id).map_err(|err| match err {
|
let mut issue = issues.get_mut(&options.id).map_err(|err| match err {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use anyhow::{anyhow, Context as _};
|
||||||
use radicle::identity::Id;
|
use radicle::identity::Id;
|
||||||
use radicle::node::Handle;
|
use radicle::node::Handle;
|
||||||
use radicle::prelude::*;
|
use radicle::prelude::*;
|
||||||
use radicle::storage::WriteStorage;
|
use radicle::storage::ReadStorage;
|
||||||
|
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
use crate::terminal::args::{Args, Error, Help};
|
use crate::terminal::args::{Args, Error, Help};
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use std::{thread, time};
|
||||||
use radicle::git;
|
use radicle::git;
|
||||||
use radicle::prelude::Id;
|
use radicle::prelude::Id;
|
||||||
use radicle::profile::Home;
|
use radicle::profile::Home;
|
||||||
use radicle::storage::{ReadRepository, WriteStorage};
|
use radicle::storage::{ReadRepository, ReadStorage};
|
||||||
use radicle::test::fixtures;
|
use radicle::test::fixtures;
|
||||||
|
|
||||||
use radicle_cli_test::TestFormula;
|
use radicle_cli_test::TestFormula;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use tower_http::cors::{self, CorsLayer};
|
||||||
|
|
||||||
use radicle::cob::issue::Issues;
|
use radicle::cob::issue::Issues;
|
||||||
use radicle::identity::Id;
|
use radicle::identity::Id;
|
||||||
use radicle::storage::{ReadRepository, WriteStorage};
|
use radicle::storage::{ReadRepository, ReadStorage};
|
||||||
use radicle::Profile;
|
use radicle::Profile;
|
||||||
|
|
||||||
mod auth;
|
mod auth;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use tower::ServiceExt;
|
||||||
use radicle::cob::issue::Issues;
|
use radicle::cob::issue::Issues;
|
||||||
use radicle::cob::patch::{MergeTarget, Patches};
|
use radicle::cob::patch::{MergeTarget, Patches};
|
||||||
use radicle::git::raw as git2;
|
use radicle::git::raw as git2;
|
||||||
use radicle::storage::WriteStorage;
|
use radicle::storage::ReadStorage;
|
||||||
use radicle_cli::commands::rad_init;
|
use radicle_cli::commands::rad_init;
|
||||||
use radicle_crypto::ssh::keystore::MemorySigner;
|
use radicle_crypto::ssh::keystore::MemorySigner;
|
||||||
use radicle_crypto::Signer;
|
use radicle_crypto::Signer;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use axum::{Json, Router};
|
||||||
|
|
||||||
use radicle::cob::issue::Issues;
|
use radicle::cob::issue::Issues;
|
||||||
use radicle::identity::Did;
|
use radicle::identity::Did;
|
||||||
use radicle::storage::{ReadRepository, WriteStorage};
|
use radicle::storage::{ReadRepository, ReadStorage};
|
||||||
|
|
||||||
use crate::api::axum_extra::{Path, Query};
|
use crate::api::axum_extra::{Path, Query};
|
||||||
use crate::api::error::Error;
|
use crate::api::error::Error;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ use radicle::cob::patch::Patches;
|
||||||
use radicle::cob::{thread, ActorId, Tag};
|
use radicle::cob::{thread, ActorId, Tag};
|
||||||
use radicle::identity::Id;
|
use radicle::identity::Id;
|
||||||
use radicle::node::NodeId;
|
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 radicle_surf::{Glob, Oid, Repository};
|
||||||
|
|
||||||
use crate::api::axum_extra::{Path, Query};
|
use crate::api::axum_extra::{Path, Query};
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use crate::service::filter::Filter;
|
||||||
use crate::service::{NodeId, Timestamp};
|
use crate::service::{NodeId, Timestamp};
|
||||||
use crate::storage;
|
use crate::storage;
|
||||||
use crate::storage::refs::SignedRefs;
|
use crate::storage::refs::SignedRefs;
|
||||||
use crate::storage::{ReadRepository, WriteStorage};
|
use crate::storage::{ReadRepository, ReadStorage};
|
||||||
use crate::wire;
|
use crate::wire;
|
||||||
|
|
||||||
/// Maximum number of addresses which can be announced to other nodes.
|
/// Maximum number of addresses which can be announced to other nodes.
|
||||||
|
|
@ -154,8 +154,14 @@ pub struct RefsAnnouncement {
|
||||||
|
|
||||||
impl RefsAnnouncement {
|
impl RefsAnnouncement {
|
||||||
/// Check if this announcement is "fresh", meaning if it contains refs we do not have.
|
/// Check if this announcement is "fresh", meaning if it contains refs we do not have.
|
||||||
pub fn is_fresh<S: WriteStorage>(&self, storage: S) -> Result<bool, storage::Error> {
|
pub fn is_fresh<S: ReadStorage>(&self, storage: S) -> Result<bool, storage::Error> {
|
||||||
let repo = storage.repository(self.rid)?;
|
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() {
|
for (remote_id, theirs) in self.refs.iter() {
|
||||||
if let Ok(ours) = repo.remote(remote_id) {
|
if let Ok(ours) = repo.remote(remote_id) {
|
||||||
|
|
|
||||||
|
|
@ -411,7 +411,11 @@ impl<S: WriteStorage + 'static, G: Signer> Simulation<S, G> {
|
||||||
Input::Fetched(f, result) => {
|
Input::Fetched(f, result) => {
|
||||||
let result = Rc::try_unwrap(result).unwrap();
|
let result = Rc::try_unwrap(result).unwrap();
|
||||||
if f.initiated {
|
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();
|
fetch(&mut repo, &f.remote, f.namespaces.clone()).unwrap();
|
||||||
}
|
}
|
||||||
p.fetched(f, result);
|
p.fetched(f, result);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::{thread, time};
|
||||||
|
|
||||||
use radicle::crypto::Signer;
|
use radicle::crypto::Signer;
|
||||||
use radicle::node::{FetchResult, Handle as _};
|
use radicle::node::{FetchResult, Handle as _};
|
||||||
use radicle::storage::{ReadRepository, WriteStorage};
|
use radicle::storage::{ReadRepository, ReadStorage};
|
||||||
use radicle::{assert_matches, rad};
|
use radicle::{assert_matches, rad};
|
||||||
|
|
||||||
use crate::service;
|
use crate::service;
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,11 @@ impl<G: Signer + Ecdh + 'static> Worker<G> {
|
||||||
fetch: &Fetch,
|
fetch: &Fetch,
|
||||||
tunnel: &mut Tunnel<WireSession<G>>,
|
tunnel: &mut Tunnel<WireSession<G>>,
|
||||||
) -> Result<Vec<RefUpdate>, FetchError> {
|
) -> Result<Vec<RefUpdate>, 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 tunnel_addr = tunnel.local_addr()?;
|
||||||
let mut cmd = process::Command::new("git");
|
let mut cmd = process::Command::new("git");
|
||||||
cmd.current_dir(repo.path())
|
cmd.current_dir(repo.path())
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ pub fn run(profile: radicle::Profile) -> Result<(), Box<dyn std::error::Error +
|
||||||
// Default to profile key.
|
// Default to profile key.
|
||||||
let namespace = url.namespace.unwrap_or(profile.public_key);
|
let namespace = url.namespace.unwrap_or(profile.public_key);
|
||||||
|
|
||||||
let proj = profile.storage.repository(url.repo)?;
|
let proj = profile.storage.repository_mut(url.repo)?;
|
||||||
if proj.is_empty()? {
|
if proj.is_empty()? {
|
||||||
return Err(Error::RepositoryNotFound(proj.path().to_path_buf()).into());
|
return Err(Error::RepositoryNotFound(proj.path().to_path_buf()).into());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use radicle::{node::Handle, storage::WriteRepository, storage::WriteStorage};
|
use radicle::{node::Handle, storage::ReadStorage, storage::WriteRepository};
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
let cwd = Path::new(".").canonicalize()?;
|
let cwd = Path::new(".").canonicalize()?;
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ mod test {
|
||||||
use crate::crypto::PublicKey;
|
use crate::crypto::PublicKey;
|
||||||
use crate::rad;
|
use crate::rad;
|
||||||
use crate::storage::git::Storage;
|
use crate::storage::git::Storage;
|
||||||
use crate::storage::{ReadStorage, WriteRepository, WriteStorage};
|
use crate::storage::{ReadStorage, WriteRepository};
|
||||||
use crate::test::fixtures;
|
use crate::test::fixtures;
|
||||||
|
|
||||||
use super::did::Did;
|
use super::did::Did;
|
||||||
|
|
|
||||||
|
|
@ -371,7 +371,7 @@ mod test {
|
||||||
use crate::rad;
|
use crate::rad;
|
||||||
use crate::storage::git::transport;
|
use crate::storage::git::transport;
|
||||||
use crate::storage::git::Storage;
|
use crate::storage::git::Storage;
|
||||||
use crate::storage::WriteStorage;
|
use crate::storage::WriteStorage as _;
|
||||||
use crate::test::arbitrary;
|
use crate::test::arbitrary;
|
||||||
use crate::test::fixtures;
|
use crate::test::fixtures;
|
||||||
|
|
||||||
|
|
@ -414,7 +414,7 @@ mod test {
|
||||||
let storage = Storage::open(tempdir.path().join("storage")).unwrap();
|
let storage = Storage::open(tempdir.path().join("storage")).unwrap();
|
||||||
let remote = arbitrary::gen::<RemoteId>(1);
|
let remote = arbitrary::gen::<RemoteId>(1);
|
||||||
let proj = arbitrary::gen::<Id>(1);
|
let proj = arbitrary::gen::<Id>(1);
|
||||||
let repo = storage.repository(proj).unwrap();
|
let repo = storage.create(proj).unwrap();
|
||||||
let oid = git2::Oid::from_str("2d52a53ce5e4f141148a5f770cfd3ead2d6a45b8").unwrap();
|
let oid = git2::Oid::from_str("2d52a53ce5e4f141148a5f770cfd3ead2d6a45b8").unwrap();
|
||||||
|
|
||||||
let err = Doc::<Unverified>::head(&remote, &repo).unwrap_err();
|
let err = Doc::<Unverified>::head(&remote, &repo).unwrap_err();
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@ use crate::identity::project::Project;
|
||||||
use crate::storage::git::transport;
|
use crate::storage::git::transport;
|
||||||
use crate::storage::git::{ProjectError, Repository, Storage};
|
use crate::storage::git::{ProjectError, Repository, Storage};
|
||||||
use crate::storage::refs::SignedRefs;
|
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};
|
use crate::{identity, storage};
|
||||||
|
|
||||||
/// Name of the radicle storage remote.
|
/// Name of the radicle storage remote.
|
||||||
|
|
@ -129,7 +130,7 @@ pub fn fork_remote<G: Signer, S: storage::WriteStorage>(
|
||||||
.get(remote, proj)?
|
.get(remote, proj)?
|
||||||
.ok_or(ForkError::NotFound(proj))?;
|
.ok_or(ForkError::NotFound(proj))?;
|
||||||
let project = doc.project()?;
|
let project = doc.project()?;
|
||||||
let repository = storage.repository(proj)?;
|
let repository = storage.repository_mut(proj)?;
|
||||||
|
|
||||||
let raw = repository.raw();
|
let raw = repository.raw();
|
||||||
let remote_head = raw.refname_to_id(&git::refs::storage::branch(
|
let remote_head = raw.refname_to_id(&git::refs::storage::branch(
|
||||||
|
|
@ -162,7 +163,7 @@ pub fn fork<G: Signer, S: storage::WriteStorage>(
|
||||||
storage: &S,
|
storage: &S,
|
||||||
) -> Result<(), ForkError> {
|
) -> Result<(), ForkError> {
|
||||||
let me = signer.public_key();
|
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.
|
// TODO: We should get the id branch pointer from a stored canonical reference.
|
||||||
let (canonical_id, _) = repository.identity_doc()?;
|
let (canonical_id, _) = repository.identity_doc()?;
|
||||||
let (canonical_branch, canonical_head) = repository.head()?;
|
let (canonical_branch, canonical_head) = repository.head()?;
|
||||||
|
|
@ -302,7 +303,7 @@ mod tests {
|
||||||
use crate::identity::Did;
|
use crate::identity::Did;
|
||||||
use crate::storage::git::transport;
|
use crate::storage::git::transport;
|
||||||
use crate::storage::git::Storage;
|
use crate::storage::git::Storage;
|
||||||
use crate::storage::{ReadStorage, WriteStorage};
|
use crate::storage::ReadStorage;
|
||||||
use crate::test::fixtures;
|
use crate::test::fixtures;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,18 @@ pub enum Error {
|
||||||
Io(#[from] io::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.
|
/// Fetch error.
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
|
@ -246,6 +258,8 @@ impl Remote<Verified> {
|
||||||
|
|
||||||
/// Read-only operations on a storage instance.
|
/// Read-only operations on a storage instance.
|
||||||
pub trait ReadStorage {
|
pub trait ReadStorage {
|
||||||
|
type Repository: ReadRepository;
|
||||||
|
|
||||||
/// Get the storage base path.
|
/// Get the storage base path.
|
||||||
fn path(&self) -> &Path;
|
fn path(&self) -> &Path;
|
||||||
/// Get an identity document of a repository under a given remote.
|
/// Get an identity document of a repository under a given remote.
|
||||||
|
|
@ -258,13 +272,18 @@ pub trait ReadStorage {
|
||||||
fn contains(&self, rid: &Id) -> Result<bool, ProjectError>;
|
fn contains(&self, rid: &Id) -> Result<bool, ProjectError>;
|
||||||
/// Get the inventory of repositories hosted under this storage.
|
/// Get the inventory of repositories hosted under this storage.
|
||||||
fn inventory(&self) -> Result<Inventory, Error>;
|
fn inventory(&self) -> Result<Inventory, Error>;
|
||||||
|
/// Open or create a read-only repository.
|
||||||
|
fn repository(&self, rid: Id) -> Result<Self::Repository, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows access to individual storage repositories.
|
/// Allows access to individual storage repositories.
|
||||||
pub trait WriteStorage: ReadStorage {
|
pub trait WriteStorage: ReadStorage {
|
||||||
type Repository: WriteRepository;
|
type RepositoryMut: WriteRepository;
|
||||||
|
|
||||||
fn repository(&self, proj: Id) -> Result<Self::Repository, Error>;
|
/// Open a read-write repository.
|
||||||
|
fn repository_mut(&self, rid: Id) -> Result<Self::RepositoryMut, Error>;
|
||||||
|
/// Create a read-write repository.
|
||||||
|
fn create(&self, rid: Id) -> Result<Self::RepositoryMut, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows read-only access to a repository.
|
/// Allows read-only access to a repository.
|
||||||
|
|
@ -355,6 +374,8 @@ where
|
||||||
T: Deref<Target = S>,
|
T: Deref<Target = S>,
|
||||||
S: ReadStorage + 'static,
|
S: ReadStorage + 'static,
|
||||||
{
|
{
|
||||||
|
type Repository = S::Repository;
|
||||||
|
|
||||||
fn path(&self) -> &Path {
|
fn path(&self) -> &Path {
|
||||||
self.deref().path()
|
self.deref().path()
|
||||||
}
|
}
|
||||||
|
|
@ -374,6 +395,10 @@ where
|
||||||
) -> Result<Option<identity::Doc<Verified>>, ProjectError> {
|
) -> Result<Option<identity::Doc<Verified>>, ProjectError> {
|
||||||
self.deref().get(remote, proj)
|
self.deref().get(remote, proj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn repository(&self, rid: Id) -> Result<Self::Repository, Error> {
|
||||||
|
self.deref().repository(rid)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> WriteStorage for T
|
impl<T, S> WriteStorage for T
|
||||||
|
|
@ -381,10 +406,14 @@ where
|
||||||
T: Deref<Target = S>,
|
T: Deref<Target = S>,
|
||||||
S: WriteStorage + 'static,
|
S: WriteStorage + 'static,
|
||||||
{
|
{
|
||||||
type Repository = S::Repository;
|
type RepositoryMut = S::RepositoryMut;
|
||||||
|
|
||||||
fn repository(&self, proj: Id) -> Result<Self::Repository, Error> {
|
fn repository_mut(&self, rid: Id) -> Result<Self::RepositoryMut, Error> {
|
||||||
self.deref().repository(proj)
|
self.deref().repository_mut(rid)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(&self, rid: Id) -> Result<Self::RepositoryMut, Error> {
|
||||||
|
self.deref().create(rid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,8 @@ pub struct Storage {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReadStorage for Storage {
|
impl ReadStorage for Storage {
|
||||||
|
type Repository = Repository;
|
||||||
|
|
||||||
fn path(&self) -> &Path {
|
fn path(&self) -> &Path {
|
||||||
self.path.as_path()
|
self.path.as_path()
|
||||||
}
|
}
|
||||||
|
|
@ -108,29 +110,39 @@ impl ReadStorage for Storage {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, remote: &RemoteId, proj: Id) -> Result<Option<Doc<Verified>>, ProjectError> {
|
fn get(&self, remote: &RemoteId, proj: Id) -> Result<Option<Doc<Verified>>, ProjectError> {
|
||||||
// TODO: Don't create a repo here if it doesn't exist?
|
let repo = match self.repository(proj) {
|
||||||
// Perhaps for checking we could have a `contains` method?
|
Ok(doc) => doc,
|
||||||
match self.repository(proj)?.identity_of(remote) {
|
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)),
|
Ok(doc) => Ok(Some(doc)),
|
||||||
|
Err(e) if e.is_not_found() => Ok(None),
|
||||||
Err(err) if err.is_not_found() => Ok(None),
|
Err(e) => Err(e),
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inventory(&self) -> Result<Inventory, Error> {
|
fn inventory(&self) -> Result<Inventory, Error> {
|
||||||
self.repositories()
|
self.repositories()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl WriteStorage for Storage {
|
|
||||||
type Repository = Repository;
|
|
||||||
|
|
||||||
fn repository(&self, rid: Id) -> Result<Self::Repository, Error> {
|
fn repository(&self, rid: Id) -> Result<Self::Repository, Error> {
|
||||||
Repository::open(paths::repository(self, &rid), rid)
|
Repository::open(paths::repository(self, &rid), rid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WriteStorage for Storage {
|
||||||
|
type RepositoryMut = Repository;
|
||||||
|
|
||||||
|
fn repository_mut(&self, rid: Id) -> Result<Self::RepositoryMut, Error> {
|
||||||
|
Repository::open(paths::repository(self, &rid), rid)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(&self, rid: Id) -> Result<Self::RepositoryMut, Error> {
|
||||||
|
Repository::create(paths::repository(self, &rid), rid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Storage {
|
impl Storage {
|
||||||
// TODO: Return a better error when not found.
|
// TODO: Return a better error when not found.
|
||||||
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, io::Error> {
|
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, io::Error> {
|
||||||
|
|
@ -207,27 +219,27 @@ pub enum VerifyError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Repository {
|
impl Repository {
|
||||||
|
/// Open an existing repository.
|
||||||
pub fn open<P: AsRef<Path>>(path: P, id: Id) -> Result<Self, Error> {
|
pub fn open<P: AsRef<Path>>(path: P, id: Id) -> Result<Self, Error> {
|
||||||
let backend = match git2::Repository::open_bare(path.as_ref()) {
|
let backend = 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()?;
|
|
||||||
|
|
||||||
// TODO: Get ahold of user name and/or key.
|
Ok(Self { id, backend })
|
||||||
config.set_str("user.name", "radicle")?;
|
}
|
||||||
config.set_str("user.email", "radicle@localhost")?;
|
|
||||||
|
|
||||||
Ok(backend)
|
/// Create a new repository.
|
||||||
}
|
pub fn create<P: AsRef<Path>>(path: P, id: Id) -> Result<Self, Error> {
|
||||||
Ok(repo) => Ok(repo),
|
let backend = git2::Repository::init_opts(
|
||||||
Err(e) => Err(e),
|
&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 })
|
Ok(Self { id, backend })
|
||||||
}
|
}
|
||||||
|
|
@ -241,7 +253,7 @@ impl Repository {
|
||||||
) -> Result<(Self, git::Oid), Error> {
|
) -> Result<(Self, git::Oid), Error> {
|
||||||
let (doc_oid, doc) = doc.encode()?;
|
let (doc_oid, doc) = doc.encode()?;
|
||||||
let id = Id::from(doc_oid);
|
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(
|
let oid = Doc::init(
|
||||||
doc.as_slice(),
|
doc.as_slice(),
|
||||||
remote,
|
remote,
|
||||||
|
|
@ -730,7 +742,7 @@ mod tests {
|
||||||
let storage = Storage::open(tmp.path()).unwrap();
|
let storage = Storage::open(tmp.path()).unwrap();
|
||||||
let proj_id = arbitrary::gen::<Id>(1);
|
let proj_id = arbitrary::gen::<Id>(1);
|
||||||
let alice = *signer.public_key();
|
let alice = *signer.public_key();
|
||||||
let project = storage.repository(proj_id).unwrap();
|
let project = storage.create(proj_id).unwrap();
|
||||||
let backend = &project.backend;
|
let backend = &project.backend;
|
||||||
let sig = git2::Signature::now(&alice.to_string(), "anonymous@radicle.xyz").unwrap();
|
let sig = git2::Signature::now(&alice.to_string(), "anonymous@radicle.xyz").unwrap();
|
||||||
let head = git::initial_commit(backend, &sig).unwrap();
|
let head = git::initial_commit(backend, &sig).unwrap();
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ impl MockStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReadStorage for MockStorage {
|
impl ReadStorage for MockStorage {
|
||||||
|
type Repository = MockRepository;
|
||||||
|
|
||||||
fn path(&self) -> &Path {
|
fn path(&self) -> &Path {
|
||||||
self.path.as_path()
|
self.path.as_path()
|
||||||
}
|
}
|
||||||
|
|
@ -51,12 +53,20 @@ impl ReadStorage for MockStorage {
|
||||||
fn inventory(&self) -> Result<Inventory, Error> {
|
fn inventory(&self) -> Result<Inventory, Error> {
|
||||||
Ok(self.inventory.keys().cloned().collect::<Vec<_>>())
|
Ok(self.inventory.keys().cloned().collect::<Vec<_>>())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn repository(&self, _proj: Id) -> Result<Self::Repository, Error> {
|
||||||
|
Ok(MockRepository {})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteStorage for MockStorage {
|
impl WriteStorage for MockStorage {
|
||||||
type Repository = MockRepository;
|
type RepositoryMut = MockRepository;
|
||||||
|
|
||||||
fn repository(&self, _proj: Id) -> Result<Self::Repository, Error> {
|
fn repository_mut(&self, _rid: Id) -> Result<Self::RepositoryMut, Error> {
|
||||||
|
Ok(MockRepository {})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(&self, _rid: Id) -> Result<Self::RepositoryMut, Error> {
|
||||||
Ok(MockRepository {})
|
Ok(MockRepository {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue