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