##// END OF EJS Templates
dirstate: fixed typo in comment
Martin Geisler -
r8645:27638a23 default
parent child Browse files
Show More
@@ -1,622 +1,622 b''
1 # dirstate.py - working directory tracking for mercurial
1 # dirstate.py - working directory tracking for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 from node import nullid
8 from node import nullid
9 from i18n import _
9 from i18n import _
10 import util, ignore, osutil, parsers
10 import util, ignore, osutil, parsers
11 import struct, os, stat, errno
11 import struct, os, stat, errno
12 import cStringIO, sys
12 import cStringIO, sys
13
13
14 _unknown = ('?', 0, 0, 0)
14 _unknown = ('?', 0, 0, 0)
15 _format = ">cllll"
15 _format = ">cllll"
16 propertycache = util.propertycache
16 propertycache = util.propertycache
17
17
18 def _finddirs(path):
18 def _finddirs(path):
19 pos = path.rfind('/')
19 pos = path.rfind('/')
20 while pos != -1:
20 while pos != -1:
21 yield path[:pos]
21 yield path[:pos]
22 pos = path.rfind('/', 0, pos)
22 pos = path.rfind('/', 0, pos)
23
23
24 def _incdirs(dirs, path):
24 def _incdirs(dirs, path):
25 for base in _finddirs(path):
25 for base in _finddirs(path):
26 if base in dirs:
26 if base in dirs:
27 dirs[base] += 1
27 dirs[base] += 1
28 return
28 return
29 dirs[base] = 1
29 dirs[base] = 1
30
30
31 def _decdirs(dirs, path):
31 def _decdirs(dirs, path):
32 for base in _finddirs(path):
32 for base in _finddirs(path):
33 if dirs[base] > 1:
33 if dirs[base] > 1:
34 dirs[base] -= 1
34 dirs[base] -= 1
35 return
35 return
36 del dirs[base]
36 del dirs[base]
37
37
38 class dirstate(object):
38 class dirstate(object):
39
39
40 def __init__(self, opener, ui, root):
40 def __init__(self, opener, ui, root):
41 self._opener = opener
41 self._opener = opener
42 self._root = root
42 self._root = root
43 self._rootdir = os.path.join(root, '')
43 self._rootdir = os.path.join(root, '')
44 self._dirty = False
44 self._dirty = False
45 self._dirtypl = False
45 self._dirtypl = False
46 self._ui = ui
46 self._ui = ui
47
47
48 @propertycache
48 @propertycache
49 def _map(self):
49 def _map(self):
50 self._read()
50 self._read()
51 return self._map
51 return self._map
52
52
53 @propertycache
53 @propertycache
54 def _copymap(self):
54 def _copymap(self):
55 self._read()
55 self._read()
56 return self._copymap
56 return self._copymap
57
57
58 @propertycache
58 @propertycache
59 def _foldmap(self):
59 def _foldmap(self):
60 f = {}
60 f = {}
61 for name in self._map:
61 for name in self._map:
62 f[os.path.normcase(name)] = name
62 f[os.path.normcase(name)] = name
63 return f
63 return f
64
64
65 @propertycache
65 @propertycache
66 def _branch(self):
66 def _branch(self):
67 try:
67 try:
68 return self._opener("branch").read().strip() or "default"
68 return self._opener("branch").read().strip() or "default"
69 except IOError:
69 except IOError:
70 return "default"
70 return "default"
71
71
72 @propertycache
72 @propertycache
73 def _pl(self):
73 def _pl(self):
74 try:
74 try:
75 st = self._opener("dirstate").read(40)
75 st = self._opener("dirstate").read(40)
76 if len(st) == 40:
76 if len(st) == 40:
77 return st[:20], st[20:40]
77 return st[:20], st[20:40]
78 if len(st) < 40:
78 if len(st) < 40:
79 raise util.Abort(_('working directory state appears damaged!'))
79 raise util.Abort(_('working directory state appears damaged!'))
80 except IOError, err:
80 except IOError, err:
81 if err.errno != errno.ENOENT: raise
81 if err.errno != errno.ENOENT: raise
82 return [nullid, nullid]
82 return [nullid, nullid]
83
83
84 @propertycache
84 @propertycache
85 def _dirs(self):
85 def _dirs(self):
86 dirs = {}
86 dirs = {}
87 for f,s in self._map.iteritems():
87 for f,s in self._map.iteritems():
88 if s[0] != 'r':
88 if s[0] != 'r':
89 _incdirs(dirs, f)
89 _incdirs(dirs, f)
90 return dirs
90 return dirs
91
91
92 @propertycache
92 @propertycache
93 def _ignore(self):
93 def _ignore(self):
94 files = [self._join('.hgignore')]
94 files = [self._join('.hgignore')]
95 for name, path in self._ui.configitems("ui"):
95 for name, path in self._ui.configitems("ui"):
96 if name == 'ignore' or name.startswith('ignore.'):
96 if name == 'ignore' or name.startswith('ignore.'):
97 files.append(os.path.expanduser(path))
97 files.append(os.path.expanduser(path))
98 return ignore.ignore(self._root, files, self._ui.warn)
98 return ignore.ignore(self._root, files, self._ui.warn)
99
99
100 @propertycache
100 @propertycache
101 def _slash(self):
101 def _slash(self):
102 return self._ui.configbool('ui', 'slash') and os.sep != '/'
102 return self._ui.configbool('ui', 'slash') and os.sep != '/'
103
103
104 @propertycache
104 @propertycache
105 def _checklink(self):
105 def _checklink(self):
106 return util.checklink(self._root)
106 return util.checklink(self._root)
107
107
108 @propertycache
108 @propertycache
109 def _checkexec(self):
109 def _checkexec(self):
110 return util.checkexec(self._root)
110 return util.checkexec(self._root)
111
111
112 @propertycache
112 @propertycache
113 def _checkcase(self):
113 def _checkcase(self):
114 return not util.checkcase(self._join('.hg'))
114 return not util.checkcase(self._join('.hg'))
115
115
116 @propertycache
116 @propertycache
117 def normalize(self):
117 def normalize(self):
118 if self._checkcase:
118 if self._checkcase:
119 return self._normalize
119 return self._normalize
120 return lambda x, y=False: x
120 return lambda x, y=False: x
121
121
122 def _join(self, f):
122 def _join(self, f):
123 # much faster than os.path.join()
123 # much faster than os.path.join()
124 # it's safe because f is always a relative path
124 # it's safe because f is always a relative path
125 return self._rootdir + f
125 return self._rootdir + f
126
126
127 def flagfunc(self, fallback):
127 def flagfunc(self, fallback):
128 if self._checklink:
128 if self._checklink:
129 if self._checkexec:
129 if self._checkexec:
130 def f(x):
130 def f(x):
131 p = self._join(x)
131 p = self._join(x)
132 if os.path.islink(p):
132 if os.path.islink(p):
133 return 'l'
133 return 'l'
134 if util.is_exec(p):
134 if util.is_exec(p):
135 return 'x'
135 return 'x'
136 return ''
136 return ''
137 return f
137 return f
138 def f(x):
138 def f(x):
139 if os.path.islink(self._join(x)):
139 if os.path.islink(self._join(x)):
140 return 'l'
140 return 'l'
141 if 'x' in fallback(x):
141 if 'x' in fallback(x):
142 return 'x'
142 return 'x'
143 return ''
143 return ''
144 return f
144 return f
145 if self._checkexec:
145 if self._checkexec:
146 def f(x):
146 def f(x):
147 if 'l' in fallback(x):
147 if 'l' in fallback(x):
148 return 'l'
148 return 'l'
149 if util.is_exec(self._join(x)):
149 if util.is_exec(self._join(x)):
150 return 'x'
150 return 'x'
151 return ''
151 return ''
152 return f
152 return f
153 return fallback
153 return fallback
154
154
155 def getcwd(self):
155 def getcwd(self):
156 cwd = os.getcwd()
156 cwd = os.getcwd()
157 if cwd == self._root: return ''
157 if cwd == self._root: return ''
158 # self._root ends with a path separator if self._root is '/' or 'C:\'
158 # self._root ends with a path separator if self._root is '/' or 'C:\'
159 rootsep = self._root
159 rootsep = self._root
160 if not util.endswithsep(rootsep):
160 if not util.endswithsep(rootsep):
161 rootsep += os.sep
161 rootsep += os.sep
162 if cwd.startswith(rootsep):
162 if cwd.startswith(rootsep):
163 return cwd[len(rootsep):]
163 return cwd[len(rootsep):]
164 else:
164 else:
165 # we're outside the repo. return an absolute path.
165 # we're outside the repo. return an absolute path.
166 return cwd
166 return cwd
167
167
168 def pathto(self, f, cwd=None):
168 def pathto(self, f, cwd=None):
169 if cwd is None:
169 if cwd is None:
170 cwd = self.getcwd()
170 cwd = self.getcwd()
171 path = util.pathto(self._root, cwd, f)
171 path = util.pathto(self._root, cwd, f)
172 if self._slash:
172 if self._slash:
173 return util.normpath(path)
173 return util.normpath(path)
174 return path
174 return path
175
175
176 def __getitem__(self, key):
176 def __getitem__(self, key):
177 ''' current states:
177 ''' current states:
178 n normal
178 n normal
179 m needs merging
179 m needs merging
180 r marked for removal
180 r marked for removal
181 a marked for addition
181 a marked for addition
182 ? not tracked'''
182 ? not tracked'''
183 return self._map.get(key, ("?",))[0]
183 return self._map.get(key, ("?",))[0]
184
184
185 def __contains__(self, key):
185 def __contains__(self, key):
186 return key in self._map
186 return key in self._map
187
187
188 def __iter__(self):
188 def __iter__(self):
189 for x in sorted(self._map):
189 for x in sorted(self._map):
190 yield x
190 yield x
191
191
192 def parents(self):
192 def parents(self):
193 return self._pl
193 return self._pl
194
194
195 def branch(self):
195 def branch(self):
196 return self._branch
196 return self._branch
197
197
198 def setparents(self, p1, p2=nullid):
198 def setparents(self, p1, p2=nullid):
199 self._dirty = self._dirtypl = True
199 self._dirty = self._dirtypl = True
200 self._pl = p1, p2
200 self._pl = p1, p2
201
201
202 def setbranch(self, branch):
202 def setbranch(self, branch):
203 self._branch = branch
203 self._branch = branch
204 self._opener("branch", "w").write(branch + '\n')
204 self._opener("branch", "w").write(branch + '\n')
205
205
206 def _read(self):
206 def _read(self):
207 self._map = {}
207 self._map = {}
208 self._copymap = {}
208 self._copymap = {}
209 try:
209 try:
210 st = self._opener("dirstate").read()
210 st = self._opener("dirstate").read()
211 except IOError, err:
211 except IOError, err:
212 if err.errno != errno.ENOENT: raise
212 if err.errno != errno.ENOENT: raise
213 return
213 return
214 if not st:
214 if not st:
215 return
215 return
216
216
217 p = parsers.parse_dirstate(self._map, self._copymap, st)
217 p = parsers.parse_dirstate(self._map, self._copymap, st)
218 if not self._dirtypl:
218 if not self._dirtypl:
219 self._pl = p
219 self._pl = p
220
220
221 def invalidate(self):
221 def invalidate(self):
222 for a in "_map _copymap _foldmap _branch _pl _dirs _ignore".split():
222 for a in "_map _copymap _foldmap _branch _pl _dirs _ignore".split():
223 if a in self.__dict__:
223 if a in self.__dict__:
224 delattr(self, a)
224 delattr(self, a)
225 self._dirty = False
225 self._dirty = False
226
226
227 def copy(self, source, dest):
227 def copy(self, source, dest):
228 """Mark dest as a copy of source. Unmark dest if source is None.
228 """Mark dest as a copy of source. Unmark dest if source is None.
229 """
229 """
230 if source == dest:
230 if source == dest:
231 return
231 return
232 self._dirty = True
232 self._dirty = True
233 if source is not None:
233 if source is not None:
234 self._copymap[dest] = source
234 self._copymap[dest] = source
235 elif dest in self._copymap:
235 elif dest in self._copymap:
236 del self._copymap[dest]
236 del self._copymap[dest]
237
237
238 def copied(self, file):
238 def copied(self, file):
239 return self._copymap.get(file, None)
239 return self._copymap.get(file, None)
240
240
241 def copies(self):
241 def copies(self):
242 return self._copymap
242 return self._copymap
243
243
244 def _droppath(self, f):
244 def _droppath(self, f):
245 if self[f] not in "?r" and "_dirs" in self.__dict__:
245 if self[f] not in "?r" and "_dirs" in self.__dict__:
246 _decdirs(self._dirs, f)
246 _decdirs(self._dirs, f)
247
247
248 def _addpath(self, f, check=False):
248 def _addpath(self, f, check=False):
249 oldstate = self[f]
249 oldstate = self[f]
250 if check or oldstate == "r":
250 if check or oldstate == "r":
251 if '\r' in f or '\n' in f:
251 if '\r' in f or '\n' in f:
252 raise util.Abort(
252 raise util.Abort(
253 _("'\\n' and '\\r' disallowed in filenames: %r") % f)
253 _("'\\n' and '\\r' disallowed in filenames: %r") % f)
254 if f in self._dirs:
254 if f in self._dirs:
255 raise util.Abort(_('directory %r already in dirstate') % f)
255 raise util.Abort(_('directory %r already in dirstate') % f)
256 # shadows
256 # shadows
257 for d in _finddirs(f):
257 for d in _finddirs(f):
258 if d in self._dirs:
258 if d in self._dirs:
259 break
259 break
260 if d in self._map and self[d] != 'r':
260 if d in self._map and self[d] != 'r':
261 raise util.Abort(
261 raise util.Abort(
262 _('file %r in dirstate clashes with %r') % (d, f))
262 _('file %r in dirstate clashes with %r') % (d, f))
263 if oldstate in "?r" and "_dirs" in self.__dict__:
263 if oldstate in "?r" and "_dirs" in self.__dict__:
264 _incdirs(self._dirs, f)
264 _incdirs(self._dirs, f)
265
265
266 def normal(self, f):
266 def normal(self, f):
267 'mark a file normal and clean'
267 'mark a file normal and clean'
268 self._dirty = True
268 self._dirty = True
269 self._addpath(f)
269 self._addpath(f)
270 s = os.lstat(self._join(f))
270 s = os.lstat(self._join(f))
271 self._map[f] = ('n', s.st_mode, s.st_size, int(s.st_mtime))
271 self._map[f] = ('n', s.st_mode, s.st_size, int(s.st_mtime))
272 if f in self._copymap:
272 if f in self._copymap:
273 del self._copymap[f]
273 del self._copymap[f]
274
274
275 def normallookup(self, f):
275 def normallookup(self, f):
276 'mark a file normal, but possibly dirty'
276 'mark a file normal, but possibly dirty'
277 if self._pl[1] != nullid and f in self._map:
277 if self._pl[1] != nullid and f in self._map:
278 # if there is a merge going on and the file was either
278 # if there is a merge going on and the file was either
279 # in state 'm' or dirty before being removed, restore that state.
279 # in state 'm' or dirty before being removed, restore that state.
280 entry = self._map[f]
280 entry = self._map[f]
281 if entry[0] == 'r' and entry[2] in (-1, -2):
281 if entry[0] == 'r' and entry[2] in (-1, -2):
282 source = self._copymap.get(f)
282 source = self._copymap.get(f)
283 if entry[2] == -1:
283 if entry[2] == -1:
284 self.merge(f)
284 self.merge(f)
285 elif entry[2] == -2:
285 elif entry[2] == -2:
286 self.normaldirty(f)
286 self.normaldirty(f)
287 if source:
287 if source:
288 self.copy(source, f)
288 self.copy(source, f)
289 return
289 return
290 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
290 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
291 return
291 return
292 self._dirty = True
292 self._dirty = True
293 self._addpath(f)
293 self._addpath(f)
294 self._map[f] = ('n', 0, -1, -1)
294 self._map[f] = ('n', 0, -1, -1)
295 if f in self._copymap:
295 if f in self._copymap:
296 del self._copymap[f]
296 del self._copymap[f]
297
297
298 def normaldirty(self, f):
298 def normaldirty(self, f):
299 'mark a file normal, but dirty'
299 'mark a file normal, but dirty'
300 self._dirty = True
300 self._dirty = True
301 self._addpath(f)
301 self._addpath(f)
302 self._map[f] = ('n', 0, -2, -1)
302 self._map[f] = ('n', 0, -2, -1)
303 if f in self._copymap:
303 if f in self._copymap:
304 del self._copymap[f]
304 del self._copymap[f]
305
305
306 def add(self, f):
306 def add(self, f):
307 'mark a file added'
307 'mark a file added'
308 self._dirty = True
308 self._dirty = True
309 self._addpath(f, True)
309 self._addpath(f, True)
310 self._map[f] = ('a', 0, -1, -1)
310 self._map[f] = ('a', 0, -1, -1)
311 if f in self._copymap:
311 if f in self._copymap:
312 del self._copymap[f]
312 del self._copymap[f]
313
313
314 def remove(self, f):
314 def remove(self, f):
315 'mark a file removed'
315 'mark a file removed'
316 self._dirty = True
316 self._dirty = True
317 self._droppath(f)
317 self._droppath(f)
318 size = 0
318 size = 0
319 if self._pl[1] != nullid and f in self._map:
319 if self._pl[1] != nullid and f in self._map:
320 entry = self._map[f]
320 entry = self._map[f]
321 if entry[0] == 'm':
321 if entry[0] == 'm':
322 size = -1
322 size = -1
323 elif entry[0] == 'n' and entry[2] == -2:
323 elif entry[0] == 'n' and entry[2] == -2:
324 size = -2
324 size = -2
325 self._map[f] = ('r', 0, size, 0)
325 self._map[f] = ('r', 0, size, 0)
326 if size == 0 and f in self._copymap:
326 if size == 0 and f in self._copymap:
327 del self._copymap[f]
327 del self._copymap[f]
328
328
329 def merge(self, f):
329 def merge(self, f):
330 'mark a file merged'
330 'mark a file merged'
331 self._dirty = True
331 self._dirty = True
332 s = os.lstat(self._join(f))
332 s = os.lstat(self._join(f))
333 self._addpath(f)
333 self._addpath(f)
334 self._map[f] = ('m', s.st_mode, s.st_size, int(s.st_mtime))
334 self._map[f] = ('m', s.st_mode, s.st_size, int(s.st_mtime))
335 if f in self._copymap:
335 if f in self._copymap:
336 del self._copymap[f]
336 del self._copymap[f]
337
337
338 def forget(self, f):
338 def forget(self, f):
339 'forget a file'
339 'forget a file'
340 self._dirty = True
340 self._dirty = True
341 try:
341 try:
342 self._droppath(f)
342 self._droppath(f)
343 del self._map[f]
343 del self._map[f]
344 except KeyError:
344 except KeyError:
345 self._ui.warn(_("not in dirstate: %s\n") % f)
345 self._ui.warn(_("not in dirstate: %s\n") % f)
346
346
347 def _normalize(self, path, knownpath=False):
347 def _normalize(self, path, knownpath=False):
348 norm_path = os.path.normcase(path)
348 norm_path = os.path.normcase(path)
349 fold_path = self._foldmap.get(norm_path, None)
349 fold_path = self._foldmap.get(norm_path, None)
350 if fold_path is None:
350 if fold_path is None:
351 if knownpath or not os.path.exists(os.path.join(self._root, path)):
351 if knownpath or not os.path.exists(os.path.join(self._root, path)):
352 fold_path = path
352 fold_path = path
353 else:
353 else:
354 fold_path = self._foldmap.setdefault(norm_path,
354 fold_path = self._foldmap.setdefault(norm_path,
355 util.fspath(path, self._root))
355 util.fspath(path, self._root))
356 return fold_path
356 return fold_path
357
357
358 def clear(self):
358 def clear(self):
359 self._map = {}
359 self._map = {}
360 if "_dirs" in self.__dict__:
360 if "_dirs" in self.__dict__:
361 delattr(self, "_dirs");
361 delattr(self, "_dirs");
362 self._copymap = {}
362 self._copymap = {}
363 self._pl = [nullid, nullid]
363 self._pl = [nullid, nullid]
364 self._dirty = True
364 self._dirty = True
365
365
366 def rebuild(self, parent, files):
366 def rebuild(self, parent, files):
367 self.clear()
367 self.clear()
368 for f in files:
368 for f in files:
369 if 'x' in files.flags(f):
369 if 'x' in files.flags(f):
370 self._map[f] = ('n', 0777, -1, 0)
370 self._map[f] = ('n', 0777, -1, 0)
371 else:
371 else:
372 self._map[f] = ('n', 0666, -1, 0)
372 self._map[f] = ('n', 0666, -1, 0)
373 self._pl = (parent, nullid)
373 self._pl = (parent, nullid)
374 self._dirty = True
374 self._dirty = True
375
375
376 def write(self):
376 def write(self):
377 if not self._dirty:
377 if not self._dirty:
378 return
378 return
379 st = self._opener("dirstate", "w", atomictemp=True)
379 st = self._opener("dirstate", "w", atomictemp=True)
380
380
381 try:
381 try:
382 gran = int(self._ui.config('dirstate', 'granularity', 1))
382 gran = int(self._ui.config('dirstate', 'granularity', 1))
383 except ValueError:
383 except ValueError:
384 gran = 1
384 gran = 1
385 limit = sys.maxint
385 limit = sys.maxint
386 if gran > 0:
386 if gran > 0:
387 limit = util.fstat(st).st_mtime - gran
387 limit = util.fstat(st).st_mtime - gran
388
388
389 cs = cStringIO.StringIO()
389 cs = cStringIO.StringIO()
390 copymap = self._copymap
390 copymap = self._copymap
391 pack = struct.pack
391 pack = struct.pack
392 write = cs.write
392 write = cs.write
393 write("".join(self._pl))
393 write("".join(self._pl))
394 for f, e in self._map.iteritems():
394 for f, e in self._map.iteritems():
395 if f in copymap:
395 if f in copymap:
396 f = "%s\0%s" % (f, copymap[f])
396 f = "%s\0%s" % (f, copymap[f])
397 if e[3] > limit and e[0] == 'n':
397 if e[3] > limit and e[0] == 'n':
398 e = (e[0], 0, -1, -1)
398 e = (e[0], 0, -1, -1)
399 e = pack(_format, e[0], e[1], e[2], e[3], len(f))
399 e = pack(_format, e[0], e[1], e[2], e[3], len(f))
400 write(e)
400 write(e)
401 write(f)
401 write(f)
402 st.write(cs.getvalue())
402 st.write(cs.getvalue())
403 st.rename()
403 st.rename()
404 self._dirty = self._dirtypl = False
404 self._dirty = self._dirtypl = False
405
405
406 def _dirignore(self, f):
406 def _dirignore(self, f):
407 if f == '.':
407 if f == '.':
408 return False
408 return False
409 if self._ignore(f):
409 if self._ignore(f):
410 return True
410 return True
411 for p in _finddirs(f):
411 for p in _finddirs(f):
412 if self._ignore(p):
412 if self._ignore(p):
413 return True
413 return True
414 return False
414 return False
415
415
416 def walk(self, match, unknown, ignored):
416 def walk(self, match, unknown, ignored):
417 '''
417 '''
418 walk recursively through the directory tree, finding all files
418 walk recursively through the directory tree, finding all files
419 matched by the match function
419 matched by the match function
420
420
421 results are yielded in a tuple (filename, stat), where stat
421 results are yielded in a tuple (filename, stat), where stat
422 and st is the stat result if the file was found in the directory.
422 and st is the stat result if the file was found in the directory.
423 '''
423 '''
424
424
425 def fwarn(f, msg):
425 def fwarn(f, msg):
426 self._ui.warn('%s: %s\n' % (self.pathto(f), msg))
426 self._ui.warn('%s: %s\n' % (self.pathto(f), msg))
427 return False
427 return False
428 badfn = fwarn
428 badfn = fwarn
429 if hasattr(match, 'bad'):
429 if hasattr(match, 'bad'):
430 badfn = match.bad
430 badfn = match.bad
431
431
432 def badtype(f, mode):
432 def badtype(f, mode):
433 kind = _('unknown')
433 kind = _('unknown')
434 if stat.S_ISCHR(mode): kind = _('character device')
434 if stat.S_ISCHR(mode): kind = _('character device')
435 elif stat.S_ISBLK(mode): kind = _('block device')
435 elif stat.S_ISBLK(mode): kind = _('block device')
436 elif stat.S_ISFIFO(mode): kind = _('fifo')
436 elif stat.S_ISFIFO(mode): kind = _('fifo')
437 elif stat.S_ISSOCK(mode): kind = _('socket')
437 elif stat.S_ISSOCK(mode): kind = _('socket')
438 elif stat.S_ISDIR(mode): kind = _('directory')
438 elif stat.S_ISDIR(mode): kind = _('directory')
439 self._ui.warn(_('%s: unsupported file type (type is %s)\n')
439 self._ui.warn(_('%s: unsupported file type (type is %s)\n')
440 % (self.pathto(f), kind))
440 % (self.pathto(f), kind))
441
441
442 ignore = self._ignore
442 ignore = self._ignore
443 dirignore = self._dirignore
443 dirignore = self._dirignore
444 if ignored:
444 if ignored:
445 ignore = util.never
445 ignore = util.never
446 dirignore = util.never
446 dirignore = util.never
447 elif not unknown:
447 elif not unknown:
448 # if unknown and ignored are False, skip step 2
448 # if unknown and ignored are False, skip step 2
449 ignore = util.always
449 ignore = util.always
450 dirignore = util.always
450 dirignore = util.always
451
451
452 matchfn = match.matchfn
452 matchfn = match.matchfn
453 dmap = self._map
453 dmap = self._map
454 normpath = util.normpath
454 normpath = util.normpath
455 normalize = self.normalize
455 normalize = self.normalize
456 listdir = osutil.listdir
456 listdir = osutil.listdir
457 lstat = os.lstat
457 lstat = os.lstat
458 getkind = stat.S_IFMT
458 getkind = stat.S_IFMT
459 dirkind = stat.S_IFDIR
459 dirkind = stat.S_IFDIR
460 regkind = stat.S_IFREG
460 regkind = stat.S_IFREG
461 lnkkind = stat.S_IFLNK
461 lnkkind = stat.S_IFLNK
462 join = self._join
462 join = self._join
463 work = []
463 work = []
464 wadd = work.append
464 wadd = work.append
465
465
466 if match.anypats():
466 if match.anypats():
467 #match.match with patterns
467 #match.match with patterns
468 dostep3 = True
468 dostep3 = True
469 nomatches = False
469 nomatches = False
470 elif not match.files():
470 elif not match.files():
471 #match.always or match.never
471 #match.always or match.never
472 dostep3 = matchfn('')
472 dostep3 = matchfn('')
473 nomatches = not dostep3
473 nomatches = not dostep3
474 else:
474 else:
475 #match.exact or match.match without pattern
475 #match.exact or match.match without pattern
476 dostep3 = False
476 dostep3 = False
477 nomatches = matchfn == match.exact
477 nomatches = matchfn == match.exact
478
478
479 if nomatches:
479 if nomatches:
480 #skip step 2
480 #skip step 2
481 dirignore = util.always
481 dirignore = util.always
482
482
483 files = set(match.files())
483 files = set(match.files())
484 if not files or '.' in files:
484 if not files or '.' in files:
485 files = ['']
485 files = ['']
486 results = {'.hg': None}
486 results = {'.hg': None}
487
487
488 # step 1: find all explicit files
488 # step 1: find all explicit files
489 for ff in sorted(files):
489 for ff in sorted(files):
490 nf = normalize(normpath(ff))
490 nf = normalize(normpath(ff))
491 if nf in results:
491 if nf in results:
492 continue
492 continue
493
493
494 try:
494 try:
495 st = lstat(join(nf))
495 st = lstat(join(nf))
496 kind = getkind(st.st_mode)
496 kind = getkind(st.st_mode)
497 if kind == dirkind:
497 if kind == dirkind:
498 dostep3 = True
498 dostep3 = True
499 if nf in dmap:
499 if nf in dmap:
500 #file deleted on disc but still in dirstate
500 #file deleted on disk but still in dirstate
501 results[nf] = None
501 results[nf] = None
502 if not dirignore(nf):
502 if not dirignore(nf):
503 wadd(nf)
503 wadd(nf)
504 elif kind == regkind or kind == lnkkind:
504 elif kind == regkind or kind == lnkkind:
505 results[nf] = st
505 results[nf] = st
506 else:
506 else:
507 badtype(ff, kind)
507 badtype(ff, kind)
508 if nf in dmap:
508 if nf in dmap:
509 results[nf] = None
509 results[nf] = None
510 except OSError, inst:
510 except OSError, inst:
511 keep = False
511 keep = False
512 prefix = nf + "/"
512 prefix = nf + "/"
513 for fn in dmap:
513 for fn in dmap:
514 if nf == fn:
514 if nf == fn:
515 if matchfn(nf):
515 if matchfn(nf):
516 results[nf] = None
516 results[nf] = None
517 keep = True
517 keep = True
518 break
518 break
519 elif fn.startswith(prefix):
519 elif fn.startswith(prefix):
520 dostep3 = True
520 dostep3 = True
521 keep = True
521 keep = True
522 break
522 break
523 if not keep:
523 if not keep:
524 if inst.errno != errno.ENOENT:
524 if inst.errno != errno.ENOENT:
525 fwarn(ff, inst.strerror)
525 fwarn(ff, inst.strerror)
526 elif badfn(ff, inst.strerror):
526 elif badfn(ff, inst.strerror):
527 if nf not in results and not ignore(nf) and matchfn(nf):
527 if nf not in results and not ignore(nf) and matchfn(nf):
528 results[nf] = None
528 results[nf] = None
529
529
530 # step 2: visit subdirectories
530 # step 2: visit subdirectories
531 while work:
531 while work:
532 nd = work.pop()
532 nd = work.pop()
533 if hasattr(match, 'dir'):
533 if hasattr(match, 'dir'):
534 match.dir(nd)
534 match.dir(nd)
535 skip = None
535 skip = None
536 if nd == '.':
536 if nd == '.':
537 nd = ''
537 nd = ''
538 else:
538 else:
539 skip = '.hg'
539 skip = '.hg'
540 try:
540 try:
541 entries = listdir(join(nd), stat=True, skip=skip)
541 entries = listdir(join(nd), stat=True, skip=skip)
542 except OSError, inst:
542 except OSError, inst:
543 if inst.errno == errno.EACCES:
543 if inst.errno == errno.EACCES:
544 fwarn(nd, inst.strerror)
544 fwarn(nd, inst.strerror)
545 continue
545 continue
546 raise
546 raise
547 for f, kind, st in entries:
547 for f, kind, st in entries:
548 nf = normalize(nd and (nd + "/" + f) or f, True)
548 nf = normalize(nd and (nd + "/" + f) or f, True)
549 if nf not in results:
549 if nf not in results:
550 if kind == dirkind:
550 if kind == dirkind:
551 if not ignore(nf):
551 if not ignore(nf):
552 wadd(nf)
552 wadd(nf)
553 if nf in dmap and matchfn(nf):
553 if nf in dmap and matchfn(nf):
554 results[nf] = None
554 results[nf] = None
555 elif kind == regkind or kind == lnkkind:
555 elif kind == regkind or kind == lnkkind:
556 if nf in dmap:
556 if nf in dmap:
557 if matchfn(nf):
557 if matchfn(nf):
558 results[nf] = st
558 results[nf] = st
559 elif matchfn(nf) and not ignore(nf):
559 elif matchfn(nf) and not ignore(nf):
560 results[nf] = st
560 results[nf] = st
561 elif nf in dmap and matchfn(nf):
561 elif nf in dmap and matchfn(nf):
562 results[nf] = None
562 results[nf] = None
563
563
564 # step 3: report unseen items in the dmap hash
564 # step 3: report unseen items in the dmap hash
565 if dostep3 and not nomatches:
565 if dostep3 and not nomatches:
566 visit = sorted([f for f in dmap if f not in results and matchfn(f)])
566 visit = sorted([f for f in dmap if f not in results and matchfn(f)])
567 for nf, st in zip(visit, util.statfiles([join(i) for i in visit])):
567 for nf, st in zip(visit, util.statfiles([join(i) for i in visit])):
568 if not st is None and not getkind(st.st_mode) in (regkind, lnkkind):
568 if not st is None and not getkind(st.st_mode) in (regkind, lnkkind):
569 st = None
569 st = None
570 results[nf] = st
570 results[nf] = st
571
571
572 del results['.hg']
572 del results['.hg']
573 return results
573 return results
574
574
575 def status(self, match, ignored, clean, unknown):
575 def status(self, match, ignored, clean, unknown):
576 listignored, listclean, listunknown = ignored, clean, unknown
576 listignored, listclean, listunknown = ignored, clean, unknown
577 lookup, modified, added, unknown, ignored = [], [], [], [], []
577 lookup, modified, added, unknown, ignored = [], [], [], [], []
578 removed, deleted, clean = [], [], []
578 removed, deleted, clean = [], [], []
579
579
580 dmap = self._map
580 dmap = self._map
581 ladd = lookup.append
581 ladd = lookup.append
582 madd = modified.append
582 madd = modified.append
583 aadd = added.append
583 aadd = added.append
584 uadd = unknown.append
584 uadd = unknown.append
585 iadd = ignored.append
585 iadd = ignored.append
586 radd = removed.append
586 radd = removed.append
587 dadd = deleted.append
587 dadd = deleted.append
588 cadd = clean.append
588 cadd = clean.append
589
589
590 for fn, st in self.walk(match, listunknown, listignored).iteritems():
590 for fn, st in self.walk(match, listunknown, listignored).iteritems():
591 if fn not in dmap:
591 if fn not in dmap:
592 if (listignored or match.exact(fn)) and self._dirignore(fn):
592 if (listignored or match.exact(fn)) and self._dirignore(fn):
593 if listignored:
593 if listignored:
594 iadd(fn)
594 iadd(fn)
595 elif listunknown:
595 elif listunknown:
596 uadd(fn)
596 uadd(fn)
597 continue
597 continue
598
598
599 state, mode, size, time = dmap[fn]
599 state, mode, size, time = dmap[fn]
600
600
601 if not st and state in "nma":
601 if not st and state in "nma":
602 dadd(fn)
602 dadd(fn)
603 elif state == 'n':
603 elif state == 'n':
604 if (size >= 0 and
604 if (size >= 0 and
605 (size != st.st_size
605 (size != st.st_size
606 or ((mode ^ st.st_mode) & 0100 and self._checkexec))
606 or ((mode ^ st.st_mode) & 0100 and self._checkexec))
607 or size == -2
607 or size == -2
608 or fn in self._copymap):
608 or fn in self._copymap):
609 madd(fn)
609 madd(fn)
610 elif time != int(st.st_mtime):
610 elif time != int(st.st_mtime):
611 ladd(fn)
611 ladd(fn)
612 elif listclean:
612 elif listclean:
613 cadd(fn)
613 cadd(fn)
614 elif state == 'm':
614 elif state == 'm':
615 madd(fn)
615 madd(fn)
616 elif state == 'a':
616 elif state == 'a':
617 aadd(fn)
617 aadd(fn)
618 elif state == 'r':
618 elif state == 'r':
619 radd(fn)
619 radd(fn)
620
620
621 return (lookup, modified, added, removed, deleted, unknown, ignored,
621 return (lookup, modified, added, removed, deleted, unknown, ignored,
622 clean)
622 clean)
General Comments 0
You need to be logged in to leave comments. Login now