Skip to content

Commit 129176f

Browse files
committed
change connection API to be consuming, otherwise async mode doesn't work due to lack of async drop (#450)
1 parent 332a978 commit 129176f

File tree

4 files changed

+54
-82
lines changed

4 files changed

+54
-82
lines changed

Diff for: git-repository/src/remote/connect.rs

+19-21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use crate::remote::{connection, Connection};
2-
use crate::{remote, Progress, Remote};
1+
use crate::remote::Connection;
2+
use crate::{Progress, Remote};
33
use git_protocol::transport::client::Transport;
44

55
mod error {
@@ -37,7 +37,6 @@ impl<'repo> Remote<'repo> {
3737
remote: self,
3838
transport,
3939
progress,
40-
state: connection::State::Connected,
4140
}
4241
}
4342

@@ -46,13 +45,27 @@ impl<'repo> Remote<'repo> {
4645
#[git_protocol::maybe_async::maybe_async]
4746
pub async fn connect<P>(
4847
&self,
49-
direction: remote::Direction,
48+
direction: crate::remote::Direction,
5049
progress: P,
5150
) -> Result<Connection<'_, 'repo, Box<dyn Transport + Send>, P>, Error>
5251
where
5352
P: Progress,
5453
{
5554
use git_protocol::transport::Protocol;
55+
fn sanitize(mut url: git_url::Url) -> Result<git_url::Url, Error> {
56+
if url.scheme == git_url::Scheme::File {
57+
let mut dir = git_path::from_bstr(url.path.as_ref());
58+
let kind = git_discover::is_git(dir.as_ref()).or_else(|_| {
59+
dir.to_mut().push(git_discover::DOT_GIT_DIR);
60+
git_discover::is_git(dir.as_ref())
61+
})?;
62+
let (git_dir, _work_dir) = git_discover::repository::Path::from_dot_git_dir(dir.into_owned(), kind)
63+
.into_repository_and_work_tree_directories();
64+
url.path = git_path::into_bstr(git_dir).into_owned();
65+
}
66+
Ok(url)
67+
}
68+
5669
let protocol = self
5770
.repo
5871
.config
@@ -72,23 +85,8 @@ impl<'repo> Remote<'repo> {
7285
})
7386
})?;
7487

75-
let url = self.processed_url(direction)?;
76-
let transport = git_protocol::transport::connect(url, protocol).await?;
88+
let url = self.url(direction).ok_or(Error::MissingUrl { direction })?.to_owned();
89+
let transport = git_protocol::transport::connect(sanitize(url)?, protocol).await?;
7790
Ok(self.to_connection_with_transport(transport, progress))
7891
}
79-
80-
fn processed_url(&self, direction: remote::Direction) -> Result<git_url::Url, Error> {
81-
let mut url = self.url(direction).ok_or(Error::MissingUrl { direction })?.to_owned();
82-
if url.scheme == git_url::Scheme::File {
83-
let mut dir = git_path::from_bstr(url.path.as_ref());
84-
let kind = git_discover::is_git(dir.as_ref()).or_else(|_| {
85-
dir.to_mut().push(git_discover::DOT_GIT_DIR);
86-
git_discover::is_git(dir.as_ref())
87-
})?;
88-
let (git_dir, _work_dir) = git_discover::repository::Path::from_dot_git_dir(dir.into_owned(), kind)
89-
.into_repository_and_work_tree_directories();
90-
url.path = git_path::into_bstr(git_dir).into_owned();
91-
}
92-
Ok(url)
93-
}
9492
}

Diff for: git-repository/src/remote/connection/list_refs.rs

+28-30
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::remote::connection::State;
1+
use crate::remote::connection::HandshakeWithRefs;
22
use crate::remote::{Connection, Direction};
33
use git_features::progress::Progress;
44
use git_protocol::transport::client::Transport;
@@ -10,6 +10,8 @@ mod error {
1010
Handshake(#[from] git_protocol::fetch::handshake::Error),
1111
#[error(transparent)]
1212
ListRefs(#[from] git_protocol::fetch::refs::Error),
13+
#[error(transparent)]
14+
Transport(#[from] git_protocol::transport::client::Error),
1315
}
1416
}
1517
pub use error::Error;
@@ -22,40 +24,36 @@ where
2224
/// List all references on the remote.
2325
///
2426
/// Note that this doesn't fetch the objects mentioned in the tips nor does it make any change to underlying repository.
25-
///
26-
/// This method is idempotent and only runs once.
2727
#[git_protocol::maybe_async::maybe_async]
28-
pub async fn list_refs(&mut self) -> Result<&[git_protocol::fetch::Ref], Error> {
29-
match self.state {
30-
State::Connected => {
31-
let mut outcome = git_protocol::fetch::handshake(
28+
pub async fn list_refs(mut self) -> Result<Vec<git_protocol::fetch::Ref>, Error> {
29+
let res = self.fetch_refs().await?;
30+
git_protocol::fetch::indicate_end_of_interaction(&mut self.transport).await?;
31+
Ok(res.refs)
32+
}
33+
34+
#[git_protocol::maybe_async::maybe_async]
35+
async fn fetch_refs(&mut self) -> Result<HandshakeWithRefs, Error> {
36+
let mut outcome = git_protocol::fetch::handshake(
37+
&mut self.transport,
38+
git_protocol::credentials::helper,
39+
Vec::new(),
40+
&mut self.progress,
41+
)
42+
.await?;
43+
let refs = match outcome.refs.take() {
44+
Some(refs) => refs,
45+
None => {
46+
git_protocol::fetch::refs(
3247
&mut self.transport,
33-
git_protocol::credentials::helper,
34-
Vec::new(),
48+
outcome.server_protocol_version,
49+
&outcome.capabilities,
50+
|_a, _b, _c| Ok(git_protocol::fetch::delegate::LsRefsAction::Continue),
3551
&mut self.progress,
3652
)
37-
.await?;
38-
let refs = match outcome.refs.take() {
39-
Some(refs) => refs,
40-
None => {
41-
git_protocol::fetch::refs(
42-
&mut self.transport,
43-
outcome.server_protocol_version,
44-
&outcome.capabilities,
45-
|_a, _b, _c| Ok(git_protocol::fetch::delegate::LsRefsAction::Continue),
46-
&mut self.progress,
47-
)
48-
.await?
49-
}
50-
};
51-
self.state = State::HandshakeWithRefs { outcome, refs };
52-
match &self.state {
53-
State::HandshakeWithRefs { refs, .. } => Ok(refs),
54-
_ => unreachable!(),
55-
}
53+
.await?
5654
}
57-
State::HandshakeWithRefs { ref refs, .. } => Ok(refs),
58-
}
55+
};
56+
Ok(HandshakeWithRefs { outcome, refs })
5957
}
6058

6159
/// List all references on the remote that have been filtered through our remote's [`refspecs`][crate::Remote::refspecs()]

Diff for: git-repository/src/remote/connection/mod.rs

+6-30
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,27 @@
11
use crate::Remote;
22

3-
pub(crate) enum State {
4-
Connected,
5-
HandshakeWithRefs {
6-
#[allow(dead_code)]
7-
outcome: git_protocol::fetch::handshake::Outcome,
8-
refs: Vec<git_protocol::fetch::Ref>,
9-
},
3+
pub(crate) struct HandshakeWithRefs {
4+
#[allow(dead_code)]
5+
outcome: git_protocol::fetch::handshake::Outcome,
6+
refs: Vec<git_protocol::fetch::Ref>,
107
}
118

129
/// A type to represent an ongoing connection to a remote host, typically with the connection already established.
1310
///
1411
/// It can be used to perform a variety of operations with the remote without worrying about protocol details,
1512
/// much like a remote procedure call.
16-
pub struct Connection<'a, 'repo, T, P>
17-
where
18-
T: git_protocol::transport::client::Transport,
19-
{
13+
pub struct Connection<'a, 'repo, T, P> {
2014
pub(crate) remote: &'a Remote<'repo>,
2115
pub(crate) transport: T,
2216
pub(crate) progress: P,
23-
pub(crate) state: State,
24-
}
25-
26-
mod impls {
27-
use crate::remote::Connection;
28-
use git_protocol::transport::client::Transport;
29-
30-
impl<'a, 'repo, T, P> Drop for Connection<'a, 'repo, T, P>
31-
where
32-
T: Transport,
33-
{
34-
fn drop(&mut self) {
35-
git_protocol::fetch::indicate_end_of_interaction(&mut self.transport).ok();
36-
}
37-
}
3817
}
3918

4019
mod access {
4120
use crate::remote::Connection;
4221
use crate::Remote;
4322

4423
/// Access and conversion
45-
impl<'a, 'repo, T, P> Connection<'a, 'repo, T, P>
46-
where
47-
T: git_protocol::transport::client::Transport,
48-
{
24+
impl<'a, 'repo, T, P> Connection<'a, 'repo, T, P> {
4925
/// Drop the transport and additional state to regain the original remote.
5026
pub fn remote(&self) -> &Remote<'repo> {
5127
self.remote

Diff for: git-repository/tests/remote/list_refs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ mod blocking_io {
88
fn all() {
99
let repo = remote::repo("clone");
1010
let remote = repo.find_remote("origin").unwrap();
11-
let mut connection = remote.connect(Fetch, progress::Discard).unwrap();
11+
let connection = remote.connect(Fetch, progress::Discard).unwrap();
1212
let refs = connection.list_refs().unwrap();
1313
assert_eq!(refs.len(), 14, "it gets all remote refs, independently of the refspec.");
1414
}

0 commit comments

Comments
 (0)