##// END OF EJS Templates
stream-clone: introduce a richer TempCopyManager object...
marmoute -
r51523:8c7b04e6 default
parent child Browse files
Show More
@@ -556,28 +556,55 b' def _filterfull(entry, copy, vfsmap):'
556 return (src, name, ftype, copy(vfsmap[src].join(name)))
556 return (src, name, ftype, copy(vfsmap[src].join(name)))
557
557
558
558
559 @contextlib.contextmanager
559 class TempCopyManager:
560 def maketempcopies():
560 """Manage temporary backup of volatile file during stream clone
561 """return a function to temporary copy file"""
561
562 This should be used as a Python context, the copies will be discarded when
563 exiting the context.
564
565 A copy can be done by calling the object on the real path (encoded full
566 path)
562
567
563 files = []
568 The backup path can be retrieved using the __getitem__ protocol, obj[path].
564 dst_dir = pycompat.mkdtemp(prefix=b'hg-clone-')
569 On file without backup, it will return the unmodified path. (equivalent to
565 try:
570 `dict.get(x, x)`)
571 """
572
573 def __init__(self):
574 self._copies = None
575 self._dst_dir = None
566
576
567 def copy(src):
577 def __enter__(self):
568 fd, dst = pycompat.mkstemp(
578 if self._copies is not None:
569 prefix=os.path.basename(src), dir=dst_dir
579 msg = "Copies context already open"
570 )
580 raise error.ProgrammingError(msg)
571 os.close(fd)
581 self._copies = {}
572 files.append(dst)
582 self._dst_dir = pycompat.mkdtemp(prefix=b'hg-clone-')
573 util.copyfiles(src, dst, hardlink=True)
583 return self
574 return dst
575
584
576 yield copy
585 def __call__(self, src):
577 finally:
586 """create a backup of the file at src"""
578 for tmp in files:
587 prefix = os.path.basename(src)
588 fd, dst = pycompat.mkstemp(prefix=prefix, dir=self._dst_dir)
589 os.close(fd)
590 self._copies[src] = dst
591 util.copyfiles(src, dst, hardlink=True)
592 return dst
593
594 def __getitem__(self, src):
595 """return the path to a valid version of `src`
596
597 If the file has no backup, the path of the file is returned
598 unmodified."""
599 return self._copies.get(src, src)
600
601 def __exit__(self, *args, **kwars):
602 """discard all backups"""
603 for tmp in self._copies.values():
579 util.tryunlink(tmp)
604 util.tryunlink(tmp)
580 util.tryrmdir(dst_dir)
605 util.tryrmdir(self._dst_dir)
606 self._copies = None
607 self._dst_dir = None
581
608
582
609
583 def _makemap(repo):
610 def _makemap(repo):
@@ -610,7 +637,7 b' def _emit2(repo, entries, totalfilesize)'
610 _(b'bundle'), total=totalfilesize, unit=_(b'bytes')
637 _(b'bundle'), total=totalfilesize, unit=_(b'bytes')
611 )
638 )
612 progress.update(0)
639 progress.update(0)
613 with maketempcopies() as copy, progress:
640 with TempCopyManager() as copy, progress:
614 # copy is delayed until we are in the try
641 # copy is delayed until we are in the try
615 entries = [_filterfull(e, copy, vfsmap) for e in entries]
642 entries = [_filterfull(e, copy, vfsmap) for e in entries]
616 yield None # this release the lock on the repository
643 yield None # this release the lock on the repository
General Comments 0
You need to be logged in to leave comments. Login now