Skip to content

Commit 7e96d18

Browse files
committed
feat: obtain a refmap after listing refs via remote::Connection::list_refs_to_map(). (#450)
With it it's possible to establish a relationship between what's about to be fetched to local tracking branches as established by refspecs for fetching.
1 parent 777ba7f commit 7e96d18

File tree

3 files changed

+44
-12
lines changed

3 files changed

+44
-12
lines changed

git-repository/src/remote/connection/list_refs.rs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ where
2727
/// Note that this doesn't fetch the objects mentioned in the tips nor does it make any change to underlying repository.
2828
#[git_protocol::maybe_async::maybe_async]
2929
pub async fn list_refs(mut self) -> Result<Vec<git_protocol::fetch::Ref>, Error> {
30-
let res = self.fetch_refs().await?;
30+
let res = self.fetch_refs().await;
3131
git_protocol::fetch::indicate_end_of_interaction(&mut self.transport).await?;
32-
Ok(res.refs)
32+
Ok(res?.refs)
3333
}
3434

3535
#[git_protocol::maybe_async::maybe_async]
@@ -99,19 +99,19 @@ pub mod to_map {
9999
/// Note that this doesn't fetch the objects mentioned in the tips nor does it make any change to underlying repository.
100100
#[git_protocol::maybe_async::maybe_async]
101101
pub async fn list_refs_to_map(mut self) -> Result<fetch::RefMap, Error> {
102-
let mappings = self.ref_map().await?;
102+
let res = self.ref_map().await;
103103
git_protocol::fetch::indicate_end_of_interaction(&mut self.transport)
104104
.await
105105
.map_err(|err| Error::ListRefs(crate::remote::list_refs::Error::Transport(err)))?;
106-
Ok(mappings)
106+
Ok(res?)
107107
}
108108

109109
#[git_protocol::maybe_async::maybe_async]
110110
async fn ref_map(&mut self) -> Result<fetch::RefMap, Error> {
111-
let res = self.fetch_refs().await?;
111+
let remote = self.fetch_refs().await?;
112112
let group = git_refspec::MatchGroup::from_fetch_specs(self.remote.fetch_specs.iter().map(|s| s.to_ref()));
113-
let (_res, fixes) = group
114-
.match_remotes(res.refs.iter().map(|r| {
113+
let (res, fixes) = group
114+
.match_remotes(remote.refs.iter().map(|r| {
115115
let (full_ref_name, target, object) = r.unpack();
116116
git_refspec::match_group::Item {
117117
full_ref_name,
@@ -120,10 +120,23 @@ pub mod to_map {
120120
}
121121
}))
122122
.validated()?;
123-
Ok(fetch::RefMap {
124-
mappings: Vec::new(),
125-
fixes,
126-
})
123+
let mappings = res.mappings;
124+
let mappings = mappings
125+
.into_iter()
126+
.map(|m| fetch::Mapping {
127+
remote: m
128+
.item_index
129+
.map(|idx| fetch::Source::Ref(remote.refs[idx].clone()))
130+
.unwrap_or_else(|| {
131+
fetch::Source::ObjectId(match m.lhs {
132+
git_refspec::match_group::SourceRef::ObjectId(id) => id,
133+
_ => unreachable!("no item index implies having an object id"),
134+
})
135+
}),
136+
local: m.rhs.map(|c| c.into_owned()),
137+
})
138+
.collect();
139+
Ok(fetch::RefMap { mappings, fixes })
127140
}
128141
}
129142
}

git-repository/src/remote/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,18 @@ pub mod fetch {
3838
pub fixes: Vec<git_refspec::match_group::validate::Fix>,
3939
}
4040

41+
/// Either an object id that the remote has or the matched remote ref itself.
42+
pub enum Source {
43+
/// An object id, as the matched ref-spec was an object id itself.
44+
ObjectId(git_hash::ObjectId),
45+
/// The remote reference that matched the ref-specs name.
46+
Ref(git_protocol::fetch::Ref),
47+
}
48+
4149
/// A mapping between a single remote reference and its advertised objects to a local destination which may or may not exist.
4250
pub struct Mapping {
4351
/// The reference on the remote side, along with information about the objects they point to as advertised by the server.
44-
pub remote: git_protocol::fetch::Ref,
52+
pub remote: Source,
4553
/// The local tracking reference to update after fetching the object visible via `remote`.
4654
pub local: Option<BString>,
4755
}

git-repository/tests/remote/list_refs.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ mod blocking_io {
2929
let refs = connection.list_refs()?;
3030
assert_eq!(refs.len(), 14, "it gets all remote refs, independently of the refspec.");
3131
}
32+
33+
{
34+
let connection = remote.connect(Fetch, progress::Discard)?;
35+
let map = connection.list_refs_to_map()?;
36+
assert_eq!(map.fixes.len(), 0);
37+
assert_eq!(
38+
map.mappings.len(),
39+
11,
40+
"mappings are only a sub-set of all remotes due to refspec matching"
41+
);
42+
}
3243
}
3344
Ok(())
3445
}

0 commit comments

Comments
 (0)