Patchwork [3,of,3,V3] share: implement shared bookmark functionality

login
register
mail settings
Submitter Ryan McElroy
Date Dec. 3, 2014, 5:09 a.m.
Message ID <2f755ab2c76e669a63eb.1417583362@devbig105.prn2.facebook.com>
Download mbox | patch
Permalink /patch/6973/
State Superseded
Headers show

Comments

Ryan McElroy - Dec. 3, 2014, 5:09 a.m.
# HG changeset patch
# User Ryan McElroy <rmcelroy@fb.com>
# Date 1417581241 28800
#      Tue Dec 02 20:34:01 2014 -0800
# Node ID 2f755ab2c76e669a63eb9404a50331725ab990a2
# Parent  e56cddc7a7f746881c40edf62eabfea6d9a829be
share: implement shared bookmark functionality

The hg.share function now creates a bookmarks.shared file in the destination
repository with contents pointing to the source repository with which the
destination should share bookmarks.

This enables bookmarks to be shared between shared repositories by extending
the bookmarks.bmstore methods that read and write bookmarks to take into account
a bookmarks.shared file that can point to another repository.

Patch

diff --git a/hgext/share.py b/hgext/share.py
--- a/hgext/share.py
+++ b/hgext/share.py
@@ -6,7 +6,9 @@ 
 '''share a common history between several working directories'''
 
 from mercurial.i18n import _
-from mercurial import cmdutil, hg, util
+from mercurial import cmdutil, hg, util, extensions, bookmarks
+from mercurial.hg import repository, parseurl
+import errno
 
 cmdtable = {}
 command = cmdutil.command(cmdtable)
@@ -20,7 +22,7 @@  def share(ui, source, dest=None, noupdat
     """create a new shared repository
 
     Initialize a new repository and working directory that shares its
-    history with another repository.
+    history and bookmarks with another repository.
 
     .. note::
 
@@ -67,3 +69,48 @@  def unshare(ui, repo):
 
     # update store, spath, sopener and sjoin of repo
     repo.unfiltered().__init__(repo.baseui, repo.root)
+
+def extsetup(ui):
+    extensions.wrapfunction(bookmarks.bmstore, 'getbkfile', getbkfile)
+    extensions.wrapfunction(bookmarks.bmstore, 'recordchange', recordchange)
+    extensions.wrapfunction(bookmarks.bmstore, 'write', write)
+
+def getsrcrepo(repo):
+    """
+    Returns the source repository object for a given shared repository.
+    If repo is not a shared repository, return None.
+    """
+    srcrepo = None
+    try:
+        # strip because some tools write with newline after
+        sharedpath = repo.vfs.read('sharedpath').strip()
+        # the sharedpath always ends in the .hg; we want the path to the repo
+        source = sharedpath.split('/.hg')[0]
+        srcurl, branches = parseurl(source)
+        srcrepo = repository(repo.ui, srcurl)
+    except IOError, inst:
+        if inst.errno != errno.ENOENT:
+            raise
+    return srcrepo
+
+def getbkfile(orig, self, repo):
+    srcrepo = getsrcrepo(repo)
+    if srcrepo is not None:
+        repo = srcrepo
+    return orig(self, repo)
+
+def recordchange(orig, self, tr):
+    # Continue with write to local bookmarks file as usual
+    orig(self, tr)
+
+    srcrepo = getsrcrepo(self._repo)
+    if srcrepo is not None:
+        category = 'share-bookmarks'
+        tr.addpostclose(category, lambda tr: self._writerepo(srcrepo))
+
+def write(orig, self):
+    # First write local bookmarks file in case we ever unshare
+    orig(self)
+    srcrepo = getsrcrepo(self._repo)
+    if srcrepo is not None:
+        self._writerepo(srcrepo)
diff --git a/tests/test-share.t b/tests/test-share.t
--- a/tests/test-share.t
+++ b/tests/test-share.t
@@ -128,6 +128,165 @@  check that a change does not propagate
 
   $ cd ..
 
+
+test sharing bookmarks
+
+  $ hg share repo1 repo3
+  updating working directory
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd repo1
+  $ hg bookmark bm1
+  $ hg bookmarks
+   * bm1                       2:c2e0ac586386
+  $ cd ../repo2
+  $ hg book bm2
+  $ hg bookmarks
+   * bm2                       3:0e6e70d1d5f1
+  $ cd ../repo3
+  $ hg bookmarks
+     bm1                       2:c2e0ac586386
+  $ hg book bm3
+  $ hg bookmarks
+     bm1                       2:c2e0ac586386
+   * bm3                       2:c2e0ac586386
+  $ cd ../repo1
+  $ hg bookmarks
+   * bm1                       2:c2e0ac586386
+     bm3                       2:c2e0ac586386
+
+test that commits work
+
+  $ echo 'shared bookmarks' > a
+  $ hg commit -m 'testing shared bookmarks'
+  $ hg bookmarks
+   * bm1                       3:b87954705719
+     bm3                       2:c2e0ac586386
+  $ cd ../repo3
+  $ hg bookmarks
+     bm1                       3:b87954705719
+   * bm3                       2:c2e0ac586386
+  $ echo 'more shared bookmarks' > a
+  $ hg commit -m 'testing shared bookmarks'
+  created new head
+  $ hg bookmarks
+     bm1                       3:b87954705719
+   * bm3                       4:62f4ded848e4
+  $ cd ../repo1
+  $ hg bookmarks
+   * bm1                       3:b87954705719
+     bm3                       4:62f4ded848e4
+  $ cd ..
+
+test pushing bookmarks works
+
+  $ hg clone repo3 repo4
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd repo4
+  $ hg boo bm4
+  $ echo foo > b
+  $ hg commit -m 'foo in b'
+  $ hg boo
+     bm1                       3:b87954705719
+     bm3                       4:62f4ded848e4
+   * bm4                       5:92793bfc8cad
+  $ hg push -B bm4
+  pushing to $TESTTMP/repo3 (glob)
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  exporting bookmark bm4
+  $ cd ../repo1
+  $ hg bookmarks
+   * bm1                       3:b87954705719
+     bm3                       4:62f4ded848e4
+     bm4                       5:92793bfc8cad
+  $ cd ../repo3
+  $ hg bookmarks
+     bm1                       3:b87954705719
+   * bm3                       4:62f4ded848e4
+     bm4                       5:92793bfc8cad
+  $ cd ..
+
+test behavior when sharing a shared repo
+
+  $ hg share repo3 repo5
+  updating working directory
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd repo5
+  $ hg book
+     bm1                       3:b87954705719
+     bm3                       4:62f4ded848e4
+     bm4                       5:92793bfc8cad
+  $ cd ..
+
+test what happens when an active bookmark is deleted
+
+  $ cd repo1
+  $ hg boo -d bm3
+  $ hg boo
+   * bm1                       3:b87954705719
+     bm4                       5:92793bfc8cad
+  $ cd ../repo3
+  $ hg boo
+     bm1                       3:b87954705719
+     bm4                       5:92793bfc8cad
+  $ cd ..
+
+verify that bookmarks are not written on failed transaction
+
+  $ cd repo4
+  $ hg boo
+     bm1                       3:b87954705719
+     bm3                       4:62f4ded848e4
+   * bm4                       5:92793bfc8cad
+  $ cd ../repo3
+  $ hg boo
+     bm1                       3:b87954705719
+     bm4                       5:92793bfc8cad
+  $ hg --config "hooks.postpullbookmarks.fail = sh -c 'exit 1'" pull $TESTTMP/repo4
+  pulling from $TESTTMP/repo4 (glob)
+  searching for changes
+  no changes found
+  adding remote bookmark bm3
+  abort: postpullbookmarks.fail  hook exited with status 1
+  [255]
+  $ hg boo
+     bm1                       3:b87954705719
+     bm4                       5:92793bfc8cad
+  $ hg pull $TESTTMP/repo4
+  pulling from $TESTTMP/repo4 (glob)
+  searching for changes
+  no changes found
+  adding remote bookmark bm3
+  $ hg boo
+     bm1                       3:b87954705719
+   * bm3                       4:62f4ded848e4
+     bm4                       5:92793bfc8cad
+  $ cd ..
+
+verify bookmark behavior after unshare
+
+  $ cd repo3
+  $ hg unshare
+  $ hg boo
+     bm1                       3:b87954705719
+   * bm3                       4:62f4ded848e4
+     bm4                       5:92793bfc8cad
+  $ hg boo -d bm4
+  $ hg boo bm5
+  $ hg boo
+     bm1                       3:b87954705719
+     bm3                       4:62f4ded848e4
+   * bm5                       4:62f4ded848e4
+  $ cd ../repo1
+  $ hg boo
+   * bm1                       3:b87954705719
+     bm3                       4:62f4ded848e4
+     bm4                       5:92793bfc8cad
+
 Explicitly kill daemons to let the test exit on Windows
 
   $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS