Showing the changes to git-ref/src/store (2 of 3 files). Show all
Unified · Split
| @@ -141,18 +141,30 @@ impl file::Store { · 140 unmodified lines | |||
| 141 | /// | 141 | /// |
| 142 | /// Otherwise it's similar to [`loose_iter()`][file::Store::loose_iter()]. | 142 | /// Otherwise it's similar to [`loose_iter()`][file::Store::loose_iter()]. |
| 143 | pub fn loose_iter_prefixed(&self, prefix: impl AsRef<Path>) -> std::io::Result<Loose<'_>> { | 143 | pub fn loose_iter_prefixed(&self, prefix: impl AsRef<Path>) -> std::io::Result<Loose<'_>> { |
| 144 | let prefix = prefix.as_ref(); | 144 | let prefix = self.validate_prefix(prefix.as_ref())?; |
| 145 | Ok(Loose::at_root(self, self.base.join(prefix), self.base.clone())) | ||
| 146 | } | ||
| 147 | |||
| 148 | pub(in crate::store::file) fn refs_dir(&self) -> PathBuf { | ||
| 149 | self.base.join("refs") | ||
| 150 | } | ||
| 151 | pub(in crate::store::file) fn validate_prefix<'a>(&self, prefix: &'a Path) -> std::io::Result<&'a Path> { | ||
| 145 | if prefix.is_absolute() { | 152 | if prefix.is_absolute() { |
| 146 | return Err(std::io::Error::new( | 153 | return Err(std::io::Error::new( |
| 147 | std::io::ErrorKind::InvalidInput, | 154 | std::io::ErrorKind::InvalidInput, |
| 148 | "prefix must be a relative path, like 'refs/heads'", | 155 | "prefix must be a relative path, like 'refs/heads'", |
| 149 | )); | 156 | )); |
| 150 | } | 157 | } |
| 151 | Ok(Loose::at_root(self, self.base.join(prefix), self.base.clone())) | 158 | for component in prefix.components() { |
| 152 | } | 159 | use std::path::Component::*; |
| 153 | 160 | if matches!(component, CurDir | ParentDir) { | |
| 154 | pub(in crate::store::file) fn refs_dir(&self) -> PathBuf { | 161 | return Err(std::io::Error::new( |
| 155 | self.base.join("refs") | 162 | std::io::ErrorKind::InvalidInput, |
| 163 | "Refusing to handle prefixes with relative path components", | ||
| 164 | )); | ||
| 165 | } | ||
| 166 | } | ||
| 167 | Ok(prefix) | ||
| 156 | } | 168 | } |
| 157 | } | 169 | } |
| 158 | 170 | ||
| @@ -3,7 +3,13 @@ use crate::{ · 2 unmodified lines | |||
| 3 | store::{file, packed}, | 3 | store::{file, packed}, |
| 4 | }; | 4 | }; |
| 5 | use bstr::BString; | 5 | use bstr::BString; |
| 6 | use std::{cmp::Ordering, convert::TryInto, io::Read, iter::Peekable, path::PathBuf}; | 6 | use std::{ |
| 7 | cmp::Ordering, | ||
| 8 | convert::TryInto, | ||
| 9 | io::Read, | ||
| 10 | iter::Peekable, | ||
| 11 | path::{Path, PathBuf}, | ||
| 12 | }; | ||
| 7 | 13 | ||
| 8 | /// An iterator stepping through sorted input of loose references and packed references, preferring loose refs over otherwise | 14 | /// An iterator stepping through sorted input of loose references and packed references, preferring loose refs over otherwise |
| 9 | /// equivalent packed references. | 15 | /// equivalent packed references. |
| @@ -141,6 +147,32 @@ impl file::Store { · 131 unmodified lines | |||
| 141 | buf: Vec::new(), | 147 | buf: Vec::new(), |
| 142 | }) | 148 | }) |
| 143 | } | 149 | } |
| 150 | |||
| 151 | /// As [`iter(…)`][file::Store::iter()], but filters by `prefix`, i.e. "refs/heads". | ||
| 152 | /// | ||
| 153 | /// Please note that "refs/heads` or "refs\\heads" is equivalent to "refs/heads/" | ||
| 154 | pub fn iter_prefixed<'p, 's>( | ||
| 155 | &'s self, | ||
| 156 | packed: &'p packed::Buffer, | ||
| 157 | prefix: impl AsRef<Path>, | ||
| 158 | ) -> std::io::Result<LooseThenPacked<'p, 's>> { | ||
| 159 | let prefix = self.validate_prefix(prefix.as_ref())?; | ||
| 160 | let packed_prefix = prefix.to_raw_bytes(); | ||
| 161 | #[cfg(windows)] | ||
| 162 | let packed_prefix = packed_prefix.replace(b"\\", b"/"); | ||
| 163 | #[cfg(not(windows))] | ||
| 164 | let packed_prefix = packed_prefix.into_owned(); | ||
| 165 | Ok(LooseThenPacked { | ||
| 166 | parent: self, | ||
| 167 | packed: packed | ||
| 168 | .iter_prefixed(packed_prefix) | ||
| 169 | .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))? | ||
| 170 | .peekable(), | ||
| 171 | loose: file::loose::iter::SortedLoosePaths::at_root_with_names(self.base.join(prefix), self.base.clone()) | ||
| 172 | .peekable(), | ||
| 173 | buf: Vec::new(), | ||
| 174 | }) | ||
| 175 | } | ||
| 144 | } | 176 | } |
| 145 | 177 | ||
| 146 | mod error { | 178 | mod error { |
| @@ -173,3 +205,4 @@ mod error { · 26 unmodified lines | |||
| 173 | } | 205 | } |
| 174 | } | 206 | } |
| 175 | pub use error::Error; | 207 | pub use error::Error; |
| 208 | use os_str_bytes::OsStrBytes; | ||