comparison mercurial/match.py @ 39261:c9a3f7f5c023

match: make exactmatcher.visitchildrenset return file children as well Previously, if we had an exactmatcher like ['foo.txt', 'a/bar.txt', 'a/b/c/baz.txt'], we'd get back the following data: '.': {'a'} 'a': {'b'} 'a/b': {'c'} 'a/b/c': 'this' 'a/b/c/d': set() This was incorrect, since visitchildrenset explicitly says not to pay attention to 'foo.txt' and 'a/bar.txt' by not returning them or 'this'. Given the near impossibility of making visitchildrenset reliabbly produce only subdirectories, a previous commit has made it documented and expected that visitchildrenset can return a set containing both files and subdirectories to visit, instead of implying/requiring that visitchildrenset() return 'this' if there are files to visit. This makes the code for exactmatcher match this clarified documentation. Differential Revision: https://phab.mercurial-scm.org/D4365
author Kyle Lippincott <spectral@google.com>
date Fri, 24 Aug 2018 10:19:31 -0700
parents 27946fca8a05
children 35ecaa999a12
comparison
equal deleted inserted replaced
39260:27946fca8a05 39261:c9a3f7f5c023
585 585
586 def visitdir(self, dir): 586 def visitdir(self, dir):
587 return dir in self._dirs 587 return dir in self._dirs
588 588
589 def visitchildrenset(self, dir): 589 def visitchildrenset(self, dir):
590 if dir in self._dirs: 590 if not self._fileset or dir not in self._dirs:
591 candidates = self._dirs - {'.'} 591 return set()
592 if dir != '.': 592
593 d = dir + '/' 593 candidates = self._fileset | self._dirs - {'.'}
594 candidates = set(c[len(d):] for c in candidates if 594 if dir != '.':
595 c.startswith(d)) 595 d = dir + '/'
596 # self._dirs includes all of the directories, recursively, so if 596 candidates = set(c[len(d):] for c in candidates if
597 # we're attempting to match foo/bar/baz.txt, it'll have '.', 'foo', 597 c.startswith(d))
598 # 'foo/bar' in it. Thus we can safely ignore a candidate that has a 598 # self._dirs includes all of the directories, recursively, so if
599 # '/' in it, indicating a it's for a subdir-of-a-subdir; the 599 # we're attempting to match foo/bar/baz.txt, it'll have '.', 'foo',
600 # immediate subdir will be in there without a slash. 600 # 'foo/bar' in it. Thus we can safely ignore a candidate that has a
601 ret = set(c for c in candidates if '/' not in c) 601 # '/' in it, indicating a it's for a subdir-of-a-subdir; the
602 # We need to emit 'this' for foo/bar, not set(), not {'baz.txt'}. 602 # immediate subdir will be in there without a slash.
603 if not ret: 603 ret = {c for c in candidates if '/' not in c}
604 return 'this' 604 # We really do not expect ret to be empty, since that would imply that
605 return ret 605 # there's something in _dirs that didn't have a file in _fileset.
606 return set() 606 assert ret
607 return ret
607 608
608 def isexact(self): 609 def isexact(self):
609 return True 610 return True
610 611
611 @encoding.strmethod 612 @encoding.strmethod