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