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