share: add --relative flag to store a relative path to the source
Storing a relative path the source repository is useful when exporting
repositories over the network or when they're located on external
drives where the mountpoint isn't always fixed.
Currently, Mercurial interprets paths in `.hg/shared` relative to
$PWD. I suspect this is very much unintentional, and you have to
manually edit `.hg/shared` in order to trigger this behaviour.
However, on the off chance that someone might rely on it, I added a
new capability called 'relshared'. In addition, this makes earlier
versions of Mercurial fail with a graceful error.
I should note that I haven't tested this patch on Windows.
--- a/hgext/share.py Wed Feb 15 11:49:12 2017 -0800
+++ b/hgext/share.py Mon Feb 13 14:05:24 2017 +0100
@@ -65,10 +65,14 @@
@command('share',
[('U', 'noupdate', None, _('do not create a working directory')),
- ('B', 'bookmarks', None, _('also share bookmarks'))],
+ ('B', 'bookmarks', None, _('also share bookmarks')),
+ ('', 'relative', None, _('point to source using a relative path '
+ '(EXPERIMENTAL)')),
+ ],
_('[-U] [-B] SOURCE [DEST]'),
norepo=True)
-def share(ui, source, dest=None, noupdate=False, bookmarks=False):
+def share(ui, source, dest=None, noupdate=False, bookmarks=False,
+ relative=False):
"""create a new shared repository
Initialize a new repository and working directory that shares its
@@ -87,7 +91,7 @@
"""
return hg.share(ui, source, dest=dest, update=not noupdate,
- bookmarks=bookmarks)
+ bookmarks=bookmarks, relative=relative)
@command('unshare', [], '')
def unshare(ui, repo):
--- a/mercurial/help/internals/requirements.txt Wed Feb 15 11:49:12 2017 -0800
+++ b/mercurial/help/internals/requirements.txt Mon Feb 13 14:05:24 2017 +0100
@@ -55,6 +55,17 @@
The requirement was added in Mercurial 1.3 (released July 2009).
+relshared
+=========
+
+Derivative of ``shared``; the location of the store is relative to the
+store of this repository.
+
+This requirement is set when a repository is created via :hg:`share`
+using the ``--relative`` option.
+
+The requirement was added in Mercurial 4.2 (released May 2017).
+
dotencode
=========
--- a/mercurial/hg.py Wed Feb 15 11:49:12 2017 -0800
+++ b/mercurial/hg.py Mon Feb 13 14:05:24 2017 +0100
@@ -195,7 +195,8 @@
return ''
return os.path.basename(os.path.normpath(path))
-def share(ui, source, dest=None, update=True, bookmarks=True, defaultpath=None):
+def share(ui, source, dest=None, update=True, bookmarks=True, defaultpath=None,
+ relative=False):
'''create a shared repository'''
if not islocal(source):
@@ -235,7 +236,16 @@
if inst.errno != errno.ENOENT:
raise
- requirements += 'shared\n'
+ if relative:
+ try:
+ sharedpath = os.path.relpath(sharedpath, destvfs.base)
+ requirements += 'relshared\n'
+ except IOError as e:
+ raise error.Abort(_('cannot calculate relative path'),
+ hint=str(e))
+ else:
+ requirements += 'shared\n'
+
destvfs.write('requires', requirements)
destvfs.write('sharedpath', sharedpath)
--- a/mercurial/localrepo.py Wed Feb 15 11:49:12 2017 -0800
+++ b/mercurial/localrepo.py Mon Feb 13 14:05:24 2017 +0100
@@ -244,7 +244,7 @@
supportedformats = set(('revlogv1', 'generaldelta', 'treemanifest',
'manifestv2'))
_basesupported = supportedformats | set(('store', 'fncache', 'shared',
- 'dotencode'))
+ 'relshared', 'dotencode'))
openerreqs = set(('revlogv1', 'generaldelta', 'treemanifest', 'manifestv2'))
filtername = None
@@ -325,8 +325,11 @@
self.sharedpath = self.path
try:
- vfs = scmutil.vfs(self.vfs.read("sharedpath").rstrip('\n'),
- realpath=True)
+ sharedpath = self.vfs.read("sharedpath").rstrip('\n')
+ if 'relshared' in self.requirements:
+ sharedpath = self.vfs.join(sharedpath)
+ vfs = scmutil.vfs(sharedpath, realpath=True)
+
s = vfs.base
if not vfs.exists():
raise error.RepoError(
--- a/tests/test-share.t Wed Feb 15 11:49:12 2017 -0800
+++ b/tests/test-share.t Mon Feb 13 14:05:24 2017 +0100
@@ -358,6 +358,41 @@
bm4 5:92793bfc8cad
$ cd ..
+test shared clones using relative paths work
+
+ $ mkdir thisdir
+ $ hg init thisdir/orig
+ $ hg share -U thisdir/orig thisdir/abs
+ $ hg share -U --relative thisdir/abs thisdir/rel
+ $ cat thisdir/rel/.hg/sharedpath
+ ../../orig/.hg (no-eol)
+ $ grep shared thisdir/*/.hg/requires
+ thisdir/abs/.hg/requires:shared
+ thisdir/rel/.hg/requires:shared
+ thisdir/rel/.hg/requires:relshared
+
+test that relative shared paths aren't relative to $PWD
+
+ $ cd thisdir
+ $ hg -R rel root
+ $TESTTMP/thisdir/rel
+ $ cd ..
+
+now test that relative paths really are relative, survive across
+renames and changes of PWD
+
+ $ hg -R thisdir/abs root
+ $TESTTMP/thisdir/abs
+ $ hg -R thisdir/rel root
+ $TESTTMP/thisdir/rel
+ $ mv thisdir thatdir
+ $ hg -R thatdir/abs root
+ abort: .hg/sharedpath points to nonexistent directory $TESTTMP/thisdir/orig/.hg!
+ [255]
+ $ hg -R thatdir/rel root
+ $TESTTMP/thatdir/rel
+ $ rm -r thatdir
+
Explicitly kill daemons to let the test exit on Windows
$ killdaemons.py