Merge default debian
authorPaul Crowley <paul@lshift.net>
Tue, 06 Sep 2011 11:16:58 +0100
branchdebian
changeset 313 f597eb3b5aaf
parent 294 31d5c6236f71 (current diff)
parent 312 4e65f8242c0b (diff)
child 314 c02eae7665af
Merge default
.hgtags
dev/chroot-test/action/install-installables
dev/chroot-test/copy-installables
--- a/.hgtags	Sun Dec 19 09:49:18 2010 +0000
+++ b/.hgtags	Tue Sep 06 11:16:58 2011 +0100
@@ -4,10 +4,11 @@
 95c9ab8e4bfc6fea6460b3147c3097373eba5d42 debian_0.7
 1ad9d5841a48a77f68dc5350bd1f941327a6348a release_0.8
 1e4050abb96e72c6324b93709e56a3e135e63ce1 debian_0.8-1
-d42d3f5311c55cab668d6962a61d44ba98645e release_0.9
+fed42d3f5311c55cab668d6962a61d44ba98645e release_0.9
 b6887a9b8792bb2b69b428448102140fce121e29 debian_0.9-1
 8ce190faa5c2b50f63cc5b11e28daf98836498d8 release_1.0
 60c2d676a754e02f1f7656a4b137399438b2ed35 debian_1.0-1
 92cb6640a6417edaf52870c8a97000e11bb8b138 release_1.0.1
 c7aca86585824f39fa47015d6ebf1bab6a25b82c debian_1.0.1-1
+01eca64f77abbf0da41cd777a365de2a5a02988b release_1.1
 32dba1a70a5443cf86a78b5a9471ad7ced034a12 debian_1.1-1
--- a/NEWS	Sun Dec 19 09:49:18 2010 +0000
+++ b/NEWS	Tue Sep 06 11:16:58 2011 +0100
@@ -40,7 +40,7 @@
 * Belatedly added NEWS file :-)
 
 Upgrading: move the paths/hgrc entry in .mercurial-server to env/HGRCPATH,
-and add an entry under paths that reads 
+and add an entry under paths that reads
 "authorized_keys = ~/.ssh/authorized_keys"
 
 ====================
@@ -89,4 +89,3 @@
 ====================
 
 * First numbered release
-
--- a/README	Sun Dec 19 09:49:18 2010 +0000
+++ b/README	Tue Sep 06 11:16:58 2011 +0100
@@ -2,7 +2,7 @@
 
 mercurial-server gives your developers remote read/write access to
 centralized Mercurial repositories using SSH public key authentication; it
-provides convenient and fine-grained key management and access control. 
+provides convenient and fine-grained key management and access control.
 
 http://www.lshift.net/mercurial-server.html
 
@@ -25,7 +25,7 @@
 Though mercurial-server is currently targeted at Debian-based systems such
 as Ubuntu, other users have reported success getting it running on other
 Unix-based systems such as Red Hat. Running it on a non-Unix system such as
-Windows is not supported. You will need root privileges to install it. 
+Windows is not supported. You will need root privileges to install it.
 
 The best way to install mercurial-server is using your package management
 system - there are pre-built .deb files on the website. However, there is
@@ -41,4 +41,3 @@
 See doc/manual.docbook for the rest of the documentation.
 
 Paul Crowley, paul@lshift.net, 2010
-
--- a/dev/chroot-test/action/go	Sun Dec 19 09:49:18 2010 +0000
+++ b/dev/chroot-test/action/go	Tue Sep 06 11:16:58 2011 +0100
@@ -15,7 +15,7 @@
 
 perl -i -pe 's/^Port 22$/Port 2222/' /etc/ssh/sshd_config
 /etc/init.d/ssh start
-ssh-keyscan -p 2222 localhost > /etc/ssh/ssh_known_hosts
+ssh-keyscan -t rsa,dsa,ecdsa -p 2222 localhost > /etc/ssh/ssh_known_hosts
 
 . ./install-installables
 
@@ -33,4 +33,3 @@
 /etc/init.d/ssh stop
 
 #touch results
-
--- a/dev/chroot-test/action/test1	Sun Dec 19 09:49:18 2010 +0000
+++ b/dev/chroot-test/action/test1	Tue Sep 06 11:16:58 2011 +0100
@@ -43,4 +43,9 @@
 echo "Pushing changes"
 hg clone . ssh://chroothg/real/project
 hg clone nested ssh://chroothg/real/project/nested
+cd ..
+echo "Creating an mq repository"
+hg init qrepo
+(cd qrepo ; hg --config extensions.mq= qinit -c)
+hg --config extensions.mq= qclone qrepo ssh://chroothg/qrepo
 echo "Done for user test1"
--- a/dev/chroot-test/run-test	Sun Dec 19 09:49:18 2010 +0000
+++ b/dev/chroot-test/run-test	Tue Sep 06 11:16:58 2011 +0100
@@ -31,6 +31,7 @@
 fi
 if [ -e $BACKING ] ; then
     echo "Copying deb files into cache"
+    mkdir -p $BUILDDIR/aptcache/$DEBVERSION
     cp $BACKING/var/cache/apt/archives/* $BUILDDIR/aptcache/$DEBVERSION || true
     echo "Deleting old filesystem backing store"
     rm -rf $BACKING
@@ -59,4 +60,4 @@
 mount -t proc proc $MOUNT/proc
 
 chroot $MOUNT ./action/go
-
+echo "Completed successfully"
--- a/doc/manual.docbook	Sun Dec 19 09:49:18 2010 +0000
+++ b/doc/manual.docbook	Tue Sep 06 11:16:58 2011 +0100
@@ -45,7 +45,7 @@
 <systemitem class="systemname">spoon</systemitem> and you have
 installed mercurial-server on <systemitem
 class="systemname">jeeves</systemitem> using the package management system (see the README for more on installation). We assume that you have created your SSH public key, set up your SSH agent with this key, and that this key gives you access to <systemitem
-class="systemname">jeeves</systemitem>.  
+class="systemname">jeeves</systemitem>.
 </para>
 <screen><computeroutput>jay@spoon:~$ </computeroutput><userinput>ssh -A jeeves</userinput>
 <computeroutput>jay@jeeves:~$ </computeroutput><userinput>ssh-add -L > my-key</userinput>
@@ -532,4 +532,3 @@
 </section>
 </section>
 </article>
-
--- a/setup.py	Sun Dec 19 09:49:18 2010 +0000
+++ b/setup.py	Tue Sep 06 11:16:58 2011 +0100
@@ -14,10 +14,9 @@
     scripts = ['src/hg-ssh', 'src/refresh-auth'],
     data_files = [
         ('init', [
-            'src/init/hginit', 
-            'src/init/dot-mercurial-server', 
+            'src/init/hginit',
+            'src/init/dot-mercurial-server',
             'src/init/hgadmin-hgrc'
         ]),
     ],
 )
-
--- a/src/hg-ssh	Sun Dec 19 09:49:18 2010 +0000
+++ b/src/hg-ssh	Tue Sep 06 11:16:58 2011 +0100
@@ -19,6 +19,11 @@
 
 from mercurial import dispatch
 
+try:
+    request = dispatch.request
+except AttributeError:
+    request = list
+
 import sys, os, os.path
 import base64
 from mercurialserver import config, ruleset
@@ -27,12 +32,41 @@
     sys.stderr.write("mercurial-server: %s\n" % message)
     sys.exit(-1)
 
-def checkDots(path):
+config.initExe()
+
+for k,v in config.getEnv():
+    os.environ[k.upper()] = v
+
+if len(sys.argv) == 3 and sys.argv[1] == "--base64":
+    ruleset.rules.set(user = base64.b64decode(sys.argv[2]))
+elif len(sys.argv) == 2:
+    ruleset.rules.set(user = sys.argv[1])
+else:
+    fail("hg-ssh wrongly called, is authorized_keys corrupt? (%s)"
+        % sys.argv)
+
+os.chdir(config.getReposPath())
+
+for f in config.getAccessPaths():
+    if os.path.isfile(f):
+        ruleset.rules.readfile(f)
+
+alloweddots = config.getAllowedDots()
+
+def dotException(pathtail):
+    for ex in alloweddots:
+        splex = ex.split("/")
+        if len(pathtail) >= len(splex) and pathtail[:len(splex)] == splex:
+            return True
+    return False
+
+def checkDots(path, pathtail = []):
     head, tail = os.path.split(path)
-    if tail.startswith("."):
-        fail("paths cannot contain dot file components")
+    pathtail = [tail] + pathtail
+    if tail.startswith(".") and not dotException(pathtail):
+            fail("paths cannot contain dot file components")
     if head:
-        checkDots(head)
+        checkDots(head, pathtail)
 
 def getrepo(op, repo):
     # First canonicalise, then check the string, then the rules
@@ -47,25 +81,6 @@
         fail("access denied")
     return repo
 
-config.initExe()
-
-for k,v in config.getEnv():
-    os.environ[k.upper()] = v
-
-if len(sys.argv) == 3 and sys.argv[1] == "--base64":
-    ruleset.rules.set(user = base64.b64decode(sys.argv[2]))
-elif len(sys.argv) == 2:
-    ruleset.rules.set(user = sys.argv[1])
-else:
-    fail("hg-ssh wrongly called, is authorized_keys corrupt? (%s)" 
-        % sys.argv)
-
-os.chdir(config.getReposPath())
-
-for f in config.getAccessPaths():
-    if os.path.isfile(f):
-        ruleset.rules.readfile(f)
-
 cmd = os.environ.get('SSH_ORIGINAL_COMMAND', None)
 if cmd is None:
     fail("direct logins on the hg account prohibited")
@@ -73,7 +88,7 @@
     repo = getrepo("read", cmd[6:-14])
     if not os.path.isdir(repo + "/.hg"):
         fail("no such repository %s" % repo)
-    dispatch.dispatch(['-R', repo, 'serve', '--stdio'])
+    dispatch.dispatch(request(['-R', repo, 'serve', '--stdio']))
 elif cmd.startswith('hg init '):
     repo = getrepo("init", cmd[8:])
     if os.path.exists(repo):
@@ -81,7 +96,6 @@
     d = os.path.dirname(repo)
     if d != "" and not os.path.isdir(d):
         os.makedirs(d)
-    dispatch.dispatch(['init', repo])
+    dispatch.dispatch(request(['init', repo]))
 else:
     fail("illegal command %r" % cmd)
-
--- a/src/init/conf/remote-hgrc.d/access.rc	Sun Dec 19 09:49:18 2010 +0000
+++ b/src/init/conf/remote-hgrc.d/access.rc	Tue Sep 06 11:16:58 2011 +0100
@@ -2,4 +2,3 @@
 
 [hooks]
 pretxnchangegroup.access = python:mercurialserver.access.hook
-
--- a/src/init/dot-mercurial-server	Sun Dec 19 09:49:18 2010 +0000
+++ b/src/init/dot-mercurial-server	Tue Sep 06 11:16:58 2011 +0100
@@ -7,9 +7,12 @@
 keys = /etc/mercurial-server/keys:~/repos/hgadmin/keys
 access = /etc/mercurial-server/access.conf:~/repos/hgadmin/access.conf
 
+[exceptions]
+# Allow the creation of mq repositories by default
+allowdots = .hg/patches
+
 [env]
 # Use a different hgrc for remote pulls - this way you can set
 # up access.py for everything at once without affecting local operations
 
 HGRCPATH = /etc/mercurial-server/remote-hgrc.d
-
--- a/src/init/hginit	Sun Dec 19 09:49:18 2010 +0000
+++ b/src/init/hginit	Tue Sep 06 11:16:58 2011 +0100
@@ -14,4 +14,3 @@
 cd repos/hgadmin
 hg init .
 cp $1/init/hgadmin-hgrc .hg/hgrc
-
--- a/src/mercurialserver/access.py	Sun Dec 19 09:49:18 2010 +0000
+++ b/src/mercurialserver/access.py	Tue Sep 06 11:16:58 2011 +0100
@@ -25,4 +25,3 @@
         if not allow(ctx):
             raise mercurial.util.Abort(_('%s: access denied for changeset %s') %
                 (__name__, mercurial.node.short(ctx.node())))
-
--- a/src/mercurialserver/config.py	Sun Dec 19 09:49:18 2010 +0000
+++ b/src/mercurialserver/config.py	Tue Sep 06 11:16:58 2011 +0100
@@ -20,7 +20,7 @@
 def _getPath(name):
     return os.path.expanduser(_getConf().get("paths", name))
 
-def _getPaths(name): 
+def _getPaths(name):
     return [os.path.expanduser(p)
         for p in _getConf().get("paths", name).split(":")]
 
@@ -40,6 +40,17 @@
 
 def getEnv(): return _getConf().items("env")
 
+def _getdefault(section, option, default, f = lambda x: x):
+    conf = _getConf()
+    if conf.has_option(section, option):
+        return f(conf.get(section, option))
+    else:
+        return default
+
+def getAllowedDots():
+    return _getdefault("exceptions", "allowdots", [],
+        lambda s: s.split(":"))
+
 # Work out where we are, don't use config.
 def initExe():
     global _exePath
@@ -49,4 +60,3 @@
 
 def getExePath():
     return _exePath
-
--- a/src/mercurialserver/refreshauth.py	Sun Dec 19 09:49:18 2010 +0000
+++ b/src/mercurialserver/refreshauth.py	Tue Sep 06 11:16:58 2011 +0100
@@ -39,7 +39,7 @@
                 if not goodkey.match(keyname):
                     # Encode it for safe quoting
                     keyname = "--base64 " + base64.b64encode(keyname)
-                p = subprocess.Popen(("ssh-keygen", "-i", "-f", ffn), 
+                p = subprocess.Popen(("ssh-keygen", "-i", "-f", ffn),
                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                 newkey = p.communicate()[0]
                 if p.wait() == 0:
@@ -57,7 +57,6 @@
     akeys.close()
     os.chmod(akeyfile + "_new", stat.S_IRUSR)
     os.rename(akeyfile + "_new", akeyfile)
-    
+
 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
     refreshAuth()
-
--- a/src/mercurialserver/ruleset.py	Sun Dec 19 09:49:18 2010 +0000
+++ b/src/mercurialserver/ruleset.py	Tue Sep 06 11:16:58 2011 +0100
@@ -13,63 +13,56 @@
     # ** means "match recursively" ie "ignore directories"
     return re.compile(p.replace("[^/]*[^/]*", ".*") + "$")
 
-# Returns True for a definite match
-# False for a definite non-match
-# None where we can't be sure because a key is None
+# Returns 1 for a definite match
+# -1 for a definite non-match
+# 0 where we can't be sure because a key is None
+def rmatch(k, m, kw):
+    if k not in kw:
+        return -1
+    kkw = kw[k]
+    if kkw is None:
+        return 0
+    elif m.match(kkw) is None:
+        return -1
+    else:
+        return 1
+
 def rule(pairs):
     matchers = [(k, globmatcher(v)) for k, v in pairs]
     def c(kw):
-        for k, m in matchers:
-            if k not in kw:
-                return False
-            kkw = kw[k]
-            if kkw is None:
-                return None
-            if m.match(kkw) is None:
-                return False
-        return True
+        return min(rmatch(k, m, kw) for k, m in matchers)
     return c
 
 class Ruleset(object):
     '''Class representing the rules in a rule file'''
-    
+
     levels = ["init", "write", "read", "deny"]
 
     def __init__(self):
         self.rules = []
         self.preset = {}
 
-    def add(self, action, conditions):
-        self.rules.append((action, conditions))
-
     def set(self, **kw):
         self.preset.update(kw)
-        
+
     def get(self, k):
         return self.preset.get(k, None)
-        
-    def matchrules(self, kw):
+
+    def allow(self, level, **kw):
+        levelindex = self.levels.index(level)
         d = self.preset.copy()
         d.update(kw)
-        res = set()
         for a, c in self.rules:
             m = c(d)
-            if m is None:
-                # "Maybe match" - add it and carry on
-                res.add(a)
-            elif m:
-                # Definite match - add it and stop
-                res.add(a)
-                break
-        return res
-
-    def allow(self, level, **kw):
-        for a in self.matchrules(kw):
-            if a in self.levels:
-                if self.levels.index(a) <= self.levels.index(level):
+            if m == 1:
+                # Definite match - what it says goes
+                return a <= levelindex
+            elif m == 0:
+                # "Maybe match" - allow if it says yes, ignore if no
+                if a <= levelindex:
                     return True
         return False
-    
+
     def readfile(self, fn):
         f = open(fn)
         try:
@@ -78,9 +71,14 @@
                 if len(l) == 0 or l.startswith("#"):
                     continue
                 l = l.split()
-                self.add(l[0], rule([c.split("=", 1) for c in l[1:]]))
+                # Unrecognized actions are off the high end
+                if l[0] in self.levels:
+                    ix = self.levels.index(l[0])
+                else:
+                    ix = len(self.levels)
+                self.rules.append((ix,
+                    rule([c.split("=", 1) for c in l[1:]])))
         finally:
             f.close()
 
 rules = Ruleset()
-
--- a/src/mercurialserver/servelog.py	Sun Dec 19 09:49:18 2010 +0000
+++ b/src/mercurialserver/servelog.py	Tue Sep 06 11:16:58 2011 +0100
@@ -9,7 +9,13 @@
 import os
 import time
 import fcntl
-import json
+
+try:
+    import json
+    json.dumps
+except ImportError:
+    import simplejson as json
+
 from mercurialserver import ruleset, changes
 
 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
@@ -25,13 +31,13 @@
         fcntl.flock(log.fileno(), fcntl.LOCK_EX)
         log.seek(0, os.SEEK_END)
         # YAML log file format
-        log.write("- {0}\n".format(json.dumps(dict(
+        log.write("- %s\n" % json.dumps(dict(
             timestamp=time.strftime("%Y-%m-%d_%H:%M:%S Z", time.gmtime()),
             op=op,
             key=ruleset.rules.get('user'),
             ssh_connection=os.environ['SSH_CONNECTION'],
             nodes=[mercurial.node.hex(ctx.node())
                 for ctx in changes.changes(repo, node)],
-         ))))
+         )))
     finally:
         log.close()