[PATCH] Support remote access to (some) "hgrc" parameters

Glenn Ammons ammons at us.ibm.com
Wed Jan 2 16:34:37 CST 2008


# HG changeset patch
# User Glenn Ammons <ammons at us.ibm.com>
# Date 1199313108 18000
# Node ID 944bd614d87b078000c28b8df38654e2325287f6
# Parent  28d9f8cd02f2d1879ef36c31df2ed116c8039d51
Support remote access to (some) "hgrc" parameters.

This changeset adds methods for remote access to hgrc parameters.  All
repositories, even local ones, now have a "config" method for
accessing parameters.  For local repositories, this method just calls
"self.ui.config".  For http and ssh repositories, the method checks
that the remote repository supports hgrc parameter access and, if so,
gets the parameter's value remotely.

To avoid exposing sensitive values like passwords, remote repositories
only return values from sections that start with "public.".  For
example, if the remote repository's hgrc contains this:

[public.foo]
bar = 1

[foo]
baz = 1

then only the value of "bar" is accessible remotely.

diff -r 28d9f8cd02f2 -r 944bd614d87b mercurial/hgweb/protocol.py
--- a/mercurial/hgweb/protocol.py	Wed Jan 02 20:22:10 2008 +0100
+++ b/mercurial/hgweb/protocol.py	Wed Jan 02 17:31:48 2008 -0500
@@ -10,6 +10,28 @@ from mercurial.i18n import gettext as _
 from mercurial.i18n import gettext as _
 from mercurial.node import *
 
+def config(web, req):
+    try:
+        section = req.form['section'][0]
+        name = req.form['name'][0]
+        if not web.repo.ui.is_section_public(section):
+            r = "section is not public"
+            success = 0
+        else:
+            val = web.repo.ui.config(section, name)
+            if val == None:
+                r = "parameter not found"
+                success = 0
+            else:
+                r = val
+                success = 1
+    except Exception,inst:
+        r = str(inst)
+        success = 0
+    resp = "%s %s\n" % (success, r)
+    req.httphdr("application/mercurial-0.1", length=len(resp))
+    req.write(resp)
+    
 def lookup(web, req):
     try:
         r = hex(web.repo.lookup(req.form['key'][0]))
@@ -90,7 +112,7 @@ def changegroupsubset(web, req):
     req.write(z.flush())
 
 def capabilities(web, req):
-    caps = ['lookup', 'changegroupsubset']
+    caps = ['lookup', 'changegroupsubset', 'config']
     if web.configbool('server', 'uncompressed'):
         caps.append('stream=%d' % web.repo.changelog.version)
     # XXX: make configurable and/or share code with do_unbundle:
diff -r 28d9f8cd02f2 -r 944bd614d87b mercurial/httprepo.py
--- a/mercurial/httprepo.py	Wed Jan 02 20:22:10 2008 +0100
+++ b/mercurial/httprepo.py	Wed Jan 02 17:31:48 2008 -0500
@@ -359,6 +359,17 @@ class httprepository(remoterepository):
             # if using keepalive, allow connection to be reused
             fp.close()
 
+    def config(self, section, name, default=None):
+        self.requirecap('config', _('look up remote configuration'))
+        d = self.do_cmd("config", section = section, name = name).read()
+        success, data = d[:-1].split(" ", 1)
+        if int(success):
+            return data
+        elif data == "parameter not found":
+            return default
+        else:
+            raise repo.RepoError(data)
+            
     def lookup(self, key):
         self.requirecap('lookup', _('look up remote revision'))
         d = self.do_cmd("lookup", key = key).read()
diff -r 28d9f8cd02f2 -r 944bd614d87b mercurial/localrepo.py
--- a/mercurial/localrepo.py	Wed Jan 02 20:22:10 2008 +0100
+++ b/mercurial/localrepo.py	Wed Jan 02 17:31:48 2008 -0500
@@ -851,6 +851,9 @@ class localrepository(repo.repository):
             if not valid: # don't save our updated dirstate
                 self.dirstate.invalidate()
             del tr, lock, wlock
+
+    def config(self, section, name, default=None):
+        return self.ui.config(section, name, default)
 
     def walk(self, node=None, files=[], match=util.always, badmatch=None):
         '''
diff -r 28d9f8cd02f2 -r 944bd614d87b mercurial/sshrepo.py
--- a/mercurial/sshrepo.py	Wed Jan 02 20:22:10 2008 +0100
+++ b/mercurial/sshrepo.py	Wed Jan 02 17:31:48 2008 -0500
@@ -130,6 +130,18 @@ class sshrepository(remoterepository):
     def unlock(self):
         self.call("unlock")
 
+    def config(self, section, name, default=None):
+        self.requirecap('config', _('look up remote configuration'))
+        param = "%s %s" % (section, name)
+        d = self.call("config", param=param)
+        success, data = d[:-1].split(" ", 1)
+        if int(success):
+            return data
+        elif data == "parameter not found":
+            return default
+        else:
+            self.raise_(repo.RepoError(data))
+            
     def lookup(self, key):
         self.requirecap('lookup', _('look up remote revision'))
         d = self.call("lookup", key=key)
diff -r 28d9f8cd02f2 -r 944bd614d87b mercurial/sshserver.py
--- a/mercurial/sshserver.py	Wed Jan 02 20:22:10 2008 +0100
+++ b/mercurial/sshserver.py	Wed Jan 02 17:31:48 2008 -0500
@@ -46,6 +46,25 @@ class sshserver(object):
             if impl: impl()
             else: self.respond("")
         return cmd != ''
+
+    def do_config(self):
+        """the config command returns the value of an hgrc
+        configuration parameter.  If the parameter's section is not
+        public, then an error is returned."""
+        arg, path = self.getarg()
+        section, name = path.split(" ")
+        if not self.ui.is_section_public(section):
+            r = "section is not public"
+            success = 0
+        else:
+            val = self.ui.config(section, name)
+            if val == None:
+                r = "parameter not found"
+                success = 0
+            else:
+                r = val
+                success = 1
+        self.respond("%s %s\n" % (success, r))
 
     def do_lookup(self):
         arg, key = self.getarg()
@@ -71,7 +90,7 @@ class sshserver(object):
         capabilities: space separated list of tokens
         '''
 
-        caps = ['unbundle', 'lookup', 'changegroupsubset']
+        caps = ['unbundle', 'lookup', 'changegroupsubset', 'config']
         if self.ui.configbool('server', 'uncompressed'):
             caps.append('stream=%d' % self.repo.changelog.version)
         self.respond("capabilities: %s\n" % (' '.join(caps),))
diff -r 28d9f8cd02f2 -r 944bd614d87b mercurial/ui.py
--- a/mercurial/ui.py	Wed Jan 02 20:22:10 2008 +0100
+++ b/mercurial/ui.py	Wed Jan 02 17:31:48 2008 -0500
@@ -283,6 +283,13 @@ class ui(object):
             result = result.replace(",", " ").split()
         return result
 
+    # Returns True iff the section is public (that is, accessible
+    # remotely)
+    def is_section_public(self, section):
+        '''return True iff the section is public.
+        Public sections start with "public."'''
+        return section.startswith("public.")
+
     def has_section(self, section, untrusted=False):
         '''tell whether section exists in config.'''
         cdata = self._get_cdata(untrusted)


More information about the Mercurial-devel mailing list