Mercurial Repositorys per HTTP publizieren

Ich habe in den vergangenen Tagen einiges darüber gelesen, wie man den Apache HTTP Server mit modwsgi dazu bewegen soll, Mercurial Repositorys zu publizieren. Ich fand dabei die lustigsten Konfigurations-Mutmaßungen. Daher sehe ich mich jetzt genötigt, die meines Erachtens erforderlichen Schritte in einer kleinen Anleitung zu veröffentlichen.

Was wird’s wenn’s fertig ist? Ein VirtualHost für die Subdomain hg.example.com, über die man alle Repositorys eines bestimmten Verzeichnisses sowie Repositorys aus weiteren Verzeichnissen publizieren kann.
Wer nicht weiß, wie man den Apache httpd konfiguriert, mit Mercurial arbeitet oder Software installiert, darf gleich weitergehen. (Dieser Beitrag ist sozusagen für Fortgeschrittene.) Wer Unbuntu-Linux einsetzt, sucht nach apache2-mercurial oder sonst einer lustigen Namenskombination. Hm, Microsoft Windows‽

Voraussetzungen

Damit die weiter unten gezeigte Konfiguration funktioniert, sollte der Apache httpd mit modwsgi funktionsfähig konfiguriert sein und die Mercurial-Installation erfolgreich abgeschlossen sein. Bei manchen Distributionen fehlt derzeit noch die Datei hgwebdir.wsgi. Diese kann aus dem offiziellen hg-stable-Repository heruntergeladen werden.

Folgende Software wurde für die Beschreibung und den Test eingesetzt:

  • Apache (MPM worker) 2.2.14
  • Mercurial 1.3.1
  • modwsgi 2.6
  • Pygments 1.1.1

VirtualHost einrichten

Ich gehe in den Konfigurations-Beispielen davon aus, dass sich die Verzeichnisse der VirtualHosts unterhalb von /srv/www befinden und der httpd seine Logs nach /var/log/apache schreibt. Zuerst wird die Verzeichnisstruktur für hg.example.com angelegt:
mkdir -p /srv/www/hg.example.com/{config,repos,wsgi}
Die Verzeichnisstruktur mit chown an die/den entsprechende/n Benutzer/innen / Gruppe übergeben.

Der Apache httpd bekommt zusätzlich folgende VirtualHost-Konfiguration.

<VirtualHost 192.0.2.127:80 [2001:db8:c001:c0de:babe::127]:80>
    ServerAdmin repomaster@example.com
    ServerName hg.example.com
    # Der Platz für alle Repositorys
    DocumentRoot /srv/www/hg.example.com/repos

    # Statische Inhalte per Alias bereitstellen (siehe auch: hgwebdir.cfg:[web] staticurl)
    Alias /static /usr/lib/python2.5/site-packages/mercurial/templates/static
    WSGIScriptAlias / /srv/www/hg.example.com/wsgi/hgwebdir.wsgi
    WSGIDaemonProcess HgWebDir user=ahguser group=hgusers processes=3 threads=10 maximum-requests=1000 umask=0007 display-name=HgWebDir
    WSGIProcessGroup HgWebDir
    <Directory /srv/www/hg.example.com/repos>
        AllowOverride None
        Order allow,deny
        Allow from all
    </Directory>

    LogLevel warn
    CustomLog /var/log/apache2/hg.example.com.access.log combined
    ErrorLog /var/log/apache2/hg.example.com.error.log
</VirtualHost>

hgwebdir konfigurieren

Im nächsten Schritt wird die globale Konfiguration, in der Datei hgwebdir.cfg, vorgenommen. Diese wird im Verzeichnis /srv/www/hg.example.com/config abgelegt. Somit ist sie vor Zugriffen aus dem Web sicher.

# Setup Informationen
#
# Erweiterungen, die im hgwebdir verwendet werden sollen. Siehe auch:
#    * hgrc(5) / Sections / extensions
#    * Using Mercurial extensions
#
[extensions]
# Erfordert die Installation von Pygments
;hgext.highlight =

#
# Einstellungen, die das Aussehen und die Fähigkeiten
# von hgwebdir beeinflussen
# Siehe auch: hgrc(5) / Sections / web
#
[web]
# Mercurial 1.3.x bietet die Web-Styles:
# coal, gitweb, monoblue, paper und spartan
style = monoblue

# Falls Repos als komprimiertes Archiv heruntergeladen werden
# sollen können, welche Formate sollen erlaubt sein?
# Mercurial 1.3.x unterstützt folgende Archiv-Formate: bz2, gz und zip
allow_archive = gz bz2

# Encoding der dynamisch generierten Websites.
# Somit braucht es nicht mehr in hgwebdir.wsgi gesetzt werden.
encoding = utf-8

# Der Alias aus httpd-Konfiguration, für statische Inhalte wie
# z. B. das Favicon oder Stylesheet. Somit werden sie nicht
# von hgwebdir.wsgi ausgeliefert, sondern vom httpd
staticurl = http://hg.example.com/static/

# Falls die Erweiterung highlight verwendet wird,
# welches Farbschema soll verwendet werden?
# `pygmentize -L styles` listet alle auf
;pygments_style = native


#
# Wo sind all die Repositorys, die hgwebdir publizieren soll?
#
[paths]
# Liste alle Repositorys aus /srv/www/hg.example.com/repos
# direkt im Mercurial repositories index auf.
# Dieser ist zu erreichen über http://hg.example.com/
/ = /srv/www/hg.example.com/repos/**

# Sollte es irgendwo ein Repository geben, das aus irgendeinem
# unerklärlich Grund nicht unter /srv/www/hg.example.com/repos
# gespeichert werden darf/kann/soll/will/whatever aber trotzdem
# mit hgwebdir publiziert werden soll, kann man hgwebdir dazu
# bewegen, auch dieses zu tun.
# Um z. B. die ersten Programmier-Gehversuche von Klaus, die er
# in einem Mercurial Repositorys verwaltet, als mittelklassigen
# IMAP-Server anzubieten, verwendet man die folgende Zeile:
;courier = /home/klaus/Ich_lerne_Programmieren/Lektion1

Die original hgwebdir.wsgi enthält noch ein paar weitere [paths]-Beispiele, auf die ich hier jetzt nicht eingehen möchte.

hgwebdir.wsgi anpassen

Yeah, nachdem ich mir schon fast ‘nen Wolf getippt habe, komme ich auch auch schon zum Kernstück der ganzen Aktion; die Datei hgwebdir.wsgi. Diese wird da erstellt und/oder gespeichert, wo der WSGIScriptAlias der httpd-Konfiguration hin verweist; in /srv/www/hg.example.com/wsgi.

Die hgwebdir.wsgi ist eine recht überschaubare Datei. Wer sie sich nicht hat, kann die folgenden paar Zeilen Python-Code auch rasch in seinem Lieblings-Editor abtippen. (Ja wirklich, ganz ohne Shebang!)

# OK, ich gebe es zu, ich habe Mercurial irgendwo, nur nicht in sys.path
# installiert, darum muss ich bei folgenden beide Zeilen die Raute
# entfernen und die zweite Zeile an meine Bedürfnisse anpassen.
#import sys
#sys.path.insert(0, "/da/wo/mein/mercurial/liegt")

# Mercurials demandimport importieren und aktiveren und hgwebdir nicht vergessen
from mercurial import demandimport; demandimport.enable()
from mercurial.hgweb.hgwebdir_mod import hgwebdir

# Wer in seiner hgwebdir.cfg kein encoding gesetzt hat, darf die Raute
# vor folgenden beiden Zeilen entfernen und die zweite an sein
# Bedürfnisse anpassen
#import os
#os.environ["HGENCODING"] = "UTF-8"

# Feuer frei! :-)
application = hgwebdir('/srv/www/hg.example.com/config/hgwebdir.cfg')

Was jetzt?

Wer es noch nicht getan hat darf jetzt seinen Apache Webserver zwingen, die Konfiguration neu einzulesen.

Wenn man unter http://hg.example.com/ jetzt schon mal einen leeren Repository Index sieht, wird es Zeit das erste Repo unter /srv/www/hg.example.com/repos zu speichern.

Nachdem ich den obigen Teil geschrieben habe, kam eben der Test. Ein wildes Copy’n’Paste. Danach einen graceful restart für den httpd. Dann schnell noch ein Repo unter /srv/www/hg.example.com/repos erstellt, Daten rein kopiert, ‘nen commit gemacht und im Browser F5 gedrückt. Alles fein.
Anders lautende Aussagen kann ich von daher nicht gelten lassen.

Vielen Dank für Ihre Aufmerksamkeit. ;-)