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 }); |
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); |