History

[ref] prefix iteration for all references

Sebastian Thiel committed 5 years ago

Commit 228ca001 parent aa6052a3 files · +104 −14Browse files

Showing the changes to git-ref/src (2 of 3 files). Show all

Unified · Split

2 files
  1. git-ref/src/store/file/loose/iter.rs +18 −6
  2. git-ref/src/store/file/overlay.rs +34 −1
git-ref/src/store/file/loose/iter.rs+18−6
@@ -141,18 +141,30 @@ impl file::Store { · 140 unmodified lines
141141 ///
142142 /// Otherwise it's similar to [`loose_iter()`][file::Store::loose_iter()].
143143 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> {
145152 if prefix.is_absolute() {
146153 return Err(std::io::Error::new(
147154 std::io::ErrorKind::InvalidInput,
148155 "prefix must be a relative path, like 'refs/heads'",
149156 ));
150157 }
151− Ok(Loose::at_root(self, self.base.join(prefix), self.base.clone()))
152− }
153−
154− pub(in crate::store::file) fn refs_dir(&self) -> PathBuf {
155− self.base.join("refs")
158+ for component in prefix.components() {
159+ use std::path::Component::*;
160+ if matches!(component, CurDir | ParentDir) {
161+ return Err(std::io::Error::new(
162+ std::io::ErrorKind::InvalidInput,
163+ "Refusing to handle prefixes with relative path components",
164+ ));
165+ }
166+ }
167+ Ok(prefix)
156168 }
157169 }
158170
git-ref/src/store/file/overlay.rs+34−1
@@ -3,7 +3,13 @@ use crate::{ · 2 unmodified lines
33 store::{file, packed},
44 };
55 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+};
713
814 /// An iterator stepping through sorted input of loose references and packed references, preferring loose refs over otherwise
915 /// equivalent packed references.
@@ -141,6 +147,32 @@ impl file::Store { · 131 unmodified lines
141147 buf: Vec::new(),
142148 })
143149 }
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+ }
144176 }
145177
146178 mod error {
@@ -173,3 +205,4 @@ mod error { · 26 unmodified lines
173205 }
174206 }
175207 pub use error::Error;
208+use os_str_bytes::OsStrBytes;