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