##// END OF EJS Templates
treemanifest: create treemanifest class...
Martin von Zweigbergk -
r24401:e6e023d5 default
parent child Browse files
Show More
@@ -328,6 +328,228 b' def _addlistdelta(addlist, x):'
328 328 + content for start, end, content in x)
329 329 return deltatext, newaddlist
330 330
331 def _splittopdir(f):
332 if '/' in f:
333 dir, subpath = f.split('/', 1)
334 return dir + '/', subpath
335 else:
336 return '', f
337
338 class treemanifest(object):
339 def __init__(self, text=''):
340 self._dirs = {}
341 # Using _lazymanifest here is a little slower than plain old dicts
342 self._files = {}
343 self._flags = {}
344 lm = _lazymanifest(text)
345 for f, n, fl in lm.iterentries():
346 self[f] = n
347 if fl:
348 self.setflag(f, fl)
349
350 def __len__(self):
351 size = len(self._files)
352 for m in self._dirs.values():
353 size += m.__len__()
354 return size
355
356 def iteritems(self):
357 for p, n in sorted(self._dirs.items() + self._files.items()):
358 if p in self._files:
359 yield p, n
360 else:
361 for sf, sn in n.iteritems():
362 yield p + sf, sn
363
364 def iterkeys(self):
365 for p in sorted(self._dirs.keys() + self._files.keys()):
366 if p in self._files:
367 yield p
368 else:
369 for f in self._dirs[p].iterkeys():
370 yield p + f
371
372 def keys(self):
373 return list(self.iterkeys())
374
375 def __iter__(self):
376 return self.iterkeys()
377
378 def __contains__(self, f):
379 if f is None:
380 return False
381 dir, subpath = _splittopdir(f)
382 if dir:
383 if dir not in self._dirs:
384 return False
385 return self._dirs[dir].__contains__(subpath)
386 else:
387 return f in self._files
388
389 def get(self, f, default=None):
390 dir, subpath = _splittopdir(f)
391 if dir:
392 if dir not in self._dirs:
393 return default
394 return self._dirs[dir].get(subpath, default)
395 else:
396 return self._files.get(f, default)
397
398 def __getitem__(self, f):
399 dir, subpath = _splittopdir(f)
400 if dir:
401 return self._dirs[dir].__getitem__(subpath)
402 else:
403 return self._files[f]
404
405 def flags(self, f):
406 dir, subpath = _splittopdir(f)
407 if dir:
408 if dir not in self._dirs:
409 return ''
410 return self._dirs[dir].flags(subpath)
411 else:
412 if f in self._dirs:
413 return ''
414 return self._flags.get(f, '')
415
416 def find(self, f):
417 dir, subpath = _splittopdir(f)
418 if dir:
419 return self._dirs[dir].find(subpath)
420 else:
421 return self._files[f], self._flags.get(f, '')
422
423 def __delitem__(self, f):
424 dir, subpath = _splittopdir(f)
425 if dir:
426 self._dirs[dir].__delitem__(subpath)
427 # If the directory is now empty, remove it
428 if not self._dirs[dir]._dirs and not self._dirs[dir]._files:
429 del self._dirs[dir]
430 else:
431 del self._files[f]
432 if f in self._flags:
433 del self._flags[f]
434
435 def __setitem__(self, f, n):
436 assert n is not None
437 dir, subpath = _splittopdir(f)
438 if dir:
439 if dir not in self._dirs:
440 self._dirs[dir] = treemanifest()
441 self._dirs[dir].__setitem__(subpath, n)
442 else:
443 self._files[f] = n
444
445 def setflag(self, f, flags):
446 """Set the flags (symlink, executable) for path f."""
447 dir, subpath = _splittopdir(f)
448 if dir:
449 if dir not in self._dirs:
450 self._dirs[dir] = treemanifest()
451 self._dirs[dir].setflag(subpath, flags)
452 else:
453 self._flags[f] = flags
454
455 def copy(self):
456 copy = treemanifest()
457 for d in self._dirs:
458 copy._dirs[d] = self._dirs[d].copy()
459 copy._files = dict.copy(self._files)
460 copy._flags = dict.copy(self._flags)
461 return copy
462
463 def intersectfiles(self, files):
464 '''make a new treemanifest with the intersection of self with files
465
466 The algorithm assumes that files is much smaller than self.'''
467 ret = treemanifest()
468 for fn in files:
469 if fn in self:
470 ret[fn] = self[fn]
471 flags = self.flags(fn)
472 if flags:
473 ret.setflag(fn, flags)
474 return ret
475
476 def filesnotin(self, m2):
477 '''Set of files in this manifest that are not in the other'''
478 files = set(self.iterkeys())
479 files.difference_update(m2.iterkeys())
480 return files
481
482 @propertycache
483 def _alldirs(self):
484 return scmutil.dirs(self)
485
486 def dirs(self):
487 return self._alldirs
488
489 def hasdir(self, dir):
490 return dir in self._alldirs
491
492 def matches(self, match):
493 '''generate a new manifest filtered by the match argument'''
494 if match.always():
495 return self.copy()
496
497 files = match.files()
498 if (match.matchfn == match.exact or
499 (not match.anypats() and util.all(fn in self for fn in files))):
500 return self.intersectfiles(files)
501
502 m = self.copy()
503 for fn in m.keys():
504 if not match(fn):
505 del m[fn]
506 return m
507
508 def diff(self, m2, clean=False):
509 '''Finds changes between the current manifest and m2.
510
511 Args:
512 m2: the manifest to which this manifest should be compared.
513 clean: if true, include files unchanged between these manifests
514 with a None value in the returned dictionary.
515
516 The result is returned as a dict with filename as key and
517 values of the form ((n1,fl1),(n2,fl2)), where n1/n2 is the
518 nodeid in the current/other manifest and fl1/fl2 is the flag
519 in the current/other manifest. Where the file does not exist,
520 the nodeid will be None and the flags will be the empty
521 string.
522 '''
523 diff = {}
524
525 for fn, n1 in self.iteritems():
526 fl1 = self.flags(fn)
527 n2 = m2.get(fn, None)
528 fl2 = m2.flags(fn)
529 if n2 is None:
530 fl2 = ''
531 if n1 != n2 or fl1 != fl2:
532 diff[fn] = ((n1, fl1), (n2, fl2))
533 elif clean:
534 diff[fn] = None
535
536 for fn, n2 in m2.iteritems():
537 if fn not in self:
538 fl2 = m2.flags(fn)
539 diff[fn] = ((None, ''), (n2, fl2))
540
541 return diff
542
543 def text(self):
544 """Get the full data of this manifest as a bytestring."""
545 fl = self.keys()
546 _checkforbidden(fl)
547
548 hex, flags = revlog.hex, self.flags
549 # if this is changed to support newlines in filenames,
550 # be sure to check the templates/ dir again (especially *-raw.tmpl)
551 return ''.join("%s\0%s%s\n" % (f, hex(self[f]), flags(f)) for f in fl)
552
331 553 class manifest(revlog.revlog):
332 554 def __init__(self, opener):
333 555 # During normal operations, we expect to deal with not more than four
General Comments 0
You need to be logged in to leave comments. Login now