Show More
@@ -328,6 +328,228 b' def _addlistdelta(addlist, x):' | |||||
328 | + content for start, end, content in x) |
|
328 | + content for start, end, content in x) | |
329 | return deltatext, newaddlist |
|
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 | class manifest(revlog.revlog): |
|
553 | class manifest(revlog.revlog): | |
332 | def __init__(self, opener): |
|
554 | def __init__(self, opener): | |
333 | # During normal operations, we expect to deal with not more than four |
|
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