[PATCH 2 of 2] localrepo: adds an optional format flag to force --pull on clone

Wagner Bruna wagner.bruna+mercurial at gmail.com
Fri Dec 9 11:57:32 CST 2011


# HG changeset patch
# User Wagner Bruna <wbruna at softwareexpress.com.br>
# Date 1323442302 7200
# Node ID 1ed6fd36ad91712c264717b368d6fde6637829b0
# Parent  0e81a5a31f94184820296b2587e3d5f8742b63bd
localrepo: adds an optional format flag to force --pull on clone

This can be used to avoid issues on filesystems with incorrect
or unreliable hardlink support.

diff --git a/hgext/relink.py b/hgext/relink.py
--- a/hgext/relink.py
+++ b/hgext/relink.py
@@ -39,10 +39,14 @@ def relink(ui, repo, origin=None, **opts
     if (not util.safehasattr(util, 'samefile') or
         not util.safehasattr(util, 'samedevice')):
         raise util.Abort(_('hardlinks are not supported on this system'))
+    if not repo.cancopy():
+        raise util.Abort(_('hardlinks are disabled on this repository'))
     src = hg.repository(ui, ui.expandpath(origin or 'default-relink',
                                           origin or 'default'))
     if not src.local():
         raise util.Abort(_('must specify local origin repository'))
+    if not src.cancopy():
+        raise util.Abort(_('hardlinks are disabled on the origin repository'))
     ui.status(_('relinking %s to %s\n') % (src.store.path, repo.store.path))
     if repo.root == src.root:
         ui.status(_('there is nothing to relink\n'))
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -1075,8 +1075,10 @@ def clone(ui, source, dest=None, **opts)
       source and destination are on the same filesystem (note this
       applies only to the repository data, not to the working
       directory). Some filesystems, such as AFS, implement hardlinking
-      incorrectly, but do not report errors. In these cases, use the
-      --pull option to avoid hardlinking.
+      incorrectly, but do not report errors. In these cases, to avoid
+      hardlinking use the --pull option or enable the ``pullonclone``
+      repository format (see the ``format`` section on
+      :hg:`help config`).
 
       In some cases, you can clone repositories and the working
       directory using full hardlinks with ::
diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
--- a/mercurial/help/config.txt
+++ b/mercurial/help/config.txt
@@ -534,6 +534,14 @@ This feature is only supported when usin
     option ensures that the on-disk format of newly created
     repositories will be compatible with Mercurial before version 1.7.
 
+``pullonclone``
+    Enable or disable the "pullonclone" repository format which
+    instructs Mercurial to always use the pull protocol when cloning
+    from this repository, thus disabling hardlink usage. This can be
+    used to avoid issues on filesystems with incorrect or unreliable
+    hardlink support. Disabled by default. Enabling this option makes
+    the repository incompatible with Mercurial before version 2.1.
+
 ``merge-patterns``
 """"""""""""""""""
 
diff --git a/mercurial/hg.py b/mercurial/hg.py
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -182,6 +182,8 @@ def copystore(ui, srcrepo, destpath):
     destlock = None
     try:
         hardlink = None
+        if not srcrepo.cancopy():
+            hardlink = False
         num = 0
         for f in srcrepo.store.copylist():
             src = os.path.join(srcrepo.sharedpath, f)
@@ -286,7 +288,8 @@ def clone(ui, peeropts, source, dest=Non
             dircleanup = DirCleanup(dest)
 
         copy = False
-        if srcrepo.cancopy() and islocal(dest):
+        if srcrepo.cancopy() and islocal(dest) and \
+          not ui.configbool('format', 'pullonclone', False):
             copy = not pull and not rev
 
         if copy:
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -24,7 +24,7 @@ class localrepository(repo.repository):
                         'known', 'getbundle'))
     supportedformats = set(('revlogv1', 'generaldelta'))
     supported = supportedformats | set(('store', 'fncache', 'shared',
-                                        'dotencode'))
+                                        'dotencode', 'pullonclone'))
 
     def __init__(self, baseui, path=None, create=False):
         repo.repository.__init__(self)
@@ -65,6 +65,8 @@ class localrepository(repo.repository):
                     )
                 if self.ui.configbool('format', 'generaldelta', False):
                     requirements.append("generaldelta")
+                if self.ui.configbool('format', 'pullonclone', False):
+                    requirements.append("pullonclone")
                 requirements = set(requirements)
             else:
                 raise error.RepoError(_("repository %s not found") % path)
@@ -622,6 +624,9 @@ class localrepository(repo.repository):
         nm = self.changelog.nodemap
         return [(n in nm) for n in nodes]
 
+    def cancopy(self):
+        return self.local() and 'pullonclone' not in self.requirements
+
     def local(self):
         return self
 
diff --git a/tests/test-clone.t b/tests/test-clone.t
--- a/tests/test-clone.t
+++ b/tests/test-clone.t
@@ -119,6 +119,39 @@ Clone to '.':
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cd ..
 
+Forbid hardlinks on destination:
+
+  $ hg clone --config format.pullonclone=1 a i
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 11 changesets with 11 changes to 2 files
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg -R i verify
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  2 files, 11 changesets, 11 total revisions
+
+Forbid hardlinks on source:
+
+  $ hg clone i j
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 11 changesets with 11 changes to 2 files
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg -R j verify
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  2 files, 11 changesets, 11 total revisions
 
 *** Tests for option -u ***
 
diff --git a/tests/test-relink.t b/tests/test-relink.t
--- a/tests/test-relink.t
+++ b/tests/test-relink.t
@@ -96,3 +96,21 @@ check hardlinks
   $ python arelinked.py repo/.hg/store/data/b.i clone/.hg/store/data/b.i
   repo/.hg/store/data/b.i != clone/.hg/store/data/b.i
 
+
+do not relink on pullonclone repositories
+
+  $ hg clone --config format.pullonclone=1 repo forbidden
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 3 changesets with 6 changes to 2 files
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg -R clone relink forbidden
+  abort: hardlinks are disabled on the origin repository
+  [255]
+  $ hg -R forbidden relink clone
+  abort: hardlinks are disabled on this repository
+  [255]
+


More information about the Mercurial-devel mailing list