comparison mercurial/match.py @ 38611:0ba4cf3f088f

match: add prefixdirmatcher to adapt subrepo matcher back This serves as an inverse function to the subdirmatcher, and will be used to wrap a fileset matcher of subrepositories. One of the root/prefix paths could be deduced from the matcher attributes to be wrapped, but we don't since the callers of this class know the root/prefix paths and can simply pass them in.
author Yuya Nishihara <yuya@tcha.org>
date Sat, 09 Jun 2018 22:04:07 +0900
parents 6467286b829c
children 760cc5dc01e8
comparison
equal deleted inserted replaced
38610:3d8ef60569d8 38611:0ba4cf3f088f
681 681
682 @encoding.strmethod 682 @encoding.strmethod
683 def __repr__(self): 683 def __repr__(self):
684 return ('<subdirmatcher path=%r, matcher=%r>' % 684 return ('<subdirmatcher path=%r, matcher=%r>' %
685 (self._path, self._matcher)) 685 (self._path, self._matcher))
686
687 class prefixdirmatcher(basematcher):
688 """Adapt a matcher to work on a parent directory.
689
690 The matcher's non-matching-attributes (root, cwd, bad, explicitdir,
691 traversedir) are ignored.
692
693 The prefix path should usually be the relative path from the root of
694 this matcher to the root of the wrapped matcher.
695
696 >>> m1 = match(b'root/d/e', b'f', [b'../a.txt', b'b.txt'])
697 >>> m2 = prefixdirmatcher(b'root', b'd/e/f', b'd/e', m1)
698 >>> bool(m2(b'a.txt'),)
699 False
700 >>> bool(m2(b'd/e/a.txt'))
701 True
702 >>> bool(m2(b'd/e/b.txt'))
703 False
704 >>> m2.files()
705 ['d/e/a.txt', 'd/e/f/b.txt']
706 >>> m2.exact(b'd/e/a.txt')
707 True
708 >>> m2.visitdir(b'd')
709 True
710 >>> m2.visitdir(b'd/e')
711 True
712 >>> m2.visitdir(b'd/e/f')
713 True
714 >>> m2.visitdir(b'd/e/g')
715 False
716 >>> m2.visitdir(b'd/ef')
717 False
718 """
719
720 def __init__(self, root, cwd, path, matcher, badfn=None):
721 super(prefixdirmatcher, self).__init__(root, cwd, badfn)
722 if not path:
723 raise error.ProgrammingError('prefix path must not be empty')
724 self._path = path
725 self._pathprefix = path + '/'
726 self._matcher = matcher
727
728 @propertycache
729 def _files(self):
730 return [self._pathprefix + f for f in self._matcher._files]
731
732 def matchfn(self, f):
733 if not f.startswith(self._pathprefix):
734 return False
735 return self._matcher.matchfn(f[len(self._pathprefix):])
736
737 @propertycache
738 def _pathdirs(self):
739 return set(util.finddirs(self._path)) | {'.'}
740
741 def visitdir(self, dir):
742 if dir == self._path:
743 return self._matcher.visitdir('.')
744 if dir.startswith(self._pathprefix):
745 return self._matcher.visitdir(dir[len(self._pathprefix):])
746 return dir in self._pathdirs
747
748 def isexact(self):
749 return self._matcher.isexact()
750
751 def prefix(self):
752 return self._matcher.prefix()
753
754 @encoding.strmethod
755 def __repr__(self):
756 return ('<prefixdirmatcher path=%r, matcher=%r>'
757 % (pycompat.bytestr(self._path), self._matcher))
686 758
687 class unionmatcher(basematcher): 759 class unionmatcher(basematcher):
688 """A matcher that is the union of several matchers. 760 """A matcher that is the union of several matchers.
689 761
690 The non-matching-attributes (root, cwd, bad, explicitdir, traversedir) are 762 The non-matching-attributes (root, cwd, bad, explicitdir, traversedir) are