@@ -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)
@@ -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