1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use git_features::progress::Progress;
use git_protocol::transport::client::Transport;
use crate::remote::{connection::HandshakeWithRefs, fetch, Connection, Direction};
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]
Handshake(#[from] git_protocol::fetch::handshake::Error),
#[error(transparent)]
ListRefs(#[from] git_protocol::fetch::refs::Error),
#[error(transparent)]
Transport(#[from] git_protocol::transport::client::Error),
#[error(transparent)]
ConfigureCredentials(#[from] crate::config::credential_helpers::Error),
#[error(transparent)]
MappingValidation(#[from] git_refspec::match_group::validate::Error),
}
impl<'remote, 'repo, T, P> Connection<'remote, 'repo, T, P>
where
T: Transport,
P: Progress,
{
#[git_protocol::maybe_async::maybe_async]
pub async fn ref_map(mut self) -> Result<fetch::RefMap<'remote>, Error> {
let res = self.ref_map_inner().await;
git_protocol::fetch::indicate_end_of_interaction(&mut self.transport).await?;
res
}
#[git_protocol::maybe_async::maybe_async]
async fn ref_map_inner(&mut self) -> Result<fetch::RefMap<'remote>, Error> {
let remote = self.fetch_refs().await?;
let group = git_refspec::MatchGroup::from_fetch_specs(self.remote.fetch_specs.iter().map(|s| s.to_ref()));
let (res, fixes) = group
.match_remotes(remote.refs.iter().map(|r| {
let (full_ref_name, target, object) = r.unpack();
git_refspec::match_group::Item {
full_ref_name,
target,
object,
}
}))
.validated()?;
let mappings = res.mappings;
let mappings = mappings
.into_iter()
.map(|m| fetch::Mapping {
remote: m
.item_index
.map(|idx| fetch::Source::Ref(remote.refs[idx].clone()))
.unwrap_or_else(|| {
fetch::Source::ObjectId(match m.lhs {
git_refspec::match_group::SourceRef::ObjectId(id) => id,
_ => unreachable!("no item index implies having an object id"),
})
}),
local: m.rhs.map(|c| c.into_owned()),
spec_index: m.spec_index,
})
.collect();
Ok(fetch::RefMap {
mappings,
fixes,
remote_refs: remote.refs,
handshake: remote.outcome,
})
}
#[git_protocol::maybe_async::maybe_async]
async fn fetch_refs(&mut self) -> Result<HandshakeWithRefs, Error> {
let mut credentials_storage;
let authenticate = match self.credentials.as_mut() {
Some(f) => f,
None => {
let url = self
.remote
.url(Direction::Fetch)
.map(ToOwned::to_owned)
.unwrap_or_else(|| {
git_url::parse(self.transport.to_url().as_bytes().into())
.expect("valid URL to be provided by transport")
});
credentials_storage = self.configured_credentials(url)?;
&mut credentials_storage
}
};
let mut outcome =
git_protocol::fetch::handshake(&mut self.transport, authenticate, Vec::new(), &mut self.progress).await?;
let refs = match outcome.refs.take() {
Some(refs) => refs,
None => {
git_protocol::fetch::refs(
&mut self.transport,
outcome.server_protocol_version,
&outcome.capabilities,
|_a, _b, _c| Ok(git_protocol::fetch::delegate::LsRefsAction::Continue),
&mut self.progress,
)
.await?
}
};
Ok(HandshakeWithRefs { outcome, refs })
}
}