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':