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, Transport, TransportV2Ext};
51 use maybe_async::maybe_async;
52
53 use super::{Action, Error};
54 use crate::{
55 handshake::{refs::from_v2_refs, Ref},
56 indicate_end_of_interaction, Command,
57 };
58
59 #[maybe_async]
64 pub async fn ls_refs(
65 mut transport: impl Transport,
66 capabilities: &Capabilities,
67 prepare_ls_refs: impl FnOnce(
68 &Capabilities,
69 &mut Vec<BString>,
70 &mut Vec<(&str, Option<Cow<'static, str>>)>,
71 ) -> std::io::Result<Action>,
72 progress: &mut impl Progress,
73 trace: bool,
74 ) -> Result<Vec<Ref>, Error> {
75 let _span = gix_features::trace::detail!("gix_protocol::ls_refs()", capabilities = ?capabilities);
76 let ls_refs = Command::LsRefs;
77 let mut ls_features = ls_refs.default_features(gix_transport::Protocol::V2, capabilities);
78 let mut ls_args = ls_refs.initial_v2_arguments(&ls_features);
79 if capabilities
80 .capability("ls-refs")
81 .and_then(|cap| cap.supports("unborn"))
82 .unwrap_or_default()
83 {
84 ls_args.push("unborn".into());
85 }
86 let refs = match prepare_ls_refs(capabilities, &mut ls_args, &mut ls_features) {
87 Ok(Action::Skip) => Vec::new(),
88 Ok(Action::Continue) => {
89 ls_refs.validate_argument_prefixes(
90 gix_transport::Protocol::V2,
91 capabilities,
92 &ls_args,
93 &ls_features,
94 )?;
95
96 progress.step();
97 progress.set_name("list refs".into());
98 let mut remote_refs = transport
99 .invoke(
100 ls_refs.as_str(),
101 ls_features.into_iter(),
102 if ls_args.is_empty() {
103 None
104 } else {
105 Some(ls_args.into_iter())
106 },
107 trace,
108 )
109 .await?;
110 from_v2_refs(&mut remote_refs).await?
111 }
112 Err(err) => {
113 indicate_end_of_interaction(transport, trace).await?;
114 return Err(err.into());
115 }
116 };
117 Ok(refs)
118 }
119}