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