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