455 def __repr__(self): |
455 def __repr__(self): |
456 return ('<exactmatcher files=%r>' % self._files) |
456 return ('<exactmatcher files=%r>' % self._files) |
457 |
457 |
458 class differencematcher(basematcher): |
458 class differencematcher(basematcher): |
459 '''Composes two matchers by matching if the first matches and the second |
459 '''Composes two matchers by matching if the first matches and the second |
460 does not. Well, almost... If the user provides a pattern like "-X foo foo", |
460 does not. |
461 Mercurial actually does match "foo" against that. That's because exact |
|
462 matches are treated specially. So, since this differencematcher is used for |
|
463 excludes, it needs to special-case exact matching. |
|
464 |
461 |
465 The second matcher's non-matching-attributes (root, cwd, bad, explicitdir, |
462 The second matcher's non-matching-attributes (root, cwd, bad, explicitdir, |
466 traversedir) are ignored. |
463 traversedir) are ignored. |
467 |
|
468 TODO: If we want to keep the behavior described above for exact matches, we |
|
469 should consider instead treating the above case something like this: |
|
470 union(exact(foo), difference(pattern(foo), include(foo))) |
|
471 ''' |
464 ''' |
472 def __init__(self, m1, m2): |
465 def __init__(self, m1, m2): |
473 super(differencematcher, self).__init__(m1._root, m1._cwd) |
466 super(differencematcher, self).__init__(m1._root, m1._cwd) |
474 self._m1 = m1 |
467 self._m1 = m1 |
475 self._m2 = m2 |
468 self._m2 = m2 |
476 self.bad = m1.bad |
469 self.bad = m1.bad |
477 self.explicitdir = m1.explicitdir |
470 self.explicitdir = m1.explicitdir |
478 self.traversedir = m1.traversedir |
471 self.traversedir = m1.traversedir |
479 |
472 |
480 def matchfn(self, f): |
473 def matchfn(self, f): |
481 return self._m1(f) and (not self._m2(f) or self._m1.exact(f)) |
474 return self._m1(f) and not self._m2(f) |
482 |
475 |
483 @propertycache |
476 @propertycache |
484 def _files(self): |
477 def _files(self): |
485 if self.isexact(): |
478 if self.isexact(): |
486 return [f for f in self._m1.files() if self(f)] |
479 return [f for f in self._m1.files() if self(f)] |
491 # because the "dir" in m1 may not be a file. |
484 # because the "dir" in m1 may not be a file. |
492 return self._m1.files() |
485 return self._m1.files() |
493 |
486 |
494 def visitdir(self, dir): |
487 def visitdir(self, dir): |
495 if self._m2.visitdir(dir) == 'all': |
488 if self._m2.visitdir(dir) == 'all': |
496 # There's a bug here: If m1 matches file 'dir/file' and m2 excludes |
|
497 # 'dir' (recursively), we should still visit 'dir' due to the |
|
498 # exception we have for exact matches. |
|
499 return False |
489 return False |
500 return bool(self._m1.visitdir(dir)) |
490 return bool(self._m1.visitdir(dir)) |
501 |
491 |
502 def isexact(self): |
492 def isexact(self): |
503 return self._m1.isexact() |
493 return self._m1.isexact() |