Skip to content

Commit 5c07c76

Browse files
committed
feat!: Repository::remote_names|remote_default_name() now returns Cow<'_, BStr> instead of Cow<'_, str>.
That way information won't degenerate due to enforcement of UTF-8.
1 parent 8dd76e3 commit 5c07c76

File tree

5 files changed

+43
-26
lines changed

5 files changed

+43
-26
lines changed

gix/src/remote/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ impl Direction {
2222
}
2323

2424
/// The name of a remote, either interpreted as symbol like `origin` or as url as returned by [`Remote::name()`][crate::Remote::name()].
25-
#[derive(Debug, PartialEq, Eq, Clone)]
25+
#[derive(Debug, PartialEq, Eq, Clone, Ord, PartialOrd, Hash)]
2626
pub enum Name<'repo> {
2727
/// A symbolic name, like `origin`.
2828
/// Note that it has not necessarily been validated yet.

gix/src/repository/config/mod.rs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -135,16 +135,25 @@ impl crate::Repository {
135135
mod transport;
136136

137137
mod remote {
138+
use crate::bstr::BStr;
138139
use std::{borrow::Cow, collections::BTreeSet};
139140

140-
use crate::{bstr::ByteSlice, remote};
141+
use crate::remote;
141142

142143
impl crate::Repository {
143144
/// Returns a sorted list unique of symbolic names of remotes that
144145
/// we deem [trustworthy][crate::open::Options::filter_config_section()].
145-
// TODO: Use `remote::Name` here
146-
pub fn remote_names(&self) -> BTreeSet<&str> {
147-
self.subsection_names_of("remote")
146+
pub fn remote_names(&self) -> BTreeSet<Cow<'_, BStr>> {
147+
self.config
148+
.resolved
149+
.sections_by_name("remote")
150+
.map(|it| {
151+
let filter = self.filter_config_section();
152+
it.filter(move |s| filter(s.meta()))
153+
.filter_map(|section| section.header().subsection_name().map(Cow::Borrowed))
154+
.collect()
155+
})
156+
.unwrap_or_default()
148157
}
149158

150159
/// Obtain the branch-independent name for a remote for use in the given `direction`, or `None` if it could not be determined.
@@ -155,25 +164,23 @@ mod remote {
155164
/// # Notes
156165
///
157166
/// It's up to the caller to determine what to do if the current `head` is unborn or detached.
158-
// TODO: use remote::Name here
159-
pub fn remote_default_name(&self, direction: remote::Direction) -> Option<Cow<'_, str>> {
167+
pub fn remote_default_name(&self, direction: remote::Direction) -> Option<Cow<'_, BStr>> {
160168
let name = (direction == remote::Direction::Push)
161169
.then(|| {
162170
self.config
163171
.resolved
164172
.string_filter("remote", None, "pushDefault", &mut self.filter_config_section())
165-
.and_then(|s| match s {
166-
Cow::Borrowed(s) => s.to_str().ok().map(Cow::Borrowed),
167-
Cow::Owned(s) => s.to_str().ok().map(|s| Cow::Owned(s.into())),
168-
})
169173
})
170174
.flatten();
171175
name.or_else(|| {
172176
let names = self.remote_names();
173177
match names.len() {
174178
0 => None,
175-
1 => names.iter().next().copied().map(Cow::Borrowed),
176-
_more_than_one => names.get("origin").copied().map(Cow::Borrowed),
179+
1 => names.into_iter().next(),
180+
_more_than_one => {
181+
let origin = Cow::Borrowed("origin".into());
182+
names.contains(&origin).then_some(origin)
183+
}
177184
}
178185
})
179186
}
@@ -191,8 +198,12 @@ mod branch {
191198
impl crate::Repository {
192199
/// Return a set of unique short branch names for which custom configuration exists in the configuration,
193200
/// if we deem them [trustworthy][crate::open::Options::filter_config_section()].
201+
///
202+
/// ### Note
203+
///
204+
/// Branch names that have illformed UTF-8 will silently be skipped.
194205
pub fn branch_names(&self) -> BTreeSet<&str> {
195-
self.subsection_names_of("branch")
206+
self.subsection_str_names_of("branch")
196207
}
197208

198209
/// Returns the validated reference on the remote associated with the given `short_branch_name`,
@@ -237,7 +248,7 @@ impl crate::Repository {
237248
.unwrap_or(config::section::is_trusted)
238249
}
239250

240-
fn subsection_names_of<'a>(&'a self, header_name: &'a str) -> BTreeSet<&'a str> {
251+
fn subsection_str_names_of<'a>(&'a self, header_name: &'a str) -> BTreeSet<&'a str> {
241252
self.config
242253
.resolved
243254
.sections_by_name(header_name)

gix/tests/remote/mod.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{borrow::Cow, path::PathBuf};
1+
use std::path::PathBuf;
22

33
use gix_testtools::scripted_fixture_read_only;
44

@@ -64,10 +64,6 @@ pub(crate) fn into_daemon_remote_if_async<'repo, 'a>(
6464
}
6565
}
6666

67-
pub(crate) fn cow_str(s: &str) -> Cow<str> {
68-
Cow::Borrowed(s)
69-
}
70-
7167
mod connect;
7268
pub(crate) mod fetch;
7369
mod ref_map;

gix/tests/repository/config/remote.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1+
use gix::bstr::BStr;
2+
use std::borrow::Cow;
13
use std::iter::FromIterator;
24

3-
use crate::{named_repo, remote, remote::cow_str, Result};
5+
use crate::{named_repo, remote, Result};
6+
7+
fn remote_names<'a>(it: impl IntoIterator<Item = &'a str>) -> Vec<Cow<'a, BStr>> {
8+
it.into_iter().map(|n| Cow::Borrowed(n.into())).collect()
9+
}
10+
11+
fn remote_name(name: &str) -> Cow<'_, BStr> {
12+
Cow::Borrowed(name.into())
13+
}
414

515
#[test]
616
fn remote_and_branch_names() {
@@ -13,15 +23,15 @@ fn remote_and_branch_names() {
1323
let repo = remote::repo("clone");
1424
assert_eq!(
1525
Vec::from_iter(repo.remote_names().into_iter()),
16-
vec!["myself", "origin"]
26+
remote_names(["myself", "origin"])
1727
);
1828
assert_eq!(
1929
repo.remote_default_name(gix::remote::Direction::Fetch),
20-
Some(cow_str("origin"))
30+
Some(remote_name("origin"))
2131
);
2232
assert_eq!(
2333
repo.remote_default_name(gix::remote::Direction::Push),
24-
Some(cow_str("origin"))
34+
Some(remote_name("origin"))
2535
);
2636
assert_eq!(Vec::from_iter(repo.branch_names()), vec!["main"]);
2737
}
@@ -32,7 +42,7 @@ fn remote_default_name() {
3242

3343
assert_eq!(
3444
repo.remote_default_name(gix::remote::Direction::Push),
35-
Some(cow_str("myself")),
45+
Some(remote_name("myself")),
3646
"overridden via remote.pushDefault"
3747
);
3848

gix/tests/repository/remote.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ mod find_remote {
133133
];
134134
for (name, (url, refspec)) in repo.remote_names().into_iter().zip(expected) {
135135
count += 1;
136-
let remote = repo.find_remote(name)?;
136+
let remote = repo.find_remote(name.as_ref())?;
137137
assert_eq!(remote.name().expect("set").as_bstr(), name);
138138

139139
assert_eq!(

0 commit comments

Comments
 (0)