For those interested in this, I ended up implementing a python CGI script to do something like this, avoiding some security problems by putting the naming of the repo largely in the hands of the server. The code is at https://bitbucket.org/jimdowning/lf-hg-server/. The main create.py
script looks like this: -
#!/usr/bin/env python
from __future__ import with_statement
import cgi
import ConfigParser
from mercurial import commands, ui
import os
import uuid
import cgitb
cgitb.enable()
def bad_request(reason):
print "Content-type: text/html"
print "Status: 400 ", reason
print
print "<html><body><h1>Bad request</h1><p>", reason, "</p></body></html>"
def abs_url(rel, env):
protocol = env["SERVER_PROTOCOL"].partition("/")[0].lower()
host = env["HTTP_HOST"]
return "%s://%s/%s" % (protocol, host, rel)
if not os.environ["REQUEST_METHOD"] == "POST":
bad_request("Method was not POST")
elif not (form.has_key("user")) :
bad_request("Missing parameter - requires 'user' param")
else :
form = cgi.FieldStorage()
user = form["user"].value
lfDir = os.path.dirname( os.environ["SCRIPT_FILENAME"])
id = str(uuid.uuid1())
userDir = os.path.join(lfDir, "repos", user)
rDir = os.path.join(userDir, id)
relPath = "lf/"+ rDir[len(lfDir)+1:]
os.makedirs(rDir)
commands.init(ui.ui(), rDir)
repoUrl = abs_url(relPath, os.environ)
config = ConfigParser.ConfigParser()
config.add_section("web")
config.set("web", "allow_push", "*")
config.set("web", "push_ssl", "false")
with open(os.path.join(rDir, ".hg", "hgrc"), "w+") as f:
config.write(f)
print "Content-Type: text/html\n"
print "Status: 201\nLocation:"
print
print "<html><body><h1>Repository Created</h1>"
print "<p>Created a repo at <a href=\""+ repoUrl + "\">"
print repoUrl+ "</a></p>"
print "</body></html>"
I stick this script in the same dir as hgwebdir.cgi
. The overall functioning of it was made much simpler with some trickery in hgweb.config
:-
[collections]
repos/ = repos/
[web]
style = gitweb