hooks: don't allow symlinks on most repos (bug 985087); r=RyanVM
authorGregory Szorc <gps@mozilla.com>
Tue, 08 Aug 2017 14:56:33 -0700
changeset 5534 02675c286d0f50a755f60ff694b26063622b8b46
parent 5533 06149d42edfa43ed48ea9078c429247c0489bfa6
child 5535 28893272abf5d3ba9723edc242c60c2010a43f18
push id2548
push usergszorc@mozilla.com
push dateThu, 10 Aug 2017 18:01:53 +0000
treeherderversion-control-tools@02675c286d0f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersRyanVM
bugs985087
hooks: don't allow symlinks on most repos (bug 985087); r=RyanVM Symlinks don't work on all platforms. While Mercurial can handle it, we want a consistent version control experience on all platforms. That means not using symlinks. We establish a new check in our hooks extension to ban symlinks on non-user repos. We allow symlinks on user repos because as far as I'm concerned user repos are a generic hosting mechanism and hooks should not interfere with that platform feature. The check is intentionally designed to allow existing symlinks to exist. However, modification of the symlink target is not allowed. The symlink can only be deleted or converted to a regular file. MozReview-Commit-ID: LpkwnpaTjTs
hghooks/mozhghooks/check/prevent_symlinks.py
hghooks/mozhghooks/extension.py
hghooks/tests/test-prevent-symlinks.t
new file mode 100644
--- /dev/null
+++ b/hghooks/mozhghooks/check/prevent_symlinks.py
@@ -0,0 +1,63 @@
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from __future__ import absolute_import
+
+
+from ..checks import (
+    PreTxnChangegroupCheck,
+    print_banner,
+)
+
+
+SYMLINK_FOUND = """
+{node} adds or modifies the following symlinks:
+
+  {symlinks}
+
+Symlinks aren't allowed in this repo. Convert these paths to regular
+files and try your push again.
+"""
+
+
+class PreventSymlinksCheck(PreTxnChangegroupCheck):
+    """Prevents symlinks from being committed.
+
+    Symlinks don't work on all platforms. While Mercurial knows how to check out
+    a symlink on platforms that don't support symlinks, the behavior is wonky.
+
+    We want cross-platform consistency with regards to repository behavior. So
+    our policy is to ban symlinks on most repos.
+    """
+
+    @property
+    def name(self):
+        return 'prevent_symlinks'
+
+    def relevant(self):
+        return not self.repo_metadata['user_repo']
+
+    def pre(self):
+        pass
+
+    def check(self, ctx):
+        manifest = ctx.manifest()
+        links = []
+
+        for f in ctx.files():
+            if f not in manifest:
+                continue
+
+            if manifest.flags(f) == 'l':
+                links.append(f)
+
+        if not links:
+            return True
+
+        print_banner(self.ui, 'error', SYMLINK_FOUND.format(
+            node=ctx.hex()[0:12],
+            symlinks='\n  '.join(links)))
+        return False
+
+    def post_check(self):
+        return True
--- a/hghooks/mozhghooks/extension.py
+++ b/hghooks/mozhghooks/extension.py
@@ -54,21 +54,23 @@ def get_checks(ui, repo, info, classes):
 
     return checks
 
 
 def pretxnchangegroup(ui, repo, node, source=None, **kwargs):
     # TODO come up with a mechanism for automatically discovering checks
     # so we don't have to enumerate them all.
     from mozhghooks.check import (
+        prevent_symlinks,
         single_root,
         try_task_config_file,
     )
 
     CHECKS = (
+        prevent_symlinks.PreventSymlinksCheck,
         single_root.SingleRootCheck,
         try_task_config_file.TryConfigCheck,
     )
 
     # Never apply hooks at pull time or when re-applying from strips.
     if source in ('pull', 'strip'):
         return 0
 
new file mode 100644
--- /dev/null
+++ b/hghooks/tests/test-prevent-symlinks.t
@@ -0,0 +1,133 @@
+#require symlink
+
+  $ . $TESTDIR/hghooks/tests/common.sh
+
+We can create symlinks on user repos
+
+  $ mkdir -p users/someuser
+  $ hg init users/someuser/repo
+  $ configurehooks users/someuser/repo
+
+  $ hg -q clone users/someuser/repo user-client
+  $ cd user-client
+
+  $ touch foo
+  $ hg -q commit -A -m initial
+  $ hg -q push
+
+  $ ln -s foo link1
+  $ hg commit -A -m 'add link1'
+  adding link1
+  $ hg push
+  pushing to $TESTTMP/users/someuser/repo
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+
+  $ cd ..
+
+Symlinks on other repos are prohibited
+
+  $ hg init server
+  $ configurehooks server
+
+  $ hg -q clone server client
+  $ cd client
+
+  $ touch foo
+  $ hg -q commit -A -m initial
+  $ hg -q push
+
+  $ ln -s foo link1
+  $ ln -s foo link2
+  $ ln -s foo link3
+  $ hg commit -A -m 'add link1 and link2 and link3'
+  adding link1
+  adding link2
+  adding link3
+  $ hg push
+  pushing to $TESTTMP/server
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 3 changes to 3 files
+  
+  ****************************** ERROR *******************************
+  af08f309d8f2 adds or modifies the following symlinks:
+  
+    link1
+    link2
+    link3
+  
+  Symlinks aren't allowed in this repo. Convert these paths to regular
+  files and try your push again.
+  ********************************************************************
+  
+  transaction abort!
+  rollback completed
+  abort: pretxnchangegroup.mozhooks hook failed
+  [255]
+
+We can delete an existing symlink
+
+  $ hg --config extensions.mozhooks=! push
+  pushing to $TESTTMP/server
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 3 changes to 3 files
+
+  $ hg rm link1
+  $ hg commit -m 'remove link1'
+  $ hg push
+  pushing to $TESTTMP/server
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 0 changes to 0 files
+
+We can change a symlink to a regular file
+
+  $ hg rm link2
+  $ echo content > link2
+  $ hg add link2
+  $ hg commit -m 'convert link2 to file'
+  $ hg push
+  pushing to $TESTTMP/server
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+
+We can't change the target of a symlink
+
+  $ rm link3
+  $ ln -s link2 link3
+  $ hg commit -m 'change target of link3'
+  $ hg push
+  pushing to $TESTTMP/server
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  
+  ****************************** ERROR *******************************
+  07fa4de1b0ce adds or modifies the following symlinks:
+  
+    link3
+  
+  Symlinks aren't allowed in this repo. Convert these paths to regular
+  files and try your push again.
+  ********************************************************************
+  
+  transaction abort!
+  rollback completed
+  abort: pretxnchangegroup.mozhooks hook failed
+  [255]