Mercurial > hg > mercurial-crew-with-dirclash
comparison mercurial/dirstate.py @ 4610:b43f17691ae6
dirstate: move ignore to its own file
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Mon, 18 Jun 2007 13:24:34 -0500 |
parents | 220211b88656 |
children | 274c99fc629f |
comparison
equal
deleted
inserted
replaced
4609:220211b88656 | 4610:b43f17691ae6 |
---|---|
7 of the GNU General Public License, incorporated herein by reference. | 7 of the GNU General Public License, incorporated herein by reference. |
8 """ | 8 """ |
9 | 9 |
10 from node import * | 10 from node import * |
11 from i18n import _ | 11 from i18n import _ |
12 import struct, os, time, bisect, stat, strutil, util, re, errno | 12 import struct, os, time, bisect, stat, strutil, util, re, errno, ignore |
13 import cStringIO | 13 import cStringIO |
14 | 14 |
15 class dirstate(object): | 15 class dirstate(object): |
16 format = ">cllll" | 16 format = ">cllll" |
17 | 17 |
18 def __init__(self, opener, ui, root): | 18 def __init__(self, opener, ui, root): |
19 self.opener = opener | 19 self.opener = opener |
20 self.root = root | 20 self.root = root |
21 self.dirty = 0 | 21 self.dirty = 0 |
22 self.ui = ui | 22 self.ui = ui |
23 self.ignorefunc = None | |
24 self._slash = None | 23 self._slash = None |
25 | 24 |
26 def __getattr__(self, name): | 25 def __getattr__(self, name): |
27 if name == 'map': | 26 if name == 'map': |
28 self.read() | 27 self.read() |
49 elif name == 'dirs': | 48 elif name == 'dirs': |
50 self.dirs = {} | 49 self.dirs = {} |
51 for f in self.map: | 50 for f in self.map: |
52 self.updatedirs(f, 1) | 51 self.updatedirs(f, 1) |
53 return self.dirs | 52 return self.dirs |
53 elif name == '_ignore': | |
54 files = [self.wjoin('.hgignore')] + self.ui.hgignorefiles() | |
55 self._ignore = ignore.ignore(self.root, files, self.ui.warn) | |
56 return self._ignore | |
54 else: | 57 else: |
55 raise AttributeError, name | 58 raise AttributeError, name |
56 | 59 |
57 def wjoin(self, f): | 60 def wjoin(self, f): |
58 return os.path.join(self.root, f) | 61 return os.path.join(self.root, f) |
78 self._slash = self.ui.configbool('ui', 'slash') and os.sep != '/' | 81 self._slash = self.ui.configbool('ui', 'slash') and os.sep != '/' |
79 if self._slash: | 82 if self._slash: |
80 path = path.replace(os.sep, '/') | 83 path = path.replace(os.sep, '/') |
81 return path | 84 return path |
82 | 85 |
83 def hgignore(self): | |
84 '''return the contents of .hgignore files as a list of patterns. | |
85 | |
86 the files parsed for patterns include: | |
87 .hgignore in the repository root | |
88 any additional files specified in the [ui] section of ~/.hgrc | |
89 | |
90 trailing white space is dropped. | |
91 the escape character is backslash. | |
92 comments start with #. | |
93 empty lines are skipped. | |
94 | |
95 lines can be of the following formats: | |
96 | |
97 syntax: regexp # defaults following lines to non-rooted regexps | |
98 syntax: glob # defaults following lines to non-rooted globs | |
99 re:pattern # non-rooted regular expression | |
100 glob:pattern # non-rooted glob | |
101 pattern # pattern of the current default type''' | |
102 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'} | |
103 def parselines(fp): | |
104 for line in fp: | |
105 if not line.endswith('\n'): | |
106 line += '\n' | |
107 escape = False | |
108 for i in xrange(len(line)): | |
109 if escape: escape = False | |
110 elif line[i] == '\\': escape = True | |
111 elif line[i] == '#': break | |
112 line = line[:i].rstrip() | |
113 if line: yield line | |
114 repoignore = self.wjoin('.hgignore') | |
115 files = [repoignore] | |
116 files.extend(self.ui.hgignorefiles()) | |
117 pats = {} | |
118 for f in files: | |
119 try: | |
120 pats[f] = [] | |
121 fp = open(f) | |
122 syntax = 'relre:' | |
123 for line in parselines(fp): | |
124 if line.startswith('syntax:'): | |
125 s = line[7:].strip() | |
126 try: | |
127 syntax = syntaxes[s] | |
128 except KeyError: | |
129 self.ui.warn(_("%s: ignoring invalid " | |
130 "syntax '%s'\n") % (f, s)) | |
131 continue | |
132 pat = syntax + line | |
133 for s in syntaxes.values(): | |
134 if line.startswith(s): | |
135 pat = line | |
136 break | |
137 pats[f].append(pat) | |
138 except IOError, inst: | |
139 if f != repoignore: | |
140 self.ui.warn(_("skipping unreadable ignore file" | |
141 " '%s': %s\n") % (f, inst.strerror)) | |
142 return pats | |
143 | |
144 def ignore(self, fn): | |
145 '''default match function used by dirstate and | |
146 localrepository. this honours the repository .hgignore file | |
147 and any other files specified in the [ui] section of .hgrc.''' | |
148 if not self.ignorefunc: | |
149 ignore = self.hgignore() | |
150 allpats = [] | |
151 [allpats.extend(patlist) for patlist in ignore.values()] | |
152 if allpats: | |
153 try: | |
154 files, self.ignorefunc, anypats = ( | |
155 util.matcher(self.root, inc=allpats, src='.hgignore')) | |
156 except util.Abort: | |
157 # Re-raise an exception where the src is the right file | |
158 for f, patlist in ignore.items(): | |
159 files, self.ignorefunc, anypats = ( | |
160 util.matcher(self.root, inc=patlist, src=f)) | |
161 else: | |
162 self.ignorefunc = util.never | |
163 return self.ignorefunc(fn) | |
164 | |
165 def __del__(self): | 86 def __del__(self): |
166 if self.dirty: | 87 if self.dirty: |
167 self.write() | 88 self.write() |
168 | 89 |
169 def __getitem__(self, key): | 90 def __getitem__(self, key): |
239 copymap[f] = c | 160 copymap[f] = c |
240 dmap[f] = e[:4] | 161 dmap[f] = e[:4] |
241 pos = newpos | 162 pos = newpos |
242 | 163 |
243 def reload(self): | 164 def reload(self): |
244 for a in "map copymap _branch pl dirs".split(): | 165 for a in "map copymap _branch pl dirs _ignore".split(): |
245 if hasattr(self, a): | 166 if hasattr(self, a): |
246 self.__delattr__(a) | 167 self.__delattr__(a) |
247 self.ignorefunc = None | |
248 | 168 |
249 def copy(self, source, dest): | 169 def copy(self, source, dest): |
250 self.markdirty() | 170 self.markdirty() |
251 self.copymap[dest] = source | 171 self.copymap[dest] = source |
252 | 172 |
418 else: | 338 else: |
419 files = util.unique(files) | 339 files = util.unique(files) |
420 dc = self.filterfiles(files) | 340 dc = self.filterfiles(files) |
421 | 341 |
422 def imatch(file_): | 342 def imatch(file_): |
423 if file_ not in dc and self.ignore(file_): | 343 if file_ not in dc and self._ignore(file_): |
424 return False | 344 return False |
425 return match(file_) | 345 return match(file_) |
426 | 346 |
427 ignore = self.ignore | 347 ignore = self._ignore |
428 if ignored: | 348 if ignored: |
429 imatch = match | 349 imatch = match |
430 ignore = util.never | 350 ignore = util.never |
431 | 351 |
432 # self.root may end with a path separator when self.root == '/' | 352 # self.root may end with a path separator when self.root == '/' |
527 | 447 |
528 for src, fn, st in self.statwalk(files, match, ignored=list_ignored): | 448 for src, fn, st in self.statwalk(files, match, ignored=list_ignored): |
529 try: | 449 try: |
530 type_, mode, size, time = self[fn] | 450 type_, mode, size, time = self[fn] |
531 except KeyError: | 451 except KeyError: |
532 if list_ignored and self.ignore(fn): | 452 if list_ignored and self._ignore(fn): |
533 ignored.append(fn) | 453 ignored.append(fn) |
534 else: | 454 else: |
535 unknown.append(fn) | 455 unknown.append(fn) |
536 continue | 456 continue |
537 if src == 'm': | 457 if src == 'm': |