diff --git a/mercurial/match.py b/mercurial/match.py --- a/mercurial/match.py +++ b/mercurial/match.py @@ -9,6 +9,14 @@ import re import scmutil, util, fileset from i18n import _ +def _rematcher(pat): + m = util.compilere(pat) + try: + # slightly faster, provided by facebook's re2 bindings + return m.test_match + except AttributeError: + return m.match + def _expandsets(pats, ctx): '''convert set: patterns into a list of files in the given context''' fset = set() @@ -280,7 +288,7 @@ def _buildregexmatch(pats, tail): pat = '(?:%s)' % '|'.join([_regex(k, p, tail) for (k, p) in pats]) if len(pat) > 20000: raise OverflowError - return pat, re.compile(pat).match + return pat, _rematcher(pat) except OverflowError: # We're using a Python with a tiny regex engine and we # made it explode, so we'll divide the pattern list in two @@ -294,7 +302,7 @@ def _buildregexmatch(pats, tail): except re.error: for k, p in pats: try: - re.compile('(?:%s)' % _regex(k, p, tail)) + _rematcher('(?:%s)' % _regex(k, p, tail)) except re.error: raise util.Abort(_("invalid pattern (%s): %s") % (k, p)) raise util.Abort(_("invalid pattern")) diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -629,6 +629,30 @@ def checkcase(path): except OSError: return True +try: + import re2 + _re2 = None +except ImportError: + _re2 = False + +def compilere(pat): + '''Compile a regular expression, using re2 if possible + + For best performance, use only re2-compatible regexp features.''' + global _re2 + if _re2 is None: + try: + re2.compile + _re2 = True + except ImportError: + _re2 = False + if _re2: + try: + return re2.compile(pat) + except re2.error: + pass + return re.compile(pat) + _fspathcache = {} def fspath(name, root): '''Get name in the case stored in the filesystem