summaryrefslogtreecommitdiffstats
path: root/vendor/gix-ignore/src/search.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-ignore/src/search.rs')
-rw-r--r--vendor/gix-ignore/src/search.rs183
1 files changed, 183 insertions, 0 deletions
diff --git a/vendor/gix-ignore/src/search.rs b/vendor/gix-ignore/src/search.rs
new file mode 100644
index 000000000..5c957f136
--- /dev/null
+++ b/vendor/gix-ignore/src/search.rs
@@ -0,0 +1,183 @@
+use std::{
+ ffi::OsString,
+ path::{Path, PathBuf},
+};
+
+use bstr::{BStr, ByteSlice};
+use gix_glob::search::{pattern, Pattern};
+
+use crate::Search;
+
+/// Describes a matching pattern within a search for ignored paths.
+#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
+pub struct Match<'a, T> {
+ /// The glob pattern itself, like `/target/*`.
+ pub pattern: &'a gix_glob::Pattern,
+ /// The value associated with the pattern.
+ pub value: &'a T,
+ /// The path to the source from which the pattern was loaded, or `None` if it was specified by other means.
+ pub source: Option<&'a Path>,
+ /// The line at which the pattern was found in its `source` file, or the occurrence in which it was provided.
+ pub sequence_number: usize,
+}
+
+/// An implementation of the [`Pattern`] trait for ignore patterns.
+#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Default)]
+pub struct Ignore;
+
+impl Pattern for Ignore {
+ type Value = ();
+
+ fn bytes_to_patterns(bytes: &[u8], _source: &std::path::Path) -> Vec<pattern::Mapping<Self::Value>> {
+ crate::parse(bytes)
+ .map(|(pattern, line_number)| pattern::Mapping {
+ pattern,
+ value: (),
+ sequence_number: line_number,
+ })
+ .collect()
+ }
+
+ fn may_use_glob_pattern(_pattern: &gix_glob::Pattern) -> bool {
+ true
+ }
+}
+
+/// Instantiation of a search for ignore patterns.
+impl Search {
+ /// Given `git_dir`, a `.git` repository, load static ignore patterns from `info/exclude`
+ /// and from `excludes_file` if it is provided.
+ /// Note that it's not considered an error if the provided `excludes_file` does not exist.
+ pub fn from_git_dir(
+ git_dir: impl AsRef<Path>,
+ excludes_file: Option<PathBuf>,
+ buf: &mut Vec<u8>,
+ ) -> std::io::Result<Self> {
+ let mut group = Self::default();
+
+ let follow_symlinks = true;
+ // order matters! More important ones first.
+ group.patterns.extend(
+ excludes_file
+ .and_then(|file| pattern::List::<Ignore>::from_file(file, None, follow_symlinks, buf).transpose())
+ .transpose()?,
+ );
+ group.patterns.extend(pattern::List::<Ignore>::from_file(
+ git_dir.as_ref().join("info").join("exclude"),
+ None,
+ follow_symlinks,
+ buf,
+ )?);
+ Ok(group)
+ }
+
+ /// Parse a list of patterns, using slashes as path separators
+ pub fn from_overrides(patterns: impl IntoIterator<Item = impl Into<OsString>>) -> Self {
+ Search {
+ patterns: vec![pattern::List {
+ patterns: patterns
+ .into_iter()
+ .map(Into::into)
+ .enumerate()
+ .filter_map(|(seq_id, pattern)| {
+ let pattern = gix_path::try_into_bstr(PathBuf::from(pattern)).ok()?;
+ gix_glob::parse(pattern.as_ref()).map(|p| pattern::Mapping {
+ pattern: p,
+ value: (),
+ sequence_number: seq_id,
+ })
+ })
+ .collect(),
+ source: None,
+ base: None,
+ }],
+ }
+ }
+}
+
+/// Mutation
+impl Search {
+ /// Add patterns as parsed from `bytes`, providing their `source` path and possibly their `root` path, the path they
+ /// are relative to. This also means that `source` is contained within `root` if `root` is provided.
+ pub fn add_patterns_buffer(&mut self, bytes: &[u8], source: impl Into<PathBuf>, root: Option<&Path>) {
+ self.patterns
+ .push(pattern::List::from_bytes(bytes, source.into(), root));
+ }
+}
+
+/// Return a match if a pattern matches `relative_path`, providing a pre-computed `basename_pos` which is the
+/// starting position of the basename of `relative_path`. `is_dir` is true if `relative_path` is a directory.
+/// `case` specifies whether cases should be folded during matching or not.
+pub fn pattern_matching_relative_path<'a>(
+ list: &'a gix_glob::search::pattern::List<Ignore>,
+ relative_path: &BStr,
+ basename_pos: Option<usize>,
+ is_dir: Option<bool>,
+ case: gix_glob::pattern::Case,
+) -> Option<Match<'a, ()>> {
+ let (relative_path, basename_start_pos) =
+ list.strip_base_handle_recompute_basename_pos(relative_path, basename_pos, case)?;
+ list.patterns
+ .iter()
+ .rev()
+ .filter(|pm| Ignore::may_use_glob_pattern(&pm.pattern))
+ .find_map(
+ |pattern::Mapping {
+ pattern,
+ value,
+ sequence_number,
+ }| {
+ pattern
+ .matches_repo_relative_path(relative_path, basename_start_pos, is_dir, case)
+ .then_some(Match {
+ pattern,
+ value,
+ source: list.source.as_deref(),
+ sequence_number: *sequence_number,
+ })
+ },
+ )
+}
+
+/// Like [`pattern_matching_relative_path()`], but returns an index to the pattern
+/// that matched `relative_path`, instead of the match itself.
+pub fn pattern_idx_matching_relative_path(
+ list: &gix_glob::search::pattern::List<Ignore>,
+ relative_path: &BStr,
+ basename_pos: Option<usize>,
+ is_dir: Option<bool>,
+ case: gix_glob::pattern::Case,
+) -> Option<usize> {
+ let (relative_path, basename_start_pos) =
+ list.strip_base_handle_recompute_basename_pos(relative_path, basename_pos, case)?;
+ list.patterns
+ .iter()
+ .enumerate()
+ .rev()
+ .filter(|(_, pm)| Ignore::may_use_glob_pattern(&pm.pattern))
+ .find_map(|(idx, pm)| {
+ pm.pattern
+ .matches_repo_relative_path(relative_path, basename_start_pos, is_dir, case)
+ .then_some(idx)
+ })
+}
+
+/// Matching of ignore patterns.
+impl Search {
+ /// Match `relative_path` and return the first match if found.
+ /// `is_dir` is true if `relative_path` is a directory.
+ /// `case` specifies whether cases should be folded during matching or not.
+ pub fn pattern_matching_relative_path<'a>(
+ &self,
+ relative_path: impl Into<&'a BStr>,
+ is_dir: Option<bool>,
+ case: gix_glob::pattern::Case,
+ ) -> Option<Match<'_, ()>> {
+ let relative_path = relative_path.into();
+ let basename_pos = relative_path.rfind(b"/").map(|p| p + 1);
+ self.patterns
+ .iter()
+ .rev()
+ .find_map(|pl| pattern_matching_relative_path(pl, relative_path, basename_pos, is_dir, case))
+ }
+}