[PATCH 5 of 6 V2 RFC] share: add "full share" suport

Angel Ezquerra angel.ezquerra at gmail.com
Fri Dec 26 05:46:53 CST 2014


# HG changeset patch
# User Angel Ezquerra <angel.ezquerra at gmail.com>
# Date 1419360788 -3600
#      Tue Dec 23 19:53:08 2014 +0100
# Node ID bb70464b9121df236db6d264d57b6f56ad78cd3b
# Parent  dd180345dd166fc51d061a8041e014f320c20d6c
share: add "full share" suport

Add a new --full flag that makes it possible to create "full shares".

The actual full commit message comes below, but first some notes and caveats:

# NOTES:
1. This is the first step on the "subrepo store" plan that we discussed during
the mercurial 3.2 sprint
2. This is RFC because I am not certain that this is the right way to do this.
Maybe there is a better, obvious way to do it. In that case I'd love to hear
about it
3. If this approach is not completely crazy, are there any files that I should
add to the fullshareexceptions list? (see below for context)
4. hg unshare is currently unsupported
5. This revision does not handle the locking of the non-store parts of the
repository properly. That will be handled on a separate patch (which in the
final form of this series should be folded into this revision).

# Actual commit message:

A "fully shared repository" is one that shares _everything_ with its source
repository including bookmarks, mq patches and configuration files. The only
difference between the source repo and the fully shared copy is that their
working directory can be different and point to a different revision,
bookmark and branch.

In order to do so we replace the regular localrepo vfs object with a unionvfs,
object, which is the union of a vfs that points to the share source and another
that points to the local repository .hg path. The unionvfs selection function
is such that all files are taken from the shared repository vfs except for a
few key files (dirstate, branch, bookmarks.current, requires, sharedpath and
sharedinfull).

The idea is to only keep the files that are strictly necessary to maintain
separate working directories and a different current branch and active bookmark
in the shared repository, and share everything else with the shared source
repository.

diff --git a/hgext/share.py b/hgext/share.py
--- a/hgext/share.py
+++ b/hgext/share.py
@@ -16,10 +16,11 @@
 
 @command('share',
     [('U', 'noupdate', None, _('do not create a working copy')),
-     ('B', 'bookmarks', None, _('also share bookmarks'))],
-    _('[-U] [-B] SOURCE [DEST]'),
+     ('B', 'bookmarks', None, _('also share bookmarks')),
+     ('', 'full', None, _('share in full'))],
+    _('[-U] [-B] [--full] SOURCE [DEST]'),
     norepo=True)
-def share(ui, source, dest=None, noupdate=False, bookmarks=False):
+def share(ui, source, dest=None, noupdate=False, bookmarks=False, full=False):
     """create a new shared repository
 
     Initialize a new repository and working directory that shares its
@@ -37,7 +38,8 @@
        the broken clone to reset it to a changeset that still exists.
     """
 
-    return hg.share(ui, source, dest, not noupdate, bookmarks)
+    return hg.share(ui, source, dest, not noupdate, bookmarks=bookmarks,
+                    fullshare=full)
 
 @command('unshare', [], '')
 def unshare(ui, repo):
@@ -46,6 +48,8 @@
     Copy the store data to the repo and remove the sharedpath data.
     """
 
+    if repo.fullshare:
+        raise util.Abort(_("unsharing a full repository share is unsupported"))
     if not repo.shared():
         raise util.Abort(_("this is not a shared repo"))
 
diff --git a/mercurial/hg.py b/mercurial/hg.py
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -158,7 +158,7 @@
         return ''
     return os.path.basename(os.path.normpath(path))
 
-def share(ui, source, dest=None, update=True, bookmarks=True):
+def share(ui, source, dest=None, update=True, bookmarks=True, fullshare=False):
     '''create a shared repository'''
 
     if not islocal(source):
@@ -201,6 +201,8 @@
     requirements += 'shared\n'
     destvfs.write('requires', requirements)
     destvfs.write('sharedpath', sharedpath)
+    if fullshare:
+        destvfs.write('sharedinfull', '')
 
     r = repository(ui, destwvfs.base)
 
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -189,6 +189,7 @@
         return self.requirements[:]
 
     def __init__(self, baseui, path=None, create=False):
+        self.fullshare = False
         self.wvfs = scmutil.vfs(path, expandpath=True, realpath=True)
         self.wopener = self.wvfs
         self.root = self.wvfs.base
@@ -256,13 +257,28 @@
 
         self.sharedpath = self.path
         try:
-            vfs = scmutil.vfs(self.vfs.read("sharedpath").rstrip('\n'),
+            fullshareexceptions = ('dirstate', 'branch', 'bookmarks.current',
+                                   'requires', 'sharedpath', 'sharedinfull')
+            sourcevfs = scmutil.vfs(self.vfs.read("sharedpath").rstrip('\n'),
                               realpath=True)
-            s = vfs.base
-            if not vfs.exists():
+            s = sourcevfs.base
+            if not sourcevfs.exists():
                 raise error.RepoError(
                     _('.hg/sharedpath points to nonexistent directory %s') % s)
             self.sharedpath = s
+            self.fullshare = self.vfs.exists('sharedinfull')
+            if self.fullshare:
+                # full shares are those in which all files except for the
+                # requires, sharedpath and sharedinfull files must be read from
+                # the source repository
+                self.origpath = self.path
+                self.path = self.sharedpath
+                def selectfn(path):
+                    if path in fullshareexceptions:
+                        return 1
+                    return 0
+                self.vfs = scmutil.unionvfs(selectfn, sourcevfs, self.vfs)
+                self.opener = self.vfs
         except IOError, inst:
             if inst.errno != errno.ENOENT:
                 raise
@@ -760,7 +776,9 @@
 
     def shared(self):
         '''the type of shared repository (None if not shared)'''
-        if self.sharedpath != self.path:
+        if self.fullshare:
+            return 'full'
+        elif self.sharedpath != self.path:
             return 'store'
         return None
 
diff --git a/tests/test-share.t b/tests/test-share.t
--- a/tests/test-share.t
+++ b/tests/test-share.t
@@ -297,6 +297,176 @@
      bm4                       5:92793bfc8cad
   $ cd ..
 
+create a full share
+
+  $ hg share --full repo1 repo-fullshare
+  updating working directory
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ cd repo-fullshare
+
+full shares share the whole set of revisions
+  $ hg log -G
+  @  changeset:   5:92793bfc8cad
+  |  bookmark:    bm4
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     foo in b
+  |
+  o  changeset:   4:62f4ded848e4
+  |  bookmark:    bm3
+  |  parent:      2:c2e0ac586386
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     testing shared bookmarks
+  |
+  | o  changeset:   3:b87954705719
+  |/   bookmark:    bm1
+  |    user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     testing shared bookmarks
+  |
+  o  changeset:   2:c2e0ac586386
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     another file
+  |
+  o  changeset:   1:8af4dc49db9e
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     change in shared clone
+  |
+  o  changeset:   0:d3873e73d99e
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     init
+  
+and bookmarks
+  $ hg bookmarks
+     bm1                       3:b87954705719
+     bm3                       4:62f4ded848e4
+     bm4                       5:92793bfc8cad
+  $ hg -R ../repo1 bookmarks
+   * bm1                       3:b87954705719
+     bm3                       4:62f4ded848e4
+     bm4                       5:92793bfc8cad
+
+the source and shared repo working directories can point to different revisions
+and bookmarks
+  $ hg update bm3
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (activating bookmark bm3)
+  $ hg log -r .
+  changeset:   4:62f4ded848e4
+  bookmark:    bm3
+  parent:      2:c2e0ac586386
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     testing shared bookmarks
+  
+  $ hg -R ../repo1 log -r .
+  changeset:   3:b87954705719
+  bookmark:    bm1
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     testing shared bookmarks
+  
+they can also commit to different branches
+  $ hg branch createdinshare
+  marked working directory as branch createdinshare
+  (branches are permanent and global, did you want a bookmark?)
+  $ hg -R ../repo1 branch
+  default
+
+and commit on top of different revisions
+  $ cat a
+  more shared bookmarks
+  $ echo a > a
+  $ hg commit -m "created in full share"
+  $ echo a > ../repo1/a
+  $ hg commit -R ../repo1 -m "created in share source"
+  $ hg log -G
+  o  changeset:   7:e0fb5f85a10b
+  |  bookmark:    bm1
+  |  tag:         tip
+  |  parent:      3:b87954705719
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     created in share source
+  |
+  | @  changeset:   6:5ea6503932c4
+  | |  branch:      createdinshare
+  | |  bookmark:    bm3
+  | |  parent:      4:62f4ded848e4
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     created in full share
+  | |
+  | | o  changeset:   5:92793bfc8cad
+  | |/   bookmark:    bm4
+  | |    user:        test
+  | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | |    summary:     foo in b
+  | |
+  | o  changeset:   4:62f4ded848e4
+  | |  parent:      2:c2e0ac586386
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     testing shared bookmarks
+  | |
+  o |  changeset:   3:b87954705719
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     testing shared bookmarks
+  |
+  o  changeset:   2:c2e0ac586386
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     another file
+  |
+  o  changeset:   1:8af4dc49db9e
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     change in shared clone
+  |
+  o  changeset:   0:d3873e73d99e
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     init
+  
+
+full shares should have a limited set of files in its .hg folder
+
+  $ ls .hg
+  bookmarks.current
+  branch
+  dirstate
+  requires
+  sharedinfull
+  sharedpath
+
+  $ ls ../repo1/.hg
+  00changelog.i
+  bookmarks
+  bookmarks.current
+  branch
+  cache
+  dirstate
+  last-message.txt
+  requires
+  store
+  undo.bookmarks
+  undo.branch
+  undo.desc
+  undo.dirstate
+
+unsharing a full share is unsupported
+
+  $ hg unshare
+  abort: unsharing a full repository share is unsupported
+  [255]
+
 Explicitly kill daemons to let the test exit on Windows
 
   $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS


More information about the Mercurial-devel mailing list