Skip to content

Commit 3b4e06a

Browse files
committed
refactor!: extract LsRefsCommand type to split preparation
1 parent 3bc5801 commit 3b4e06a

File tree

4 files changed

+85
-70
lines changed

4 files changed

+85
-70
lines changed

gix-protocol/src/fetch/refmap/init.rs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,14 @@ impl RefMap {
7777
{
7878
let _span = gix_trace::coarse!("gix_protocol::fetch::RefMap::new()");
7979
let all_refspecs = context.aggregate_refspecs();
80-
let remote_refs = crate::ls_refs(
81-
transport,
82-
capabilities,
83-
push_prefix_arguments(prefix_from_spec_as_filter_on_remote, &all_refspecs),
84-
&mut progress,
85-
trace_packetlines,
86-
user_agent,
87-
)
88-
.await?;
80+
let mut refs_cmd = crate::LsRefsCommand::new(capabilities, user_agent);
81+
push_prefix_arguments(
82+
prefix_from_spec_as_filter_on_remote,
83+
&all_refspecs,
84+
refs_cmd.arguments(),
85+
);
8986

87+
let remote_refs = refs_cmd.invoke(transport, &mut progress, trace_packetlines).await?;
9088
Self::from_refs(remote_refs, capabilities, context)
9189
}
9290

@@ -162,12 +160,12 @@ impl RefMap {
162160
fn push_prefix_arguments(
163161
prefix_from_spec_as_filter_on_remote: bool,
164162
all_refspecs: &[gix_refspec::RefSpec],
165-
) -> Vec<BString> {
163+
arguments: &mut Vec<BString>,
164+
) {
166165
if !prefix_from_spec_as_filter_on_remote {
167-
return Vec::new();
166+
return;
168167
}
169168

170-
let mut arguments = Vec::new();
171169
let mut seen = HashSet::new();
172170
for spec in all_refspecs {
173171
let spec = spec.to_ref();
@@ -180,6 +178,4 @@ fn push_prefix_arguments(
180178
}
181179
}
182180
}
183-
184-
arguments
185181
}

gix-protocol/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//! * create a `Transport`, either blocking or async
66
//! * perform a [`handshake()`]
77
//! * execute a [`Command`]
8-
//! - [list references](ls_refs())
8+
//! - [list references](LsRefsCommand)
99
//! - create a mapping between [refspecs and references](fetch::RefMap)
1010
//! - [receive a pack](fetch())
1111
//!
@@ -67,7 +67,7 @@ pub use handshake::hero::Handshake;
6767
///
6868
pub mod ls_refs;
6969
#[cfg(any(feature = "blocking-client", feature = "async-client"))]
70-
pub use ls_refs::function::ls_refs;
70+
pub use ls_refs::function::LsRefsCommand;
7171

7272
mod util;
7373
pub use util::*;

gix-protocol/src/ls_refs.rs

Lines changed: 69 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
mod error {
33
use crate::handshake::refs::parse;
44

5-
/// The error returned by [`ls_refs()`][crate::ls_refs()].
5+
/// The error returned by invoking a [`super::function::LsRefsCommand`].
66
#[derive(Debug, thiserror::Error)]
77
#[allow(missing_docs)]
88
pub enum Error {
@@ -48,51 +48,76 @@ pub(crate) mod function {
4848
Command,
4949
};
5050

51-
/// Invoke a ls-refs V2 command on `transport`, which requires a prior handshake that yielded
52-
/// server `capabilities`. `prepare_ls_refs(capabilities)` can be used to alter the _ls-refs_.
53-
/// `arguments` are extra arguments to send to the server.
54-
/// `progress` is used to provide feedback.
55-
/// The `agent` information will be added to the features sent to the server.
56-
/// If `trace` is `true`, all packetlines received or sent will be passed to the facilities of the `gix-trace` crate.
57-
#[maybe_async]
58-
pub async fn ls_refs(
59-
mut transport: impl Transport,
60-
capabilities: &Capabilities,
61-
extra_args: Vec<BString>,
62-
progress: &mut impl Progress,
63-
trace: bool,
64-
agent: (&'static str, Option<Cow<'static, str>>),
65-
) -> Result<Vec<Ref>, Error> {
66-
let _span = gix_features::trace::detail!("gix_protocol::ls_refs()", capabilities = ?capabilities);
67-
let ls_refs = Command::LsRefs;
68-
let mut ls_features = ls_refs.default_features(gix_transport::Protocol::V2, capabilities);
69-
ls_features.push(agent);
70-
let mut ls_args = ls_refs.initial_v2_arguments(&ls_features);
71-
if capabilities
72-
.capability("ls-refs")
73-
.and_then(|cap| cap.supports("unborn"))
74-
.unwrap_or_default()
75-
{
76-
ls_args.push("unborn".into());
51+
/// A command to list references from a remote Git repository.
52+
pub struct LsRefsCommand<'a> {
53+
capabilities: &'a Capabilities,
54+
features: Vec<(&'static str, Option<Cow<'static, str>>)>,
55+
arguments: Vec<BString>,
56+
}
57+
58+
impl<'a> LsRefsCommand<'a> {
59+
/// Build a command to list refs from the given server `capabilities`,
60+
/// using `agent` information to identify ourselves.
61+
pub fn new(capabilities: &'a Capabilities, agent: (&'static str, Option<Cow<'static, str>>)) -> Self {
62+
let _span =
63+
gix_features::trace::detail!("gix_protocol::LsRefsCommand::new()", capabilities = ?capabilities);
64+
let ls_refs = Command::LsRefs;
65+
let mut features = ls_refs.default_features(gix_transport::Protocol::V2, capabilities);
66+
features.push(agent);
67+
let mut arguments = ls_refs.initial_v2_arguments(&features);
68+
if capabilities
69+
.capability("ls-refs")
70+
.and_then(|cap| cap.supports("unborn"))
71+
.unwrap_or_default()
72+
{
73+
arguments.push("unborn".into());
74+
}
75+
76+
Self {
77+
capabilities,
78+
features,
79+
arguments,
80+
}
7781
}
7882

79-
ls_args.extend(extra_args);
80-
ls_refs.validate_argument_prefixes(gix_transport::Protocol::V2, capabilities, &ls_args, &ls_features)?;
83+
/// Invoke a ls-refs V2 command on `transport`.
84+
///
85+
/// `progress` is used to provide feedback.
86+
/// If `trace` is `true`, all packetlines received or sent will be passed to the facilities of the `gix-trace` crate.
87+
#[maybe_async]
88+
pub async fn invoke(
89+
self,
90+
mut transport: impl Transport,
91+
progress: &mut impl Progress,
92+
trace: bool,
93+
) -> Result<Vec<Ref>, Error> {
94+
Command::LsRefs.validate_argument_prefixes(
95+
gix_transport::Protocol::V2,
96+
self.capabilities,
97+
&self.arguments,
98+
&self.features,
99+
)?;
100+
101+
progress.step();
102+
progress.set_name("list refs".into());
103+
let mut remote_refs = transport
104+
.invoke(
105+
Command::LsRefs.as_str(),
106+
self.features.into_iter(),
107+
if self.arguments.is_empty() {
108+
None
109+
} else {
110+
Some(self.arguments.into_iter())
111+
},
112+
trace,
113+
)
114+
.await?;
115+
Ok(from_v2_refs(&mut remote_refs).await?)
116+
}
81117

82-
progress.step();
83-
progress.set_name("list refs".into());
84-
let mut remote_refs = transport
85-
.invoke(
86-
ls_refs.as_str(),
87-
ls_features.into_iter(),
88-
if ls_args.is_empty() {
89-
None
90-
} else {
91-
Some(ls_args.into_iter())
92-
},
93-
trace,
94-
)
95-
.await?;
96-
Ok(from_v2_refs(&mut remote_refs).await?)
118+
/// The arguments that will be sent to the server as part of the ls-refs command.
119+
pub fn arguments(&mut self) -> &mut Vec<BString> {
120+
&mut self.arguments
121+
}
97122
}
98123
}

gix-protocol/tests/protocol/fetch/_impl.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ mod fetch_fn {
1717
use gix_protocol::{
1818
credentials,
1919
fetch::{Arguments, Response},
20-
indicate_end_of_interaction, Command,
20+
indicate_end_of_interaction, Command, LsRefsCommand,
2121
};
2222
#[cfg(feature = "async-client")]
2323
use gix_transport::client::async_io::{ExtendedBufRead, HandleProgress, Transport};
@@ -106,15 +106,9 @@ mod fetch_fn {
106106
None => match delegate.action() {
107107
Ok(RefsAction::Skip) => Vec::new(),
108108
Ok(RefsAction::Continue) => {
109-
gix_protocol::ls_refs(
110-
&mut transport,
111-
&capabilities,
112-
Vec::new(),
113-
&mut progress,
114-
trace,
115-
("agent", Some(Cow::Owned(agent.clone()))),
116-
)
117-
.await?
109+
LsRefsCommand::new(&capabilities, ("agent", Some(Cow::Owned(agent.clone()))))
110+
.invoke(&mut transport, &mut progress, trace)
111+
.await?
118112
}
119113
Err(err) => {
120114
indicate_end_of_interaction(transport, trace).await?;

0 commit comments

Comments
 (0)