<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>geek# &#187; Mercurial</title>
	<atom:link href="http://geeksharp.com/tag/mercurial/feed/" rel="self" type="application/rss+xml" />
	<link>http://geeksharp.com</link>
	<description>techno-babble for the masses</description>
	<lastBuildDate>Thu, 27 May 2010 14:57:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Mercurial Web with FastCGI &amp; Nginx</title>
		<link>http://geeksharp.com/2010/01/20/mercurial-web-with-fastcgi-nginx/</link>
		<comments>http://geeksharp.com/2010/01/20/mercurial-web-with-fastcgi-nginx/#comments</comments>
		<pubDate>Thu, 21 Jan 2010 01:29:07 +0000</pubDate>
		<dc:creator>Scott Anderson</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mercurial]]></category>
		<category><![CDATA[Source Control]]></category>

		<guid isPermaLink="false">http://geeksharp.com/2010/01/20/mercurial-web-with-fastcgi-nginx/</guid>
		<description><![CDATA[So I’ve finally decided to make the switch to a distributed source control system.&#160; The benefits are well-documented, and I&#8217;ve grown weary of Subversion.&#160; After some research, I decided Mercurial would be best for me.&#160; Since I have OCD, and I wanted to push via HTTP to my remote repository, I did some homework and [...]]]></description>
			<content:encoded><![CDATA[<p>So I’ve finally decided to make the switch to a distributed source control system.&#160; The benefits are well-documented, and I&#8217;ve grown weary of Subversion.&#160; After some research, I decided Mercurial would be best for me.&#160; Since I have OCD, and I wanted to push via HTTP to my remote repository, I did some homework and figured out how to get everything running on my VPS.&#160; If you’d like to see how I did it, read on.</p>
<h4>Step 1:&#160; Prerequisites</h4>
<p>Since my VPS runs Ubuntu Linux 9.10, there are a few packages to install before we get started.&#160; Run the following command to install them:</p>
<pre class="brush: plain;">sudo apt-get install python-setuptools acl python-dev spawn-fcgi</pre>
<p>Now you need to make sure your main partition has the acl system enabled in /etc/fstab.&#160; Modify the partition options to look something like this:</p>
<pre class="brush: plain;"># /etc/fstab: static file system information.
#
# &lt;file system&gt; &lt;mount point&gt;   &lt;type&gt;  &lt;options&gt;       &lt;dump&gt;  &lt;pass&gt;
proc            /proc           proc    defaults        0       0
/dev/xvda       /               ext3    noatime,errors=remount-ro,acl 0       1
/dev/xvdb       none            swap    sw              0       0</pre>
<p>Pay attention to that <b>acl</b> option in the default partition above.&#160; Now you can just remount the partition:</p>
<pre class="brush: plain;">sudo mount -o remount,acl /</pre>
<h4>Step 2:&#160; Install Mercurial and flup</h4>
<p>Mercurial is obvious, but flup might be new to you.&#160; Flup is a python module that allows us to create a WSGI server to host the repositories.</p>
<pre class="brush: plain;">sudo easy_install mercurial
sudo easy_install flup</pre>
<h4>Step 3:&#160; Create a user account to hold your repositories</h4>
<p>I prefer to place my repositories underneath a normal user account and then add www-data and myself to the group.&#160; Here are the commands to set it all up:</p>
<pre class="brush: plain;">sudo /usr/sbin/groupadd hg
sudo /usr/sbin/useradd -g hg -s /bin/false hg
sudo mkdir /var/hg
sudo chown hg:hg /var/hg
sudo /usr/sbin/usermod -G hg www-data
sudo /usr/sbin/usermod -G hg scott</pre>
<p>The next part deserves a little bit of explaining.&#160; Basically the whole /var/hg folder should be owned by the group <strong>hg</strong> that we just created.&#160; But what we need to ensure three things.&#160; First, the hg group should have write permissions to the root folder.&#160; Second, we need to make sure that any new files created under this folder will belong to the group <strong>hg</strong> also.&#160; And third, we need to make sure that the default permissions for this folder are read/write for the owner and the group.&#160; These two commands will ensure each of these rules is followed, which is why we added the <strong>acl</strong> package earlier and remounted the main filesystem.</p>
<p>I’m sure there are other ways to accomplish this (like running Nginx and the FastCGI process as the <strong>hg</strong> user), but this is the method I prefer, and it saves a lot of headaches down the road dealing with why a push won’t go.&#160; So here are the three commands you need to execute:</p>
<pre class="brush: plain;">sudo chmod -R g+rwxs,o+rx /var/hg
sudo setfacl -R -m d:u::rwx,d:g::rwx,d:m:rwx,d:o:r-x /var/hg</pre>
<h4>Step 4:&#160; Create the hgwebdir.cgi script</h4>
<p>This script is used to serve the incoming requests for the FastCGI interface, mine is <strong>/opt/hg-fastcgi/hgwebdir.fcgi</strong></p>
<pre class="brush: plain;">#!/usr/bin/env python
#
# An example CGI script to export multiple hgweb repos, edit as necessary

# adjust python path if not a system-wide install:
#import sys
#sys.path.insert(0, "/path/to/python/lib")

# enable demandloading to reduce startup time
from mercurial import demandimport; demandimport.enable()

# Uncomment to send python tracebacks to the browser if an error occurs:
#import cgitb
#cgitb.enable()

# If you'd like to serve pages with UTF-8 instead of your default
# locale charset, you can do so by uncommenting the following lines.
# Note that this will cause your .hgrc files to be interpreted in
# UTF-8 and all your repo files to be displayed using UTF-8.
#
#import os
#os.environ["HGENCODING"] = "UTF-8"

from mercurial.hgweb.hgwebdir_mod import hgwebdir
from flup.server.fcgi import WSGIServer

# The config file looks like this.  You can have paths to individual
# repos, collections of repos in a directory tree, or both.
#
# [paths]
# virtual/path1 = /real/path1
# virtual/path2 = /real/path2
# virtual/root = /real/root/*
# / = /real/root2/*
#
# [collections]
# /prefix/to/strip/off = /root/of/tree/full/of/repos
#
# paths example:
#
# * First two lines mount one repository into one virtual path, like
# '/real/path1' into 'virtual/path1'.
#
# * The third entry tells every mercurial repository found in
# '/real/root', recursively, should be mounted in 'virtual/root'. This
# format is preferred over the [collections] one, using absolute paths
# as configuration keys is not supported on every platform (including
# Windows).
#
# * The last entry is a special case mounting all repositories in
# '/real/root2' in the root of the virtual directory.
#
# collections example: say directory tree /foo contains repos /foo/bar,
# /foo/quux/baz.  Give this config section:
#   [collections]
#   /foo = /foo
# Then repos will list as bar and quux/baz.
#
# Alternatively you can pass a list of ('virtual/path', '/real/path') tuples
# or use a dictionary with entries like 'virtual/path': '/real/path'

WSGIServer(hgwebdir('/var/hg/hgweb.config')).run()</pre>
<p>Make sure you set this script as executable with the following command:</p>
<pre class="brush: plain;">chmod +x /opt/hg-fastcgi/hgwebdir.fcgi</pre>
<h4>Step 5:&#160; Create the Mercurial hgweb.config</h4>
<p>There’s a simple INI-style config file we have to create.&#160; I called mine <strong>/var/hg/hgweb.config</strong>.&#160; If you decide to place yours elsewhere, you need to modify the last line of the <strong>hgwebdir.fcgi</strong> script you created in step 4.</p>
<pre class="brush: plain;">[web]
baseurl = /
allow_push = *
push_ssl = false

[collections]
/var/hg = /var/hg</pre>
<h4>Step 6:&#160; Create the FastCGI init.d script</h4>
<p>This script will not only handle starting and stopping your FastCGI process for Mercurial; it will also handle restarting the service on reboot.&#160; Make sure you save this as <strong>/etc/init.d/fcgi-hg.</strong></p>
<pre class="brush: plain;">#! /bin/sh
#
# fcgi-hg     Startup script for the nginx HTTP Server
#
# chkconfig: - 84 15
# description: Loading php-cgi using spawn-cgi
#	       HTML files and CGI.
#
# Author:  Ryan Norbauer &lt;ryan.norbauer@gmail.com&gt;
# Modified:     Geoffrey Grosenbach http://topfunky.com
# Modified:     David Krmpotic http://davidhq.com
# Modified:	Kun Xi http://kunxi.org
PATH=/opt/python/bin:$PATH
DAEMON=/usr/bin/spawn-fcgi
FCGIHOST=127.0.0.1
FCGIPORT=9003
FCGIUSER=www-data
FCGIGROUP=www-data
FCGIAPP=/opt/hg-fastcgi/hgwebdir.fcgi
PIDFILE=/var/run/fcgi-hg.pid
DESC="HG in FastCGI mode"

# Gracefully exit if the package has been removed.
test -x $DAEMON || exit 0
test -x $FCGIAPP || exit 0

start() {
	$DAEMON -a $FCGIHOST -p $FCGIPORT -u $FCGIUSER -g $FCGIGROUP -f $FCGIAPP -P $PIDFILE 2> /dev/null || echo -en "\n already running"
}

stop() {
	kill -QUIT `cat $PIDFILE` || echo -en "\n not running"
}

restart() {
	kill -HUP `cat $PIDFILE` || echo -en "\n can't reload"
}

case "$1" in
  start)
    echo -n "Starting $DESC: "
    start
  ;;
  stop)
    echo -n "Stopping $DESC: "
    stop
  ;;
  restart|reload)
    echo -n "Restarting $DESC: "
    stop
    # One second might not be time enough for a daemon to stop,
    # if this happens, d_start will fail (and dpkg will break if
    # the package is being upgraded). Change the timeout if needed
    # be, or change d_stop to have start-stop-daemon use --retry.
    # Notice that using --retry slows down the shutdown process somewhat.
    sleep 1
    start
  ;;
  *)
    echo "Usage: $SCRIPTNAME {start|stop|restart|reload}" >&#038;2
    exit 3
  ;;
esac

exit $?</pre>
<p>Now you need to update the rc.d directories so this service will start when you reboot your box.&#160; This simple command will do it for you:</p>
<pre class="brush: plain;">update-rc.d fcgi-hg defaults</pre>
<p>Now you’ll be able to start and stop your service like this:</p>
<pre class="brush: plain;">/etc/init.d/fcgi-hg start
/etc/init.d/fcgi-hg stop
/etc/init.d/fcgi-hg restart</pre>
<h4>Step 7:&#160; Create hguser.config for user setup</h4>
<p>I prefer not to keep my repositories open to everyone (for obvious reasons) so we need to create an htpasswd-style user configuration file.&#160; Note that since this will be used for <strong>basic</strong> authentication, credentials will be sent in plain text.&#160; If that matters to you, then you should configure your Nginx install to use SSL, but this is outside the scope of this article.&#160; Anyway, onward.&#160; You should put this file at <strong>/var/hg/hguser.config</strong></p>
<pre class="brush: plain;"># Format &lt;user&gt;:&lt;encrypted-password&gt;:&lt;comment&gt;
scott:myencryptedpassword:Scott Anderson</pre>
<p>Obviously you need to replace the username with your username, and the password with an appropriately encrypted value.&#160; If you have Ruby installed, this is easy, just launch <strong>irb</strong> and type the following command:</p>
<pre class="brush: plain;">&quot;password&quot;.crypt(&quot;salt&quot;)</pre>
<p>Copy the encrypted value into the file and you’re all set.</p>
<h4>Step 8:&#160; Modify your Nginx configuration</h4>
<p>There are about 100 ways to setup websites in Nginx, so I’ll assume you know where to place server sections.&#160; If you followed my previous tutorial, this will be in a file something like <strong>/usr/local/nginx/sites-enabled/geeksharp.com</strong>.&#160; The block should look something like this:</p>
<pre class="brush: plain;">server {
    listen 80;
    server_name dev.geeksharp.com;
    root /var/hg/;
    gzip on;

    location / {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9003;
        fastcgi_param DOCUMENT_ROOT /var/hg/;
        fastcgi_param QUERY_STRING $query_string;
        fastcgi_param REQUEST_METHOD $request_method;
        fastcgi_param CONTENT_TYPE $content_type;
        fastcgi_param CONTENT_LENGTH $content_length;
        fastcgi_param SCRIPT_FILENAME /opt/hg-fastcgi/hgwebdir.fcgi;
        auth_basic 'geek# Source Control';
        auth_basic_user_file /var/hg/hgusers.config;
    }
}</pre>
<p>That’s it!&#160; You can edit all these miscellaneous files to suit your needs.&#160; If you did everything correctly, all you need to do is start the <strong>fcgi-hg</strong> script and then restart nginx.&#160; When you want to create a new repository, you should create it in <strong>/var/hg</strong> like so:</p>
<pre class="brush: plain;">hg init /var/hg/project</pre>
<p>Once you get everything running and you create a few repositories, you should see something like this:</p>
<p><a href="http://geeksharp.com/wp-content/uploads/2010/01/mercrepos.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="merc-repos" border="0" alt="merc-repos" src="http://geeksharp.com/wp-content/uploads/2010/01/mercrepos_thumb.png" width="636" height="294" /></a> </p>
<p>Hope this helps someone out there.&#160; If you have questions, or something doesn’t work, let me know and I try and help you out.&#160; Good luck! <img src='http://geeksharp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://geeksharp.com/2010/01/20/mercurial-web-with-fastcgi-nginx/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
