changeset 9091:79a886bcf461

ignore: separate pattern extraction from match compilation hgignore files have slightly different syntax from match objects, e.g. syntax: foo headers, regexp: forms, and re being relre. Put conversion from hgignore syntax into match syntax into a standalone function so that it is easier to validate hgignore hunks externally.
author Brendan Cully <brendan@kublai.com>
date Thu, 09 Jul 2009 15:14:42 -0700
parents 6cf043b1aa14
children 9aebeea7ac00
files mercurial/ignore.py
diffstat 1 files changed, 35 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/ignore.py	Thu Jul 09 11:59:56 2009 +0200
+++ b/mercurial/ignore.py	Thu Jul 09 15:14:42 2009 -0700
@@ -11,8 +11,16 @@
 
 _commentre = None
 
-def _parselines(fp):
-    for line in fp:
+def ignorepats(lines):
+    '''parse lines (iterable) of .hgignore text, returning a tuple of
+    (patterns, parse errors). These patterns should be given to compile()
+    to be validated and converted into a match function.'''
+    syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
+    syntax = 'relre:'
+    patterns = []
+    warnings = []
+
+    for line in lines:
         if "#" in line:
             global _commentre
             if not _commentre:
@@ -22,11 +30,30 @@
             # fixup properly escaped comments that survived the above
             line = line.replace("\\#", "#")
         line = line.rstrip()
-        if line:
-            yield line
+        if not line:
+            continue
+
+        if line.startswith('syntax:'):
+            s = line[7:].strip()
+            try:
+                syntax = syntaxes[s]
+            except KeyError:
+                warnings.append(_("ignoring invalid syntax '%s'") % s)
+            continue
+        pat = syntax + line
+        for s, rels in syntaxes.iteritems():
+            if line.startswith(rels):
+                pat = line
+                break
+            elif line.startswith(s+':'):
+                pat = rels + line[len(s)+1:]
+                break
+        patterns.append(pat)
+
+    return patterns, warnings
 
 def ignore(root, files, warn):
-    '''return the contents of .hgignore files as a list of patterns.
+    '''return matcher covering patterns in 'files'.
 
     the files parsed for patterns include:
     .hgignore in the repository root
@@ -45,30 +72,14 @@
     glob:pattern   # non-rooted glob
     pattern        # pattern of the current default type'''
 
-    syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
     pats = {}
     for f in files:
         try:
             pats[f] = []
             fp = open(f)
-            syntax = 'relre:'
-            for line in _parselines(fp):
-                if line.startswith('syntax:'):
-                    s = line[7:].strip()
-                    try:
-                        syntax = syntaxes[s]
-                    except KeyError:
-                        warn(_("%s: ignoring invalid syntax '%s'\n") % (f, s))
-                    continue
-                pat = syntax + line
-                for s, rels in syntaxes.iteritems():
-                    if line.startswith(rels):
-                        pat = line
-                        break
-                    elif line.startswith(s+':'):
-                        pat = rels + line[len(s)+1:]
-                        break
-                pats[f].append(pat)
+            pats[f], warnings = ignorepats(fp)
+            for warning in warnings:
+                warn("%s: %s\n" % (f, warning))
         except IOError, inst:
             if f != files[0]:
                 warn(_("skipping unreadable ignore file '%s': %s\n") %