changeset 39848:4ece3cdfd907

localrepo: support shared repo creation Previously, hg.share() had its own logic for creating a new repository on the filesystem. With the recent introduction of the createopts dict for passing options to influence repository creation, it is now possible to consolidate the repo creation code for both the normal and shared use cases. This commit teaches the repo creation code in localrepo to recognize when we're creating a shared repo and to act appropriately. Meaningful behavior should be identical. However, there are a few subtle changes: * The .hg/requires file is written out in sorted order (rather than having share-related requirements appended at end). * The .hg directory is created with notindexed=True when a shared repo is being created. Differential Revision: https://phab.mercurial-scm.org/D4707
author Gregory Szorc <gregory.szorc@gmail.com>
date Wed, 19 Sep 2018 17:05:59 -0700
parents b504ff813c4f
children d3d4b4b5f725
files mercurial/hg.py mercurial/localrepo.py tests/test-share.t
diffstat 3 files changed, 49 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/hg.py	Wed Sep 19 16:51:57 2018 -0700
+++ b/mercurial/hg.py	Wed Sep 19 17:05:59 2018 -0700
@@ -49,10 +49,6 @@
     vfs as vfsmod,
 )
 
-from .utils import (
-    stringutil,
-)
-
 release = lock.release
 
 # shared features
@@ -261,44 +257,13 @@
         rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
     else:
         srcrepo = source.local()
-        origsource = source = srcrepo.url()
         checkout = None
 
-    sharedpath = srcrepo.sharedpath # if our source is already sharing
-
-    destwvfs = vfsmod.vfs(dest, realpath=True)
-    destvfs = vfsmod.vfs(os.path.join(destwvfs.base, '.hg'), realpath=True)
-
-    if destvfs.lexists():
-        raise error.Abort(_('destination already exists'))
-
-    if not destwvfs.isdir():
-        destwvfs.makedirs()
-    destvfs.makedir()
+    r = repository(ui, dest, create=True, createopts={
+        'sharedrepo': srcrepo,
+        'sharedrelative': relative,
+    })
 
-    requirements = ''
-    try:
-        requirements = srcrepo.vfs.read('requires')
-    except IOError as inst:
-        if inst.errno != errno.ENOENT:
-            raise
-
-    if relative:
-        try:
-            sharedpath = os.path.relpath(sharedpath, destvfs.base)
-            requirements += 'relshared\n'
-        except (IOError, ValueError) as e:
-            # ValueError is raised on Windows if the drive letters differ on
-            # each path
-            raise error.Abort(_('cannot calculate relative path'),
-                              hint=stringutil.forcebytestr(e))
-    else:
-        requirements += 'shared\n'
-
-    destvfs.write('requires', requirements)
-    destvfs.write('sharedpath', sharedpath)
-
-    r = repository(ui, destwvfs.base)
     postshare(srcrepo, r, bookmarks=bookmarks, defaultpath=defaultpath)
     _postshareupdate(r, update, checkout=checkout)
     return r
--- a/mercurial/localrepo.py	Wed Sep 19 16:51:57 2018 -0700
+++ b/mercurial/localrepo.py	Wed Sep 19 17:05:59 2018 -0700
@@ -2714,6 +2714,17 @@
     """
     createopts = createopts or {}
 
+    # If the repo is being created from a shared repository, we copy
+    # its requirements.
+    if 'sharedrepo' in createopts:
+        requirements = set(createopts['sharedrepo'].requirements)
+        if createopts.get('sharedrelative'):
+            requirements.add('relshared')
+        else:
+            requirements.add('shared')
+
+        return requirements
+
     requirements = {'revlogv1'}
     if ui.configbool('format', 'usestore'):
         requirements.add('store')
@@ -2771,7 +2782,11 @@
     Extensions can wrap this function to filter out creation options
     they know how to handle.
     """
-    known = {'narrowfiles'}
+    known = {
+        'narrowfiles',
+        'sharedrepo',
+        'sharedrelative',
+    }
 
     return {k: v for k, v in createopts.items() if k not in known}
 
@@ -2780,6 +2795,17 @@
 
     ``path`` path to the new repo's working directory.
     ``createopts`` options for the new repository.
+
+    The following keys for ``createopts`` are recognized:
+
+    narrowfiles
+       Set up repository to support narrow file storage.
+    sharedrepo
+       Repository object from which storage should be shared.
+    sharedrelative
+       Boolean indicating if the path to the shared repo should be
+       stored as relative. By default, the pointer to the "parent" repo
+       is stored as an absolute path.
     """
     createopts = createopts or {}
 
@@ -2803,12 +2829,24 @@
     if hgvfs.exists():
         raise error.RepoError(_('repository %s already exists') % path)
 
+    if 'sharedrepo' in createopts:
+        sharedpath = createopts['sharedrepo'].sharedpath
+
+        if createopts.get('sharedrelative'):
+            try:
+                sharedpath = os.path.relpath(sharedpath, hgvfs.base)
+            except (IOError, ValueError) as e:
+                # ValueError is raised on Windows if the drive letters differ
+                # on each path.
+                raise error.Abort(_('cannot calculate relative path'),
+                                  hint=stringutil.forcebytestr(e))
+
     if not wdirvfs.exists():
         wdirvfs.makedirs()
 
     hgvfs.makedir(notindexed=True)
 
-    if b'store' in requirements:
+    if b'store' in requirements and 'sharedrepo' not in createopts:
         hgvfs.mkdir(b'store')
 
         # We create an invalid changelog outside the store so very old
@@ -2825,6 +2863,10 @@
 
     scmutil.writerequires(hgvfs, requirements)
 
+    # Write out file telling readers where to find the shared store.
+    if 'sharedrepo' in createopts:
+        hgvfs.write(b'sharedpath', sharedpath)
+
 def poisonrepository(repo):
     """Poison a repository instance so it can no longer be used."""
     # Perform any cleanup on the instance.
--- a/tests/test-share.t	Wed Sep 19 16:51:57 2018 -0700
+++ b/tests/test-share.t	Wed Sep 19 17:05:59 2018 -0700
@@ -399,8 +399,8 @@
   ../../orig/.hg (no-eol)
   $ grep shared thisdir/*/.hg/requires
   thisdir/abs/.hg/requires:shared
+  thisdir/rel/.hg/requires:relshared
   thisdir/rel/.hg/requires:shared
-  thisdir/rel/.hg/requires:relshared
 
 test that relative shared paths aren't relative to $PWD