fetch: introduce domain type RefPrefix
Better represent the domain by introducing the `RefPrefix` type. It captures the different `ref-prefix` values that can be used in the `ls-refs` step of the protocol. These are turned into their equivalent `ref-prefix` values using `RefPrefix::into_bstring`. This better connects the `ProtocolStage::ls_refs` method with the `ls_refs::run` through the use of the `RefPrefix` type, rather than any set of `BString` values.
This commit is contained in:
parent
8070f98a5b
commit
391571178e
|
|
@ -89,6 +89,42 @@ pub mod error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A `ref-prefix` used in the `ls-refs` step of the fetch protocol.
|
||||||
|
///
|
||||||
|
/// Since the Radicle protocol only wants to filter by very specific references,
|
||||||
|
/// this type captures the possible reference prefixes.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub(crate) enum RefPrefix {
|
||||||
|
/// Represents `refs/rad/id`.
|
||||||
|
RadId,
|
||||||
|
/// Represents `"refs/namespaces/<namespace>/refs/rad/id"`.
|
||||||
|
NamespacedRadId { namespace: PublicKey },
|
||||||
|
/// Represents `"refs/namespaces/<namespace>/refs/rad/sigrefs"`.
|
||||||
|
NamespacedRadSigrefs { namespace: PublicKey },
|
||||||
|
/// Represents `"refs/namespaces"`
|
||||||
|
AllNamespaces,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RefPrefix {
|
||||||
|
/// Convert the [`RefPrefix`] into its equivalent [`BString`].
|
||||||
|
///
|
||||||
|
/// See the [`RefPrefix`] variants for their [`BString`] values.
|
||||||
|
pub fn into_bstring(self) -> BString {
|
||||||
|
match self {
|
||||||
|
RefPrefix::RadId => refs::REFS_RAD_ID.as_bstr().into(),
|
||||||
|
RefPrefix::NamespacedRadId { namespace } => {
|
||||||
|
radicle::git::refs::storage::id(&namespace).as_bstr().into()
|
||||||
|
}
|
||||||
|
RefPrefix::NamespacedRadSigrefs { namespace } => {
|
||||||
|
radicle::git::refs::storage::sigrefs(&namespace)
|
||||||
|
.as_bstr()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
RefPrefix::AllNamespaces => "refs/namespaces".into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A [`ProtocolStage`] describes a single roundtrip with the Radicle
|
/// A [`ProtocolStage`] describes a single roundtrip with the Radicle
|
||||||
/// node that is serving the data.
|
/// node that is serving the data.
|
||||||
///
|
///
|
||||||
|
|
@ -107,7 +143,7 @@ pub mod error {
|
||||||
/// refdb (in-memory and production).
|
/// refdb (in-memory and production).
|
||||||
pub(crate) trait ProtocolStage {
|
pub(crate) trait ProtocolStage {
|
||||||
/// If and how to perform `ls-refs`.
|
/// If and how to perform `ls-refs`.
|
||||||
fn ls_refs(&self) -> Option<NonEmpty<BString>>;
|
fn ls_refs(&self) -> Option<NonEmpty<RefPrefix>>;
|
||||||
|
|
||||||
/// Filter a remote-advertised [`Ref`].
|
/// Filter a remote-advertised [`Ref`].
|
||||||
///
|
///
|
||||||
|
|
@ -163,8 +199,8 @@ pub struct CanonicalId {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProtocolStage for CanonicalId {
|
impl ProtocolStage for CanonicalId {
|
||||||
fn ls_refs(&self) -> Option<NonEmpty<BString>> {
|
fn ls_refs(&self) -> Option<NonEmpty<RefPrefix>> {
|
||||||
Some(NonEmpty::new(refs::REFS_RAD_ID.as_bstr().into()))
|
Some(NonEmpty::new(RefPrefix::RadId))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ref_filter(&self, r: Ref) -> Option<ReceivedRef> {
|
fn ref_filter(&self, r: Ref) -> Option<ReceivedRef> {
|
||||||
|
|
@ -250,17 +286,17 @@ pub struct SpecialRefs {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProtocolStage for SpecialRefs {
|
impl ProtocolStage for SpecialRefs {
|
||||||
fn ls_refs(&self) -> Option<NonEmpty<BString>> {
|
fn ls_refs(&self) -> Option<NonEmpty<RefPrefix>> {
|
||||||
match &self.followed {
|
match &self.followed {
|
||||||
policy::Allowed::All => Some(NonEmpty::new("refs/namespaces".into())),
|
policy::Allowed::All => Some(NonEmpty::new(RefPrefix::AllNamespaces)),
|
||||||
policy::Allowed::Followed { remotes } => NonEmpty::collect(
|
policy::Allowed::Followed { remotes } => NonEmpty::collect(
|
||||||
remotes
|
remotes
|
||||||
.iter()
|
.iter()
|
||||||
.chain(self.delegates.iter())
|
.chain(self.delegates.iter())
|
||||||
.flat_map(|remote| {
|
.flat_map(|remote| {
|
||||||
[
|
[
|
||||||
BString::from(radicle::git::refs::storage::id(remote).to_string()),
|
RefPrefix::NamespacedRadSigrefs { namespace: *remote },
|
||||||
BString::from(radicle::git::refs::storage::sigrefs(remote).to_string()),
|
RefPrefix::NamespacedRadId { namespace: *remote },
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
@ -331,12 +367,16 @@ pub struct SigrefsAt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProtocolStage for SigrefsAt {
|
impl ProtocolStage for SigrefsAt {
|
||||||
fn ls_refs(&self) -> Option<NonEmpty<BString>> {
|
fn ls_refs(&self) -> Option<NonEmpty<RefPrefix>> {
|
||||||
// N.b. the `Oid`s are known but the `rad/sigrefs` are still
|
// N.b. the `Oid`s are known but the `rad/sigrefs` are still
|
||||||
// asked for to mark them for updating the fetch state.
|
// asked for to mark them for updating the fetch state.
|
||||||
NonEmpty::collect(self.refs_at.iter().map(|refs_at| {
|
NonEmpty::collect(
|
||||||
BString::from(radicle::git::refs::storage::sigrefs(&refs_at.remote).to_string())
|
self.refs_at
|
||||||
}))
|
.iter()
|
||||||
|
.map(|refs_at| RefPrefix::NamespacedRadSigrefs {
|
||||||
|
namespace: refs_at.remote,
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only asked for `rad/sigrefs` so we should only get
|
// We only asked for `rad/sigrefs` so we should only get
|
||||||
|
|
@ -421,7 +461,7 @@ pub struct DataRefs {
|
||||||
impl ProtocolStage for DataRefs {
|
impl ProtocolStage for DataRefs {
|
||||||
// We don't need to ask for refs since we have all reference names
|
// We don't need to ask for refs since we have all reference names
|
||||||
// and `Oid`s in `rad/sigrefs`.
|
// and `Oid`s in `rad/sigrefs`.
|
||||||
fn ls_refs(&self) -> Option<NonEmpty<BString>> {
|
fn ls_refs(&self) -> Option<NonEmpty<RefPrefix>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,7 @@ impl FetchState {
|
||||||
let refs = match step.ls_refs() {
|
let refs = match step.ls_refs() {
|
||||||
Some(refs) => handle
|
Some(refs) => handle
|
||||||
.transport
|
.transport
|
||||||
.ls_refs(refs.into(), handshake)?
|
.ls_refs(refs, handshake)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|r| step.ref_filter(r))
|
.filter_map(|r| step.ref_filter(r))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ use thiserror::Error;
|
||||||
|
|
||||||
use crate::git::packfile::Keepfile;
|
use crate::git::packfile::Keepfile;
|
||||||
use crate::git::repository;
|
use crate::git::repository;
|
||||||
|
use crate::stage::RefPrefix;
|
||||||
|
|
||||||
/// Open a reader and writer stream to pass to the ls-refs and fetch
|
/// Open a reader and writer stream to pass to the ls-refs and fetch
|
||||||
/// processes for communicating during their respective protocols.
|
/// processes for communicating during their respective protocols.
|
||||||
|
|
@ -104,11 +105,10 @@ where
|
||||||
/// Perform ls-refs with the server side.
|
/// Perform ls-refs with the server side.
|
||||||
pub(crate) fn ls_refs(
|
pub(crate) fn ls_refs(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut prefixes: Vec<BString>,
|
prefixes: impl IntoIterator<Item = RefPrefix>,
|
||||||
handshake: &handshake::Outcome,
|
handshake: &handshake::Outcome,
|
||||||
) -> Result<Vec<handshake::Ref>, Error> {
|
) -> Result<Vec<handshake::Ref>, Error> {
|
||||||
prefixes.sort();
|
let prefixes = prefixes.into_iter().collect::<BTreeSet<_>>();
|
||||||
prefixes.dedup();
|
|
||||||
let (read, write) = self.stream.open();
|
let (read, write) = self.stream.open();
|
||||||
Ok(ls_refs::run(
|
Ok(ls_refs::run(
|
||||||
ls_refs::Config {
|
ls_refs::Config {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::collections::BTreeSet;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use gix_features::progress::Progress;
|
use gix_features::progress::Progress;
|
||||||
|
|
@ -7,6 +8,8 @@ use gix_protocol::ls_refs;
|
||||||
use gix_protocol::transport::Protocol;
|
use gix_protocol::transport::Protocol;
|
||||||
use gix_transport::bstr::{BString, ByteVec};
|
use gix_transport::bstr::{BString, ByteVec};
|
||||||
|
|
||||||
|
use crate::stage::RefPrefix;
|
||||||
|
|
||||||
use super::{agent_name, Connection};
|
use super::{agent_name, Connection};
|
||||||
|
|
||||||
/// Configuration for running an ls-refs process.
|
/// Configuration for running an ls-refs process.
|
||||||
|
|
@ -17,7 +20,7 @@ pub struct Config {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub repo: BString,
|
pub repo: BString,
|
||||||
/// Ref prefixes for filtering the output of the ls-refs process.
|
/// Ref prefixes for filtering the output of the ls-refs process.
|
||||||
pub prefixes: Vec<BString>,
|
pub prefixes: BTreeSet<RefPrefix>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the ls-refs process using the provided `config`.
|
/// Run the ls-refs process using the provided `config`.
|
||||||
|
|
@ -51,11 +54,17 @@ where
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let prefixes = config
|
||||||
|
.prefixes
|
||||||
|
.into_iter()
|
||||||
|
.map(|prefix| prefix.into_bstring())
|
||||||
|
.collect::<BTreeSet<_>>();
|
||||||
|
|
||||||
let refs = gix_protocol::ls_refs(
|
let refs = gix_protocol::ls_refs(
|
||||||
&mut conn,
|
&mut conn,
|
||||||
capabilities,
|
capabilities,
|
||||||
|_caps, args, features| {
|
|_caps, args, features| {
|
||||||
for prefix in &config.prefixes {
|
for prefix in &prefixes {
|
||||||
let mut arg = BString::from("ref-prefix ");
|
let mut arg = BString::from("ref-prefix ");
|
||||||
arg.push_str(prefix);
|
arg.push_str(prefix);
|
||||||
args.push(arg)
|
args.push(arg)
|
||||||
|
|
@ -74,10 +83,7 @@ where
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|r| {
|
.filter(|r| {
|
||||||
let (refname, _, _) = r.unpack();
|
let (refname, _, _) = r.unpack();
|
||||||
config
|
prefixes.iter().any(|prefix| refname.starts_with(prefix))
|
||||||
.prefixes
|
|
||||||
.iter()
|
|
||||||
.any(|prefix| refname.starts_with(prefix))
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue