Skip to content

Commit 449ff06

Browse files
committed
change!: Repository::branch_remote_name() returns reference::remote::Name. (#450)
That way it's made clear the remote can also be a URL, while rejecting illformed UTF8. The latter isn't valid for remote names anyway as these only support a very limited character set. Note that this error currently is degenerated, making it appear if the remote name doesn't exists if illformed UTF-8 is found in what appears to be a symbolic ref.
1 parent 07efbce commit 449ff06

File tree

2 files changed

+60
-28
lines changed

2 files changed

+60
-28
lines changed

git-repository/src/reference/remote.rs

+54-23
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use std::borrow::Cow;
2+
use std::convert::TryInto;
23

34
use crate::{
4-
bstr::{BStr, ByteSlice, ByteVec},
5+
bstr::{BStr, ByteSlice},
56
remote, Reference,
67
};
78

@@ -14,20 +15,60 @@ pub enum Name<'repo> {
1415
Url(Cow<'repo, BStr>),
1516
}
1617

17-
impl Name<'_> {
18-
/// Return this instance as a symbolic name, if it is one.
19-
pub fn as_symbol(&self) -> Option<&str> {
20-
match self {
21-
Name::Symbol(n) => n.as_ref().into(),
22-
Name::Url(_) => None,
18+
mod name {
19+
use super::Name;
20+
use crate::bstr::{BStr, ByteSlice, ByteVec};
21+
use std::borrow::Cow;
22+
use std::convert::TryFrom;
23+
24+
impl Name<'_> {
25+
/// Obtain the name as string representation.
26+
pub fn as_bstr(&self) -> &BStr {
27+
match self {
28+
Name::Symbol(v) => v.as_ref().into(),
29+
Name::Url(v) => v.as_ref(),
30+
}
31+
}
32+
33+
/// Return this instance as a symbolic name, if it is one.
34+
pub fn as_symbol(&self) -> Option<&str> {
35+
match self {
36+
Name::Symbol(n) => n.as_ref().into(),
37+
Name::Url(_) => None,
38+
}
39+
}
40+
41+
/// Return this instance as url, if it is one.
42+
pub fn as_url(&self) -> Option<&BStr> {
43+
match self {
44+
Name::Url(n) => n.as_ref().into(),
45+
Name::Symbol(_) => None,
46+
}
47+
}
48+
}
49+
50+
impl<'a> TryFrom<Cow<'a, BStr>> for Name<'a> {
51+
type Error = Cow<'a, BStr>;
52+
53+
fn try_from(name: Cow<'a, BStr>) -> Result<Self, Self::Error> {
54+
if name.contains(&b'/') {
55+
Ok(Name::Url(name))
56+
} else {
57+
match name {
58+
Cow::Borrowed(n) => n.to_str().ok().map(Cow::Borrowed).ok_or(name),
59+
Cow::Owned(n) => Vec::from(n)
60+
.into_string()
61+
.map_err(|err| Cow::Owned(err.into_vec().into()))
62+
.map(Cow::Owned),
63+
}
64+
.map(Name::Symbol)
65+
}
2366
}
2467
}
2568

26-
/// Return this instance as url, if it is one.
27-
pub fn as_url(&self) -> Option<&BStr> {
28-
match self {
29-
Name::Url(n) => n.as_ref().into(),
30-
Name::Symbol(_) => None,
69+
impl<'a> AsRef<BStr> for Name<'a> {
70+
fn as_ref(&self) -> &BStr {
71+
self.as_bstr()
3172
}
3273
}
3374
}
@@ -56,17 +97,7 @@ impl<'repo> Reference<'repo> {
5697
})
5798
.flatten()
5899
.or_else(|| config.string("branch", Some(name), "remote"))
59-
.and_then(|name| {
60-
if name.contains(&b'/') {
61-
Some(Name::Url(name))
62-
} else {
63-
match name {
64-
Cow::Borrowed(n) => n.to_str().ok().map(Cow::Borrowed),
65-
Cow::Owned(n) => Vec::from(n).into_string().ok().map(Cow::Owned),
66-
}
67-
.map(Name::Symbol)
68-
}
69-
})
100+
.and_then(|name| name.try_into().ok())
70101
}
71102

72103
/// Like [`remote_name(…)`][Self::remote_name()], but configures the returned `Remote` with additional information like

git-repository/src/repository/config.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,6 @@ mod branch {
8383
use git_ref::FullNameRef;
8484
use git_validate::reference::name::Error as ValidateNameError;
8585

86-
use crate::bstr::BStr;
87-
8886
impl crate::Repository {
8987
/// Return a set of unique short branch names for which custom configuration exists in the configuration,
9088
/// if we deem them [trustworthy][crate::open::Options::filter_config_section()].
@@ -114,12 +112,15 @@ mod branch {
114112
/// Returns the unvalidated name of the remote associated with the given `short_branch_name`,
115113
/// typically `main` instead of `refs/heads/main`.
116114
/// In some cases, the returned name will be an URL.
117-
/// Returns `None` if the remote was not found.
115+
/// Returns `None` if the remote was not found or if the name contained illformed UTF-8.
118116
///
119117
/// See also [Reference::remote_name()][crate::Reference::remote_name()] for a more typesafe version
120118
/// to be used when a `Reference` is available.
121-
pub fn branch_remote_name(&self, short_branch_name: &str) -> Option<Cow<'_, BStr>> {
122-
self.config.resolved.string("branch", Some(short_branch_name), "remote")
119+
pub fn branch_remote_name(&self, short_branch_name: &str) -> Option<crate::reference::remote::Name<'_>> {
120+
self.config
121+
.resolved
122+
.string("branch", Some(short_branch_name), "remote")
123+
.and_then(|name| name.try_into().ok())
123124
}
124125
}
125126
}

0 commit comments

Comments
 (0)