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
|
||||
/// node that is serving the data.
|
||||
///
|
||||
|
|
@ -107,7 +143,7 @@ pub mod error {
|
|||
/// refdb (in-memory and production).
|
||||
pub(crate) trait ProtocolStage {
|
||||
/// 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`].
|
||||
///
|
||||
|
|
@ -163,8 +199,8 @@ pub struct CanonicalId {
|
|||
}
|
||||
|
||||
impl ProtocolStage for CanonicalId {
|
||||
fn ls_refs(&self) -> Option<NonEmpty<BString>> {
|
||||
Some(NonEmpty::new(refs::REFS_RAD_ID.as_bstr().into()))
|
||||
fn ls_refs(&self) -> Option<NonEmpty<RefPrefix>> {
|
||||
Some(NonEmpty::new(RefPrefix::RadId))
|
||||
}
|
||||
|
||||
fn ref_filter(&self, r: Ref) -> Option<ReceivedRef> {
|
||||
|
|
@ -250,17 +286,17 @@ pub struct SpecialRefs {
|
|||
}
|
||||
|
||||
impl ProtocolStage for SpecialRefs {
|
||||
fn ls_refs(&self) -> Option<NonEmpty<BString>> {
|
||||
fn ls_refs(&self) -> Option<NonEmpty<RefPrefix>> {
|
||||
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(
|
||||
remotes
|
||||
.iter()
|
||||
.chain(self.delegates.iter())
|
||||
.flat_map(|remote| {
|
||||
[
|
||||
BString::from(radicle::git::refs::storage::id(remote).to_string()),
|
||||
BString::from(radicle::git::refs::storage::sigrefs(remote).to_string()),
|
||||
RefPrefix::NamespacedRadSigrefs { namespace: *remote },
|
||||
RefPrefix::NamespacedRadId { namespace: *remote },
|
||||
]
|
||||
}),
|
||||
),
|
||||
|
|
@ -331,12 +367,16 @@ pub struct 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
|
||||
// asked for to mark them for updating the fetch state.
|
||||
NonEmpty::collect(self.refs_at.iter().map(|refs_at| {
|
||||
BString::from(radicle::git::refs::storage::sigrefs(&refs_at.remote).to_string())
|
||||
}))
|
||||
NonEmpty::collect(
|
||||
self.refs_at
|
||||
.iter()
|
||||
.map(|refs_at| RefPrefix::NamespacedRadSigrefs {
|
||||
namespace: refs_at.remote,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// We only asked for `rad/sigrefs` so we should only get
|
||||
|
|
@ -421,7 +461,7 @@ pub struct DataRefs {
|
|||
impl ProtocolStage for DataRefs {
|
||||
// We don't need to ask for refs since we have all reference names
|
||||
// and `Oid`s in `rad/sigrefs`.
|
||||
fn ls_refs(&self) -> Option<NonEmpty<BString>> {
|
||||
fn ls_refs(&self) -> Option<NonEmpty<RefPrefix>> {
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ impl FetchState {
|
|||
let refs = match step.ls_refs() {
|
||||
Some(refs) => handle
|
||||
.transport
|
||||
.ls_refs(refs.into(), handshake)?
|
||||
.ls_refs(refs, handshake)?
|
||||
.into_iter()
|
||||
.filter_map(|r| step.ref_filter(r))
|
||||
.collect::<Vec<_>>(),
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ use thiserror::Error;
|
|||
|
||||
use crate::git::packfile::Keepfile;
|
||||
use crate::git::repository;
|
||||
use crate::stage::RefPrefix;
|
||||
|
||||
/// Open a reader and writer stream to pass to the ls-refs and fetch
|
||||
/// processes for communicating during their respective protocols.
|
||||
|
|
@ -104,11 +105,10 @@ where
|
|||
/// Perform ls-refs with the server side.
|
||||
pub(crate) fn ls_refs(
|
||||
&mut self,
|
||||
mut prefixes: Vec<BString>,
|
||||
prefixes: impl IntoIterator<Item = RefPrefix>,
|
||||
handshake: &handshake::Outcome,
|
||||
) -> Result<Vec<handshake::Ref>, Error> {
|
||||
prefixes.sort();
|
||||
prefixes.dedup();
|
||||
let prefixes = prefixes.into_iter().collect::<BTreeSet<_>>();
|
||||
let (read, write) = self.stream.open();
|
||||
Ok(ls_refs::run(
|
||||
ls_refs::Config {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use std::borrow::Cow;
|
||||
use std::collections::BTreeSet;
|
||||
use std::io;
|
||||
|
||||
use gix_features::progress::Progress;
|
||||
|
|
@ -7,6 +8,8 @@ use gix_protocol::ls_refs;
|
|||
use gix_protocol::transport::Protocol;
|
||||
use gix_transport::bstr::{BString, ByteVec};
|
||||
|
||||
use crate::stage::RefPrefix;
|
||||
|
||||
use super::{agent_name, Connection};
|
||||
|
||||
/// Configuration for running an ls-refs process.
|
||||
|
|
@ -17,7 +20,7 @@ pub struct Config {
|
|||
#[allow(dead_code)]
|
||||
pub repo: BString,
|
||||
/// 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`.
|
||||
|
|
@ -51,11 +54,17 @@ where
|
|||
)));
|
||||
}
|
||||
|
||||
let prefixes = config
|
||||
.prefixes
|
||||
.into_iter()
|
||||
.map(|prefix| prefix.into_bstring())
|
||||
.collect::<BTreeSet<_>>();
|
||||
|
||||
let refs = gix_protocol::ls_refs(
|
||||
&mut conn,
|
||||
capabilities,
|
||||
|_caps, args, features| {
|
||||
for prefix in &config.prefixes {
|
||||
for prefix in &prefixes {
|
||||
let mut arg = BString::from("ref-prefix ");
|
||||
arg.push_str(prefix);
|
||||
args.push(arg)
|
||||
|
|
@ -74,10 +83,7 @@ where
|
|||
.into_iter()
|
||||
.filter(|r| {
|
||||
let (refname, _, _) = r.unpack();
|
||||
config
|
||||
.prefixes
|
||||
.iter()
|
||||
.any(|prefix| refname.starts_with(prefix))
|
||||
prefixes.iter().any(|prefix| refname.starts_with(prefix))
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue