##// END OF EJS Templates
dirstate.invalidate: clear dirty flag
Alexis S. L. Carvalho -
r4657:27a386b9 default
parent child Browse files
Show More
@@ -1,489 +1,490 b''
1 """
1 """
2 dirstate.py - working directory tracking for mercurial
2 dirstate.py - working directory tracking for mercurial
3
3
4 Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 Copyright 2005-2007 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 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, ignore
12 import struct, os, time, bisect, stat, strutil, util, re, errno, ignore
13 import cStringIO
13 import cStringIO
14
14
15 _unknown = ('?', 0, 0, 0)
15 _unknown = ('?', 0, 0, 0)
16 _format = ">cllll"
16 _format = ">cllll"
17
17
18 class dirstate(object):
18 class dirstate(object):
19
19
20 def __init__(self, opener, ui, root):
20 def __init__(self, opener, ui, root):
21 self._opener = opener
21 self._opener = opener
22 self._root = root
22 self._root = root
23 self._dirty = 0
23 self._dirty = 0
24 self._ui = ui
24 self._ui = ui
25
25
26 def __getattr__(self, name):
26 def __getattr__(self, name):
27 if name == '_map':
27 if name == '_map':
28 self._read()
28 self._read()
29 return self._map
29 return self._map
30 elif name == '_copymap':
30 elif name == '_copymap':
31 self._read()
31 self._read()
32 return self._copymap
32 return self._copymap
33 elif name == '_branch':
33 elif name == '_branch':
34 try:
34 try:
35 self._branch = (self._opener("branch").read().strip()
35 self._branch = (self._opener("branch").read().strip()
36 or "default")
36 or "default")
37 except IOError:
37 except IOError:
38 self._branch = "default"
38 self._branch = "default"
39 return self._branch
39 return self._branch
40 elif name == '_pl':
40 elif name == '_pl':
41 self._pl = [nullid, nullid]
41 self._pl = [nullid, nullid]
42 try:
42 try:
43 st = self._opener("dirstate").read(40)
43 st = self._opener("dirstate").read(40)
44 if len(st) == 40:
44 if len(st) == 40:
45 self._pl = st[:20], st[20:40]
45 self._pl = st[:20], st[20:40]
46 except IOError, err:
46 except IOError, err:
47 if err.errno != errno.ENOENT: raise
47 if err.errno != errno.ENOENT: raise
48 return self._pl
48 return self._pl
49 elif name == '_dirs':
49 elif name == '_dirs':
50 self._dirs = {}
50 self._dirs = {}
51 for f in self._map:
51 for f in self._map:
52 self._incpath(f)
52 self._incpath(f)
53 return self._dirs
53 return self._dirs
54 elif name == '_ignore':
54 elif name == '_ignore':
55 files = [self.wjoin('.hgignore')]
55 files = [self.wjoin('.hgignore')]
56 for name, path in self._ui.configitems("ui"):
56 for name, path in self._ui.configitems("ui"):
57 if name == 'ignore' or name.startswith('ignore.'):
57 if name == 'ignore' or name.startswith('ignore.'):
58 files.append(os.path.expanduser(path))
58 files.append(os.path.expanduser(path))
59 self._ignore = ignore.ignore(self._root, files, self._ui.warn)
59 self._ignore = ignore.ignore(self._root, files, self._ui.warn)
60 return self._ignore
60 return self._ignore
61 elif name == '_slash':
61 elif name == '_slash':
62 self._slash = self._ui.configbool('ui', 'slash') and os.sep != '/'
62 self._slash = self._ui.configbool('ui', 'slash') and os.sep != '/'
63 return self._slash
63 return self._slash
64 else:
64 else:
65 raise AttributeError, name
65 raise AttributeError, name
66
66
67 def wjoin(self, f):
67 def wjoin(self, f):
68 return os.path.join(self._root, f)
68 return os.path.join(self._root, f)
69
69
70 def getcwd(self):
70 def getcwd(self):
71 cwd = os.getcwd()
71 cwd = os.getcwd()
72 if cwd == self._root: return ''
72 if cwd == self._root: return ''
73 # self._root ends with a path separator if self._root is '/' or 'C:\'
73 # self._root ends with a path separator if self._root is '/' or 'C:\'
74 rootsep = self._root
74 rootsep = self._root
75 if not rootsep.endswith(os.sep):
75 if not rootsep.endswith(os.sep):
76 rootsep += os.sep
76 rootsep += os.sep
77 if cwd.startswith(rootsep):
77 if cwd.startswith(rootsep):
78 return cwd[len(rootsep):]
78 return cwd[len(rootsep):]
79 else:
79 else:
80 # we're outside the repo. return an absolute path.
80 # we're outside the repo. return an absolute path.
81 return cwd
81 return cwd
82
82
83 def pathto(self, f, cwd=None):
83 def pathto(self, f, cwd=None):
84 if cwd is None:
84 if cwd is None:
85 cwd = self.getcwd()
85 cwd = self.getcwd()
86 path = util.pathto(self._root, cwd, f)
86 path = util.pathto(self._root, cwd, f)
87 if self._slash:
87 if self._slash:
88 return path.replace(os.sep, '/')
88 return path.replace(os.sep, '/')
89 return path
89 return path
90
90
91 def __del__(self):
91 def __del__(self):
92 self.write()
92 self.write()
93
93
94 def __getitem__(self, key):
94 def __getitem__(self, key):
95 return self._map[key]
95 return self._map[key]
96
96
97 def __contains__(self, key):
97 def __contains__(self, key):
98 return key in self._map
98 return key in self._map
99
99
100 def __iter__(self):
100 def __iter__(self):
101 a = self._map.keys()
101 a = self._map.keys()
102 a.sort()
102 a.sort()
103 for x in a:
103 for x in a:
104 yield x
104 yield x
105
105
106 def parents(self):
106 def parents(self):
107 return self._pl
107 return self._pl
108
108
109 def branch(self):
109 def branch(self):
110 return self._branch
110 return self._branch
111
111
112 def markdirty(self):
112 def markdirty(self):
113 self._dirty = 1
113 self._dirty = 1
114
114
115 def setparents(self, p1, p2=nullid):
115 def setparents(self, p1, p2=nullid):
116 self.markdirty()
116 self.markdirty()
117 self._pl = p1, p2
117 self._pl = p1, p2
118
118
119 def setbranch(self, branch):
119 def setbranch(self, branch):
120 self._branch = branch
120 self._branch = branch
121 self._opener("branch", "w").write(branch + '\n')
121 self._opener("branch", "w").write(branch + '\n')
122
122
123 def state(self, key):
123 def state(self, key):
124 return self._map.get(key, ("?",))[0]
124 return self._map.get(key, ("?",))[0]
125
125
126 def _read(self):
126 def _read(self):
127 self._map = {}
127 self._map = {}
128 self._copymap = {}
128 self._copymap = {}
129 self._pl = [nullid, nullid]
129 self._pl = [nullid, nullid]
130 try:
130 try:
131 st = self._opener("dirstate").read()
131 st = self._opener("dirstate").read()
132 except IOError, err:
132 except IOError, err:
133 if err.errno != errno.ENOENT: raise
133 if err.errno != errno.ENOENT: raise
134 return
134 return
135 if not st:
135 if not st:
136 return
136 return
137
137
138 self._pl = [st[:20], st[20: 40]]
138 self._pl = [st[:20], st[20: 40]]
139
139
140 # deref fields so they will be local in loop
140 # deref fields so they will be local in loop
141 dmap = self._map
141 dmap = self._map
142 copymap = self._copymap
142 copymap = self._copymap
143 unpack = struct.unpack
143 unpack = struct.unpack
144
144
145 pos = 40
145 pos = 40
146 e_size = struct.calcsize(_format)
146 e_size = struct.calcsize(_format)
147
147
148 while pos < len(st):
148 while pos < len(st):
149 newpos = pos + e_size
149 newpos = pos + e_size
150 e = unpack(_format, st[pos:newpos])
150 e = unpack(_format, st[pos:newpos])
151 l = e[4]
151 l = e[4]
152 pos = newpos
152 pos = newpos
153 newpos = pos + l
153 newpos = pos + l
154 f = st[pos:newpos]
154 f = st[pos:newpos]
155 if '\0' in f:
155 if '\0' in f:
156 f, c = f.split('\0')
156 f, c = f.split('\0')
157 copymap[f] = c
157 copymap[f] = c
158 dmap[f] = e[:4]
158 dmap[f] = e[:4]
159 pos = newpos
159 pos = newpos
160
160
161 def invalidate(self):
161 def invalidate(self):
162 for a in "_map _copymap _branch _pl _dirs _ignore".split():
162 for a in "_map _copymap _branch _pl _dirs _ignore".split():
163 if hasattr(self, a):
163 if hasattr(self, a):
164 self.__delattr__(a)
164 self.__delattr__(a)
165 self._dirty = 0
165
166
166 def copy(self, source, dest):
167 def copy(self, source, dest):
167 self.markdirty()
168 self.markdirty()
168 self._copymap[dest] = source
169 self._copymap[dest] = source
169
170
170 def copied(self, file):
171 def copied(self, file):
171 return self._copymap.get(file, None)
172 return self._copymap.get(file, None)
172
173
173 def copies(self):
174 def copies(self):
174 return self._copymap
175 return self._copymap
175
176
176 def _incpath(self, path):
177 def _incpath(self, path):
177 for c in strutil.findall(path, '/'):
178 for c in strutil.findall(path, '/'):
178 pc = path[:c]
179 pc = path[:c]
179 self._dirs.setdefault(pc, 0)
180 self._dirs.setdefault(pc, 0)
180 self._dirs[pc] += 1
181 self._dirs[pc] += 1
181
182
182 def _decpath(self, path):
183 def _decpath(self, path):
183 for c in strutil.findall(path, '/'):
184 for c in strutil.findall(path, '/'):
184 pc = path[:c]
185 pc = path[:c]
185 self._dirs.setdefault(pc, 0)
186 self._dirs.setdefault(pc, 0)
186 self._dirs[pc] -= 1
187 self._dirs[pc] -= 1
187
188
188 def _incpathcheck(self, f):
189 def _incpathcheck(self, f):
189 if '\r' in f or '\n' in f:
190 if '\r' in f or '\n' in f:
190 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames"))
191 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames"))
191 # shadows
192 # shadows
192 if f in self._dirs:
193 if f in self._dirs:
193 raise util.Abort(_('directory named %r already in dirstate') % f)
194 raise util.Abort(_('directory named %r already in dirstate') % f)
194 for c in strutil.rfindall(f, '/'):
195 for c in strutil.rfindall(f, '/'):
195 d = f[:c]
196 d = f[:c]
196 if d in self._dirs:
197 if d in self._dirs:
197 break
198 break
198 if d in self._map:
199 if d in self._map:
199 raise util.Abort(_('file named %r already in dirstate') % d)
200 raise util.Abort(_('file named %r already in dirstate') % d)
200 self._incpath(f)
201 self._incpath(f)
201
202
202 def update(self, files, state, **kw):
203 def update(self, files, state, **kw):
203 ''' current states:
204 ''' current states:
204 n normal
205 n normal
205 m needs merging
206 m needs merging
206 r marked for removal
207 r marked for removal
207 a marked for addition'''
208 a marked for addition'''
208
209
209 if not files: return
210 if not files: return
210 self.markdirty()
211 self.markdirty()
211 for f in files:
212 for f in files:
212 if self._copymap.has_key(f):
213 if self._copymap.has_key(f):
213 del self._copymap[f]
214 del self._copymap[f]
214
215
215 if state == "r":
216 if state == "r":
216 self._map[f] = ('r', 0, 0, 0)
217 self._map[f] = ('r', 0, 0, 0)
217 self._decpath(f)
218 self._decpath(f)
218 continue
219 continue
219 else:
220 else:
220 if state == "a":
221 if state == "a":
221 self._incpathcheck(f)
222 self._incpathcheck(f)
222 s = os.lstat(self.wjoin(f))
223 s = os.lstat(self.wjoin(f))
223 st_size = kw.get('st_size', s.st_size)
224 st_size = kw.get('st_size', s.st_size)
224 st_mtime = kw.get('st_mtime', s.st_mtime)
225 st_mtime = kw.get('st_mtime', s.st_mtime)
225 self._map[f] = (state, s.st_mode, st_size, st_mtime)
226 self._map[f] = (state, s.st_mode, st_size, st_mtime)
226
227
227 def forget(self, files):
228 def forget(self, files):
228 if not files: return
229 if not files: return
229 self.markdirty()
230 self.markdirty()
230 for f in files:
231 for f in files:
231 try:
232 try:
232 del self._map[f]
233 del self._map[f]
233 self._decpath(f)
234 self._decpath(f)
234 except KeyError:
235 except KeyError:
235 self._ui.warn(_("not in dirstate: %s!\n") % f)
236 self._ui.warn(_("not in dirstate: %s!\n") % f)
236 pass
237 pass
237
238
238 def rebuild(self, parent, files):
239 def rebuild(self, parent, files):
239 self.invalidate()
240 self.invalidate()
240 for f in files:
241 for f in files:
241 if files.execf(f):
242 if files.execf(f):
242 self._map[f] = ('n', 0777, -1, 0)
243 self._map[f] = ('n', 0777, -1, 0)
243 else:
244 else:
244 self._map[f] = ('n', 0666, -1, 0)
245 self._map[f] = ('n', 0666, -1, 0)
245 self._pl = (parent, nullid)
246 self._pl = (parent, nullid)
246 self.markdirty()
247 self.markdirty()
247
248
248 def write(self):
249 def write(self):
249 if not self._dirty:
250 if not self._dirty:
250 return
251 return
251 cs = cStringIO.StringIO()
252 cs = cStringIO.StringIO()
252 cs.write("".join(self._pl))
253 cs.write("".join(self._pl))
253 for f, e in self._map.iteritems():
254 for f, e in self._map.iteritems():
254 c = self.copied(f)
255 c = self.copied(f)
255 if c:
256 if c:
256 f = f + "\0" + c
257 f = f + "\0" + c
257 e = struct.pack(_format, e[0], e[1], e[2], e[3], len(f))
258 e = struct.pack(_format, e[0], e[1], e[2], e[3], len(f))
258 cs.write(e)
259 cs.write(e)
259 cs.write(f)
260 cs.write(f)
260 st = self._opener("dirstate", "w", atomictemp=True)
261 st = self._opener("dirstate", "w", atomictemp=True)
261 st.write(cs.getvalue())
262 st.write(cs.getvalue())
262 st.rename()
263 st.rename()
263 self._dirty = 0
264 self._dirty = 0
264
265
265 def filterfiles(self, files):
266 def filterfiles(self, files):
266 ret = {}
267 ret = {}
267 unknown = []
268 unknown = []
268
269
269 for x in files:
270 for x in files:
270 if x == '.':
271 if x == '.':
271 return self._map.copy()
272 return self._map.copy()
272 if x not in self._map:
273 if x not in self._map:
273 unknown.append(x)
274 unknown.append(x)
274 else:
275 else:
275 ret[x] = self._map[x]
276 ret[x] = self._map[x]
276
277
277 if not unknown:
278 if not unknown:
278 return ret
279 return ret
279
280
280 b = self._map.keys()
281 b = self._map.keys()
281 b.sort()
282 b.sort()
282 blen = len(b)
283 blen = len(b)
283
284
284 for x in unknown:
285 for x in unknown:
285 bs = bisect.bisect(b, "%s%s" % (x, '/'))
286 bs = bisect.bisect(b, "%s%s" % (x, '/'))
286 while bs < blen:
287 while bs < blen:
287 s = b[bs]
288 s = b[bs]
288 if len(s) > len(x) and s.startswith(x):
289 if len(s) > len(x) and s.startswith(x):
289 ret[s] = self._map[s]
290 ret[s] = self._map[s]
290 else:
291 else:
291 break
292 break
292 bs += 1
293 bs += 1
293 return ret
294 return ret
294
295
295 def _supported(self, f, st, verbose=False):
296 def _supported(self, f, st, verbose=False):
296 if stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
297 if stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
297 return True
298 return True
298 if verbose:
299 if verbose:
299 kind = 'unknown'
300 kind = 'unknown'
300 if stat.S_ISCHR(st.st_mode): kind = _('character device')
301 if stat.S_ISCHR(st.st_mode): kind = _('character device')
301 elif stat.S_ISBLK(st.st_mode): kind = _('block device')
302 elif stat.S_ISBLK(st.st_mode): kind = _('block device')
302 elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
303 elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
303 elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
304 elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
304 elif stat.S_ISDIR(st.st_mode): kind = _('directory')
305 elif stat.S_ISDIR(st.st_mode): kind = _('directory')
305 self._ui.warn(_('%s: unsupported file type (type is %s)\n')
306 self._ui.warn(_('%s: unsupported file type (type is %s)\n')
306 % (self.pathto(f), kind))
307 % (self.pathto(f), kind))
307 return False
308 return False
308
309
309 def walk(self, files=None, match=util.always, badmatch=None):
310 def walk(self, files=None, match=util.always, badmatch=None):
310 # filter out the stat
311 # filter out the stat
311 for src, f, st in self.statwalk(files, match, badmatch=badmatch):
312 for src, f, st in self.statwalk(files, match, badmatch=badmatch):
312 yield src, f
313 yield src, f
313
314
314 def statwalk(self, files=None, match=util.always, ignored=False,
315 def statwalk(self, files=None, match=util.always, ignored=False,
315 badmatch=None, directories=False):
316 badmatch=None, directories=False):
316 '''
317 '''
317 walk recursively through the directory tree, finding all files
318 walk recursively through the directory tree, finding all files
318 matched by the match function
319 matched by the match function
319
320
320 results are yielded in a tuple (src, filename, st), where src
321 results are yielded in a tuple (src, filename, st), where src
321 is one of:
322 is one of:
322 'f' the file was found in the directory tree
323 'f' the file was found in the directory tree
323 'd' the file is a directory of the tree
324 'd' the file is a directory of the tree
324 'm' the file was only in the dirstate and not in the tree
325 'm' the file was only in the dirstate and not in the tree
325 'b' file was not found and matched badmatch
326 'b' file was not found and matched badmatch
326
327
327 and st is the stat result if the file was found in the directory.
328 and st is the stat result if the file was found in the directory.
328 '''
329 '''
329
330
330 # walk all files by default
331 # walk all files by default
331 if not files:
332 if not files:
332 files = ['.']
333 files = ['.']
333 dc = self._map.copy()
334 dc = self._map.copy()
334 else:
335 else:
335 files = util.unique(files)
336 files = util.unique(files)
336 dc = self.filterfiles(files)
337 dc = self.filterfiles(files)
337
338
338 def imatch(file_):
339 def imatch(file_):
339 if file_ not in dc and self._ignore(file_):
340 if file_ not in dc and self._ignore(file_):
340 return False
341 return False
341 return match(file_)
342 return match(file_)
342
343
343 ignore = self._ignore
344 ignore = self._ignore
344 if ignored:
345 if ignored:
345 imatch = match
346 imatch = match
346 ignore = util.never
347 ignore = util.never
347
348
348 # self._root may end with a path separator when self._root == '/'
349 # self._root may end with a path separator when self._root == '/'
349 common_prefix_len = len(self._root)
350 common_prefix_len = len(self._root)
350 if not self._root.endswith(os.sep):
351 if not self._root.endswith(os.sep):
351 common_prefix_len += 1
352 common_prefix_len += 1
352 # recursion free walker, faster than os.walk.
353 # recursion free walker, faster than os.walk.
353 def findfiles(s):
354 def findfiles(s):
354 work = [s]
355 work = [s]
355 if directories:
356 if directories:
356 yield 'd', util.normpath(s[common_prefix_len:]), os.lstat(s)
357 yield 'd', util.normpath(s[common_prefix_len:]), os.lstat(s)
357 while work:
358 while work:
358 top = work.pop()
359 top = work.pop()
359 names = os.listdir(top)
360 names = os.listdir(top)
360 names.sort()
361 names.sort()
361 # nd is the top of the repository dir tree
362 # nd is the top of the repository dir tree
362 nd = util.normpath(top[common_prefix_len:])
363 nd = util.normpath(top[common_prefix_len:])
363 if nd == '.':
364 if nd == '.':
364 nd = ''
365 nd = ''
365 else:
366 else:
366 # do not recurse into a repo contained in this
367 # do not recurse into a repo contained in this
367 # one. use bisect to find .hg directory so speed
368 # one. use bisect to find .hg directory so speed
368 # is good on big directory.
369 # is good on big directory.
369 hg = bisect.bisect_left(names, '.hg')
370 hg = bisect.bisect_left(names, '.hg')
370 if hg < len(names) and names[hg] == '.hg':
371 if hg < len(names) and names[hg] == '.hg':
371 if os.path.isdir(os.path.join(top, '.hg')):
372 if os.path.isdir(os.path.join(top, '.hg')):
372 continue
373 continue
373 for f in names:
374 for f in names:
374 np = util.pconvert(os.path.join(nd, f))
375 np = util.pconvert(os.path.join(nd, f))
375 if seen(np):
376 if seen(np):
376 continue
377 continue
377 p = os.path.join(top, f)
378 p = os.path.join(top, f)
378 # don't trip over symlinks
379 # don't trip over symlinks
379 st = os.lstat(p)
380 st = os.lstat(p)
380 if stat.S_ISDIR(st.st_mode):
381 if stat.S_ISDIR(st.st_mode):
381 if not ignore(np):
382 if not ignore(np):
382 work.append(p)
383 work.append(p)
383 if directories:
384 if directories:
384 yield 'd', np, st
385 yield 'd', np, st
385 if imatch(np) and np in dc:
386 if imatch(np) and np in dc:
386 yield 'm', np, st
387 yield 'm', np, st
387 elif imatch(np):
388 elif imatch(np):
388 if self._supported(np, st):
389 if self._supported(np, st):
389 yield 'f', np, st
390 yield 'f', np, st
390 elif np in dc:
391 elif np in dc:
391 yield 'm', np, st
392 yield 'm', np, st
392
393
393 known = {'.hg': 1}
394 known = {'.hg': 1}
394 def seen(fn):
395 def seen(fn):
395 if fn in known: return True
396 if fn in known: return True
396 known[fn] = 1
397 known[fn] = 1
397
398
398 # step one, find all files that match our criteria
399 # step one, find all files that match our criteria
399 files.sort()
400 files.sort()
400 for ff in files:
401 for ff in files:
401 nf = util.normpath(ff)
402 nf = util.normpath(ff)
402 f = self.wjoin(ff)
403 f = self.wjoin(ff)
403 try:
404 try:
404 st = os.lstat(f)
405 st = os.lstat(f)
405 except OSError, inst:
406 except OSError, inst:
406 found = False
407 found = False
407 for fn in dc:
408 for fn in dc:
408 if nf == fn or (fn.startswith(nf) and fn[len(nf)] == '/'):
409 if nf == fn or (fn.startswith(nf) and fn[len(nf)] == '/'):
409 found = True
410 found = True
410 break
411 break
411 if not found:
412 if not found:
412 if inst.errno != errno.ENOENT or not badmatch:
413 if inst.errno != errno.ENOENT or not badmatch:
413 self._ui.warn('%s: %s\n' %
414 self._ui.warn('%s: %s\n' %
414 (self.pathto(ff), inst.strerror))
415 (self.pathto(ff), inst.strerror))
415 elif badmatch and badmatch(ff) and imatch(nf):
416 elif badmatch and badmatch(ff) and imatch(nf):
416 yield 'b', ff, None
417 yield 'b', ff, None
417 continue
418 continue
418 if stat.S_ISDIR(st.st_mode):
419 if stat.S_ISDIR(st.st_mode):
419 cmp1 = (lambda x, y: cmp(x[1], y[1]))
420 cmp1 = (lambda x, y: cmp(x[1], y[1]))
420 sorted_ = [ x for x in findfiles(f) ]
421 sorted_ = [ x for x in findfiles(f) ]
421 sorted_.sort(cmp1)
422 sorted_.sort(cmp1)
422 for e in sorted_:
423 for e in sorted_:
423 yield e
424 yield e
424 else:
425 else:
425 if not seen(nf) and match(nf):
426 if not seen(nf) and match(nf):
426 if self._supported(ff, st, verbose=True):
427 if self._supported(ff, st, verbose=True):
427 yield 'f', nf, st
428 yield 'f', nf, st
428 elif ff in dc:
429 elif ff in dc:
429 yield 'm', nf, st
430 yield 'm', nf, st
430
431
431 # step two run through anything left in the dc hash and yield
432 # step two run through anything left in the dc hash and yield
432 # if we haven't already seen it
433 # if we haven't already seen it
433 ks = dc.keys()
434 ks = dc.keys()
434 ks.sort()
435 ks.sort()
435 for k in ks:
436 for k in ks:
436 if not seen(k) and imatch(k):
437 if not seen(k) and imatch(k):
437 yield 'm', k, None
438 yield 'm', k, None
438
439
439 def status(self, files=None, match=util.always, list_ignored=False,
440 def status(self, files=None, match=util.always, list_ignored=False,
440 list_clean=False):
441 list_clean=False):
441 lookup, modified, added, unknown, ignored = [], [], [], [], []
442 lookup, modified, added, unknown, ignored = [], [], [], [], []
442 removed, deleted, clean = [], [], []
443 removed, deleted, clean = [], [], []
443
444
444 for src, fn, st in self.statwalk(files, match, ignored=list_ignored):
445 for src, fn, st in self.statwalk(files, match, ignored=list_ignored):
445 try:
446 try:
446 type_, mode, size, time = self[fn]
447 type_, mode, size, time = self[fn]
447 except KeyError:
448 except KeyError:
448 if list_ignored and self._ignore(fn):
449 if list_ignored and self._ignore(fn):
449 ignored.append(fn)
450 ignored.append(fn)
450 else:
451 else:
451 unknown.append(fn)
452 unknown.append(fn)
452 continue
453 continue
453 if src == 'm':
454 if src == 'm':
454 nonexistent = True
455 nonexistent = True
455 if not st:
456 if not st:
456 try:
457 try:
457 st = os.lstat(self.wjoin(fn))
458 st = os.lstat(self.wjoin(fn))
458 except OSError, inst:
459 except OSError, inst:
459 if inst.errno != errno.ENOENT:
460 if inst.errno != errno.ENOENT:
460 raise
461 raise
461 st = None
462 st = None
462 # We need to re-check that it is a valid file
463 # We need to re-check that it is a valid file
463 if st and self._supported(fn, st):
464 if st and self._supported(fn, st):
464 nonexistent = False
465 nonexistent = False
465 # XXX: what to do with file no longer present in the fs
466 # XXX: what to do with file no longer present in the fs
466 # who are not removed in the dirstate ?
467 # who are not removed in the dirstate ?
467 if nonexistent and type_ in "nm":
468 if nonexistent and type_ in "nm":
468 deleted.append(fn)
469 deleted.append(fn)
469 continue
470 continue
470 # check the common case first
471 # check the common case first
471 if type_ == 'n':
472 if type_ == 'n':
472 if not st:
473 if not st:
473 st = os.lstat(self.wjoin(fn))
474 st = os.lstat(self.wjoin(fn))
474 if size >= 0 and (size != st.st_size
475 if size >= 0 and (size != st.st_size
475 or (mode ^ st.st_mode) & 0100):
476 or (mode ^ st.st_mode) & 0100):
476 modified.append(fn)
477 modified.append(fn)
477 elif time != int(st.st_mtime):
478 elif time != int(st.st_mtime):
478 lookup.append(fn)
479 lookup.append(fn)
479 elif list_clean:
480 elif list_clean:
480 clean.append(fn)
481 clean.append(fn)
481 elif type_ == 'm':
482 elif type_ == 'm':
482 modified.append(fn)
483 modified.append(fn)
483 elif type_ == 'a':
484 elif type_ == 'a':
484 added.append(fn)
485 added.append(fn)
485 elif type_ == 'r':
486 elif type_ == 'r':
486 removed.append(fn)
487 removed.append(fn)
487
488
488 return (lookup, modified, added, removed, deleted, unknown, ignored,
489 return (lookup, modified, added, removed, deleted, unknown, ignored,
489 clean)
490 clean)
General Comments 0
You need to be logged in to leave comments. Login now