rust/hg-core/src/matchers.rs
branchstable
changeset 51570 b39057b713b1
parent 51568 2a89d2f6336f
child 51571 74230abb2504
equal deleted inserted replaced
51569:b32c3146ec34 51570:b39057b713b1
   297     patterns: Vec<u8>,
   297     patterns: Vec<u8>,
   298     match_fn: IgnoreFnType<'a>,
   298     match_fn: IgnoreFnType<'a>,
   299     /// Whether all the patterns match a prefix (i.e. recursively)
   299     /// Whether all the patterns match a prefix (i.e. recursively)
   300     prefix: bool,
   300     prefix: bool,
   301     files: HashSet<HgPathBuf>,
   301     files: HashSet<HgPathBuf>,
       
   302     dirs_explicit: HashSet<HgPathBuf>,
   302     dirs: DirsMultiset,
   303     dirs: DirsMultiset,
   303 }
   304 }
   304 
   305 
   305 impl core::fmt::Debug for PatternMatcher<'_> {
   306 impl core::fmt::Debug for PatternMatcher<'_> {
   306     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
   307     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
   313     }
   314     }
   314 }
   315 }
   315 
   316 
   316 impl<'a> PatternMatcher<'a> {
   317 impl<'a> PatternMatcher<'a> {
   317     pub fn new(ignore_patterns: Vec<IgnorePattern>) -> PatternResult<Self> {
   318     pub fn new(ignore_patterns: Vec<IgnorePattern>) -> PatternResult<Self> {
   318         let (files, _) = roots_and_dirs(&ignore_patterns);
   319         let RootsDirsAndParents {
   319         let dirs = DirsMultiset::from_manifest(&files)?;
   320             roots,
       
   321             dirs: dirs_explicit,
       
   322             parents,
       
   323         } = roots_dirs_and_parents(&ignore_patterns)?;
       
   324         let files = roots;
       
   325         let dirs = parents;
   320         let files: HashSet<HgPathBuf> = HashSet::from_iter(files);
   326         let files: HashSet<HgPathBuf> = HashSet::from_iter(files);
   321 
   327 
   322         let prefix = ignore_patterns.iter().all(|k| {
   328         let prefix = ignore_patterns.iter().all(|k| {
   323             matches!(k.syntax, PatternSyntax::Path | PatternSyntax::RelPath)
   329             matches!(k.syntax, PatternSyntax::Path | PatternSyntax::RelPath)
   324         });
   330         });
   328             patterns,
   334             patterns,
   329             match_fn,
   335             match_fn,
   330             prefix,
   336             prefix,
   331             files,
   337             files,
   332             dirs,
   338             dirs,
       
   339             dirs_explicit,
   333         })
   340         })
   334     }
   341     }
   335 }
   342 }
   336 
   343 
   337 impl<'a> Matcher for PatternMatcher<'a> {
   344 impl<'a> Matcher for PatternMatcher<'a> {
   355             return VisitChildrenSet::Recursive;
   362             return VisitChildrenSet::Recursive;
   356         }
   363         }
   357         if self.dirs.contains(directory) {
   364         if self.dirs.contains(directory) {
   358             return VisitChildrenSet::This;
   365             return VisitChildrenSet::This;
   359         }
   366         }
   360         if dir_ancestors(directory)
   367         if dir_ancestors(directory).any(|parent_dir| {
   361             .any(|parent_dir| self.files.contains(parent_dir))
   368             self.files.contains(parent_dir)
   362         {
   369                 || self.dirs_explicit.contains(parent_dir)
       
   370         }) {
   363             VisitChildrenSet::This
   371             VisitChildrenSet::This
   364         } else {
   372         } else {
   365             VisitChildrenSet::Empty
   373             VisitChildrenSet::Empty
   366         }
   374         }
   367     }
   375     }
   408     match_fn: IgnoreFnType<'a>,
   416     match_fn: IgnoreFnType<'a>,
   409     /// Whether all the patterns match a prefix (i.e. recursively)
   417     /// Whether all the patterns match a prefix (i.e. recursively)
   410     prefix: bool,
   418     prefix: bool,
   411     roots: HashSet<HgPathBuf>,
   419     roots: HashSet<HgPathBuf>,
   412     dirs: HashSet<HgPathBuf>,
   420     dirs: HashSet<HgPathBuf>,
   413     parents: HashSet<HgPathBuf>,
   421     parents: DirsMultiset,
   414 }
   422 }
   415 
   423 
   416 impl core::fmt::Debug for IncludeMatcher<'_> {
   424 impl core::fmt::Debug for IncludeMatcher<'_> {
   417     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
   425     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
   418         f.debug_struct("IncludeMatcher")
   426         f.debug_struct("IncludeMatcher")
   888     /// Directories to match recursively
   896     /// Directories to match recursively
   889     pub roots: HashSet<HgPathBuf>,
   897     pub roots: HashSet<HgPathBuf>,
   890     /// Directories to match non-recursively
   898     /// Directories to match non-recursively
   891     pub dirs: HashSet<HgPathBuf>,
   899     pub dirs: HashSet<HgPathBuf>,
   892     /// Implicitly required directories to go to items in either roots or dirs
   900     /// Implicitly required directories to go to items in either roots or dirs
   893     pub parents: HashSet<HgPathBuf>,
   901     pub parents: DirsMultiset,
   894 }
   902 }
   895 
   903 
   896 /// Extract roots, dirs and parents from patterns.
   904 /// Extract roots, dirs and parents from patterns.
   897 fn roots_dirs_and_parents(
   905 fn roots_dirs_and_parents(
   898     ignore_patterns: &[IgnorePattern],
   906     ignore_patterns: &[IgnorePattern],
   899 ) -> PatternResult<RootsDirsAndParents> {
   907 ) -> PatternResult<RootsDirsAndParents> {
   900     let (roots, dirs) = roots_and_dirs(ignore_patterns);
   908     let (roots, dirs) = roots_and_dirs(ignore_patterns);
   901 
   909 
   902     let mut parents = HashSet::new();
   910     let mut parents = DirsMultiset::from_manifest(&dirs)?;
   903 
   911 
   904     parents.extend(
   912     for path in &roots {
   905         DirsMultiset::from_manifest(&dirs)?
   913         parents.add_path(path)?
   906             .iter()
   914     }
   907             .map(ToOwned::to_owned),
       
   908     );
       
   909     parents.extend(
       
   910         DirsMultiset::from_manifest(&roots)?
       
   911             .iter()
       
   912             .map(ToOwned::to_owned),
       
   913     );
       
   914 
   915 
   915     Ok(RootsDirsAndParents {
   916     Ok(RootsDirsAndParents {
   916         roots: HashSet::from_iter(roots),
   917         roots: HashSet::from_iter(roots),
   917         dirs: HashSet::from_iter(dirs),
   918         dirs: HashSet::from_iter(dirs),
   918         parents,
   919         parents,
  1080         let thing = self
  1081         let thing = self
  1081             .dirs
  1082             .dirs
  1082             .iter()
  1083             .iter()
  1083             .chain(self.roots.iter())
  1084             .chain(self.roots.iter())
  1084             .chain(self.parents.iter());
  1085             .chain(self.parents.iter());
  1085         DirsChildrenMultiset::new(thing, Some(&self.parents))
  1086         DirsChildrenMultiset::new(thing, Some(self.parents.iter()))
  1086     }
  1087     }
  1087 
  1088 
  1088     pub fn debug_get_patterns(&self) -> &[u8] {
  1089     pub fn debug_get_patterns(&self) -> &[u8] {
  1089         self.patterns.as_ref()
  1090         self.patterns.as_ref()
  1090     }
  1091     }
  1147         roots.insert(HgPathBuf::from_bytes(b"g/h"));
  1148         roots.insert(HgPathBuf::from_bytes(b"g/h"));
  1148         roots.insert(HgPathBuf::new());
  1149         roots.insert(HgPathBuf::new());
  1149 
  1150 
  1150         let dirs = HashSet::new();
  1151         let dirs = HashSet::new();
  1151 
  1152 
  1152         let mut parents = HashSet::new();
  1153         let parents = DirsMultiset::from_manifest(&[
  1153         parents.insert(HgPathBuf::new());
  1154             HgPathBuf::from_bytes(b"x"),
  1154         parents.insert(HgPathBuf::from_bytes(b"g"));
  1155             HgPathBuf::from_bytes(b"g/x"),
       
  1156             HgPathBuf::from_bytes(b"g/y"),
       
  1157         ])
       
  1158         .unwrap();
  1155 
  1159 
  1156         assert_eq!(
  1160         assert_eq!(
  1157             roots_dirs_and_parents(&pats).unwrap(),
  1161             roots_dirs_and_parents(&pats).unwrap(),
  1158             RootsDirsAndParents {
  1162             RootsDirsAndParents {
  1159                 roots,
  1163                 roots,
  1329             Path::new(""),
  1333             Path::new(""),
  1330         )])
  1334         )])
  1331         .unwrap();
  1335         .unwrap();
  1332         assert_eq!(
  1336         assert_eq!(
  1333             m.visit_children_set(HgPath::new(b"dir/subdir/x")),
  1337             m.visit_children_set(HgPath::new(b"dir/subdir/x")),
  1334             VisitChildrenSet::Empty
  1338             VisitChildrenSet::This
  1335         );
  1339         );
  1336         assert_eq!(
  1340         assert_eq!(
  1337             m.visit_children_set(HgPath::new(b"folder")),
  1341             m.visit_children_set(HgPath::new(b"folder")),
  1338             VisitChildrenSet::Empty
  1342             VisitChildrenSet::Empty
  1339         );
  1343         );
  1340         // FIXME: These should probably be This.
       
  1341         assert_eq!(
  1344         assert_eq!(
  1342             m.visit_children_set(HgPath::new(b"")),
  1345             m.visit_children_set(HgPath::new(b"")),
  1343             VisitChildrenSet::Empty
  1346             VisitChildrenSet::This
  1344         );
  1347         );
  1345         assert_eq!(
  1348         assert_eq!(
  1346             m.visit_children_set(HgPath::new(b"dir")),
  1349             m.visit_children_set(HgPath::new(b"dir")),
  1347             VisitChildrenSet::Empty
  1350             VisitChildrenSet::This
  1348         );
  1351         );
  1349         assert_eq!(
  1352         assert_eq!(
  1350             m.visit_children_set(HgPath::new(b"dir/subdir")),
  1353             m.visit_children_set(HgPath::new(b"dir/subdir")),
  1351             VisitChildrenSet::Empty
  1354             VisitChildrenSet::This
  1352         );
  1355         );
  1353 
  1356 
  1354         // VisitchildrensetRootfilesin
  1357         // VisitchildrensetRootfilesin
  1355         let m = PatternMatcher::new(vec![IgnorePattern::new(
  1358         let m = PatternMatcher::new(vec![IgnorePattern::new(
  1356             PatternSyntax::RootFilesIn,
  1359             PatternSyntax::RootFilesIn,
  1358             Path::new(""),
  1361             Path::new(""),
  1359         )])
  1362         )])
  1360         .unwrap();
  1363         .unwrap();
  1361         assert_eq!(
  1364         assert_eq!(
  1362             m.visit_children_set(HgPath::new(b"dir/subdir/x")),
  1365             m.visit_children_set(HgPath::new(b"dir/subdir/x")),
  1363             VisitChildrenSet::Empty
  1366             VisitChildrenSet::This
  1364         );
  1367         );
  1365         assert_eq!(
  1368         assert_eq!(
  1366             m.visit_children_set(HgPath::new(b"folder")),
  1369             m.visit_children_set(HgPath::new(b"folder")),
  1367             VisitChildrenSet::Empty
  1370             VisitChildrenSet::Empty
  1368         );
  1371         );
  1369         // FIXME: These should probably be {'dir'}, {'subdir'} and This,
  1372         // FIXME: These should probably be {'dir'}, {'subdir'} and This,
  1370         // respectively, or at least This for all three.
  1373         // respectively
  1371         assert_eq!(
  1374         assert_eq!(
  1372             m.visit_children_set(HgPath::new(b"")),
  1375             m.visit_children_set(HgPath::new(b"")),
  1373             VisitChildrenSet::Empty
  1376             VisitChildrenSet::This
  1374         );
  1377         );
  1375         assert_eq!(
  1378         assert_eq!(
  1376             m.visit_children_set(HgPath::new(b"dir")),
  1379             m.visit_children_set(HgPath::new(b"dir")),
  1377             VisitChildrenSet::Empty
  1380             VisitChildrenSet::This
  1378         );
  1381         );
  1379         assert_eq!(
  1382         assert_eq!(
  1380             m.visit_children_set(HgPath::new(b"dir/subdir")),
  1383             m.visit_children_set(HgPath::new(b"dir/subdir")),
  1381             VisitChildrenSet::Empty
  1384             VisitChildrenSet::This
  1382         );
  1385         );
  1383 
  1386 
  1384         // VisitdirGlob
  1387         // VisitdirGlob
  1385         let m = PatternMatcher::new(vec![IgnorePattern::new(
  1388         let m = PatternMatcher::new(vec![IgnorePattern::new(
  1386             PatternSyntax::Glob,
  1389             PatternSyntax::Glob,
  1390         .unwrap();
  1393         .unwrap();
  1391         assert_eq!(
  1394         assert_eq!(
  1392             m.visit_children_set(HgPath::new(b"")),
  1395             m.visit_children_set(HgPath::new(b"")),
  1393             VisitChildrenSet::This
  1396             VisitChildrenSet::This
  1394         );
  1397         );
  1395         // FIXME: This probably should be This
       
  1396         assert_eq!(
  1398         assert_eq!(
  1397             m.visit_children_set(HgPath::new(b"dir")),
  1399             m.visit_children_set(HgPath::new(b"dir")),
  1398             VisitChildrenSet::Empty
  1400             VisitChildrenSet::This
  1399         );
  1401         );
  1400         assert_eq!(
  1402         assert_eq!(
  1401             m.visit_children_set(HgPath::new(b"folder")),
  1403             m.visit_children_set(HgPath::new(b"folder")),
  1402             VisitChildrenSet::Empty
  1404             VisitChildrenSet::Empty
  1403         );
  1405         );
  1424         );
  1426         );
  1425         assert_eq!(
  1427         assert_eq!(
  1426             m.visit_children_set(HgPath::new(b"folder")),
  1428             m.visit_children_set(HgPath::new(b"folder")),
  1427             VisitChildrenSet::Empty
  1429             VisitChildrenSet::Empty
  1428         );
  1430         );
  1429         // FIXME: This probably should be This
       
  1430         assert_eq!(
  1431         assert_eq!(
  1431             m.visit_children_set(HgPath::new(b"dir")),
  1432             m.visit_children_set(HgPath::new(b"dir")),
  1432             VisitChildrenSet::Empty
  1433             VisitChildrenSet::This
  1433         );
  1434         );
  1434         // OPT: these should probably be Empty
  1435         // OPT: these should probably be Empty
  1435         assert_eq!(
  1436         assert_eq!(
  1436             m.visit_children_set(HgPath::new(b"dir/subdir")),
  1437             m.visit_children_set(HgPath::new(b"dir/subdir")),
  1437             VisitChildrenSet::This
  1438             VisitChildrenSet::This
  2339             HgPathBuf::from_bytes(b"a/b/file.txt"),
  2340             HgPathBuf::from_bytes(b"a/b/file.txt"),
  2340             // No file in a/b/c
  2341             // No file in a/b/c
  2341             HgPathBuf::from_bytes(b"a/b/c/d/file.txt"),
  2342             HgPathBuf::from_bytes(b"a/b/c/d/file.txt"),
  2342         ];
  2343         ];
  2343         let file_abcdfile = FileMatcher::new(files).unwrap();
  2344         let file_abcdfile = FileMatcher::new(files).unwrap();
  2344         let _rootfilesin_dir = PatternMatcher::new(vec![IgnorePattern::new(
  2345         let rootfilesin_dir = PatternMatcher::new(vec![IgnorePattern::new(
  2345             PatternSyntax::RootFilesIn,
  2346             PatternSyntax::RootFilesIn,
  2346             b"dir",
  2347             b"dir",
  2347             Path::new(""),
  2348             Path::new(""),
  2348         )])
  2349         )])
  2349         .unwrap();
  2350         .unwrap();
  2417             ),
  2418             ),
  2418             11,
  2419             11,
  2419         );
  2420         );
  2420         tree.check_matcher(&file_dir_subdir_b, 1);
  2421         tree.check_matcher(&file_dir_subdir_b, 1);
  2421         tree.check_matcher(&file_abcdfile, 4);
  2422         tree.check_matcher(&file_abcdfile, 4);
  2422         //        // TODO: re-enable this test when the corresponding bug is
  2423         tree.check_matcher(&rootfilesin_dir, 8);
  2423         // fixed
       
  2424         //
       
  2425         //        if false {
       
  2426         //            tree.check_matcher(&rootfilesin_dir, 6);
       
  2427         //        }
       
  2428         tree.check_matcher(&pattern_filepath_dir_subdir, 1);
  2424         tree.check_matcher(&pattern_filepath_dir_subdir, 1);
  2429         tree.check_matcher(&include_dir_subdir, 9);
  2425         tree.check_matcher(&include_dir_subdir, 9);
  2430         tree.check_matcher(&more_includematchers[0], 17);
  2426         tree.check_matcher(&more_includematchers[0], 17);
  2431         tree.check_matcher(&more_includematchers[1], 25);
  2427         tree.check_matcher(&more_includematchers[1], 25);
  2432         tree.check_matcher(&more_includematchers[2], 35);
  2428         tree.check_matcher(&more_includematchers[2], 35);