Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
fetch: use `AsRef<Repository>`
Fintan Halpenny committed 7 months ago
commit ee105ae9c0ecc9245dd4d424ca2cac5ac0f35007
parent 8506b305ed12b637fef7241339255d8c22810da2
6 files changed +91 -50
modified crates/radicle-fetch/src/handle.rs
@@ -12,9 +12,9 @@ use crate::policy::{Allowed, BlockList};
use crate::transport::{ConnectionStream, Transport};

/// The handle used for pulling or cloning changes from a remote peer.
-
pub struct Handle<S> {
+
pub struct Handle<R, S> {
    pub(crate) local: PublicKey,
-
    repo: Repository,
+
    repo: R,
    pub(crate) allowed: Allowed,
    pub(crate) transport: Transport<S>,
    /// The set of keys we will ignore when fetching from a
@@ -29,10 +29,32 @@ pub struct Handle<S> {
    pub(crate) interrupt: Arc<AtomicBool>,
}

-
impl<S> Handle<S> {
+
impl<R, S> Handle<R, S> {
+
    pub fn is_blocked(&self, key: &PublicKey) -> bool {
+
        self.blocked.is_blocked(key)
+
    }
+

+
    #[inline]
+
    pub fn local(&self) -> &PublicKey {
+
        &self.local
+
    }
+

+
    pub fn interrupt_pack_writer(&mut self) {
+
        self.interrupt.store(true, atomic::Ordering::Relaxed);
+
    }
+

+
    pub fn allowed(&self) -> Allowed {
+
        self.allowed.clone()
+
    }
+
}
+

+
impl<R, S> Handle<R, S>
+
where
+
    R: AsRef<Repository>,
+
{
    pub fn new(
        local: PublicKey,
-
        repo: Repository,
+
        repo: R,
        follow: Allowed,
        blocked: BlockList,
        connection: S,
@@ -40,8 +62,12 @@ impl<S> Handle<S> {
    where
        S: ConnectionStream,
    {
-
        let git_dir = repo.backend.path().to_path_buf();
-
        let transport = Transport::new(git_dir, BString::from(repo.id.canonical()), connection);
+
        let git_dir = repo.as_ref().backend.path().to_path_buf();
+
        let transport = Transport::new(
+
            git_dir,
+
            BString::from(repo.as_ref().id.canonical()),
+
            connection,
+
        );

        Ok(Self {
            local,
@@ -53,30 +79,13 @@ impl<S> Handle<S> {
        })
    }

-
    pub fn is_blocked(&self, key: &PublicKey) -> bool {
-
        self.blocked.is_blocked(key)
-
    }
-

    #[inline]
    pub fn repository(&self) -> &Repository {
-
        &self.repo
-
    }
-

-
    #[inline]
-
    pub fn local(&self) -> &PublicKey {
-
        &self.local
-
    }
-

-
    pub fn interrupt_pack_writer(&mut self) {
-
        self.interrupt.store(true, atomic::Ordering::Relaxed);
+
        self.repo.as_ref()
    }

    pub fn verified(&self, head: Oid) -> Result<Doc, DocError> {
-
        Ok(self.repo.identity_doc_at(head)?.doc)
-
    }
-

-
    pub fn allowed(&self) -> Allowed {
-
        self.allowed.clone()
+
        Ok(self.repository().identity_doc_at(head)?.doc)
    }
}

modified crates/radicle-fetch/src/lib.rs
@@ -16,6 +16,7 @@ use gix_protocol::handshake;
pub use gix_protocol::{transport::bstr::ByteSlice, RemoteProgress};
pub use handle::Handle;
pub use policy::{Allowed, BlockList, Scope};
+
use radicle::storage::git::Repository;
pub use state::{FetchLimit, FetchResult};
pub use transport::Transport;

@@ -47,13 +48,14 @@ pub enum Error {
/// It is expected that the local peer has a copy of the repository
/// and is pulling new changes. If the repository does not exist, then
/// [`clone`] should be used.
-
pub fn pull<S>(
-
    handle: &mut Handle<S>,
+
pub fn pull<R, S>(
+
    handle: &mut Handle<R, S>,
    limit: FetchLimit,
    remote: PublicKey,
    refs_at: Option<Vec<RefsAt>>,
) -> Result<FetchResult, Error>
where
+
    R: AsRef<Repository>,
    S: transport::ConnectionStream,
{
    let start = Instant::now();
@@ -83,12 +85,13 @@ where
///
/// It is expected that the local peer has an empty repository which
/// they want to populate with the `remote`'s view of the project.
-
pub fn clone<S>(
-
    handle: &mut Handle<S>,
+
pub fn clone<R, S>(
+
    handle: &mut Handle<R, S>,
    limit: FetchLimit,
    remote: PublicKey,
) -> Result<FetchResult, Error>
where
+
    R: AsRef<Repository>,
    S: transport::ConnectionStream,
{
    let start = Instant::now();
@@ -120,7 +123,7 @@ where
    result
}

-
fn perform_handshake<S>(handle: &mut Handle<S>) -> Result<handshake::Outcome, Error>
+
fn perform_handshake<R, S>(handle: &mut Handle<R, S>) -> Result<handshake::Outcome, Error>
where
    S: transport::ConnectionStream,
{
modified crates/radicle-fetch/src/sigrefs.rs
@@ -1,6 +1,7 @@
use std::collections::{BTreeMap, BTreeSet};
use std::ops::{Deref, Not as _};

+
use radicle::storage::git::Repository;
pub use radicle::storage::refs::SignedRefsAt;
pub use radicle::storage::{git::Validation, Validations};
use radicle::{crypto::PublicKey, storage::ValidateRepository};
@@ -53,10 +54,13 @@ impl<T> DelegateStatus<T> {

    /// Construct a `DelegateStatus` with [`SignedRefsAt`] signed reference
    /// data, if it can be found in `repo`.
-
    pub fn load<S>(
+
    pub fn load<R, S>(
        self,
-
        cached: &Cached<S>,
-
    ) -> Result<DelegateStatus<Option<SignedRefsAt>>, radicle::storage::refs::Error> {
+
        cached: &Cached<R, S>,
+
    ) -> Result<DelegateStatus<Option<SignedRefsAt>>, radicle::storage::refs::Error>
+
    where
+
        R: AsRef<Repository>,
+
    {
        let remote = *self.remote();
        self.traverse(|_| cached.load(&remote))
    }
@@ -102,10 +106,13 @@ impl RemoteRefs {
    ///
    /// If the sigrefs are missing for a given remote, regardless of delegate
    /// status, then that remote is filtered out.
-
    pub(crate) fn load<'a, S>(
-
        cached: &Cached<S>,
+
    pub(crate) fn load<'a, R, S>(
+
        cached: &Cached<R, S>,
        remotes: impl Iterator<Item = &'a PublicKey>,
-
    ) -> Result<Self, error::RemoteRefs> {
+
    ) -> Result<Self, error::RemoteRefs>
+
    where
+
        R: AsRef<Repository>,
+
    {
        remotes
            .filter_map(|id| match cached.load(id) {
                Ok(None) => None,
modified crates/radicle-fetch/src/state.rs
@@ -8,6 +8,7 @@ use radicle::identity::{Did, Doc, DocError};

use radicle::prelude::Verified;
use radicle::storage;
+
use radicle::storage::git::Repository;
use radicle::storage::refs::RefsAt;
use radicle::storage::{
    git::Validation, Remote, RemoteId, RemoteRepository, Remotes, ValidateRepository, Validations,
@@ -196,7 +197,10 @@ impl FetchState {
        ap
    }

-
    pub(crate) fn as_cached<'a, S>(&'a mut self, handle: &'a mut Handle<S>) -> Cached<'a, S> {
+
    pub(crate) fn as_cached<'a, R, S>(
+
        &'a mut self,
+
        handle: &'a mut Handle<R, S>,
+
    ) -> Cached<'a, R, S> {
        Cached {
            handle,
            state: self,
@@ -207,13 +211,14 @@ impl FetchState {
impl FetchState {
    /// Perform the ls-refs and fetch for the given `step`. The result
    /// of these processes is kept track of in the internal state.
-
    pub(super) fn run_stage<S, F>(
+
    pub(super) fn run_stage<R, S, F>(
        &mut self,
-
        handle: &mut Handle<S>,
+
        handle: &mut Handle<R, S>,
        handshake: &handshake::Outcome,
        step: &F,
    ) -> Result<BTreeSet<PublicKey>, error::Step>
    where
+
        R: AsRef<Repository>,
        S: transport::ConnectionStream,
        F: ProtocolStage,
    {
@@ -280,9 +285,9 @@ impl FetchState {
    /// The resulting [`sigrefs::RemoteRefs`] will be the set of
    /// `rad/sigrefs` of the fetched remotes.
    #[allow(clippy::too_many_arguments)]
-
    fn run_special_refs<S>(
+
    fn run_special_refs<R, S>(
        &mut self,
-
        handle: &mut Handle<S>,
+
        handle: &mut Handle<R, S>,
        handshake: &handshake::Outcome,
        delegates: BTreeSet<PublicKey>,
        threshold: usize,
@@ -291,6 +296,7 @@ impl FetchState {
        refs_at: Option<Vec<RefsAt>>,
    ) -> Result<sigrefs::RemoteRefs, error::Protocol>
    where
+
        R: AsRef<Repository>,
        S: transport::ConnectionStream,
    {
        match refs_at {
@@ -348,15 +354,16 @@ impl FetchState {
    ///      of updating tips.
    ///   7. Apply the valid tips, iff no delegates failed validation.
    ///   8. Signal to the other side that the process has completed.
-
    pub(super) fn run<S>(
+
    pub(super) fn run<R, S>(
        mut self,
-
        handle: &mut Handle<S>,
+
        handle: &mut Handle<R, S>,
        handshake: &handshake::Outcome,
        limit: FetchLimit,
        remote: PublicKey,
        refs_at: Option<Vec<RefsAt>>,
    ) -> Result<FetchResult, error::Protocol>
    where
+
        R: AsRef<Repository>,
        S: transport::ConnectionStream,
    {
        let start = Instant::now();
@@ -598,12 +605,15 @@ impl FetchState {

/// A cached version of [`Handle`] by using the underlying
/// [`FetchState`]'s data for performing lookups.
-
pub(crate) struct Cached<'a, S> {
-
    handle: &'a mut Handle<S>,
+
pub(crate) struct Cached<'a, R, S> {
+
    handle: &'a mut Handle<R, S>,
    state: &'a mut FetchState,
}

-
impl<S> Cached<'_, S> {
+
impl<R, S> Cached<'_, R, S>
+
where
+
    R: AsRef<Repository>,
+
{
    /// Resolves `refname` to its [`ObjectId`] by first looking at the
    /// [`FetchState`] and falling back to the [`Handle::refdb`].
    pub fn refname_to_id<'b, N>(
@@ -651,7 +661,10 @@ impl<S> Cached<'_, S> {
    }
}

-
impl<S> RemoteRepository for Cached<'_, S> {
+
impl<R, S> RemoteRepository for Cached<'_, R, S>
+
where
+
    R: AsRef<Repository>,
+
{
    fn remote(&self, remote: &RemoteId) -> Result<Remote, storage::refs::Error> {
        // N.b. this is unused so we just delegate to the underlying
        // repository for a correct implementation.
@@ -671,7 +684,10 @@ impl<S> RemoteRepository for Cached<'_, S> {
    }
}

-
impl<S> ValidateRepository for Cached<'_, S> {
+
impl<R, S> ValidateRepository for Cached<'_, R, S>
+
where
+
    R: AsRef<Repository>,
+
{
    // N.b. we don't verify the `rad/id` of each remote since they may
    // not have a reference to the COB if they have not interacted
    // with it.
modified crates/radicle-node/src/worker/fetch.rs
@@ -27,11 +27,11 @@ use super::channels::ChannelsFlush;

pub enum Handle {
    Clone {
-
        handle: radicle_fetch::Handle<ChannelsFlush>,
+
        handle: radicle_fetch::Handle<Repository, ChannelsFlush>,
        tmp: tempfile::TempDir,
    },
    Pull {
-
        handle: radicle_fetch::Handle<ChannelsFlush>,
+
        handle: radicle_fetch::Handle<Repository, ChannelsFlush>,
        notifications: node::notifications::StoreWriter,
    },
}
modified crates/radicle/src/storage/git.rs
@@ -285,6 +285,12 @@ pub struct Repository {
    pub backend: git2::Repository,
}

+
impl AsRef<Repository> for Repository {
+
    fn as_ref(&self) -> &Repository {
+
        self
+
    }
+
}
+

impl git::canonical::effects::Ancestry for Repository {
    fn graph_ahead_behind(
        &self,