#[cfg(any(feature = "blocking-client", feature = "async-client"))]mod error { use crate::handshake::refs::parse; /// The error returned by invoking a [`super::function::LsRefsCommand`]. #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { #[error(transparent)] Io(#[from] std::io::Error), #[error(transparent)] Transport(#[from] gix_transport::client::Error), #[error(transparent)] Parse(#[from] parse::Error), #[error(transparent)] ArgumentValidation(#[from] crate::command::validate_argument_prefixes::Error), } impl gix_transport::IsSpuriousError for Error { fn is_spurious(&self) -> bool { match self { Error::Io(err) => err.is_spurious(), Error::Transport(err) => err.is_spurious(), _ => false, } } }}#[cfg(any(feature = "blocking-client", feature = "async-client"))]pub use error::Error; #[cfg(any(feature = "blocking-client", feature = "async-client"))]pub(crate) mod function { use std::{borrow::Cow, collections::HashSet}; use bstr::{BString, ByteVec}; use gix_features::progress::Progress; use gix_transport::client::Capabilities; use super::Error; #[cfg(feature = "async-client")] use crate::transport::client::async_io::{self, TransportV2Ext as _}; #[cfg(feature = "blocking-client")] use crate::transport::client::blocking_io::{self, TransportV2Ext as _}; use crate::{ handshake::{refs::from_v2_refs, Ref}, Command, }; /// A command to list references from a remote Git repository. /// /// It acts as a utility to separate the invocation into the shared blocking portion, /// and the one that performs IO either blocking or `async`. pub struct LsRefsCommand<'a> { pub(crate) capabilities: &'a Capabilities, features: Vec<(&'static str, Option<Cow<'static, str>>)>, arguments: Vec<BString>, } impl<'a> LsRefsCommand<'a> { /// Build a command to list refs from the given server `capabilities`, /// using `agent` information to identify ourselves. pub fn new( prefix_refspecs: Option<&[gix_refspec::RefSpec]>, capabilities: &'a Capabilities, agent: (&'static str, Option<Cow<'static, str>>), ) -> Self { let ls_refs = Command::LsRefs; let mut features = ls_refs.default_features(gix_transport::Protocol::V2, capabilities); features.push(agent); let mut arguments = ls_refs.initial_v2_arguments(&features); if capabilities .capability("ls-refs") .and_then(|cap| cap.supports("unborn")) .unwrap_or_default() { arguments.push("unborn".into()); } if let Some(refspecs) = prefix_refspecs { let mut seen = HashSet::new(); for spec in refspecs { let spec = spec.to_ref(); if seen.insert(spec.instruction()) { let mut prefixes = Vec::with_capacity(1); spec.expand_prefixes(&mut prefixes); for mut prefix in prefixes { prefix.insert_str(0, "ref-prefix "); arguments.push(prefix); } } } } Self { capabilities, features, arguments, } } /// Invoke a ls-refs V2 command on `transport`. /// /// `progress` is used to provide feedback. /// If `trace` is `true`, all packetlines received or sent will be passed to the facilities of the `gix-trace` crate. #[cfg(feature = "async-client")] pub async fn invoke_async( self, mut transport: impl async_io::Transport, progress: &mut impl Progress, trace: bool, ) -> Result<Vec<Ref>, Error> { let _span = gix_features::trace::detail!("gix_protocol::LsRefsCommand::invoke_async()"); Command::LsRefs.validate_argument_prefixes( gix_transport::Protocol::V2, self.capabilities, &self.arguments, &self.features, )?; progress.step(); progress.set_name("list refs".into()); let mut remote_refs = transport .invoke( Command::LsRefs.as_str(), self.features.into_iter(), if self.arguments.is_empty() { None } else { Some(self.arguments.into_iter()) }, trace, ) .await?; Ok(from_v2_refs(&mut remote_refs).await?) } /// Invoke a ls-refs V2 command on `transport`. /// /// `progress` is used to provide feedback. /// If `trace` is `true`, all packetlines received or sent will be passed to the facilities of the `gix-trace` crate. #[cfg(feature = "blocking-client")] pub fn invoke_blocking( self, mut transport: impl blocking_io::Transport, progress: &mut impl Progress, trace: bool, ) -> Result<Vec<Ref>, Error> { let _span = gix_features::trace::detail!("gix_protocol::LsRefsCommand::invoke_blocking()"); Command::LsRefs.validate_argument_prefixes( gix_transport::Protocol::V2, self.capabilities, &self.arguments, &self.features, )?; progress.step(); progress.set_name("list refs".into()); let mut remote_refs = transport.invoke( Command::LsRefs.as_str(), self.features.into_iter(), if self.arguments.is_empty() { None } else { Some(self.arguments.into_iter()) }, trace, )?; Ok(from_v2_refs(&mut remote_refs)?) } }}
#[cfg(any(feature = "blocking-client", feature = "async-client"))]
mod error {
use crate::handshake::refs::parse;
/// The error returned by invoking a [`super::function::LsRefsCommand`].
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
Transport(#[from] gix_transport::client::Error),
#[error(transparent)]
Parse(#[from] parse::Error),
#[error(transparent)]
ArgumentValidation(#[from] crate::command::validate_argument_prefixes::Error),
}
impl gix_transport::IsSpuriousError for Error {
fn is_spurious(&self) -> bool {
match self {
Error::Io(err) => err.is_spurious(),
Error::Transport(err) => err.is_spurious(),
_ => false,
}
}
}
}
#[cfg(any(feature = "blocking-client", feature = "async-client"))]
pub use error::Error;
#[cfg(any(feature = "blocking-client", feature = "async-client"))]
pub(crate) mod function {
use std::{borrow::Cow, collections::HashSet};
use bstr::{BString, ByteVec};
use gix_features::progress::Progress;
use gix_transport::client::Capabilities;
use super::Error;
#[cfg(feature = "async-client")]
use crate::transport::client::async_io::{self, TransportV2Ext as _};
#[cfg(feature = "blocking-client")]
use crate::transport::client::blocking_io::{self, TransportV2Ext as _};
use crate::{
handshake::{refs::from_v2_refs, Ref},
Command,
};
/// A command to list references from a remote Git repository.
///
/// It acts as a utility to separate the invocation into the shared blocking portion,
/// and the one that performs IO either blocking or `async`.
pub struct LsRefsCommand<'a> {
pub(crate) capabilities: &'a Capabilities,
features: Vec<(&'static str, Option<Cow<'static, str>>)>,
arguments: Vec<BString>,
}
impl<'a> LsRefsCommand<'a> {
/// Build a command to list refs from the given server `capabilities`,
/// using `agent` information to identify ourselves.
pub fn new(
prefix_refspecs: Option<&[gix_refspec::RefSpec]>,
capabilities: &'a Capabilities,
agent: (&'static str, Option<Cow<'static, str>>),
) -> Self {
let ls_refs = Command::LsRefs;
let mut features = ls_refs.default_features(gix_transport::Protocol::V2, capabilities);
features.push(agent);
let mut arguments = ls_refs.initial_v2_arguments(&features);
if capabilities
.capability("ls-refs")
.and_then(|cap| cap.supports("unborn"))
.unwrap_or_default()
{
arguments.push("unborn".into());
}
if let Some(refspecs) = prefix_refspecs {
let mut seen = HashSet::new();
for spec in refspecs {
let spec = spec.to_ref();
if seen.insert(spec.instruction()) {
let mut prefixes = Vec::with_capacity(1);
spec.expand_prefixes(&mut prefixes);
for mut prefix in prefixes {
prefix.insert_str(0, "ref-prefix ");
arguments.push(prefix);
}
}
}
}
Self {
capabilities,
features,
arguments,
}
}
/// Invoke a ls-refs V2 command on `transport`.
///
/// `progress` is used to provide feedback.
/// If `trace` is `true`, all packetlines received or sent will be passed to the facilities of the `gix-trace` crate.
#[cfg(feature = "async-client")]
pub async fn invoke_async(
self,
mut transport: impl async_io::Transport,
progress: &mut impl Progress,
trace: bool,
) -> Result<Vec<Ref>, Error> {
let _span = gix_features::trace::detail!("gix_protocol::LsRefsCommand::invoke_async()");
Command::LsRefs.validate_argument_prefixes(
gix_transport::Protocol::V2,
self.capabilities,
&self.arguments,
&self.features,
)?;
progress.step();
progress.set_name("list refs".into());
let mut remote_refs = transport
.invoke(
Command::LsRefs.as_str(),
self.features.into_iter(),
if self.arguments.is_empty() {
None
} else {
Some(self.arguments.into_iter())
},
trace,
)
.await?;
Ok(from_v2_refs(&mut remote_refs).await?)
}
/// Invoke a ls-refs V2 command on `transport`.
///
/// `progress` is used to provide feedback.
/// If `trace` is `true`, all packetlines received or sent will be passed to the facilities of the `gix-trace` crate.
#[cfg(feature = "blocking-client")]
pub fn invoke_blocking(
self,
mut transport: impl blocking_io::Transport,
progress: &mut impl Progress,
trace: bool,
) -> Result<Vec<Ref>, Error> {
let _span = gix_features::trace::detail!("gix_protocol::LsRefsCommand::invoke_blocking()");
Command::LsRefs.validate_argument_prefixes(
gix_transport::Protocol::V2,
self.capabilities,
&self.arguments,
&self.features,
)?;
progress.step();
progress.set_name("list refs".into());
let mut remote_refs = transport.invoke(
Command::LsRefs.as_str(),
self.features.into_iter(),
if self.arguments.is_empty() {
None
} else {
Some(self.arguments.into_iter())
},
trace,
)?;
Ok(from_v2_refs(&mut remote_refs)?)
}
}
}