Patchwork [bugfix] Skip repositories not readable with current privileges; skip empty “.hg” directories, e.g. unmounted mountpoints

login
register
mail settings
Submitter Roland Eggner
Date Dec. 30, 2013, 6:52 p.m.
Message ID <20131230185207.GB23913@mobil.systemanalysen.net>
Download mbox | patch
Permalink /patch/3241/
State Superseded
Headers show

Comments

Roland Eggner - Dec. 30, 2013, 6:52 p.m.
# HG changeset patch
# Parent ad445599010834299cb1d6cc7db0315df3b61923
# User Roland Eggner < odv@systomanalyson.not s/o/e/g >
# Date 1388261157 -3600

[bugfix] Skip repositories not readable with current privileges;  skip empty “.hg” directories, e.g. unmounted mountpoints.

[bug]  Existence of an unreadable “/.hg” directory causes run-tests.py failures.

[bugfix]  Skip repositories not readable with current privileges;  skip empty “.hg” directories.

By this bugfix empty “.hg” directories are no more considered valid mercurial repositories.
In case of an unmounted mount point mercurial does no more write repository data  _silently_  to the wrong filesystem.

Bug reported at
http://thread.gmane.org/gmane.comp.version-control.mercurial.devel/51339

Patch

diff --git a/contrib/bash_completion b/contrib/bash_completion
--- a/contrib/bash_completion
+++ b/contrib/bash_completion
@@ -75,8 +75,10 @@  shopt -s extglob
 _hg_repos()
 {
     local i
-    for i in $(compgen -d -- "$cur"); do
-	test ! -d "$i"/.hg || COMPREPLY=(${COMPREPLY[@]:-} "$i")
+    for i in $( compgen -d -- "$cur" ) ;  do
+	[[ -r "$i/.hg/requires" \
+	    || -r "$i/.hg/00changelog.i" ]] \
+            && COMPREPLY+=( "$i" )
     done
 }
 
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -9,6 +9,7 @@  from node import hex, nullid, nullrev, s
 from i18n import _
 import os, sys, errno, re, tempfile
 import util, scmutil, templater, patch, error, templatekw, revlog, copies
+from readable_repository import readable_repository
 import match as matchmod
 import subrepo, context, repair, graphmod, revset, phases, obsolete
 import changelog
@@ -72,7 +73,7 @@  def findcmd(cmd, table, strict=True):
     raise error.UnknownCommand(cmd)
 
 def findrepo(p):
-    while not os.path.isdir(os.path.join(p, ".hg")):
+    while not readable_repository(p):
         oldp, p = p, os.path.dirname(p)
         if p == oldp:
             return None
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -10,6 +10,7 @@  import peer, changegroup, subrepo, disco
 import changelog, dirstate, filelog, manifest, context, bookmarks, phases
 import lock, transaction, store, encoding
 import scmutil, util, extensions, hook, error, revset
+from readable_repository import readable_repository
 import match as matchmod
 import merge as mergemod
 import tags as tagsmod
@@ -191,7 +192,7 @@  class localrepository(object):
         else:
             self.supported = self._basesupported
 
-        if not self.vfs.isdir():
+        if not readable_repository(self.root):
             if create:
                 if not self.wvfs.exists():
                     self.wvfs.makedirs()
diff --git a/mercurial/readable_repository.py b/mercurial/readable_repository.py
new file mode 100644
--- /dev/null
+++ b/mercurial/readable_repository.py
@@ -0,0 +1,23 @@ 
+# readable_repository.py
+#       check if there is a readable, valid mercurial repository in the
+#       given "reporoot" directory
+#
+# Copyright 2013 Matt Mackall <mpm@selenic.com>, Roland Eggner <edv@systemanalysen.net>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+import os
+
+def readable_repository(reporoot):
+    # Assumptions:
+    # In valid revlogv1 and later repositories there is always a readable file '.hg/requires'.
+    # In valid revlogv0 repositories there is always a readable file '.hg/00changelog.i'.
+    # Targets:
+    # Skip empty '.hg' directories, e.g. currently not mounted mount points.
+    # Skip repositories unreadable with current privileges.
+    reporoot_hg = os.path.join(reporoot, '.hg')
+    return (os.path.isdir(reporoot_hg)
+        and ((os.path.isfile(os.path.join(reporoot_hg, 'requires'     )) and os.access(os.path.join(reporoot_hg, 'requires'     ), os.R_OK))
+        or   (os.path.isfile(os.path.join(reporoot_hg, '00changelog.i')) and os.access(os.path.join(reporoot_hg, '00changelog.i'), os.R_OK))))
+
diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -8,6 +8,7 @@ 
 from i18n import _
 from mercurial.node import nullrev
 import util, error, osutil, revset, similar, encoding, phases, parsers
+from readable_repository import readable_repository
 import match as matchmod
 import os, errno, re, stat, glob
 
@@ -516,7 +517,7 @@  def walkrepos(path, followsym=False, see
         adddir(seen_dirs, path)
     for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
         dirs.sort()
-        if '.hg' in dirs:
+        if readable_repository(root):
             yield root # found a repository
             qroot = os.path.join(root, '.hg', 'patches')
             if os.path.isdir(os.path.join(qroot, '.hg')):