-
-
Notifications
You must be signed in to change notification settings - Fork 394
Handle trailing slash in ref list prefix filtering #1936
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,9 +7,9 @@ use std::{ | |
| }; | ||
|
|
||
| use crate::{ | ||
| file::{loose, loose::iter::SortedLoosePaths, path_to_name}, | ||
| file::{loose, loose::iter::SortedLoosePaths}, | ||
| store_impl::{file, packed}, | ||
| BString, FullName, Namespace, Reference, | ||
| BStr, FullName, Namespace, Reference, | ||
| }; | ||
|
|
||
| /// An iterator stepping through sorted input of loose references and packed references, preferring loose refs over otherwise | ||
|
|
@@ -195,10 +195,9 @@ impl Platform<'_> { | |
| self.store.iter_packed(self.packed.as_ref().map(|b| &***b)) | ||
| } | ||
|
|
||
| /// As [`iter(…)`][file::Store::iter()], but filters by `prefix`, i.e. "refs/heads". | ||
| /// | ||
| /// Please note that "refs/heads" or "refs\\heads" is equivalent to "refs/heads/" | ||
| pub fn prefixed(&self, prefix: &Path) -> std::io::Result<LooseThenPacked<'_, '_>> { | ||
| /// As [`iter(…)`][file::Store::iter()], but filters by `prefix`, i.e. "refs/heads/" or | ||
| /// "refs/heads/feature-". | ||
| pub fn prefixed(&self, prefix: Cow<'_, BStr>) -> std::io::Result<LooseThenPacked<'_, '_>> { | ||
|
||
| self.store | ||
| .iter_prefixed_packed(prefix, self.packed.as_ref().map(|b| &***b)) | ||
| } | ||
|
|
@@ -242,22 +241,19 @@ pub(crate) enum IterInfo<'a> { | |
| /// The top-level directory as boundary of all references, used to create their short-names after iteration | ||
| base: &'a Path, | ||
| /// The original prefix | ||
| prefix: Cow<'a, Path>, | ||
| /// The remainder of the prefix that wasn't a valid path | ||
| remainder: Option<BString>, | ||
| prefix: Cow<'a, BStr>, | ||
| /// If `true`, we will convert decomposed into precomposed unicode. | ||
| precompose_unicode: bool, | ||
| }, | ||
| } | ||
|
|
||
| impl<'a> IterInfo<'a> { | ||
| fn prefix(&self) -> Option<&Path> { | ||
| fn prefix(&self) -> Option<Cow<'_, BStr>> { | ||
| match self { | ||
| IterInfo::Base { .. } => None, | ||
| IterInfo::PrefixAndBase { prefix, .. } => Some(*prefix), | ||
| IterInfo::ComputedIterationRoot { prefix, .. } | IterInfo::BaseAndIterRoot { prefix, .. } => { | ||
| prefix.as_ref().into() | ||
| } | ||
| IterInfo::PrefixAndBase { prefix, .. } => Some(gix_path::into_bstr(*prefix)), | ||
| IterInfo::BaseAndIterRoot { prefix, .. } => Some(gix_path::into_bstr(prefix.clone())), | ||
| IterInfo::ComputedIterationRoot { prefix, .. } => Some(prefix.clone()), | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -281,48 +277,37 @@ impl<'a> IterInfo<'a> { | |
| IterInfo::ComputedIterationRoot { | ||
| iter_root, | ||
| base, | ||
| prefix: _, | ||
| remainder, | ||
| prefix, | ||
| precompose_unicode, | ||
| } => SortedLoosePaths::at(&iter_root, base.into(), remainder, precompose_unicode), | ||
| } => SortedLoosePaths::at(&iter_root, base.into(), Some(prefix.into_owned()), precompose_unicode), | ||
| } | ||
| .peekable() | ||
| } | ||
|
|
||
| fn from_prefix(base: &'a Path, prefix: Cow<'a, Path>, precompose_unicode: bool) -> std::io::Result<Self> { | ||
| if prefix.is_absolute() { | ||
| fn from_prefix(base: &'a Path, prefix: Cow<'a, BStr>, precompose_unicode: bool) -> std::io::Result<Self> { | ||
| let prefix_path = gix_path::from_bstring(prefix.as_ref()); | ||
| if prefix_path.is_absolute() { | ||
| return Err(std::io::Error::new( | ||
| std::io::ErrorKind::InvalidInput, | ||
| "prefix must be a relative path, like 'refs/heads'", | ||
| "prefix must be a relative path, like 'refs/heads/'", | ||
| )); | ||
| } | ||
| use std::path::Component::*; | ||
| if prefix.components().any(|c| matches!(c, CurDir | ParentDir)) { | ||
| if prefix_path.components().any(|c| matches!(c, CurDir | ParentDir)) { | ||
| return Err(std::io::Error::new( | ||
| std::io::ErrorKind::InvalidInput, | ||
| "Refusing to handle prefixes with relative path components", | ||
| )); | ||
| } | ||
| let iter_root = base.join(prefix.as_ref()); | ||
| if iter_root.is_dir() { | ||
| let iter_root = base.join(&prefix_path); | ||
| if prefix.ends_with(b"/") { | ||
| Ok(IterInfo::BaseAndIterRoot { | ||
| base, | ||
| iter_root, | ||
| prefix, | ||
| prefix: prefix_path.into(), | ||
| precompose_unicode, | ||
| }) | ||
| } else { | ||
| let filename_prefix = iter_root | ||
| .file_name() | ||
| .map(ToOwned::to_owned) | ||
| .map(|p| { | ||
| gix_path::try_into_bstr(PathBuf::from(p)) | ||
| .map(std::borrow::Cow::into_owned) | ||
| .map_err(|_| { | ||
| std::io::Error::new(std::io::ErrorKind::InvalidInput, "prefix contains ill-formed UTF-8") | ||
| }) | ||
| }) | ||
| .transpose()?; | ||
| let iter_root = iter_root | ||
| .parent() | ||
| .expect("a parent is always there unless empty") | ||
|
|
@@ -331,7 +316,6 @@ impl<'a> IterInfo<'a> { | |
| base, | ||
| prefix, | ||
| iter_root, | ||
| remainder: filename_prefix, | ||
| precompose_unicode, | ||
| }) | ||
| } | ||
|
|
@@ -374,30 +358,28 @@ impl file::Store { | |
| } | ||
| } | ||
|
|
||
| /// As [`iter(…)`][file::Store::iter()], but filters by `prefix`, i.e. "refs/heads". | ||
| /// | ||
| /// Please note that "refs/heads" or "refs\\heads" is equivalent to "refs/heads/" | ||
| /// As [`iter(…)`][file::Store::iter()], but filters by `prefix`, i.e. "refs/heads/" or | ||
| /// "refs/heads/feature-". | ||
| pub fn iter_prefixed_packed<'s, 'p>( | ||
| &'s self, | ||
| prefix: &Path, | ||
| prefix: Cow<'_, BStr>, | ||
| packed: Option<&'p packed::Buffer>, | ||
| ) -> std::io::Result<LooseThenPacked<'p, 's>> { | ||
| match self.namespace.as_ref() { | ||
| None => { | ||
| let git_dir_info = IterInfo::from_prefix(self.git_dir(), prefix.into(), self.precompose_unicode)?; | ||
| let git_dir_info = IterInfo::from_prefix(self.git_dir(), prefix.clone(), self.precompose_unicode)?; | ||
| let common_dir_info = self | ||
| .common_dir() | ||
| .map(|base| IterInfo::from_prefix(base, prefix.into(), self.precompose_unicode)) | ||
| .map(|base| IterInfo::from_prefix(base, prefix, self.precompose_unicode)) | ||
| .transpose()?; | ||
| self.iter_from_info(git_dir_info, common_dir_info, packed) | ||
| } | ||
| Some(namespace) => { | ||
| let prefix = namespace.to_owned().into_namespaced_prefix(prefix); | ||
| let git_dir_info = | ||
| IterInfo::from_prefix(self.git_dir(), prefix.clone().into(), self.precompose_unicode)?; | ||
| let prefix = namespace.to_owned().into_namespaced_prefix(prefix.as_ref()); | ||
| let git_dir_info = IterInfo::from_prefix(self.git_dir(), prefix.clone(), self.precompose_unicode)?; | ||
| let common_dir_info = self | ||
| .common_dir() | ||
| .map(|base| IterInfo::from_prefix(base, prefix.into(), self.precompose_unicode)) | ||
| .map(|base| IterInfo::from_prefix(base, prefix, self.precompose_unicode)) | ||
| .transpose()?; | ||
| self.iter_from_info(git_dir_info, common_dir_info, packed) | ||
| } | ||
|
|
@@ -416,7 +398,7 @@ impl file::Store { | |
| iter_packed: match packed { | ||
| Some(packed) => Some( | ||
| match git_dir_info.prefix() { | ||
| Some(prefix) => packed.iter_prefixed(path_to_name(prefix).into_owned()), | ||
| Some(prefix) => packed.iter_prefixed(prefix.into_owned()), | ||
| None => packed.iter(), | ||
| } | ||
| .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))? | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,10 +10,13 @@ git branch A | |
| git tag -m "tag object" tag-object | ||
|
|
||
| mkdir -p .git/refs/remotes/origin | ||
| mkdir -p .git/refs/heads/sub/dir | ||
|
|
||
| cp .git/refs/heads/main .git/refs/remotes/origin/ | ||
|
|
||
| echo "ref: refs/remotes/origin/main" > .git/refs/remotes/origin/HEAD | ||
| echo "ref: refs/heads/main" > .git/refs/heads-packed | ||
| echo "ref: refs/heads/main" > .git/refs/heads/sub/dir/packed | ||
|
||
|
|
||
| git pack-refs --all --prune | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be
&BStrif it was&Pathbefore.It could also be
impl Into<…>if that makes it more convenient to call, even for the test-suite.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put
impl Into<Cow<...>>in most places. Not sure if some should just be&BStror not.