##// END OF EJS Templates
On error parsing hgignore file, print the correct filename.
mcmillen@cs.cmu.edu -
r2005:bc47af2d default
parent child Browse files
Show More
@@ -1,451 +1,455
1 """
1 """
2 dirstate.py - working directory tracking for mercurial
2 dirstate.py - working directory tracking for mercurial
3
3
4 Copyright 2005 Matt Mackall <mpm@selenic.com>
4 Copyright 2005 Matt Mackall <mpm@selenic.com>
5
5
6 This software may be used and distributed according to the terms
6 This software may be used and distributed according to the terms
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 import struct, os
10 import struct, os
11 from node import *
11 from node import *
12 from i18n import gettext as _
12 from i18n import gettext as _
13 from demandload import *
13 from demandload import *
14 demandload(globals(), "time bisect stat util re errno")
14 demandload(globals(), "time bisect stat util re errno")
15
15
16 class dirstate(object):
16 class dirstate(object):
17 def __init__(self, opener, ui, root):
17 def __init__(self, opener, ui, root):
18 self.opener = opener
18 self.opener = opener
19 self.root = root
19 self.root = root
20 self.dirty = 0
20 self.dirty = 0
21 self.ui = ui
21 self.ui = ui
22 self.map = None
22 self.map = None
23 self.pl = None
23 self.pl = None
24 self.copies = {}
24 self.copies = {}
25 self.ignorefunc = None
25 self.ignorefunc = None
26 self.blockignore = False
26 self.blockignore = False
27
27
28 def wjoin(self, f):
28 def wjoin(self, f):
29 return os.path.join(self.root, f)
29 return os.path.join(self.root, f)
30
30
31 def getcwd(self):
31 def getcwd(self):
32 cwd = os.getcwd()
32 cwd = os.getcwd()
33 if cwd == self.root: return ''
33 if cwd == self.root: return ''
34 return cwd[len(self.root) + 1:]
34 return cwd[len(self.root) + 1:]
35
35
36 def hgignore(self):
36 def hgignore(self):
37 '''return the contents of .hgignore files as a list of patterns.
37 '''return the contents of .hgignore files as a list of patterns.
38
38
39 the files parsed for patterns include:
39 the files parsed for patterns include:
40 .hgignore in the repository root
40 .hgignore in the repository root
41 any additional files specified in the [ui] section of ~/.hgrc
41 any additional files specified in the [ui] section of ~/.hgrc
42
42
43 trailing white space is dropped.
43 trailing white space is dropped.
44 the escape character is backslash.
44 the escape character is backslash.
45 comments start with #.
45 comments start with #.
46 empty lines are skipped.
46 empty lines are skipped.
47
47
48 lines can be of the following formats:
48 lines can be of the following formats:
49
49
50 syntax: regexp # defaults following lines to non-rooted regexps
50 syntax: regexp # defaults following lines to non-rooted regexps
51 syntax: glob # defaults following lines to non-rooted globs
51 syntax: glob # defaults following lines to non-rooted globs
52 re:pattern # non-rooted regular expression
52 re:pattern # non-rooted regular expression
53 glob:pattern # non-rooted glob
53 glob:pattern # non-rooted glob
54 pattern # pattern of the current default type'''
54 pattern # pattern of the current default type'''
55 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
55 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
56 def parselines(fp):
56 def parselines(fp):
57 for line in fp:
57 for line in fp:
58 escape = False
58 escape = False
59 for i in xrange(len(line)):
59 for i in xrange(len(line)):
60 if escape: escape = False
60 if escape: escape = False
61 elif line[i] == '\\': escape = True
61 elif line[i] == '\\': escape = True
62 elif line[i] == '#': break
62 elif line[i] == '#': break
63 line = line[:i].rstrip()
63 line = line[:i].rstrip()
64 if line: yield line
64 if line: yield line
65 repoignore = self.wjoin('.hgignore')
65 repoignore = self.wjoin('.hgignore')
66 files = [repoignore]
66 files = [repoignore]
67 files.extend(self.ui.hgignorefiles())
67 files.extend(self.ui.hgignorefiles())
68 pats = []
68 pats = {}
69 for f in files:
69 for f in files:
70 try:
70 try:
71 pats[f] = []
71 fp = open(f)
72 fp = open(f)
72 syntax = 'relre:'
73 syntax = 'relre:'
73 for line in parselines(fp):
74 for line in parselines(fp):
74 if line.startswith('syntax:'):
75 if line.startswith('syntax:'):
75 s = line[7:].strip()
76 s = line[7:].strip()
76 try:
77 try:
77 syntax = syntaxes[s]
78 syntax = syntaxes[s]
78 except KeyError:
79 except KeyError:
79 self.ui.warn(_("%s: ignoring invalid "
80 self.ui.warn(_("%s: ignoring invalid "
80 "syntax '%s'\n") % (f, s))
81 "syntax '%s'\n") % (f, s))
81 continue
82 continue
82 pat = syntax + line
83 pat = syntax + line
83 for s in syntaxes.values():
84 for s in syntaxes.values():
84 if line.startswith(s):
85 if line.startswith(s):
85 pat = line
86 pat = line
86 break
87 break
87 pats.append(pat)
88 pats[f].append(pat)
88 except IOError:
89 except IOError:
89 if f != repoignore:
90 if f != repoignore:
90 self.ui.warn(_("ignore file %s not found\n") % f)
91 self.ui.warn(_("ignore file %s not found\n") % f)
91 return pats
92 return pats
92
93
93 def ignore(self, fn):
94 def ignore(self, fn):
94 '''default match function used by dirstate and
95 '''default match function used by dirstate and
95 localrepository. this honours the repository .hgignore file
96 localrepository. this honours the repository .hgignore file
96 and any other files specified in the [ui] section of .hgrc.'''
97 and any other files specified in the [ui] section of .hgrc.'''
97 if self.blockignore:
98 if self.blockignore:
98 return False
99 return False
99 if not self.ignorefunc:
100 if not self.ignorefunc:
100 ignore = self.hgignore()
101 ignore = self.hgignore()
101 if ignore:
102 if ignore:
102 # FIXME: if there are errors in patterns, matcher will
103 try:
103 # print out an error containing src ('.hgignore');
104 allpats = []
104 # really, we want the original source file to be
105 [allpats.extend(patlist) for patlist in ignore.values()]
105 # printed instead.
106 files, self.ignorefunc, anypats = (
106 files, self.ignorefunc, anypats = util.matcher(self.root,
107 util.matcher(self.root, inc=allpats, src='.hgignore'))
107 inc=ignore,
108 except util.Abort:
108 src='.hgignore')
109 # Re-raise an exception where the src is the right file
110 for f, patlist in ignore.items():
111 files, self.ignorefunc, anypats = (
112 util.matcher(self.root, inc=patlist, src=f))
109 else:
113 else:
110 self.ignorefunc = util.never
114 self.ignorefunc = util.never
111 return self.ignorefunc(fn)
115 return self.ignorefunc(fn)
112
116
113 def __del__(self):
117 def __del__(self):
114 if self.dirty:
118 if self.dirty:
115 self.write()
119 self.write()
116
120
117 def __getitem__(self, key):
121 def __getitem__(self, key):
118 try:
122 try:
119 return self.map[key]
123 return self.map[key]
120 except TypeError:
124 except TypeError:
121 self.lazyread()
125 self.lazyread()
122 return self[key]
126 return self[key]
123
127
124 def __contains__(self, key):
128 def __contains__(self, key):
125 self.lazyread()
129 self.lazyread()
126 return key in self.map
130 return key in self.map
127
131
128 def parents(self):
132 def parents(self):
129 self.lazyread()
133 self.lazyread()
130 return self.pl
134 return self.pl
131
135
132 def markdirty(self):
136 def markdirty(self):
133 if not self.dirty:
137 if not self.dirty:
134 self.dirty = 1
138 self.dirty = 1
135
139
136 def setparents(self, p1, p2=nullid):
140 def setparents(self, p1, p2=nullid):
137 self.lazyread()
141 self.lazyread()
138 self.markdirty()
142 self.markdirty()
139 self.pl = p1, p2
143 self.pl = p1, p2
140
144
141 def state(self, key):
145 def state(self, key):
142 try:
146 try:
143 return self[key][0]
147 return self[key][0]
144 except KeyError:
148 except KeyError:
145 return "?"
149 return "?"
146
150
147 def lazyread(self):
151 def lazyread(self):
148 if self.map is None:
152 if self.map is None:
149 self.read()
153 self.read()
150
154
151 def read(self):
155 def read(self):
152 self.map = {}
156 self.map = {}
153 self.pl = [nullid, nullid]
157 self.pl = [nullid, nullid]
154 try:
158 try:
155 st = self.opener("dirstate").read()
159 st = self.opener("dirstate").read()
156 if not st: return
160 if not st: return
157 except: return
161 except: return
158
162
159 self.pl = [st[:20], st[20: 40]]
163 self.pl = [st[:20], st[20: 40]]
160
164
161 pos = 40
165 pos = 40
162 while pos < len(st):
166 while pos < len(st):
163 e = struct.unpack(">cllll", st[pos:pos+17])
167 e = struct.unpack(">cllll", st[pos:pos+17])
164 l = e[4]
168 l = e[4]
165 pos += 17
169 pos += 17
166 f = st[pos:pos + l]
170 f = st[pos:pos + l]
167 if '\0' in f:
171 if '\0' in f:
168 f, c = f.split('\0')
172 f, c = f.split('\0')
169 self.copies[f] = c
173 self.copies[f] = c
170 self.map[f] = e[:4]
174 self.map[f] = e[:4]
171 pos += l
175 pos += l
172
176
173 def copy(self, source, dest):
177 def copy(self, source, dest):
174 self.lazyread()
178 self.lazyread()
175 self.markdirty()
179 self.markdirty()
176 self.copies[dest] = source
180 self.copies[dest] = source
177
181
178 def copied(self, file):
182 def copied(self, file):
179 return self.copies.get(file, None)
183 return self.copies.get(file, None)
180
184
181 def update(self, files, state, **kw):
185 def update(self, files, state, **kw):
182 ''' current states:
186 ''' current states:
183 n normal
187 n normal
184 m needs merging
188 m needs merging
185 r marked for removal
189 r marked for removal
186 a marked for addition'''
190 a marked for addition'''
187
191
188 if not files: return
192 if not files: return
189 self.lazyread()
193 self.lazyread()
190 self.markdirty()
194 self.markdirty()
191 for f in files:
195 for f in files:
192 if state == "r":
196 if state == "r":
193 self.map[f] = ('r', 0, 0, 0)
197 self.map[f] = ('r', 0, 0, 0)
194 else:
198 else:
195 s = os.lstat(self.wjoin(f))
199 s = os.lstat(self.wjoin(f))
196 st_size = kw.get('st_size', s.st_size)
200 st_size = kw.get('st_size', s.st_size)
197 st_mtime = kw.get('st_mtime', s.st_mtime)
201 st_mtime = kw.get('st_mtime', s.st_mtime)
198 self.map[f] = (state, s.st_mode, st_size, st_mtime)
202 self.map[f] = (state, s.st_mode, st_size, st_mtime)
199 if self.copies.has_key(f):
203 if self.copies.has_key(f):
200 del self.copies[f]
204 del self.copies[f]
201
205
202 def forget(self, files):
206 def forget(self, files):
203 if not files: return
207 if not files: return
204 self.lazyread()
208 self.lazyread()
205 self.markdirty()
209 self.markdirty()
206 for f in files:
210 for f in files:
207 try:
211 try:
208 del self.map[f]
212 del self.map[f]
209 except KeyError:
213 except KeyError:
210 self.ui.warn(_("not in dirstate: %s!\n") % f)
214 self.ui.warn(_("not in dirstate: %s!\n") % f)
211 pass
215 pass
212
216
213 def clear(self):
217 def clear(self):
214 self.map = {}
218 self.map = {}
215 self.copies = {}
219 self.copies = {}
216 self.markdirty()
220 self.markdirty()
217
221
218 def rebuild(self, parent, files):
222 def rebuild(self, parent, files):
219 self.clear()
223 self.clear()
220 umask = os.umask(0)
224 umask = os.umask(0)
221 os.umask(umask)
225 os.umask(umask)
222 for f, mode in files:
226 for f, mode in files:
223 if mode:
227 if mode:
224 self.map[f] = ('n', ~umask, -1, 0)
228 self.map[f] = ('n', ~umask, -1, 0)
225 else:
229 else:
226 self.map[f] = ('n', ~umask & 0666, -1, 0)
230 self.map[f] = ('n', ~umask & 0666, -1, 0)
227 self.pl = (parent, nullid)
231 self.pl = (parent, nullid)
228 self.markdirty()
232 self.markdirty()
229
233
230 def write(self):
234 def write(self):
231 if not self.dirty:
235 if not self.dirty:
232 return
236 return
233 st = self.opener("dirstate", "w", atomic=True)
237 st = self.opener("dirstate", "w", atomic=True)
234 st.write("".join(self.pl))
238 st.write("".join(self.pl))
235 for f, e in self.map.items():
239 for f, e in self.map.items():
236 c = self.copied(f)
240 c = self.copied(f)
237 if c:
241 if c:
238 f = f + "\0" + c
242 f = f + "\0" + c
239 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f))
243 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f))
240 st.write(e + f)
244 st.write(e + f)
241 self.dirty = 0
245 self.dirty = 0
242
246
243 def filterfiles(self, files):
247 def filterfiles(self, files):
244 ret = {}
248 ret = {}
245 unknown = []
249 unknown = []
246
250
247 for x in files:
251 for x in files:
248 if x == '.':
252 if x == '.':
249 return self.map.copy()
253 return self.map.copy()
250 if x not in self.map:
254 if x not in self.map:
251 unknown.append(x)
255 unknown.append(x)
252 else:
256 else:
253 ret[x] = self.map[x]
257 ret[x] = self.map[x]
254
258
255 if not unknown:
259 if not unknown:
256 return ret
260 return ret
257
261
258 b = self.map.keys()
262 b = self.map.keys()
259 b.sort()
263 b.sort()
260 blen = len(b)
264 blen = len(b)
261
265
262 for x in unknown:
266 for x in unknown:
263 bs = bisect.bisect(b, x)
267 bs = bisect.bisect(b, x)
264 if bs != 0 and b[bs-1] == x:
268 if bs != 0 and b[bs-1] == x:
265 ret[x] = self.map[x]
269 ret[x] = self.map[x]
266 continue
270 continue
267 while bs < blen:
271 while bs < blen:
268 s = b[bs]
272 s = b[bs]
269 if len(s) > len(x) and s.startswith(x) and s[len(x)] == '/':
273 if len(s) > len(x) and s.startswith(x) and s[len(x)] == '/':
270 ret[s] = self.map[s]
274 ret[s] = self.map[s]
271 else:
275 else:
272 break
276 break
273 bs += 1
277 bs += 1
274 return ret
278 return ret
275
279
276 def supported_type(self, f, st, verbose=False):
280 def supported_type(self, f, st, verbose=False):
277 if stat.S_ISREG(st.st_mode):
281 if stat.S_ISREG(st.st_mode):
278 return True
282 return True
279 if verbose:
283 if verbose:
280 kind = 'unknown'
284 kind = 'unknown'
281 if stat.S_ISCHR(st.st_mode): kind = _('character device')
285 if stat.S_ISCHR(st.st_mode): kind = _('character device')
282 elif stat.S_ISBLK(st.st_mode): kind = _('block device')
286 elif stat.S_ISBLK(st.st_mode): kind = _('block device')
283 elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
287 elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
284 elif stat.S_ISLNK(st.st_mode): kind = _('symbolic link')
288 elif stat.S_ISLNK(st.st_mode): kind = _('symbolic link')
285 elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
289 elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
286 elif stat.S_ISDIR(st.st_mode): kind = _('directory')
290 elif stat.S_ISDIR(st.st_mode): kind = _('directory')
287 self.ui.warn(_('%s: unsupported file type (type is %s)\n') % (
291 self.ui.warn(_('%s: unsupported file type (type is %s)\n') % (
288 util.pathto(self.getcwd(), f),
292 util.pathto(self.getcwd(), f),
289 kind))
293 kind))
290 return False
294 return False
291
295
292 def statwalk(self, files=None, match=util.always, dc=None):
296 def statwalk(self, files=None, match=util.always, dc=None):
293 self.lazyread()
297 self.lazyread()
294
298
295 # walk all files by default
299 # walk all files by default
296 if not files:
300 if not files:
297 files = [self.root]
301 files = [self.root]
298 if not dc:
302 if not dc:
299 dc = self.map.copy()
303 dc = self.map.copy()
300 elif not dc:
304 elif not dc:
301 dc = self.filterfiles(files)
305 dc = self.filterfiles(files)
302
306
303 def statmatch(file_, stat):
307 def statmatch(file_, stat):
304 file_ = util.pconvert(file_)
308 file_ = util.pconvert(file_)
305 if file_ not in dc and self.ignore(file_):
309 if file_ not in dc and self.ignore(file_):
306 return False
310 return False
307 return match(file_)
311 return match(file_)
308
312
309 return self.walkhelper(files=files, statmatch=statmatch, dc=dc)
313 return self.walkhelper(files=files, statmatch=statmatch, dc=dc)
310
314
311 def walk(self, files=None, match=util.always, dc=None):
315 def walk(self, files=None, match=util.always, dc=None):
312 # filter out the stat
316 # filter out the stat
313 for src, f, st in self.statwalk(files, match, dc):
317 for src, f, st in self.statwalk(files, match, dc):
314 yield src, f
318 yield src, f
315
319
316 # walk recursively through the directory tree, finding all files
320 # walk recursively through the directory tree, finding all files
317 # matched by the statmatch function
321 # matched by the statmatch function
318 #
322 #
319 # results are yielded in a tuple (src, filename, st), where src
323 # results are yielded in a tuple (src, filename, st), where src
320 # is one of:
324 # is one of:
321 # 'f' the file was found in the directory tree
325 # 'f' the file was found in the directory tree
322 # 'm' the file was only in the dirstate and not in the tree
326 # 'm' the file was only in the dirstate and not in the tree
323 # and st is the stat result if the file was found in the directory.
327 # and st is the stat result if the file was found in the directory.
324 #
328 #
325 # dc is an optional arg for the current dirstate. dc is not modified
329 # dc is an optional arg for the current dirstate. dc is not modified
326 # directly by this function, but might be modified by your statmatch call.
330 # directly by this function, but might be modified by your statmatch call.
327 #
331 #
328 def walkhelper(self, files, statmatch, dc):
332 def walkhelper(self, files, statmatch, dc):
329 # recursion free walker, faster than os.walk.
333 # recursion free walker, faster than os.walk.
330 def findfiles(s):
334 def findfiles(s):
331 work = [s]
335 work = [s]
332 while work:
336 while work:
333 top = work.pop()
337 top = work.pop()
334 names = os.listdir(top)
338 names = os.listdir(top)
335 names.sort()
339 names.sort()
336 # nd is the top of the repository dir tree
340 # nd is the top of the repository dir tree
337 nd = util.normpath(top[len(self.root) + 1:])
341 nd = util.normpath(top[len(self.root) + 1:])
338 if nd == '.': nd = ''
342 if nd == '.': nd = ''
339 for f in names:
343 for f in names:
340 np = util.pconvert(os.path.join(nd, f))
344 np = util.pconvert(os.path.join(nd, f))
341 if seen(np):
345 if seen(np):
342 continue
346 continue
343 p = os.path.join(top, f)
347 p = os.path.join(top, f)
344 # don't trip over symlinks
348 # don't trip over symlinks
345 st = os.lstat(p)
349 st = os.lstat(p)
346 if stat.S_ISDIR(st.st_mode):
350 if stat.S_ISDIR(st.st_mode):
347 ds = os.path.join(nd, f +'/')
351 ds = os.path.join(nd, f +'/')
348 if statmatch(ds, st):
352 if statmatch(ds, st):
349 work.append(p)
353 work.append(p)
350 if statmatch(np, st) and np in dc:
354 if statmatch(np, st) and np in dc:
351 yield 'm', np, st
355 yield 'm', np, st
352 elif statmatch(np, st):
356 elif statmatch(np, st):
353 if self.supported_type(np, st):
357 if self.supported_type(np, st):
354 yield 'f', np, st
358 yield 'f', np, st
355 elif np in dc:
359 elif np in dc:
356 yield 'm', np, st
360 yield 'm', np, st
357
361
358 known = {'.hg': 1}
362 known = {'.hg': 1}
359 def seen(fn):
363 def seen(fn):
360 if fn in known: return True
364 if fn in known: return True
361 known[fn] = 1
365 known[fn] = 1
362
366
363 # step one, find all files that match our criteria
367 # step one, find all files that match our criteria
364 files.sort()
368 files.sort()
365 for ff in util.unique(files):
369 for ff in util.unique(files):
366 f = self.wjoin(ff)
370 f = self.wjoin(ff)
367 try:
371 try:
368 st = os.lstat(f)
372 st = os.lstat(f)
369 except OSError, inst:
373 except OSError, inst:
370 nf = util.normpath(ff)
374 nf = util.normpath(ff)
371 found = False
375 found = False
372 for fn in dc:
376 for fn in dc:
373 if nf == fn or (fn.startswith(nf) and fn[len(nf)] == '/'):
377 if nf == fn or (fn.startswith(nf) and fn[len(nf)] == '/'):
374 found = True
378 found = True
375 break
379 break
376 if not found:
380 if not found:
377 self.ui.warn('%s: %s\n' % (
381 self.ui.warn('%s: %s\n' % (
378 util.pathto(self.getcwd(), ff),
382 util.pathto(self.getcwd(), ff),
379 inst.strerror))
383 inst.strerror))
380 continue
384 continue
381 if stat.S_ISDIR(st.st_mode):
385 if stat.S_ISDIR(st.st_mode):
382 cmp1 = (lambda x, y: cmp(x[1], y[1]))
386 cmp1 = (lambda x, y: cmp(x[1], y[1]))
383 sorted_ = [ x for x in findfiles(f) ]
387 sorted_ = [ x for x in findfiles(f) ]
384 sorted_.sort(cmp1)
388 sorted_.sort(cmp1)
385 for e in sorted_:
389 for e in sorted_:
386 yield e
390 yield e
387 else:
391 else:
388 ff = util.normpath(ff)
392 ff = util.normpath(ff)
389 if seen(ff):
393 if seen(ff):
390 continue
394 continue
391 self.blockignore = True
395 self.blockignore = True
392 if statmatch(ff, st):
396 if statmatch(ff, st):
393 if self.supported_type(ff, st, verbose=True):
397 if self.supported_type(ff, st, verbose=True):
394 yield 'f', ff, st
398 yield 'f', ff, st
395 elif ff in dc:
399 elif ff in dc:
396 yield 'm', ff, st
400 yield 'm', ff, st
397 self.blockignore = False
401 self.blockignore = False
398
402
399 # step two run through anything left in the dc hash and yield
403 # step two run through anything left in the dc hash and yield
400 # if we haven't already seen it
404 # if we haven't already seen it
401 ks = dc.keys()
405 ks = dc.keys()
402 ks.sort()
406 ks.sort()
403 for k in ks:
407 for k in ks:
404 if not seen(k) and (statmatch(k, None)):
408 if not seen(k) and (statmatch(k, None)):
405 yield 'm', k, None
409 yield 'm', k, None
406
410
407 def changes(self, files=None, match=util.always):
411 def changes(self, files=None, match=util.always):
408 lookup, modified, added, unknown = [], [], [], []
412 lookup, modified, added, unknown = [], [], [], []
409 removed, deleted = [], []
413 removed, deleted = [], []
410
414
411 for src, fn, st in self.statwalk(files, match):
415 for src, fn, st in self.statwalk(files, match):
412 try:
416 try:
413 type_, mode, size, time = self[fn]
417 type_, mode, size, time = self[fn]
414 except KeyError:
418 except KeyError:
415 unknown.append(fn)
419 unknown.append(fn)
416 continue
420 continue
417 if src == 'm':
421 if src == 'm':
418 nonexistent = True
422 nonexistent = True
419 if not st:
423 if not st:
420 try:
424 try:
421 f = self.wjoin(fn)
425 f = self.wjoin(fn)
422 st = os.lstat(f)
426 st = os.lstat(f)
423 except OSError, inst:
427 except OSError, inst:
424 if inst.errno != errno.ENOENT:
428 if inst.errno != errno.ENOENT:
425 raise
429 raise
426 st = None
430 st = None
427 # We need to re-check that it is a valid file
431 # We need to re-check that it is a valid file
428 if st and self.supported_type(fn, st):
432 if st and self.supported_type(fn, st):
429 nonexistent = False
433 nonexistent = False
430 # XXX: what to do with file no longer present in the fs
434 # XXX: what to do with file no longer present in the fs
431 # who are not removed in the dirstate ?
435 # who are not removed in the dirstate ?
432 if nonexistent and type_ in "nm":
436 if nonexistent and type_ in "nm":
433 deleted.append(fn)
437 deleted.append(fn)
434 continue
438 continue
435 # check the common case first
439 # check the common case first
436 if type_ == 'n':
440 if type_ == 'n':
437 if not st:
441 if not st:
438 st = os.stat(fn)
442 st = os.stat(fn)
439 if size >= 0 and (size != st.st_size
443 if size >= 0 and (size != st.st_size
440 or (mode ^ st.st_mode) & 0100):
444 or (mode ^ st.st_mode) & 0100):
441 modified.append(fn)
445 modified.append(fn)
442 elif time != st.st_mtime:
446 elif time != st.st_mtime:
443 lookup.append(fn)
447 lookup.append(fn)
444 elif type_ == 'm':
448 elif type_ == 'm':
445 modified.append(fn)
449 modified.append(fn)
446 elif type_ == 'a':
450 elif type_ == 'a':
447 added.append(fn)
451 added.append(fn)
448 elif type_ == 'r':
452 elif type_ == 'r':
449 removed.append(fn)
453 removed.append(fn)
450
454
451 return (lookup, modified, added, removed, deleted, unknown)
455 return (lookup, modified, added, removed, deleted, unknown)
General Comments 0
You need to be logged in to leave comments. Login now