# HG changeset patch # User Matt Mackall # Date 2010-06-16 21:05:19 # Node ID db3f6f0e4e7d521a5218c8acb63cbc169117ac6c # Parent 02a4373ca5cdf7c11d2fbae138567a5f88f831fe pushkey: add http support pushkey requires the same permissions as push listitems requires the same permissions as pull diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py --- a/mercurial/hgweb/hgweb_mod.py +++ b/mercurial/hgweb/hgweb_mod.py @@ -16,8 +16,10 @@ import webcommands, protocol, webutil perms = { 'changegroup': 'pull', 'changegroupsubset': 'pull', + 'stream_out': 'pull', + 'listkeys': 'pull', 'unbundle': 'push', - 'stream_out': 'pull', + 'pushkey': 'push', } class hgweb(object): diff --git a/mercurial/hgweb/protocol.py b/mercurial/hgweb/protocol.py --- a/mercurial/hgweb/protocol.py +++ b/mercurial/hgweb/protocol.py @@ -6,7 +6,7 @@ # GNU General Public License version 2 or any later version. import cStringIO, zlib, tempfile, errno, os, sys, urllib, copy -from mercurial import util, streamclone +from mercurial import util, streamclone, pushkey from mercurial.node import bin, hex from mercurial import changegroup as changegroupmod from common import ErrorResponse, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR @@ -17,11 +17,11 @@ from common import ErrorResponse, HTTP_O __all__ = [ 'lookup', 'heads', 'branches', 'between', 'changegroup', 'changegroupsubset', 'capabilities', 'unbundle', 'stream_out', - 'branchmap', + 'branchmap', 'pushkey', 'listkeys' ] HGTYPE = 'application/mercurial-0.1' -basecaps = 'lookup changegroupsubset branchmap'.split() +basecaps = 'lookup changegroupsubset branchmap pushkey'.split() def lookup(repo, req): try: @@ -204,3 +204,22 @@ def stream_out(repo, req): yield chunk except streamclone.StreamException, inst: yield str(inst) + +def pushkey(repo, req): + namespace = req.form['namespace'][0] + key = req.form['key'][0] + old = req.form['old'][0] + new = req.form['new'][0] + + r = repo.pushkey(namespace, key, old, new) + r = '%d\n' % int(r) + req.respond(HTTP_OK, HGTYPE, length=len(r)) + yield r + +def listkeys(repo, req): + namespace = req.form['namespace'][0] + d = repo.listkeys(namespace).items() + t = '\n'.join(['%s\t%s' % (k.encode('string-escape'), + v.encode('string-escape')) for k, v in d]) + req.respond(HTTP_OK, HGTYPE, length=len(t)) + yield t diff --git a/mercurial/httprepo.py b/mercurial/httprepo.py --- a/mercurial/httprepo.py +++ b/mercurial/httprepo.py @@ -8,7 +8,7 @@ from node import bin, hex, nullid from i18n import _ -import repo, changegroup, statichttprepo, error, url, util +import repo, changegroup, statichttprepo, error, url, util, pushkey import os, urllib, urllib2, urlparse, zlib, httplib import errno, socket import encoding @@ -259,6 +259,31 @@ class httprepository(repo.repository): def stream_out(self): return self.do_cmd('stream_out') + def pushkey(self, namespace, key, old, new): + if not self.capable('pushkey'): + return False + d = self.do_cmd("pushkey", data="", # force a POST + namespace=namespace, key=key, old=old, new=new).read() + code, output = d.split('\n', 1) + try: + ret = bool(int(code)) + except ValueError, err: + raise error.ResponseError( + _('push failed (unexpected response):'), d) + for l in output.splitlines(True): + self.ui.status(_('remote: '), l) + return ret + + def listkeys(self, namespace): + if not self.capable('pushkey'): + return {} + d = self.do_cmd("listkeys", namespace=namespace).read() + r = {} + for l in d.splitlines(): + k, v = l.split('\t') + r[k.decode('string-escape')] = v.decode('string-escape') + return r + class httpsrepository(httprepository): def __init__(self, ui, path): if not url.has_https: diff --git a/tests/test-hgweb-commands.out b/tests/test-hgweb-commands.out --- a/tests/test-hgweb-commands.out +++ b/tests/test-hgweb-commands.out @@ -845,7 +845,7 @@ graph.render(data); % capabilities 200 Script output follows -lookup changegroupsubset branchmap unbundle=HG10GZ,HG10BZ,HG10UN% heads +lookup changegroupsubset branchmap pushkey unbundle=HG10GZ,HG10BZ,HG10UN% heads 200 Script output follows 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe