##// END OF EJS Templates
ignore: separate pattern extraction from match compilation...
Brendan Cully -
r9091:79a886bc default
parent child Browse files
Show More
@@ -1,92 +1,103 b''
1 # ignore.py - ignored file handling for mercurial
1 # ignore.py - ignored file handling for mercurial
2 #
2 #
3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import util, match
9 import util, match
10 import re
10 import re
11
11
12 _commentre = None
12 _commentre = None
13
13
14 def _parselines(fp):
14 def ignorepats(lines):
15 for line in fp:
15 '''parse lines (iterable) of .hgignore text, returning a tuple of
16 (patterns, parse errors). These patterns should be given to compile()
17 to be validated and converted into a match function.'''
18 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
19 syntax = 'relre:'
20 patterns = []
21 warnings = []
22
23 for line in lines:
16 if "#" in line:
24 if "#" in line:
17 global _commentre
25 global _commentre
18 if not _commentre:
26 if not _commentre:
19 _commentre = re.compile(r'((^|[^\\])(\\\\)*)#.*')
27 _commentre = re.compile(r'((^|[^\\])(\\\\)*)#.*')
20 # remove comments prefixed by an even number of escapes
28 # remove comments prefixed by an even number of escapes
21 line = _commentre.sub(r'\1', line)
29 line = _commentre.sub(r'\1', line)
22 # fixup properly escaped comments that survived the above
30 # fixup properly escaped comments that survived the above
23 line = line.replace("\\#", "#")
31 line = line.replace("\\#", "#")
24 line = line.rstrip()
32 line = line.rstrip()
25 if line:
33 if not line:
26 yield line
34 continue
35
36 if line.startswith('syntax:'):
37 s = line[7:].strip()
38 try:
39 syntax = syntaxes[s]
40 except KeyError:
41 warnings.append(_("ignoring invalid syntax '%s'") % s)
42 continue
43 pat = syntax + line
44 for s, rels in syntaxes.iteritems():
45 if line.startswith(rels):
46 pat = line
47 break
48 elif line.startswith(s+':'):
49 pat = rels + line[len(s)+1:]
50 break
51 patterns.append(pat)
52
53 return patterns, warnings
27
54
28 def ignore(root, files, warn):
55 def ignore(root, files, warn):
29 '''return the contents of .hgignore files as a list of patterns.
56 '''return matcher covering patterns in 'files'.
30
57
31 the files parsed for patterns include:
58 the files parsed for patterns include:
32 .hgignore in the repository root
59 .hgignore in the repository root
33 any additional files specified in the [ui] section of ~/.hgrc
60 any additional files specified in the [ui] section of ~/.hgrc
34
61
35 trailing white space is dropped.
62 trailing white space is dropped.
36 the escape character is backslash.
63 the escape character is backslash.
37 comments start with #.
64 comments start with #.
38 empty lines are skipped.
65 empty lines are skipped.
39
66
40 lines can be of the following formats:
67 lines can be of the following formats:
41
68
42 syntax: regexp # defaults following lines to non-rooted regexps
69 syntax: regexp # defaults following lines to non-rooted regexps
43 syntax: glob # defaults following lines to non-rooted globs
70 syntax: glob # defaults following lines to non-rooted globs
44 re:pattern # non-rooted regular expression
71 re:pattern # non-rooted regular expression
45 glob:pattern # non-rooted glob
72 glob:pattern # non-rooted glob
46 pattern # pattern of the current default type'''
73 pattern # pattern of the current default type'''
47
74
48 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
49 pats = {}
75 pats = {}
50 for f in files:
76 for f in files:
51 try:
77 try:
52 pats[f] = []
78 pats[f] = []
53 fp = open(f)
79 fp = open(f)
54 syntax = 'relre:'
80 pats[f], warnings = ignorepats(fp)
55 for line in _parselines(fp):
81 for warning in warnings:
56 if line.startswith('syntax:'):
82 warn("%s: %s\n" % (f, warning))
57 s = line[7:].strip()
58 try:
59 syntax = syntaxes[s]
60 except KeyError:
61 warn(_("%s: ignoring invalid syntax '%s'\n") % (f, s))
62 continue
63 pat = syntax + line
64 for s, rels in syntaxes.iteritems():
65 if line.startswith(rels):
66 pat = line
67 break
68 elif line.startswith(s+':'):
69 pat = rels + line[len(s)+1:]
70 break
71 pats[f].append(pat)
72 except IOError, inst:
83 except IOError, inst:
73 if f != files[0]:
84 if f != files[0]:
74 warn(_("skipping unreadable ignore file '%s': %s\n") %
85 warn(_("skipping unreadable ignore file '%s': %s\n") %
75 (f, inst.strerror))
86 (f, inst.strerror))
76
87
77 allpats = []
88 allpats = []
78 [allpats.extend(patlist) for patlist in pats.values()]
89 [allpats.extend(patlist) for patlist in pats.values()]
79 if not allpats:
90 if not allpats:
80 return util.never
91 return util.never
81
92
82 try:
93 try:
83 ignorefunc = match.match(root, '', [], allpats)
94 ignorefunc = match.match(root, '', [], allpats)
84 except util.Abort:
95 except util.Abort:
85 # Re-raise an exception where the src is the right file
96 # Re-raise an exception where the src is the right file
86 for f, patlist in pats.iteritems():
97 for f, patlist in pats.iteritems():
87 try:
98 try:
88 match.match(root, '', [], patlist)
99 match.match(root, '', [], patlist)
89 except util.Abort, inst:
100 except util.Abort, inst:
90 raise util.Abort('%s: %s' % (f, inst[0]))
101 raise util.Abort('%s: %s' % (f, inst[0]))
91
102
92 return ignorefunc
103 return ignorefunc
General Comments 0
You need to be logged in to leave comments. Login now