annotate mercurial/ignore.py @ 21812:73e4a02e6d23

hg: add support for HGUNICODEPEDANTRY environment variable This lets us easily verify that there are no implicit conversions between unicodes and bytes in Mercurial's codebase. Based on something mpm did by hand periodically, but it kept regressing, so just open the door to running it in a buildbot.
author Augie Fackler <raf@durin42.com>
date Mon, 23 Jun 2014 09:33:07 -0400
parents 0127366df8fe
children 8cf7f0c4cb14
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
1 # ignore.py - ignored file handling for mercurial
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
2 #
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
4 #
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 7622
diff changeset
5 # This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9091
diff changeset
6 # GNU General Public License version 2 or any later version.
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
7
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
8 from i18n import _
8566
744d6322b05b match: change all users of util.matcher to match.match
Matt Mackall <mpm@selenic.com>
parents: 8312
diff changeset
9 import util, match
8312
b87a50b7125c separate import lines from mercurial and general python modules
Simon Heimberg <simohe@besonet.ch>
parents: 8225
diff changeset
10 import re
5640
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
11
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
12 _commentre = None
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
13
9091
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
14 def ignorepats(lines):
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
15 '''parse lines (iterable) of .hgignore text, returning a tuple of
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
16 (patterns, parse errors). These patterns should be given to compile()
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
17 to be validated and converted into a match function.'''
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
18 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
19 syntax = 'relre:'
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
20 patterns = []
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
21 warnings = []
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
22
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
23 for line in lines:
5640
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
24 if "#" in line:
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
25 global _commentre
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
26 if not _commentre:
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
27 _commentre = re.compile(r'((^|[^\\])(\\\\)*)#.*')
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
28 # remove comments prefixed by an even number of escapes
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
29 line = _commentre.sub(r'\1', line)
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
30 # fixup properly escaped comments that survived the above
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
31 line = line.replace("\\#", "#")
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
32 line = line.rstrip()
9091
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
33 if not line:
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
34 continue
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
35
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
36 if line.startswith('syntax:'):
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
37 s = line[7:].strip()
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
38 try:
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
39 syntax = syntaxes[s]
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
40 except KeyError:
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
41 warnings.append(_("ignoring invalid syntax '%s'") % s)
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
42 continue
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
43 pat = syntax + line
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
44 for s, rels in syntaxes.iteritems():
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
45 if line.startswith(rels):
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
46 pat = line
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
47 break
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
48 elif line.startswith(s+':'):
18054
b35e3364f94a check-code: there must also be whitespace between ')' and operator
Mads Kiilerich <madski@unity3d.com>
parents: 15407
diff changeset
49 pat = rels + line[len(s) + 1:]
9091
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
50 break
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
51 patterns.append(pat)
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
52
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
53 return patterns, warnings
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
54
18087
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
55 def readpats(root, files, warn):
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
56 '''return a dict mapping ignore-file-name to list-of-patterns'''
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
57
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
58 pats = {}
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
59 for f in files:
18088
52620e5db2f6 ignore: only read an ignore file once
Bryan O'Sullivan <bryano@fb.com>
parents: 18087
diff changeset
60 if f in pats:
52620e5db2f6 ignore: only read an ignore file once
Bryan O'Sullivan <bryano@fb.com>
parents: 18087
diff changeset
61 continue
18087
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
62 try:
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
63 pats[f] = []
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
64 fp = open(f)
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
65 pats[f], warnings = ignorepats(fp)
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
66 fp.close()
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
67 for warning in warnings:
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
68 warn("%s: %s\n" % (f, warning))
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
69 except IOError, inst:
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
70 if f != files[0]:
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
71 warn(_("skipping unreadable ignore file '%s': %s\n") %
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
72 (f, inst.strerror))
18089
0127366df8fe ignore: process hgignore files in deterministic order
Bryan O'Sullivan <bryano@fb.com>
parents: 18088
diff changeset
73 return [(f, pats[f]) for f in files if f in pats]
18087
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
74
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
75 def ignore(root, files, warn):
9091
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
76 '''return matcher covering patterns in 'files'.
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
77
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
78 the files parsed for patterns include:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
79 .hgignore in the repository root
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
80 any additional files specified in the [ui] section of ~/.hgrc
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
81
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
82 trailing white space is dropped.
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
83 the escape character is backslash.
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
84 comments start with #.
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
85 empty lines are skipped.
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
86
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
87 lines can be of the following formats:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
88
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
89 syntax: regexp # defaults following lines to non-rooted regexps
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
90 syntax: glob # defaults following lines to non-rooted globs
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
91 re:pattern # non-rooted regular expression
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
92 glob:pattern # non-rooted glob
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
93 pattern # pattern of the current default type'''
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
94
18087
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
95 pats = readpats(root, files, warn)
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
96
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
97 allpats = []
18089
0127366df8fe ignore: process hgignore files in deterministic order
Bryan O'Sullivan <bryano@fb.com>
parents: 18088
diff changeset
98 for f, patlist in pats:
13412
58c497d0e44d remove unnecessary list comprehensions
Martin Geisler <mg@aragost.com>
parents: 10263
diff changeset
99 allpats.extend(patlist)
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
100 if not allpats:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
101 return util.never
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
102
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
103 try:
8567
fea40a677d43 match: add some default args
Matt Mackall <mpm@selenic.com>
parents: 8566
diff changeset
104 ignorefunc = match.match(root, '', [], allpats)
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
105 except util.Abort:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
106 # Re-raise an exception where the src is the right file
18089
0127366df8fe ignore: process hgignore files in deterministic order
Bryan O'Sullivan <bryano@fb.com>
parents: 18088
diff changeset
107 for f, patlist in pats:
8566
744d6322b05b match: change all users of util.matcher to match.match
Matt Mackall <mpm@selenic.com>
parents: 8312
diff changeset
108 try:
8567
fea40a677d43 match: add some default args
Matt Mackall <mpm@selenic.com>
parents: 8566
diff changeset
109 match.match(root, '', [], patlist)
8566
744d6322b05b match: change all users of util.matcher to match.match
Matt Mackall <mpm@selenic.com>
parents: 8312
diff changeset
110 except util.Abort, inst:
744d6322b05b match: change all users of util.matcher to match.match
Matt Mackall <mpm@selenic.com>
parents: 8312
diff changeset
111 raise util.Abort('%s: %s' % (f, inst[0]))
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
112
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
113 return ignorefunc