mercurial/streamclone.py
changeset 47447 377d8fc20e34
parent 47444 2f4ca4807033
child 47448 d370256636fe
equal deleted inserted replaced
47446:09ff5d532a25 47447:377d8fc20e34
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 from __future__ import absolute_import
     8 from __future__ import absolute_import
     9 
     9 
    10 import contextlib
    10 import contextlib
       
    11 import errno
    11 import os
    12 import os
    12 import struct
    13 import struct
    13 
    14 
    14 from .i18n import _
    15 from .i18n import _
    15 from .pycompat import open
    16 from .pycompat import open
    16 from .interfaces import repository
    17 from .interfaces import repository
    17 from . import (
    18 from . import (
       
    19     bookmarks,
    18     cacheutil,
    20     cacheutil,
    19     error,
    21     error,
    20     narrowspec,
    22     narrowspec,
    21     phases,
    23     phases,
    22     pycompat,
    24     pycompat,
    23     requirements as requirementsmod,
    25     requirements as requirementsmod,
    24     scmutil,
    26     scmutil,
    25     store,
    27     store,
    26     util,
    28     util,
       
    29 )
       
    30 from .utils import (
       
    31     stringutil,
    27 )
    32 )
    28 
    33 
    29 
    34 
    30 def canperformstreamclone(pullop, bundle2=False):
    35 def canperformstreamclone(pullop, bundle2=False):
    31     """Whether it is possible to perform a streaming clone as part of pull.
    36     """Whether it is possible to perform a streaming clone as part of pull.
   769     )
   774     )
   770     repo.svfs.options = localrepo.resolvestorevfsoptions(
   775     repo.svfs.options = localrepo.resolvestorevfsoptions(
   771         repo.ui, repo.requirements, repo.features
   776         repo.ui, repo.requirements, repo.features
   772     )
   777     )
   773     scmutil.writereporequirements(repo)
   778     scmutil.writereporequirements(repo)
       
   779 
       
   780 
       
   781 def _copy_files(src_vfs_map, dst_vfs_map, entries, progress):
       
   782     hardlink = [True]
       
   783 
       
   784     def copy_used():
       
   785         hardlink[0] = False
       
   786         progress.topic = _(b'copying')
       
   787 
       
   788     for k, path, size in entries:
       
   789         src_vfs = src_vfs_map[k]
       
   790         dst_vfs = dst_vfs_map[k]
       
   791         src_path = src_vfs.join(path)
       
   792         dst_path = dst_vfs.join(path)
       
   793         dirname = dst_vfs.dirname(path)
       
   794         if not dst_vfs.exists(dirname):
       
   795             dst_vfs.makedirs(dirname)
       
   796         dst_vfs.register_file(path)
       
   797         # XXX we could use the #nb_bytes argument.
       
   798         util.copyfile(
       
   799             src_path,
       
   800             dst_path,
       
   801             hardlink=hardlink[0],
       
   802             no_hardlink_cb=copy_used,
       
   803             check_fs_hardlink=False,
       
   804         )
       
   805         progress.increment()
       
   806     return hardlink[0]
       
   807 
       
   808 
       
   809 def local_copy(src_repo, dest_repo):
       
   810     """copy all content from one local repository to another
       
   811 
       
   812     This is useful for local clone"""
       
   813     src_store_requirements = {
       
   814         r
       
   815         for r in src_repo.requirements
       
   816         if r not in requirementsmod.WORKING_DIR_REQUIREMENTS
       
   817     }
       
   818     dest_store_requirements = {
       
   819         r
       
   820         for r in dest_repo.requirements
       
   821         if r not in requirementsmod.WORKING_DIR_REQUIREMENTS
       
   822     }
       
   823     assert src_store_requirements == dest_store_requirements
       
   824 
       
   825     with dest_repo.lock():
       
   826         with src_repo.lock():
       
   827             entries, totalfilesize = _v2_walk(
       
   828                 src_repo,
       
   829                 includes=None,
       
   830                 excludes=None,
       
   831                 includeobsmarkers=True,
       
   832             )
       
   833             src_vfs_map = _makemap(src_repo)
       
   834             dest_vfs_map = _makemap(dest_repo)
       
   835             progress = src_repo.ui.makeprogress(
       
   836                 topic=_(b'linking'),
       
   837                 total=len(entries),
       
   838                 unit=_(b'files'),
       
   839             )
       
   840             # copy  files
       
   841             #
       
   842             # We could copy the full file while the source repository is locked
       
   843             # and the other one without the lock. However, in the linking case,
       
   844             # this would also requires checks that nobody is appending any data
       
   845             # to the files while we do the clone, so this is not done yet. We
       
   846             # could do this blindly when copying files.
       
   847             files = ((k, path, size) for k, path, ftype, size in entries)
       
   848             hardlink = _copy_files(src_vfs_map, dest_vfs_map, files, progress)
       
   849 
       
   850             # copy bookmarks over
       
   851             src_book_vfs = bookmarks.bookmarksvfs(src_repo)
       
   852             srcbookmarks = src_book_vfs.join(b'bookmarks')
       
   853             dst_book_vfs = bookmarks.bookmarksvfs(dest_repo)
       
   854             dstbookmarks = dst_book_vfs.join(b'bookmarks')
       
   855             if os.path.exists(srcbookmarks):
       
   856                 util.copyfile(srcbookmarks, dstbookmarks)
       
   857         progress.complete()
       
   858         if hardlink:
       
   859             msg = b'linked %d files\n'
       
   860         else:
       
   861             msg = b'copied %d files\n'
       
   862         src_repo.ui.debug(msg % len(entries))
       
   863 
       
   864         with dest_repo.transaction(b"localclone") as tr:
       
   865             dest_repo.store.write(tr)
       
   866 
       
   867         # clean up transaction file as they do not make sense
       
   868         undo_files = [(dest_repo.svfs, b'undo.backupfiles')]
       
   869         undo_files.extend(dest_repo.undofiles())
       
   870         for undovfs, undofile in undo_files:
       
   871             try:
       
   872                 undovfs.unlink(undofile)
       
   873             except OSError as e:
       
   874                 if e.errno != errno.ENOENT:
       
   875                     msg = _(b'error removing %s: %s\n')
       
   876                     path = undovfs.join(undofile)
       
   877                     e_msg = stringutil.forcebytestr(e)
       
   878                     msg %= (path, e_msg)
       
   879                     dest_repo.ui.warn(msg)