Mercurial > hg
changeset 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 | 3d8ef60569d8 |
children | 760cc5dc01e8 |
files | mercurial/match.py |
diffstat | 1 files changed, 72 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/match.py Sat Jun 09 18:58:16 2018 +0900 +++ b/mercurial/match.py Sat Jun 09 22:04:07 2018 +0900 @@ -684,6 +684,78 @@ return ('<subdirmatcher path=%r, matcher=%r>' % (self._path, self._matcher)) +class prefixdirmatcher(basematcher): + """Adapt a matcher to work on a parent directory. + + The matcher's non-matching-attributes (root, cwd, bad, explicitdir, + traversedir) are ignored. + + The prefix path should usually be the relative path from the root of + this matcher to the root of the wrapped matcher. + + >>> m1 = match(b'root/d/e', b'f', [b'../a.txt', b'b.txt']) + >>> m2 = prefixdirmatcher(b'root', b'd/e/f', b'd/e', m1) + >>> bool(m2(b'a.txt'),) + False + >>> bool(m2(b'd/e/a.txt')) + True + >>> bool(m2(b'd/e/b.txt')) + False + >>> m2.files() + ['d/e/a.txt', 'd/e/f/b.txt'] + >>> m2.exact(b'd/e/a.txt') + True + >>> m2.visitdir(b'd') + True + >>> m2.visitdir(b'd/e') + True + >>> m2.visitdir(b'd/e/f') + True + >>> m2.visitdir(b'd/e/g') + False + >>> m2.visitdir(b'd/ef') + False + """ + + def __init__(self, root, cwd, path, matcher, badfn=None): + super(prefixdirmatcher, self).__init__(root, cwd, badfn) + if not path: + raise error.ProgrammingError('prefix path must not be empty') + self._path = path + self._pathprefix = path + '/' + self._matcher = matcher + + @propertycache + def _files(self): + return [self._pathprefix + f for f in self._matcher._files] + + def matchfn(self, f): + if not f.startswith(self._pathprefix): + return False + return self._matcher.matchfn(f[len(self._pathprefix):]) + + @propertycache + def _pathdirs(self): + return set(util.finddirs(self._path)) | {'.'} + + def visitdir(self, dir): + if dir == self._path: + return self._matcher.visitdir('.') + if dir.startswith(self._pathprefix): + return self._matcher.visitdir(dir[len(self._pathprefix):]) + return dir in self._pathdirs + + def isexact(self): + return self._matcher.isexact() + + def prefix(self): + return self._matcher.prefix() + + @encoding.strmethod + def __repr__(self): + return ('<prefixdirmatcher path=%r, matcher=%r>' + % (pycompat.bytestr(self._path), self._matcher)) + class unionmatcher(basematcher): """A matcher that is the union of several matchers.