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