From b219033960026615054f19eb0f643e4701fcc3d0 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 1 Nov 2022 21:20:44 +0100 Subject: [PATCH] fix: support for proper identification of '.' remote paths in `reference::remote::Name` (#450) --- .../reference/{remote.rs => remote/mod.rs} | 58 +------------------ git-repository/src/reference/remote/name.rs | 55 ++++++++++++++++++ .../tests/fixtures/make_remote_repos.sh | 6 ++ git-repository/tests/reference/remote.rs | 34 +++++++++++ 4 files changed, 96 insertions(+), 57 deletions(-) rename git-repository/src/reference/{remote.rs => remote/mod.rs} (61%) create mode 100644 git-repository/src/reference/remote/name.rs diff --git a/git-repository/src/reference/remote.rs b/git-repository/src/reference/remote/mod.rs similarity index 61% rename from git-repository/src/reference/remote.rs rename to git-repository/src/reference/remote/mod.rs index 410ff16604..9176c48b1d 100644 --- a/git-repository/src/reference/remote.rs +++ b/git-repository/src/reference/remote/mod.rs @@ -15,63 +15,7 @@ pub enum Name<'repo> { Url(Cow<'repo, BStr>), } -mod name { - use super::Name; - use crate::bstr::{BStr, ByteSlice, ByteVec}; - use std::borrow::Cow; - use std::convert::TryFrom; - - impl Name<'_> { - /// Obtain the name as string representation. - pub fn as_bstr(&self) -> &BStr { - match self { - Name::Symbol(v) => v.as_ref().into(), - Name::Url(v) => v.as_ref(), - } - } - - /// Return this instance as a symbolic name, if it is one. - pub fn as_symbol(&self) -> Option<&str> { - match self { - Name::Symbol(n) => n.as_ref().into(), - Name::Url(_) => None, - } - } - - /// Return this instance as url, if it is one. - pub fn as_url(&self) -> Option<&BStr> { - match self { - Name::Url(n) => n.as_ref().into(), - Name::Symbol(_) => None, - } - } - } - - impl<'a> TryFrom> for Name<'a> { - type Error = Cow<'a, BStr>; - - fn try_from(name: Cow<'a, BStr>) -> Result { - if name.contains(&b'/') { - Ok(Name::Url(name)) - } else { - match name { - Cow::Borrowed(n) => n.to_str().ok().map(Cow::Borrowed).ok_or(name), - Cow::Owned(n) => Vec::from(n) - .into_string() - .map_err(|err| Cow::Owned(err.into_vec().into())) - .map(Cow::Owned), - } - .map(Name::Symbol) - } - } - } - - impl<'a> AsRef for Name<'a> { - fn as_ref(&self) -> &BStr { - self.as_bstr() - } - } -} +mod name; /// Remotes impl<'repo> Reference<'repo> { diff --git a/git-repository/src/reference/remote/name.rs b/git-repository/src/reference/remote/name.rs new file mode 100644 index 0000000000..49bfba0c89 --- /dev/null +++ b/git-repository/src/reference/remote/name.rs @@ -0,0 +1,55 @@ +use super::Name; +use crate::bstr::{BStr, ByteSlice, ByteVec}; +use std::borrow::Cow; +use std::convert::TryFrom; + +impl Name<'_> { + /// Obtain the name as string representation. + pub fn as_bstr(&self) -> &BStr { + match self { + Name::Symbol(v) => v.as_ref().into(), + Name::Url(v) => v.as_ref(), + } + } + + /// Return this instance as a symbolic name, if it is one. + pub fn as_symbol(&self) -> Option<&str> { + match self { + Name::Symbol(n) => n.as_ref().into(), + Name::Url(_) => None, + } + } + + /// Return this instance as url, if it is one. + pub fn as_url(&self) -> Option<&BStr> { + match self { + Name::Url(n) => n.as_ref().into(), + Name::Symbol(_) => None, + } + } +} + +impl<'a> TryFrom> for Name<'a> { + type Error = Cow<'a, BStr>; + + fn try_from(name: Cow<'a, BStr>) -> Result { + if name.contains(&b'/') || name.as_ref() == "." { + Ok(Name::Url(name)) + } else { + match name { + Cow::Borrowed(n) => n.to_str().ok().map(Cow::Borrowed).ok_or(name), + Cow::Owned(n) => Vec::from(n) + .into_string() + .map_err(|err| Cow::Owned(err.into_vec().into())) + .map(Cow::Owned), + } + .map(Name::Symbol) + } + } +} + +impl<'a> AsRef for Name<'a> { + fn as_ref(&self) -> &BStr { + self.as_bstr() + } +} diff --git a/git-repository/tests/fixtures/make_remote_repos.sh b/git-repository/tests/fixtures/make_remote_repos.sh index 2f05bac782..b7aed46cea 100644 --- a/git-repository/tests/fixtures/make_remote_repos.sh +++ b/git-repository/tests/fixtures/make_remote_repos.sh @@ -126,6 +126,12 @@ git clone --shared base branch-push-remote git config branch.main.pushRemote myself ) +git clone --shared base branch-dot-remote +(cd branch-dot-remote + + git config branch.main.remote . +) + git init --bare url-rewriting (cd url-rewriting diff --git a/git-repository/tests/reference/remote.rs b/git-repository/tests/reference/remote.rs index aa0511c469..fc2fea7a9a 100644 --- a/git-repository/tests/reference/remote.rs +++ b/git-repository/tests/reference/remote.rs @@ -82,6 +82,40 @@ fn not_configured() -> crate::Result { Ok(()) } +#[test] +fn dot_remote_behind_symbol() -> crate::Result { + let repo = remote::repo("branch-dot-remote"); + let head = repo.head()?; + let branch = head.clone().try_into_referent().expect("history"); + + assert_eq!( + branch + .remote_name(git::remote::Direction::Push) + .expect("derived push") + .as_url(), + Some(".".into()) + ); + assert_eq!( + branch + .remote_name(git::remote::Direction::Fetch) + .expect("fetch") + .as_url(), + Some(".".into()) + ); + + { + let remote = branch + .remote(git::remote::Direction::Push) + .transpose()? + .expect("present"); + assert_eq!(remote.name(), None, "It's a url after all, anonymous"); + assert_eq!(remote.url(git::remote::Direction::Push).unwrap().path, "."); + assert_eq!(remote.url(git::remote::Direction::Fetch).unwrap().path, "."); + } + + Ok(()) +} + #[test] fn url_as_remote_name() -> crate::Result { let repo = remote::repo("remote-as-url");