Erlang databases:
Erlang web servers and frameworks:
Erlang databases:
Erlang web servers and frameworks:
If you’re managing multiple mercurial repositories, it’s nice to see them all in one place, using a simple web-based repository browser. There’s various ways to publish mercurial repositories, but hgwebdir
is the only method that supports multiple repos. Since I prefer fastcgi and nginx, I decided to use hgwebdir.fcgi
, which unfortunately isn’t documented on the mercurial wiki.
hgweb.config
Let’s start by creating hgweb.config
, which tells hgwebdir
where the repos are and what the web UI should look like.
[paths] /REPO1NAME = /PATH/TO/REPO1 /REPO2NAME = /PATH/TO/REPO2 [web] base = style = monoblue
There’s a few different included themes you can choose from, I like the monoblue
style. The empty base=
line is apparently required to make everything work.
hgwebdir.fcgi
Next, make a copy of hgwebdir.fcgi
, which in Ubuntu can be found in /usr/share/doc/mercurial/examples
. Below is a simplified version with all comments removed. The one line you may want to change is the path to hgweb.config
on the server, but I’ll assume you’ll want it in /etc/mercurial
.
from mercurial import demandimport; demandimport.enable() from mercurial.hgweb.hgwebdir_mod import hgwebdir from mercurial.hgweb.request import wsgiapplication from flup.server.fcgi import WSGIServer def make_web_app(): return hgwebdir("/etc/mercurial/hgweb.config") WSGIServer(wsgiapplication(make_web_app)).run()
hg_server.conf
This is a simple nginx fastcgi config you can modify for your own purposes. It forwards all requests for hg.DOMAIN.COM
to the hgwebdir.fcgi
socket we’ll be starting below.
server { listen 80; server_name hg; server_name hg.DOMAIN.COM; access_log /var/log/hg_access.log; error_log /var/log/hg_error.log; location / { fastcgi_pass unix:/var/run/hgwebdir.sock; fastcgi_param PATH_INFO $fastcgi_script_name; 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 SERVER_PROTOCOL $server_protocol; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; } }
The hg_server.conf
file will need a link from /etc/nginx/sites-enabled
to its location in /etc/nginx/sites-available
, assuming that you’re using the default nginx config which includes every server conf found in /etc/nginx/sites-available
.
fab hgweb restart_nginx
To make deployment easy, I use fab, so that if I make any changes to hgweb.config
or hg_server.conf
, I can simply run fab hgweb restart_nginx
. For starting hgwebdir.fcgi
, we can use spawn-fcgi
, which usually comes with lighttpd, so you’ll need that installed too.
hgweb
copies hgweb.config
and hgwebdir.fcgi
to appropriate locations on the server, then starts the fastcgi process with a socket at /var/run/hgwebdir.sock
.
restart_nginx
copies hg_server.conf
to the server and tells nginx to reload its config.
def hgweb(): env.runpath = '/var/run' put('hgweb.config', '/tmp') put('hgwebdir.fcgi', '/tmp') sudo('mv /tmp/hgwebdir.fcgi /usr/local/bin/') sudo('chmod +x /usr/local/bin/hgwebdir.fcgi') sudo('mv /tmp/hgweb.config /etc/mercurial/hgweb.config') sudo('kill `cat %s/hgwebdir.pid`' % env.runpath) sudo('spawn-fcgi -f /usr/local/bin/hgwebdir.fcgi -s %s/hgwebdir.sock -P %s/hgwebdir.pid' % (env.runpath, env.runpath), user='www-data') def restart_nginx(): put('hg_server.conf', '/tmp/') sudo('mv /tmp/hg_server.conf /etc/nginx/sites-available/') sudo('killall -HUP nginx')
Once you’ve got these commands in your fabfile.py
, you can run fab hgweb restart_nginx
to deploy.
hgrc
Now that you’ve got hgwebdir.fcgi
running (you can make sure it works by going to http://hg.DOMAIN.COM), you’ll probably want to customize the info about each repo by editing .hg/hgrc
.
[web] description = All about my repo contacts = Me
And that’s it, you should now have a fast web-based browser for multiple repos 🙂
Writing web apps with Django can be a lot of fun, but deploying them can be a chore, even if you’re using Apache. Here’s a setup I’ve been using that makes deployment fast and easy. This all assumes you’ve got sudo
access on a remote server running Ubuntu or something similar.
This setup assumes you’ve got 2 mercurial repositories: 1 on your local machine, and 1 on the remote server you’re deploying to. In the remote repository, add the following to .hg/hgrc
[hooks]
changegroup = hg up
This makes mercurial run hg up
whenever you push new code. Then in your local repo’s .hg/hgrc, make sure the default path is to your remote repo. Here’s an example
[paths] default = ssh://user@domain.com/repo
Now when you run hg push
, you don’t need to include the path to the repo, and your code will be updated immediately.
Since I’m using nginx instead of Apache, we’ll be deploying Django with FastCGI. Here’s an example script you can use to start and restart your Django FastCGI server. Add this script to your mercurial repo as run_fcgi.sh
.
#!/bin/bash
PIDFILE="/tmp/django.pid"
SOCKET="/tmp/django.sock"
# kill current fcgi process if it exists
if [ -f $PIDFILE ]; then
kill `cat -- $PIDFILE`
rm -f -- $PIDFILE
fi
python manage.py runfcgi socket=$SOCKET pidfile=$PIDFILE method=prefork
Important note: the FastCGI socket file will need to be readable & writable by nginx worker processes, which run as the www-data user in Ubuntu. This will be handled by the fab restart
command below, or you could add chmod a+w $SOCKET
to the end of the above script.
Nginx is a great high performance web server with simple configuration. Here’s a simple example server config for proxying to your Django FastCGI process. Add this config to your mercurial repo as django.nginx
.
server {
listen 80;
# change to your FQDN
server_name YOUR.DOMAIN.COM;
location / {
# must be the same socket file as in the above fcgi script
fastcgi_pass unix:/tmp/django.sock;
}
}
On the remote server, make sure the following lines are in the http
section of /etc/nginx/nginx.conf
include /etc/nginx/sites-enabled/*;
# fastcgi_params should contain a lot of fastcgi_param variables
include /etc/nginx/fastcgi_params;
You must also make sure there is a link in /etc/nginx/sites-enabled
to your django.nginx
config. Don’t worry if django.nginx
doesn’t exist yet, it will once you run fab nginx
the first time.
you@remote.ubuntu$ cd /etc/nginx/sites-enabled
you@remote.ubuntu$ sudo ln -s ../sites-available/django.nginx django.nginx
Fab, or properly Fabric, is my favorite new tool. It’s designed specifically for making remote deployment simple and easy. You create a fabfile
where each function is a fab command that can run remote and sudo commands on one or more remote hosts. So let’s deploy Django using fab. Here’s an example fabfile
with 2 commands: restart
and nginx
. These commands should only be run after you’ve done a hg push
.
config.fab_hosts = ['YOUR.DOMAIN.COM'] config.projdir = '/PATH/TO/YOUR/REMOTE/HG/REPO' def restart(): sudo('cd %(projdir)s; run_fcgi.sh', user='www-data', fail='abort') def nginx(): sudo('cp %(projdir)s/django.nginx /etc/nginx/sites-available/', fail='abort') sudo('killall -HUP nginx', fail='abort')
You only need to run fab restart
if you’ve changed the actual Django python code. Changes to templates or static files don’t require a restart and will be used automatically (because of the hg up
changegroup hook). Executing run_fcgi.sh
as the www-data user ensures that nginx can read & write the socket.
If you’ve changed your nginx server config, you can run fab nginx
to install and reload the new server config without restarting the nginx server.
Now that everything is setup, the next time you want to deploy some new code, it’s as simple as hg push && fab restart
. And if you’ve only changed templates, all you need to do is hg push
. I hope this helps make your Django development life easier. It has certainly done so for me 🙂