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