1#[cfg(any(feature = "blocking-client", feature = "async-client"))]
2mod error {
3 use crate::handshake::refs::parse;
4
5 #[derive(Debug, thiserror::Error)]
7 #[allow(missing_docs)]
8 pub enum Error {
9 #[error(transparent)]
10 Io(#[from] std::io::Error),
11 #[error(transparent)]
12 Transport(#[from] gix_transport::client::Error),
13 #[error(transparent)]
14 Parse(#[from] parse::Error),
15 #[error(transparent)]
16 ArgumentValidation(#[from] crate::command::validate_argument_prefixes::Error),
17 }
18
19 impl gix_transport::IsSpuriousError for Error {
20 fn is_spurious(&self) -> bool {
21 match self {
22 Error::Io(err) => err.is_spurious(),
23 Error::Transport(err) => err.is_spurious(),
24 _ => false,
25 }
26 }
27 }
28}
29#[cfg(any(feature = "blocking-client", feature = "async-client"))]
30pub use error::Error;
31
32#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
34pub enum Action {
35 Continue,
37 Skip,
42}
43
44#[cfg(any(feature = "blocking-client", feature = "async-client"))]
45pub(crate) mod function {
46 use std::borrow::Cow;
47
48 use bstr::BString;
49 use gix_features::progress::Progress;
50 use gix_transport::client::Capabilities;
51 use maybe_async::maybe_async;
52
53 use super::{Action, Error};
54 #[cfg(feature = "async-client")]
55 use crate::transport::client::async_io::{Transport, TransportV2Ext};
56 #[cfg(feature = "blocking-client")]
57 use crate::transport::client::blocking_io::{Transport, TransportV2Ext};
58 use crate::{
59 handshake::{refs::from_v2_refs, Ref},
60 indicate_end_of_interaction, Command,
61 };
62
63 #[maybe_async]
69 pub async fn ls_refs(
70 mut transport: impl Transport,
71 capabilities: &Capabilities,
72 prepare_ls_refs: impl FnOnce(&Capabilities, &mut Vec<BString>) -> std::io::Result<Action>,
73 progress: &mut impl Progress,
74 trace: bool,
75 agent: (&'static str, Option<Cow<'static, str>>),
76 ) -> Result<Vec<Ref>, Error> {
77 let _span = gix_features::trace::detail!("gix_protocol::ls_refs()", capabilities = ?capabilities);
78 let ls_refs = Command::LsRefs;
79 let mut ls_features = ls_refs.default_features(gix_transport::Protocol::V2, capabilities);
80 ls_features.push(agent);
81 let mut ls_args = ls_refs.initial_v2_arguments(&ls_features);
82 if capabilities
83 .capability("ls-refs")
84 .and_then(|cap| cap.supports("unborn"))
85 .unwrap_or_default()
86 {
87 ls_args.push("unborn".into());
88 }
89 let refs = match prepare_ls_refs(capabilities, &mut ls_args) {
90 Ok(Action::Skip) => Vec::new(),
91 Ok(Action::Continue) => {
92 ls_refs.validate_argument_prefixes(
93 gix_transport::Protocol::V2,
94 capabilities,
95 &ls_args,
96 &ls_features,
97 )?;
98
99 progress.step();
100 progress.set_name("list refs".into());
101 let mut remote_refs = transport
102 .invoke(
103 ls_refs.as_str(),
104 ls_features.into_iter(),
105 if ls_args.is_empty() {
106 None
107 } else {
108 Some(ls_args.into_iter())
109 },
110 trace,
111 )
112 .await?;
113 from_v2_refs(&mut remote_refs).await?
114 }
115 Err(err) => {
116 indicate_end_of_interaction(transport, trace).await?;
117 return Err(err.into());
118 }
119 };
120 Ok(refs)
121 }
122}