##// END OF EJS Templates
remove unnecessary call to umask
Benoit Boissinot -
r3842:47c634bf default
parent child Browse files
Show More
@@ -1,533 +1,531
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 gettext as _
11 from i18n import gettext as _
12 from demandload import *
12 from demandload import *
13 demandload(globals(), "struct os time bisect stat strutil util re errno")
13 demandload(globals(), "struct os time bisect stat strutil util re errno")
14
14
15 class dirstate(object):
15 class dirstate(object):
16 format = ">cllll"
16 format = ">cllll"
17
17
18 def __init__(self, opener, ui, root):
18 def __init__(self, opener, ui, root):
19 self.opener = opener
19 self.opener = opener
20 self.root = root
20 self.root = root
21 self.dirty = 0
21 self.dirty = 0
22 self.ui = ui
22 self.ui = ui
23 self.map = None
23 self.map = None
24 self.pl = None
24 self.pl = None
25 self.dirs = None
25 self.dirs = None
26 self.copymap = {}
26 self.copymap = {}
27 self.ignorefunc = None
27 self.ignorefunc = None
28
28
29 def wjoin(self, f):
29 def wjoin(self, f):
30 return os.path.join(self.root, f)
30 return os.path.join(self.root, f)
31
31
32 def getcwd(self):
32 def getcwd(self):
33 cwd = os.getcwd()
33 cwd = os.getcwd()
34 if cwd == self.root: return ''
34 if cwd == self.root: return ''
35 # self.root ends with a path separator if self.root is '/' or 'C:\'
35 # self.root ends with a path separator if self.root is '/' or 'C:\'
36 common_prefix_len = len(self.root)
36 common_prefix_len = len(self.root)
37 if not self.root.endswith(os.sep):
37 if not self.root.endswith(os.sep):
38 common_prefix_len += 1
38 common_prefix_len += 1
39 return cwd[common_prefix_len:]
39 return cwd[common_prefix_len:]
40
40
41 def hgignore(self):
41 def hgignore(self):
42 '''return the contents of .hgignore files as a list of patterns.
42 '''return the contents of .hgignore files as a list of patterns.
43
43
44 the files parsed for patterns include:
44 the files parsed for patterns include:
45 .hgignore in the repository root
45 .hgignore in the repository root
46 any additional files specified in the [ui] section of ~/.hgrc
46 any additional files specified in the [ui] section of ~/.hgrc
47
47
48 trailing white space is dropped.
48 trailing white space is dropped.
49 the escape character is backslash.
49 the escape character is backslash.
50 comments start with #.
50 comments start with #.
51 empty lines are skipped.
51 empty lines are skipped.
52
52
53 lines can be of the following formats:
53 lines can be of the following formats:
54
54
55 syntax: regexp # defaults following lines to non-rooted regexps
55 syntax: regexp # defaults following lines to non-rooted regexps
56 syntax: glob # defaults following lines to non-rooted globs
56 syntax: glob # defaults following lines to non-rooted globs
57 re:pattern # non-rooted regular expression
57 re:pattern # non-rooted regular expression
58 glob:pattern # non-rooted glob
58 glob:pattern # non-rooted glob
59 pattern # pattern of the current default type'''
59 pattern # pattern of the current default type'''
60 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
60 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
61 def parselines(fp):
61 def parselines(fp):
62 for line in fp:
62 for line in fp:
63 escape = False
63 escape = False
64 for i in xrange(len(line)):
64 for i in xrange(len(line)):
65 if escape: escape = False
65 if escape: escape = False
66 elif line[i] == '\\': escape = True
66 elif line[i] == '\\': escape = True
67 elif line[i] == '#': break
67 elif line[i] == '#': break
68 line = line[:i].rstrip()
68 line = line[:i].rstrip()
69 if line: yield line
69 if line: yield line
70 repoignore = self.wjoin('.hgignore')
70 repoignore = self.wjoin('.hgignore')
71 files = [repoignore]
71 files = [repoignore]
72 files.extend(self.ui.hgignorefiles())
72 files.extend(self.ui.hgignorefiles())
73 pats = {}
73 pats = {}
74 for f in files:
74 for f in files:
75 try:
75 try:
76 pats[f] = []
76 pats[f] = []
77 fp = open(f)
77 fp = open(f)
78 syntax = 'relre:'
78 syntax = 'relre:'
79 for line in parselines(fp):
79 for line in parselines(fp):
80 if line.startswith('syntax:'):
80 if line.startswith('syntax:'):
81 s = line[7:].strip()
81 s = line[7:].strip()
82 try:
82 try:
83 syntax = syntaxes[s]
83 syntax = syntaxes[s]
84 except KeyError:
84 except KeyError:
85 self.ui.warn(_("%s: ignoring invalid "
85 self.ui.warn(_("%s: ignoring invalid "
86 "syntax '%s'\n") % (f, s))
86 "syntax '%s'\n") % (f, s))
87 continue
87 continue
88 pat = syntax + line
88 pat = syntax + line
89 for s in syntaxes.values():
89 for s in syntaxes.values():
90 if line.startswith(s):
90 if line.startswith(s):
91 pat = line
91 pat = line
92 break
92 break
93 pats[f].append(pat)
93 pats[f].append(pat)
94 except IOError, inst:
94 except IOError, inst:
95 if f != repoignore:
95 if f != repoignore:
96 self.ui.warn(_("skipping unreadable ignore file"
96 self.ui.warn(_("skipping unreadable ignore file"
97 " '%s': %s\n") % (f, inst.strerror))
97 " '%s': %s\n") % (f, inst.strerror))
98 return pats
98 return pats
99
99
100 def ignore(self, fn):
100 def ignore(self, fn):
101 '''default match function used by dirstate and
101 '''default match function used by dirstate and
102 localrepository. this honours the repository .hgignore file
102 localrepository. this honours the repository .hgignore file
103 and any other files specified in the [ui] section of .hgrc.'''
103 and any other files specified in the [ui] section of .hgrc.'''
104 if not self.ignorefunc:
104 if not self.ignorefunc:
105 ignore = self.hgignore()
105 ignore = self.hgignore()
106 allpats = []
106 allpats = []
107 [allpats.extend(patlist) for patlist in ignore.values()]
107 [allpats.extend(patlist) for patlist in ignore.values()]
108 if allpats:
108 if allpats:
109 try:
109 try:
110 files, self.ignorefunc, anypats = (
110 files, self.ignorefunc, anypats = (
111 util.matcher(self.root, inc=allpats, src='.hgignore'))
111 util.matcher(self.root, inc=allpats, src='.hgignore'))
112 except util.Abort:
112 except util.Abort:
113 # Re-raise an exception where the src is the right file
113 # Re-raise an exception where the src is the right file
114 for f, patlist in ignore.items():
114 for f, patlist in ignore.items():
115 files, self.ignorefunc, anypats = (
115 files, self.ignorefunc, anypats = (
116 util.matcher(self.root, inc=patlist, src=f))
116 util.matcher(self.root, inc=patlist, src=f))
117 else:
117 else:
118 self.ignorefunc = util.never
118 self.ignorefunc = util.never
119 return self.ignorefunc(fn)
119 return self.ignorefunc(fn)
120
120
121 def __del__(self):
121 def __del__(self):
122 if self.dirty:
122 if self.dirty:
123 self.write()
123 self.write()
124
124
125 def __getitem__(self, key):
125 def __getitem__(self, key):
126 try:
126 try:
127 return self.map[key]
127 return self.map[key]
128 except TypeError:
128 except TypeError:
129 self.lazyread()
129 self.lazyread()
130 return self[key]
130 return self[key]
131
131
132 def __contains__(self, key):
132 def __contains__(self, key):
133 self.lazyread()
133 self.lazyread()
134 return key in self.map
134 return key in self.map
135
135
136 def parents(self):
136 def parents(self):
137 self.lazyread()
137 self.lazyread()
138 return self.pl
138 return self.pl
139
139
140 def markdirty(self):
140 def markdirty(self):
141 if not self.dirty:
141 if not self.dirty:
142 self.dirty = 1
142 self.dirty = 1
143
143
144 def setparents(self, p1, p2=nullid):
144 def setparents(self, p1, p2=nullid):
145 self.lazyread()
145 self.lazyread()
146 self.markdirty()
146 self.markdirty()
147 self.pl = p1, p2
147 self.pl = p1, p2
148
148
149 def state(self, key):
149 def state(self, key):
150 try:
150 try:
151 return self[key][0]
151 return self[key][0]
152 except KeyError:
152 except KeyError:
153 return "?"
153 return "?"
154
154
155 def lazyread(self):
155 def lazyread(self):
156 if self.map is None:
156 if self.map is None:
157 self.read()
157 self.read()
158
158
159 def parse(self, st):
159 def parse(self, st):
160 self.pl = [st[:20], st[20: 40]]
160 self.pl = [st[:20], st[20: 40]]
161
161
162 # deref fields so they will be local in loop
162 # deref fields so they will be local in loop
163 map = self.map
163 map = self.map
164 copymap = self.copymap
164 copymap = self.copymap
165 format = self.format
165 format = self.format
166 unpack = struct.unpack
166 unpack = struct.unpack
167
167
168 pos = 40
168 pos = 40
169 e_size = struct.calcsize(format)
169 e_size = struct.calcsize(format)
170
170
171 while pos < len(st):
171 while pos < len(st):
172 newpos = pos + e_size
172 newpos = pos + e_size
173 e = unpack(format, st[pos:newpos])
173 e = unpack(format, st[pos:newpos])
174 l = e[4]
174 l = e[4]
175 pos = newpos
175 pos = newpos
176 newpos = pos + l
176 newpos = pos + l
177 f = st[pos:newpos]
177 f = st[pos:newpos]
178 if '\0' in f:
178 if '\0' in f:
179 f, c = f.split('\0')
179 f, c = f.split('\0')
180 copymap[f] = c
180 copymap[f] = c
181 map[f] = e[:4]
181 map[f] = e[:4]
182 pos = newpos
182 pos = newpos
183
183
184 def read(self):
184 def read(self):
185 self.map = {}
185 self.map = {}
186 self.pl = [nullid, nullid]
186 self.pl = [nullid, nullid]
187 try:
187 try:
188 st = self.opener("dirstate").read()
188 st = self.opener("dirstate").read()
189 if st:
189 if st:
190 self.parse(st)
190 self.parse(st)
191 except IOError, err:
191 except IOError, err:
192 if err.errno != errno.ENOENT: raise
192 if err.errno != errno.ENOENT: raise
193
193
194 def copy(self, source, dest):
194 def copy(self, source, dest):
195 self.lazyread()
195 self.lazyread()
196 self.markdirty()
196 self.markdirty()
197 self.copymap[dest] = source
197 self.copymap[dest] = source
198
198
199 def copied(self, file):
199 def copied(self, file):
200 return self.copymap.get(file, None)
200 return self.copymap.get(file, None)
201
201
202 def copies(self):
202 def copies(self):
203 return self.copymap
203 return self.copymap
204
204
205 def initdirs(self):
205 def initdirs(self):
206 if self.dirs is None:
206 if self.dirs is None:
207 self.dirs = {}
207 self.dirs = {}
208 for f in self.map:
208 for f in self.map:
209 self.updatedirs(f, 1)
209 self.updatedirs(f, 1)
210
210
211 def updatedirs(self, path, delta):
211 def updatedirs(self, path, delta):
212 if self.dirs is not None:
212 if self.dirs is not None:
213 for c in strutil.findall(path, '/'):
213 for c in strutil.findall(path, '/'):
214 pc = path[:c]
214 pc = path[:c]
215 self.dirs.setdefault(pc, 0)
215 self.dirs.setdefault(pc, 0)
216 self.dirs[pc] += delta
216 self.dirs[pc] += delta
217
217
218 def checkinterfering(self, files):
218 def checkinterfering(self, files):
219 def prefixes(f):
219 def prefixes(f):
220 for c in strutil.rfindall(f, '/'):
220 for c in strutil.rfindall(f, '/'):
221 yield f[:c]
221 yield f[:c]
222 self.lazyread()
222 self.lazyread()
223 self.initdirs()
223 self.initdirs()
224 seendirs = {}
224 seendirs = {}
225 for f in files:
225 for f in files:
226 # shadows
226 # shadows
227 if self.dirs.get(f):
227 if self.dirs.get(f):
228 raise util.Abort(_('directory named %r already in dirstate') %
228 raise util.Abort(_('directory named %r already in dirstate') %
229 f)
229 f)
230 for d in prefixes(f):
230 for d in prefixes(f):
231 if d in seendirs:
231 if d in seendirs:
232 break
232 break
233 if d in self.map:
233 if d in self.map:
234 raise util.Abort(_('file named %r already in dirstate') %
234 raise util.Abort(_('file named %r already in dirstate') %
235 d)
235 d)
236 seendirs[d] = True
236 seendirs[d] = True
237 # disallowed
237 # disallowed
238 if '\r' in f or '\n' in f:
238 if '\r' in f or '\n' in f:
239 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames"))
239 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames"))
240
240
241 def update(self, files, state, **kw):
241 def update(self, files, state, **kw):
242 ''' current states:
242 ''' current states:
243 n normal
243 n normal
244 m needs merging
244 m needs merging
245 r marked for removal
245 r marked for removal
246 a marked for addition'''
246 a marked for addition'''
247
247
248 if not files: return
248 if not files: return
249 self.lazyread()
249 self.lazyread()
250 self.markdirty()
250 self.markdirty()
251 if state == "a":
251 if state == "a":
252 self.initdirs()
252 self.initdirs()
253 self.checkinterfering(files)
253 self.checkinterfering(files)
254 for f in files:
254 for f in files:
255 if state == "r":
255 if state == "r":
256 self.map[f] = ('r', 0, 0, 0)
256 self.map[f] = ('r', 0, 0, 0)
257 self.updatedirs(f, -1)
257 self.updatedirs(f, -1)
258 else:
258 else:
259 if state == "a":
259 if state == "a":
260 self.updatedirs(f, 1)
260 self.updatedirs(f, 1)
261 s = os.lstat(self.wjoin(f))
261 s = os.lstat(self.wjoin(f))
262 st_size = kw.get('st_size', s.st_size)
262 st_size = kw.get('st_size', s.st_size)
263 st_mtime = kw.get('st_mtime', s.st_mtime)
263 st_mtime = kw.get('st_mtime', s.st_mtime)
264 self.map[f] = (state, s.st_mode, st_size, st_mtime)
264 self.map[f] = (state, s.st_mode, st_size, st_mtime)
265 if self.copymap.has_key(f):
265 if self.copymap.has_key(f):
266 del self.copymap[f]
266 del self.copymap[f]
267
267
268 def forget(self, files):
268 def forget(self, files):
269 if not files: return
269 if not files: return
270 self.lazyread()
270 self.lazyread()
271 self.markdirty()
271 self.markdirty()
272 self.initdirs()
272 self.initdirs()
273 for f in files:
273 for f in files:
274 try:
274 try:
275 del self.map[f]
275 del self.map[f]
276 self.updatedirs(f, -1)
276 self.updatedirs(f, -1)
277 except KeyError:
277 except KeyError:
278 self.ui.warn(_("not in dirstate: %s!\n") % f)
278 self.ui.warn(_("not in dirstate: %s!\n") % f)
279 pass
279 pass
280
280
281 def clear(self):
281 def clear(self):
282 self.map = {}
282 self.map = {}
283 self.copymap = {}
283 self.copymap = {}
284 self.dirs = None
284 self.dirs = None
285 self.markdirty()
285 self.markdirty()
286
286
287 def rebuild(self, parent, files):
287 def rebuild(self, parent, files):
288 self.clear()
288 self.clear()
289 umask = os.umask(0)
290 os.umask(umask)
291 for f in files:
289 for f in files:
292 if files.execf(f):
290 if files.execf(f):
293 self.map[f] = ('n', ~umask, -1, 0)
291 self.map[f] = ('n', 0777, -1, 0)
294 else:
292 else:
295 self.map[f] = ('n', ~umask & 0666, -1, 0)
293 self.map[f] = ('n', 0666, -1, 0)
296 self.pl = (parent, nullid)
294 self.pl = (parent, nullid)
297 self.markdirty()
295 self.markdirty()
298
296
299 def write(self):
297 def write(self):
300 if not self.dirty:
298 if not self.dirty:
301 return
299 return
302 st = self.opener("dirstate", "w", atomic=True)
300 st = self.opener("dirstate", "w", atomic=True)
303 st.write("".join(self.pl))
301 st.write("".join(self.pl))
304 for f, e in self.map.items():
302 for f, e in self.map.items():
305 c = self.copied(f)
303 c = self.copied(f)
306 if c:
304 if c:
307 f = f + "\0" + c
305 f = f + "\0" + c
308 e = struct.pack(self.format, e[0], e[1], e[2], e[3], len(f))
306 e = struct.pack(self.format, e[0], e[1], e[2], e[3], len(f))
309 st.write(e + f)
307 st.write(e + f)
310 self.dirty = 0
308 self.dirty = 0
311
309
312 def filterfiles(self, files):
310 def filterfiles(self, files):
313 ret = {}
311 ret = {}
314 unknown = []
312 unknown = []
315
313
316 for x in files:
314 for x in files:
317 if x == '.':
315 if x == '.':
318 return self.map.copy()
316 return self.map.copy()
319 if x not in self.map:
317 if x not in self.map:
320 unknown.append(x)
318 unknown.append(x)
321 else:
319 else:
322 ret[x] = self.map[x]
320 ret[x] = self.map[x]
323
321
324 if not unknown:
322 if not unknown:
325 return ret
323 return ret
326
324
327 b = self.map.keys()
325 b = self.map.keys()
328 b.sort()
326 b.sort()
329 blen = len(b)
327 blen = len(b)
330
328
331 for x in unknown:
329 for x in unknown:
332 bs = bisect.bisect(b, "%s%s" % (x, '/'))
330 bs = bisect.bisect(b, "%s%s" % (x, '/'))
333 while bs < blen:
331 while bs < blen:
334 s = b[bs]
332 s = b[bs]
335 if len(s) > len(x) and s.startswith(x):
333 if len(s) > len(x) and s.startswith(x):
336 ret[s] = self.map[s]
334 ret[s] = self.map[s]
337 else:
335 else:
338 break
336 break
339 bs += 1
337 bs += 1
340 return ret
338 return ret
341
339
342 def supported_type(self, f, st, verbose=False):
340 def supported_type(self, f, st, verbose=False):
343 if stat.S_ISREG(st.st_mode):
341 if stat.S_ISREG(st.st_mode):
344 return True
342 return True
345 if verbose:
343 if verbose:
346 kind = 'unknown'
344 kind = 'unknown'
347 if stat.S_ISCHR(st.st_mode): kind = _('character device')
345 if stat.S_ISCHR(st.st_mode): kind = _('character device')
348 elif stat.S_ISBLK(st.st_mode): kind = _('block device')
346 elif stat.S_ISBLK(st.st_mode): kind = _('block device')
349 elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
347 elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
350 elif stat.S_ISLNK(st.st_mode): kind = _('symbolic link')
348 elif stat.S_ISLNK(st.st_mode): kind = _('symbolic link')
351 elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
349 elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
352 elif stat.S_ISDIR(st.st_mode): kind = _('directory')
350 elif stat.S_ISDIR(st.st_mode): kind = _('directory')
353 self.ui.warn(_('%s: unsupported file type (type is %s)\n') % (
351 self.ui.warn(_('%s: unsupported file type (type is %s)\n') % (
354 util.pathto(self.getcwd(), f),
352 util.pathto(self.getcwd(), f),
355 kind))
353 kind))
356 return False
354 return False
357
355
358 def walk(self, files=None, match=util.always, badmatch=None):
356 def walk(self, files=None, match=util.always, badmatch=None):
359 # filter out the stat
357 # filter out the stat
360 for src, f, st in self.statwalk(files, match, badmatch=badmatch):
358 for src, f, st in self.statwalk(files, match, badmatch=badmatch):
361 yield src, f
359 yield src, f
362
360
363 def statwalk(self, files=None, match=util.always, ignored=False,
361 def statwalk(self, files=None, match=util.always, ignored=False,
364 badmatch=None):
362 badmatch=None):
365 '''
363 '''
366 walk recursively through the directory tree, finding all files
364 walk recursively through the directory tree, finding all files
367 matched by the match function
365 matched by the match function
368
366
369 results are yielded in a tuple (src, filename, st), where src
367 results are yielded in a tuple (src, filename, st), where src
370 is one of:
368 is one of:
371 'f' the file was found in the directory tree
369 'f' the file was found in the directory tree
372 'm' the file was only in the dirstate and not in the tree
370 'm' the file was only in the dirstate and not in the tree
373 'b' file was not found and matched badmatch
371 'b' file was not found and matched badmatch
374
372
375 and st is the stat result if the file was found in the directory.
373 and st is the stat result if the file was found in the directory.
376 '''
374 '''
377 self.lazyread()
375 self.lazyread()
378
376
379 # walk all files by default
377 # walk all files by default
380 if not files:
378 if not files:
381 files = [self.root]
379 files = [self.root]
382 dc = self.map.copy()
380 dc = self.map.copy()
383 else:
381 else:
384 files = util.unique(files)
382 files = util.unique(files)
385 dc = self.filterfiles(files)
383 dc = self.filterfiles(files)
386
384
387 def imatch(file_):
385 def imatch(file_):
388 if file_ not in dc and self.ignore(file_):
386 if file_ not in dc and self.ignore(file_):
389 return False
387 return False
390 return match(file_)
388 return match(file_)
391
389
392 if ignored: imatch = match
390 if ignored: imatch = match
393
391
394 # self.root may end with a path separator when self.root == '/'
392 # self.root may end with a path separator when self.root == '/'
395 common_prefix_len = len(self.root)
393 common_prefix_len = len(self.root)
396 if not self.root.endswith('/'):
394 if not self.root.endswith('/'):
397 common_prefix_len += 1
395 common_prefix_len += 1
398 # recursion free walker, faster than os.walk.
396 # recursion free walker, faster than os.walk.
399 def findfiles(s):
397 def findfiles(s):
400 work = [s]
398 work = [s]
401 while work:
399 while work:
402 top = work.pop()
400 top = work.pop()
403 names = os.listdir(top)
401 names = os.listdir(top)
404 names.sort()
402 names.sort()
405 # nd is the top of the repository dir tree
403 # nd is the top of the repository dir tree
406 nd = util.normpath(top[common_prefix_len:])
404 nd = util.normpath(top[common_prefix_len:])
407 if nd == '.':
405 if nd == '.':
408 nd = ''
406 nd = ''
409 else:
407 else:
410 # do not recurse into a repo contained in this
408 # do not recurse into a repo contained in this
411 # one. use bisect to find .hg directory so speed
409 # one. use bisect to find .hg directory so speed
412 # is good on big directory.
410 # is good on big directory.
413 hg = bisect.bisect_left(names, '.hg')
411 hg = bisect.bisect_left(names, '.hg')
414 if hg < len(names) and names[hg] == '.hg':
412 if hg < len(names) and names[hg] == '.hg':
415 if os.path.isdir(os.path.join(top, '.hg')):
413 if os.path.isdir(os.path.join(top, '.hg')):
416 continue
414 continue
417 for f in names:
415 for f in names:
418 np = util.pconvert(os.path.join(nd, f))
416 np = util.pconvert(os.path.join(nd, f))
419 if seen(np):
417 if seen(np):
420 continue
418 continue
421 p = os.path.join(top, f)
419 p = os.path.join(top, f)
422 # don't trip over symlinks
420 # don't trip over symlinks
423 st = os.lstat(p)
421 st = os.lstat(p)
424 if stat.S_ISDIR(st.st_mode):
422 if stat.S_ISDIR(st.st_mode):
425 ds = util.pconvert(os.path.join(nd, f +'/'))
423 ds = util.pconvert(os.path.join(nd, f +'/'))
426 if imatch(ds):
424 if imatch(ds):
427 work.append(p)
425 work.append(p)
428 if imatch(np) and np in dc:
426 if imatch(np) and np in dc:
429 yield 'm', np, st
427 yield 'm', np, st
430 elif imatch(np):
428 elif imatch(np):
431 if self.supported_type(np, st):
429 if self.supported_type(np, st):
432 yield 'f', np, st
430 yield 'f', np, st
433 elif np in dc:
431 elif np in dc:
434 yield 'm', np, st
432 yield 'm', np, st
435
433
436 known = {'.hg': 1}
434 known = {'.hg': 1}
437 def seen(fn):
435 def seen(fn):
438 if fn in known: return True
436 if fn in known: return True
439 known[fn] = 1
437 known[fn] = 1
440
438
441 # step one, find all files that match our criteria
439 # step one, find all files that match our criteria
442 files.sort()
440 files.sort()
443 for ff in files:
441 for ff in files:
444 nf = util.normpath(ff)
442 nf = util.normpath(ff)
445 f = self.wjoin(ff)
443 f = self.wjoin(ff)
446 try:
444 try:
447 st = os.lstat(f)
445 st = os.lstat(f)
448 except OSError, inst:
446 except OSError, inst:
449 found = False
447 found = False
450 for fn in dc:
448 for fn in dc:
451 if nf == fn or (fn.startswith(nf) and fn[len(nf)] == '/'):
449 if nf == fn or (fn.startswith(nf) and fn[len(nf)] == '/'):
452 found = True
450 found = True
453 break
451 break
454 if not found:
452 if not found:
455 if inst.errno != errno.ENOENT or not badmatch:
453 if inst.errno != errno.ENOENT or not badmatch:
456 self.ui.warn('%s: %s\n' % (
454 self.ui.warn('%s: %s\n' % (
457 util.pathto(self.getcwd(), ff),
455 util.pathto(self.getcwd(), ff),
458 inst.strerror))
456 inst.strerror))
459 elif badmatch and badmatch(ff) and imatch(nf):
457 elif badmatch and badmatch(ff) and imatch(nf):
460 yield 'b', ff, None
458 yield 'b', ff, None
461 continue
459 continue
462 if stat.S_ISDIR(st.st_mode):
460 if stat.S_ISDIR(st.st_mode):
463 cmp1 = (lambda x, y: cmp(x[1], y[1]))
461 cmp1 = (lambda x, y: cmp(x[1], y[1]))
464 sorted_ = [ x for x in findfiles(f) ]
462 sorted_ = [ x for x in findfiles(f) ]
465 sorted_.sort(cmp1)
463 sorted_.sort(cmp1)
466 for e in sorted_:
464 for e in sorted_:
467 yield e
465 yield e
468 else:
466 else:
469 if not seen(nf) and match(nf):
467 if not seen(nf) and match(nf):
470 if self.supported_type(ff, st, verbose=True):
468 if self.supported_type(ff, st, verbose=True):
471 yield 'f', nf, st
469 yield 'f', nf, st
472 elif ff in dc:
470 elif ff in dc:
473 yield 'm', nf, st
471 yield 'm', nf, st
474
472
475 # step two run through anything left in the dc hash and yield
473 # step two run through anything left in the dc hash and yield
476 # if we haven't already seen it
474 # if we haven't already seen it
477 ks = dc.keys()
475 ks = dc.keys()
478 ks.sort()
476 ks.sort()
479 for k in ks:
477 for k in ks:
480 if not seen(k) and imatch(k):
478 if not seen(k) and imatch(k):
481 yield 'm', k, None
479 yield 'm', k, None
482
480
483 def status(self, files=None, match=util.always, list_ignored=False,
481 def status(self, files=None, match=util.always, list_ignored=False,
484 list_clean=False):
482 list_clean=False):
485 lookup, modified, added, unknown, ignored = [], [], [], [], []
483 lookup, modified, added, unknown, ignored = [], [], [], [], []
486 removed, deleted, clean = [], [], []
484 removed, deleted, clean = [], [], []
487
485
488 for src, fn, st in self.statwalk(files, match, ignored=list_ignored):
486 for src, fn, st in self.statwalk(files, match, ignored=list_ignored):
489 try:
487 try:
490 type_, mode, size, time = self[fn]
488 type_, mode, size, time = self[fn]
491 except KeyError:
489 except KeyError:
492 if list_ignored and self.ignore(fn):
490 if list_ignored and self.ignore(fn):
493 ignored.append(fn)
491 ignored.append(fn)
494 else:
492 else:
495 unknown.append(fn)
493 unknown.append(fn)
496 continue
494 continue
497 if src == 'm':
495 if src == 'm':
498 nonexistent = True
496 nonexistent = True
499 if not st:
497 if not st:
500 try:
498 try:
501 st = os.lstat(self.wjoin(fn))
499 st = os.lstat(self.wjoin(fn))
502 except OSError, inst:
500 except OSError, inst:
503 if inst.errno != errno.ENOENT:
501 if inst.errno != errno.ENOENT:
504 raise
502 raise
505 st = None
503 st = None
506 # We need to re-check that it is a valid file
504 # We need to re-check that it is a valid file
507 if st and self.supported_type(fn, st):
505 if st and self.supported_type(fn, st):
508 nonexistent = False
506 nonexistent = False
509 # XXX: what to do with file no longer present in the fs
507 # XXX: what to do with file no longer present in the fs
510 # who are not removed in the dirstate ?
508 # who are not removed in the dirstate ?
511 if nonexistent and type_ in "nm":
509 if nonexistent and type_ in "nm":
512 deleted.append(fn)
510 deleted.append(fn)
513 continue
511 continue
514 # check the common case first
512 # check the common case first
515 if type_ == 'n':
513 if type_ == 'n':
516 if not st:
514 if not st:
517 st = os.lstat(self.wjoin(fn))
515 st = os.lstat(self.wjoin(fn))
518 if size >= 0 and (size != st.st_size
516 if size >= 0 and (size != st.st_size
519 or (mode ^ st.st_mode) & 0100):
517 or (mode ^ st.st_mode) & 0100):
520 modified.append(fn)
518 modified.append(fn)
521 elif time != int(st.st_mtime):
519 elif time != int(st.st_mtime):
522 lookup.append(fn)
520 lookup.append(fn)
523 elif list_clean:
521 elif list_clean:
524 clean.append(fn)
522 clean.append(fn)
525 elif type_ == 'm':
523 elif type_ == 'm':
526 modified.append(fn)
524 modified.append(fn)
527 elif type_ == 'a':
525 elif type_ == 'a':
528 added.append(fn)
526 added.append(fn)
529 elif type_ == 'r':
527 elif type_ == 'r':
530 removed.append(fn)
528 removed.append(fn)
531
529
532 return (lookup, modified, added, removed, deleted, unknown, ignored,
530 return (lookup, modified, added, removed, deleted, unknown, ignored,
533 clean)
531 clean)
General Comments 0
You need to be logged in to leave comments. Login now