mercurial/hg.py
changeset 25761 0d37b9b21467
parent 25660 328739ea70c3
child 25939 130c0b83e963
child 26026 d08e7449ff27
equal deleted inserted replaced
25760:648323f41a89 25761:0d37b9b21467
   282         return destlock
   282         return destlock
   283     except: # re-raises
   283     except: # re-raises
   284         release(destlock)
   284         release(destlock)
   285         raise
   285         raise
   286 
   286 
       
   287 def clonewithshare(ui, peeropts, sharepath, source, srcpeer, dest, pull=False,
       
   288                    rev=None, update=True, stream=False):
       
   289     """Perform a clone using a shared repo.
       
   290 
       
   291     The store for the repository will be located at <sharepath>/.hg. The
       
   292     specified revisions will be cloned or pulled from "source". A shared repo
       
   293     will be created at "dest" and a working copy will be created if "update" is
       
   294     True.
       
   295     """
       
   296     revs = None
       
   297     if rev:
       
   298         if not srcpeer.capable('lookup'):
       
   299             raise util.Abort(_("src repository does not support "
       
   300                                "revision lookup and so doesn't "
       
   301                                "support clone by revision"))
       
   302         revs = [srcpeer.lookup(r) for r in rev]
       
   303 
       
   304     basename = os.path.basename(sharepath)
       
   305 
       
   306     if os.path.exists(sharepath):
       
   307         ui.status(_('(sharing from existing pooled repository %s)\n') %
       
   308                   basename)
       
   309     else:
       
   310         ui.status(_('(sharing from new pooled repository %s)\n') % basename)
       
   311         # Always use pull mode because hardlinks in share mode don't work well.
       
   312         # Never update because working copies aren't necessary in share mode.
       
   313         clone(ui, peeropts, source, dest=sharepath, pull=True,
       
   314               rev=rev, update=False, stream=stream)
       
   315 
       
   316     sharerepo = repository(ui, path=sharepath)
       
   317     share(ui, sharerepo, dest=dest, update=update, bookmarks=False)
       
   318 
       
   319     # We need to perform a pull against the dest repo to fetch bookmarks
       
   320     # and other non-store data that isn't shared by default. In the case of
       
   321     # non-existing shared repo, this means we pull from the remote twice. This
       
   322     # is a bit weird. But at the time it was implemented, there wasn't an easy
       
   323     # way to pull just non-changegroup data.
       
   324     destrepo = repository(ui, path=dest)
       
   325     exchange.pull(destrepo, srcpeer, heads=revs)
       
   326 
       
   327     return srcpeer, peer(ui, peeropts, dest)
       
   328 
   287 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
   329 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
   288           update=True, stream=False, branch=None):
   330           update=True, stream=False, branch=None, shareopts=None):
   289     """Make a copy of an existing repository.
   331     """Make a copy of an existing repository.
   290 
   332 
   291     Create a copy of an existing repository in a new directory.  The
   333     Create a copy of an existing repository in a new directory.  The
   292     source and destination are URLs, as passed to the repository
   334     source and destination are URLs, as passed to the repository
   293     function.  Returns a pair of repository peers, the source and
   335     function.  Returns a pair of repository peers, the source and
   318     update: update working directory after clone completes, if
   360     update: update working directory after clone completes, if
   319     destination is local repository (True means update to default rev,
   361     destination is local repository (True means update to default rev,
   320     anything else is treated as a revision)
   362     anything else is treated as a revision)
   321 
   363 
   322     branch: branches to clone
   364     branch: branches to clone
       
   365 
       
   366     shareopts: dict of options to control auto sharing behavior. The "pool" key
       
   367     activates auto sharing mode and defines the directory for stores. The
       
   368     "mode" key determines how to construct the directory name of the shared
       
   369     repository. "identity" means the name is derived from the node of the first
       
   370     changeset in the repository. "remote" means the name is derived from the
       
   371     remote's path/URL. Defaults to "identity."
   323     """
   372     """
   324 
   373 
   325     if isinstance(source, str):
   374     if isinstance(source, str):
   326         origsource = ui.expandpath(source)
   375         origsource = ui.expandpath(source)
   327         source, branch = parseurl(origsource, branch)
   376         source, branch = parseurl(origsource, branch)
   349     if destvfs.lexists():
   398     if destvfs.lexists():
   350         if not destvfs.isdir():
   399         if not destvfs.isdir():
   351             raise util.Abort(_("destination '%s' already exists") % dest)
   400             raise util.Abort(_("destination '%s' already exists") % dest)
   352         elif destvfs.listdir():
   401         elif destvfs.listdir():
   353             raise util.Abort(_("destination '%s' is not empty") % dest)
   402             raise util.Abort(_("destination '%s' is not empty") % dest)
       
   403 
       
   404     shareopts = shareopts or {}
       
   405     sharepool = shareopts.get('pool')
       
   406     sharenamemode = shareopts.get('mode')
       
   407     if sharepool:
       
   408         sharepath = None
       
   409         if sharenamemode == 'identity':
       
   410             # Resolve the name from the initial changeset in the remote
       
   411             # repository. This returns nullid when the remote is empty. It
       
   412             # raises RepoLookupError if revision 0 is filtered or otherwise
       
   413             # not available. If we fail to resolve, sharing is not enabled.
       
   414             try:
       
   415                 rootnode = srcpeer.lookup('0')
       
   416                 if rootnode != node.nullid:
       
   417                     sharepath = os.path.join(sharepool, node.hex(rootnode))
       
   418                 else:
       
   419                     ui.status(_('(not using pooled storage: '
       
   420                                 'remote appears to be empty)\n'))
       
   421             except error.RepoLookupError:
       
   422                 ui.status(_('(not using pooled storage: '
       
   423                             'unable to resolve identity of remote)\n'))
       
   424         elif sharenamemode == 'remote':
       
   425             sharepath = os.path.join(sharepool, util.sha1(source).hexdigest())
       
   426         else:
       
   427             raise util.Abort('unknown share naming mode: %s' % sharenamemode)
       
   428 
       
   429         if sharepath:
       
   430             return clonewithshare(ui, peeropts, sharepath, source, srcpeer,
       
   431                                   dest, pull=pull, rev=rev, update=update,
       
   432                                   stream=stream)
   354 
   433 
   355     srclock = destlock = cleandir = None
   434     srclock = destlock = cleandir = None
   356     srcrepo = srcpeer.local()
   435     srcrepo = srcpeer.local()
   357     try:
   436     try:
   358         abspath = origsource
   437         abspath = origsource