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

Roland Eggner edvx1 at systemanalysen.net
Mon Dec 30 12:52:07 CST 2013


# HG changeset patch
# Parent ad445599010834299cb1d6cc7db0315df3b61923
# User Roland Eggner < odv at 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

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 at selenic.com>, Roland Eggner <edv at 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')):
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://selenic.com/pipermail/mercurial-devel/attachments/20131230/b11a6828/attachment.pgp>


More information about the Mercurial-devel mailing list