Patchwork D7923: rust-matchers: add functions to get roots, dirs and parents from patterns

login
register
mail settings
Submitter phabricator
Date March 11, 2020, 4:23 p.m.
Message ID <5d4e783f18ce997b4d4f9866d88fe402@localhost.localdomain>
Download mbox | patch
Permalink /patch/45716/
State Not Applicable
Headers show

Comments

phabricator - March 11, 2020, 4:23 p.m.
Closed by commit rHGd4e8cfcde012: rust-matchers: add functions to get roots, dirs and parents from patterns (authored by Alphare).
This revision was automatically updated to reflect the committed changes.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7923?vs=20161&id=20713

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7923/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D7923

AFFECTED FILES
  rust/hg-core/src/matchers.rs

CHANGE DETAILS




To: Alphare, #hg-reviewers, kevincox, martinvonz
Cc: durin42, kevincox, mercurial-devel

Patch

diff --git a/rust/hg-core/src/matchers.rs b/rust/hg-core/src/matchers.rs
--- a/rust/hg-core/src/matchers.rs
+++ b/rust/hg-core/src/matchers.rs
@@ -10,8 +10,10 @@ 
 #[cfg(feature = "with-re2")]
 use crate::re2::Re2;
 use crate::{
-    filepatterns::PatternResult, utils::hg_path::HgPath, DirsMultiset,
-    DirstateMapError, PatternError,
+    filepatterns::PatternResult,
+    utils::hg_path::{HgPath, HgPathBuf},
+    DirsMultiset, DirstateMapError, IgnorePattern, PatternError,
+    PatternSyntax,
 };
 use std::collections::HashSet;
 use std::iter::FromIterator;
@@ -240,10 +242,156 @@ 
     Err(PatternError::Re2NotInstalled)
 }
 
+/// Returns roots and directories corresponding to each pattern.
+///
+/// This calculates the roots and directories exactly matching the patterns and
+/// returns a tuple of (roots, dirs). It does not return other directories
+/// which may also need to be considered, like the parent directories.
+fn roots_and_dirs(
+    ignore_patterns: &[IgnorePattern],
+) -> (Vec<HgPathBuf>, Vec<HgPathBuf>) {
+    let mut roots = Vec::new();
+    let mut dirs = Vec::new();
+
+    for ignore_pattern in ignore_patterns {
+        let IgnorePattern {
+            syntax, pattern, ..
+        } = ignore_pattern;
+        match syntax {
+            PatternSyntax::RootGlob | PatternSyntax::Glob => {
+                let mut root = vec![];
+
+                for p in pattern.split(|c| *c == b'/') {
+                    if p.iter().any(|c| match *c {
+                        b'[' | b'{' | b'*' | b'?' => true,
+                        _ => false,
+                    }) {
+                        break;
+                    }
+                    root.push(HgPathBuf::from_bytes(p));
+                }
+                let buf =
+                    root.iter().fold(HgPathBuf::new(), |acc, r| acc.join(r));
+                roots.push(buf);
+            }
+            PatternSyntax::Path | PatternSyntax::RelPath => {
+                let pat = HgPath::new(if pattern == b"." {
+                    &[] as &[u8]
+                } else {
+                    pattern
+                });
+                roots.push(pat.to_owned());
+            }
+            PatternSyntax::RootFiles => {
+                let pat = if pattern == b"." {
+                    &[] as &[u8]
+                } else {
+                    pattern
+                };
+                dirs.push(HgPathBuf::from_bytes(pat));
+            }
+            _ => {
+                roots.push(HgPathBuf::new());
+            }
+        }
+    }
+    (roots, dirs)
+}
+
+/// Paths extracted from patterns
+#[derive(Debug, PartialEq)]
+struct RootsDirsAndParents {
+    /// Directories to match recursively
+    pub roots: HashSet<HgPathBuf>,
+    /// Directories to match non-recursively
+    pub dirs: HashSet<HgPathBuf>,
+    /// Implicitly required directories to go to items in either roots or dirs
+    pub parents: HashSet<HgPathBuf>,
+}
+
+/// Extract roots, dirs and parents from patterns.
+fn roots_dirs_and_parents(
+    ignore_patterns: &[IgnorePattern],
+) -> PatternResult<RootsDirsAndParents> {
+    let (roots, dirs) = roots_and_dirs(ignore_patterns);
+
+    let mut parents = HashSet::new();
+
+    parents.extend(
+        DirsMultiset::from_manifest(&dirs)
+            .map_err(|e| match e {
+                DirstateMapError::InvalidPath(e) => e,
+                _ => unreachable!(),
+            })?
+            .iter()
+            .map(|k| k.to_owned()),
+    );
+    parents.extend(
+        DirsMultiset::from_manifest(&roots)
+            .map_err(|e| match e {
+                DirstateMapError::InvalidPath(e) => e,
+                _ => unreachable!(),
+            })?
+            .iter()
+            .map(|k| k.to_owned()),
+    );
+
+    Ok(RootsDirsAndParents {
+        roots: HashSet::from_iter(roots),
+        dirs: HashSet::from_iter(dirs),
+        parents,
+    })
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
     use pretty_assertions::assert_eq;
+    use std::path::Path;
+
+    #[test]
+    fn test_roots_and_dirs() {
+        let pats = vec![
+            IgnorePattern::new(PatternSyntax::Glob, b"g/h/*", Path::new("")),
+            IgnorePattern::new(PatternSyntax::Glob, b"g/h", Path::new("")),
+            IgnorePattern::new(PatternSyntax::Glob, b"g*", Path::new("")),
+        ];
+        let (roots, dirs) = roots_and_dirs(&pats);
+
+        assert_eq!(
+            roots,
+            vec!(
+                HgPathBuf::from_bytes(b"g/h"),
+                HgPathBuf::from_bytes(b"g/h"),
+                HgPathBuf::new()
+            ),
+        );
+        assert_eq!(dirs, vec!());
+    }
+
+    #[test]
+    fn test_roots_dirs_and_parents() {
+        let pats = vec![
+            IgnorePattern::new(PatternSyntax::Glob, b"g/h/*", Path::new("")),
+            IgnorePattern::new(PatternSyntax::Glob, b"g/h", Path::new("")),
+            IgnorePattern::new(PatternSyntax::Glob, b"g*", Path::new("")),
+        ];
+
+        let mut roots = HashSet::new();
+        roots.insert(HgPathBuf::from_bytes(b"g/h"));
+        roots.insert(HgPathBuf::new());
+
+        let dirs = HashSet::new();
+
+        let mut parents = HashSet::new();
+        parents.insert(HgPathBuf::new());
+        parents.insert(HgPathBuf::from_bytes(b"g"));
+
+        assert_eq!(
+            roots_dirs_and_parents(&pats).unwrap(),
+            RootsDirsAndParents {roots, dirs, parents}
+        );
+    }
 
     #[test]
     fn test_filematcher_visit_children_set() {