views:

301

answers:

4

I'm in need of a software (not a service) that has a web API to both create as well as interact with mercurial repositories. In my mind's eye I imagine the API might look like:

 POST /repos
 name=foo

Creates a repository at /repos/foo, which then works as per hgwebdir.cgi.

Does such software exist? If not, any recommendations about how to go about implementing it (I'm OK with python syntax but relatively clueless about the best way of constructing apps like this).

A: 

hgwebdir.cgi can get you halfway there, assuming they are already created this is one way to host them.

Tom Willis
+3  A: 

I am not aware of such software, but it would be pretty trivial to create one yourself if you are familiar with web applications and python.

import os
from mercurial import commands,ui
os.mkdir("/repos/foo")
commands.init(ui.ui(),"/repos/foo")

should do the trick. Of course you need to wrap it inside a nice WSGI script to have the web interface / API

For further info, consult the Mercurial API documentation

Kimvais
+1  A: 

I wrote a cheesy shell CGI to do exactly this awhile ago. Please head the security warnings:

#!/bin/sh

echo -n -e "Content-Type: text/plain\n\n"

mkdir -p /my/repos/$PATH_INFO
cd /my/repos/$PATH_INFO
hg init

Please heed the security warnings found with the full instructions.

Ry4an
+1  A: 

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
Jim Downing