##// END OF EJS Templates
dirstate: simplify/optimize path checking...
Matt Mackall -
r6767:80605a81 default
parent child Browse files
Show More
@@ -9,12 +9,20 b' of the GNU General Public License, incor'
9
9
10 from node import nullid
10 from node import nullid
11 from i18n import _
11 from i18n import _
12 import struct, os, bisect, stat, strutil, util, errno, ignore
12 import struct, os, bisect, stat, util, errno, ignore
13 import cStringIO, osutil, sys
13 import cStringIO, osutil, sys
14
14
15 _unknown = ('?', 0, 0, 0)
15 _unknown = ('?', 0, 0, 0)
16 _format = ">cllll"
16 _format = ">cllll"
17
17
18 def _finddirs(path):
19 pos = len(path)
20 while 1:
21 pos = path.rfind('/', 0, pos)
22 if pos == -1:
23 break
24 yield path[:pos]
25
18 class dirstate(object):
26 class dirstate(object):
19
27
20 def __init__(self, opener, ui, root):
28 def __init__(self, opener, ui, root):
@@ -55,10 +63,12 b' class dirstate(object):'
55 if err.errno != errno.ENOENT: raise
63 if err.errno != errno.ENOENT: raise
56 return self._pl
64 return self._pl
57 elif name == '_dirs':
65 elif name == '_dirs':
58 self._dirs = {}
66 dirs = {}
59 for f in self._map:
67 for f,s in self._map.items():
60 if self[f] != 'r':
68 if s[0] != 'r':
61 self._incpath(f)
69 for base in _finddirs(f):
70 dirs[base] = dirs.get(base, 0) + 1
71 self._dirs = dirs
62 return self._dirs
72 return self._dirs
63 elif name == '_ignore':
73 elif name == '_ignore':
64 files = [self._join('.hgignore')]
74 files = [self._join('.hgignore')]
@@ -223,67 +233,39 b' class dirstate(object):'
223 def copies(self):
233 def copies(self):
224 return self._copymap
234 return self._copymap
225
235
226 def _incpath(self, path):
236 def _droppath(self, f):
227 c = path.rfind('/')
237 if self[f] not in "?r" and "_dirs" in self.__dict__:
228 if c >= 0:
229 dirs = self._dirs
238 dirs = self._dirs
230 base = path[:c]
239 for base in _finddirs(f):
231 if base not in dirs:
240 if dirs[base] == 1:
232 self._incpath(base)
241 del dirs[base]
233 dirs[base] = 1
242 else:
234 else:
243 dirs[base] -= 1
235 dirs[base] += 1
236
237 def _decpath(self, path):
238 c = path.rfind('/')
239 if c >= 0:
240 base = path[:c]
241 dirs = self._dirs
242 if dirs[base] == 1:
243 del dirs[base]
244 self._decpath(base)
245 else:
246 dirs[base] -= 1
247
244
248 def _incpathcheck(self, f):
245 def _addpath(self, f, check=False):
249 if '\r' in f or '\n' in f:
250 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames: %r")
251 % f)
252 # shadows
253 if f in self._dirs:
254 raise util.Abort(_('directory %r already in dirstate') % f)
255 for c in strutil.rfindall(f, '/'):
256 d = f[:c]
257 if d in self._dirs:
258 break
259 if d in self._map and self[d] != 'r':
260 raise util.Abort(_('file %r in dirstate clashes with %r') %
261 (d, f))
262 self._incpath(f)
263
264 def _changepath(self, f, newstate, relaxed=False):
265 # handle upcoming path changes
266 oldstate = self[f]
246 oldstate = self[f]
267 if oldstate not in "?r" and newstate in "?r":
247 if check or oldstate == "r":
268 if "_dirs" in self.__dict__:
248 if '\r' in f or '\n' in f:
269 self._decpath(f)
249 raise util.Abort(
270 return
250 _("'\\n' and '\\r' disallowed in filenames: %r") % f)
271 if oldstate in "?r" and newstate not in "?r":
251 if f in self._dirs:
272 if relaxed and oldstate == '?':
252 raise util.Abort(_('directory %r already in dirstate') % f)
273 # XXX
253 # shadows
274 # in relaxed mode we assume the caller knows
254 for d in _finddirs(f):
275 # what it is doing, workaround for updating
255 if d in self._dirs:
276 # dir-to-file revisions
256 break
277 if "_dirs" in self.__dict__:
257 if d in self._map and self[d] != 'r':
278 self._incpath(f)
258 raise util.Abort(
279 return
259 _('file %r in dirstate clashes with %r') % (d, f))
280 self._incpathcheck(f)
260 if oldstate in "?r" and "_dirs" in self.__dict__:
281 return
261 dirs = self._dirs
262 for base in _finddirs(f):
263 dirs[base] = dirs.get(base, 0) + 1
282
264
283 def normal(self, f):
265 def normal(self, f):
284 'mark a file normal and clean'
266 'mark a file normal and clean'
285 self._dirty = True
267 self._dirty = True
286 self._changepath(f, 'n', True)
268 self._addpath(f)
287 s = os.lstat(self._join(f))
269 s = os.lstat(self._join(f))
288 self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime, 0)
270 self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime, 0)
289 if f in self._copymap:
271 if f in self._copymap:
@@ -307,7 +289,7 b' class dirstate(object):'
307 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
289 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
308 return
290 return
309 self._dirty = True
291 self._dirty = True
310 self._changepath(f, 'n', True)
292 self._addpath(f)
311 self._map[f] = ('n', 0, -1, -1, 0)
293 self._map[f] = ('n', 0, -1, -1, 0)
312 if f in self._copymap:
294 if f in self._copymap:
313 del self._copymap[f]
295 del self._copymap[f]
@@ -315,7 +297,7 b' class dirstate(object):'
315 def normaldirty(self, f):
297 def normaldirty(self, f):
316 'mark a file normal, but dirty'
298 'mark a file normal, but dirty'
317 self._dirty = True
299 self._dirty = True
318 self._changepath(f, 'n', True)
300 self._addpath(f)
319 self._map[f] = ('n', 0, -2, -1, 0)
301 self._map[f] = ('n', 0, -2, -1, 0)
320 if f in self._copymap:
302 if f in self._copymap:
321 del self._copymap[f]
303 del self._copymap[f]
@@ -323,7 +305,7 b' class dirstate(object):'
323 def add(self, f):
305 def add(self, f):
324 'mark a file added'
306 'mark a file added'
325 self._dirty = True
307 self._dirty = True
326 self._changepath(f, 'a')
308 self._addpath(f, True)
327 self._map[f] = ('a', 0, -1, -1, 0)
309 self._map[f] = ('a', 0, -1, -1, 0)
328 if f in self._copymap:
310 if f in self._copymap:
329 del self._copymap[f]
311 del self._copymap[f]
@@ -331,7 +313,7 b' class dirstate(object):'
331 def remove(self, f):
313 def remove(self, f):
332 'mark a file removed'
314 'mark a file removed'
333 self._dirty = True
315 self._dirty = True
334 self._changepath(f, 'r')
316 self._droppath(f)
335 size = 0
317 size = 0
336 if self._pl[1] != nullid and f in self._map:
318 if self._pl[1] != nullid and f in self._map:
337 entry = self._map[f]
319 entry = self._map[f]
@@ -347,7 +329,7 b' class dirstate(object):'
347 'mark a file merged'
329 'mark a file merged'
348 self._dirty = True
330 self._dirty = True
349 s = os.lstat(self._join(f))
331 s = os.lstat(self._join(f))
350 self._changepath(f, 'm', True)
332 self._addpath(f)
351 self._map[f] = ('m', s.st_mode, s.st_size, s.st_mtime, 0)
333 self._map[f] = ('m', s.st_mode, s.st_size, s.st_mtime, 0)
352 if f in self._copymap:
334 if f in self._copymap:
353 del self._copymap[f]
335 del self._copymap[f]
@@ -356,7 +338,7 b' class dirstate(object):'
356 'forget a file'
338 'forget a file'
357 self._dirty = True
339 self._dirty = True
358 try:
340 try:
359 self._changepath(f, '?')
341 self._droppath('?')
360 del self._map[f]
342 del self._map[f]
361 except KeyError:
343 except KeyError:
362 self._ui.warn(_("not in dirstate: %s\n") % f)
344 self._ui.warn(_("not in dirstate: %s\n") % f)
@@ -467,8 +449,8 b' class dirstate(object):'
467 return False
449 return False
468 if self._ignore(f):
450 if self._ignore(f):
469 return True
451 return True
470 for c in strutil.findall(f, '/'):
452 for p in _finddirs(f):
471 if self._ignore(f[:c]):
453 if self._ignore(p):
472 return True
454 return True
473 return False
455 return False
474
456
General Comments 0
You need to be logged in to leave comments. Login now