我知道有cgi脚本可以提供多个mercurial存储库,但我正在尝试创建一个django web应用程序来执行此操作。例如,按照bitbucket或任何其他存储库托管站点的方式思考。
这样做的最佳方式(或者无论如何,真的)是什么?
基本上,我需要做的是在我的网站上为项目特定的URL提供Merucrial HttpCommandProtocol的实现,以便mercurial客户端可以将他们的repos与存储在站点上的repos同步。我以为我可以使用hglib
来执行此操作,但似乎在CommandServer命令和HttpCommandProtocol命令之间没有任何直接的映射。我自己可以实现HttpCommandProtocol:我已经成功完成了其中的一些,但大部分命令都没有记录,我无法弄清楚它们应该做什么。
另一种选择是为每个存储库运行hg serve
并且基本上从客户端到hg服务器进行传递,但是可以有任意数量的存储库,并且每个服务器都需要在不同的存储库上端口,除非有某些方法我可以通过管道或文件描述符而不是TCP端口与HttpServer交谈。您可以使用hg serve --commandserver pipe
执行此操作,但CommandServer协议不是HTTP所需的。
答案 0 :(得分:2)
如果您对GPL的条款没有问题,最简单的方法就是从您的django视图中调用hgweb。 hgweb是一个全功能,多存储库的python wsgi应用程序,django喜欢使用它。
完全有可能你的整个django视图可能是:
from mercurial.hgweb import hgweb
def hg_view(request):
""" relay a WSGI Request to HG """
hgweb(config).run_wsgi(request)
并且您使用正常的django视图路由到那个。您可能必须修改删除前导路径元素的请求,但更重要的一点是,如果目标是让wsgi应用程序(django是)调用另一个wsgi应用程序(hgweb是),那么它就是'绝对最容易避免使用TCP套接字和本地管道,而是将所有内容保存在系列中。
答案 1 :(得分:0)
根据Ry4an接受的答案,这是我实际使用的解决方案。 django HttpRequest
对象完全有可能作为wsgirequest
可以直接传递给hgweb_mod.run_wsgi
,但我无法弄清楚要返回的内容。以下对我有用,它肯定无法处理所有边缘情况,但我能够以这种方式推送和撤回我的回购:
#!/usr/bin/python
class WsgiWrapper(object):
"""
A wrapper object that works reasonably well (at least in the cases in which it is currently being used)
to turn a django request into a Wsgi thingy.
"""
def __init__(self, request):
self.request = request
self.status = None
self.headers = None
self.exc_info = None
def __call__(self, status=None, response_headers=None, exc_info=None):
if status is not None:
self.status = status
self.headers = response_headers
self.exc_info = exc_info
self.outputbuffer = cStringIO.StringIO()
return self.outputbuffer.write
def serve_hg(request, repopath):
"""
Delegates to mercurial's built-in hgweb WSGI application to serve up access
to mercurial HTTPCommand Protocol.
"""
#Put together a wsgi request from the django request.
wrapper = WsgiWrapper(request)
env = {}
env.update(request.META)
env['SCRIPT_NAME'] = '/'
env['PATH_INFO'] = '/'
req = hgweb.request.wsgirequest(env, wrapper)
#Invoke hgweb as a wsgi application.
hgw = hgweb.hgweb(repopath)
hgw.repo.baseui.setconfig('web', 'allow_push', '*')
hgw.repo.baseui.setconfig('web', 'push_ssl', 'false')
gen = hgw.run_wsgi(req)
data = wrapper.outputbuffer.getvalue()
if len(data):
gen = [data]
wrapper.outputbuffer.close()
#Now build up the django response object from that.
resp = HttpResponse("".join(gen))
stat = wrapper.status
if stat is None:
resp.status_code = 200
else:
pair = stat.split(' ', 1)
resp.status_code = pair[0]
if len(pair) > 1:
resp.reason_phrase = pair[1]
hopbyhop = (
'Connection',
'Keep-Alive',
'Proxy-Authenticate',
'Proxy-Authorization',
'TE',
'Trailers',
'Transfer-Encoding',
'Upgrade',
)
if wrapper.headers is not None:
for k, v in wrapper.headers:
if k not in hopbyhop:
resp[k] = v
return resp