13050
Comment: Link to SharedSSH
|
20885
|
Deletions are marked like this. | Additions are marked like this. |
Line 2: | Line 2: |
<<Include(A:style)>> <<Include(A:dated)>> <<Include(A:merge)>> |
|
Line 3: | Line 8: |
[[TableOfContents]] |
{{{#!wiki tip The multiple repository CGI server is now described [[PublishingRepositories#multiple|in the Publishing Repositories document]] together with other related information. However, this guide gives some additional useful details for publishing repositories. }}} |
Line 7: | Line 12: |
Well, we have a certain setup with subversion. I'd like to reproduce it using Mercurial. |
{{{#!wiki tip Starting with version 1.6 of Mercurial, the ''`hgwebdir.cgi`'' script has been unified with the hgweb.cgi script. Wherever ''`hgwebdir.cgi`'' is referred to in these directions, you can substitute the ''`hgweb.cgi`'' script instead. }}} This page explains how to make a bunch of repositories accessible through CGI using the {{{hgwebdir.cgi}}}-script and a webserver (apache, lighttpd or nginx). Once the script is set up, it is very easy to open new repositories. To quickly serve a single repository, please have a look at [[CGIinstall]]. <<TableOfContents>> |
Line 11: | Line 20: |
Line 13: | Line 21: |
* A webserver that can run CGI scripts such as apache2 (apache2, apache2-common, apache2-mpm-prefork, apache2-utils) or lighttpd | * A webserver that can run CGI scripts such as apache2 (apache2, apache2-common, apache2-mpm-prefork, apache2-utils), lighttpd or nginx (newer than 0.8.48) |
Line 15: | Line 24: |
* [[http://www.aprelium.com/abyssws/|The free version of Abyss Web Server works well under windows]] | |
Line 17: | Line 27: |
* Ubuntu/Edgy comes with python 2.4 * you will need the python2.4-dev package as well |
* Ubuntu/Edgy comes with python 2.4 * you will need the python2.4-dev package as well |
Line 23: | Line 33: |
The whole point was to try pull/push over http. So the following was done (I'm a real newbie for hg, so please bear with me :)): |
If you are on Linux, you probably want to install the Mercurial version packaged by your distribution. Like for RPM-based distributions: {{{ $ cd download-directory $ wget http://download.opensuse.org/repositories/devel:/tools:/scm/openSUSE_10.2/x86_64/mercurial-1.0-1.2.x86_64.rpm $ sudo rpm -ihv mercurial-1.0-1.2.x86_64.rpm }}} If you can only get a pre-1.0 version from your distribution, you should probably acquire another version somehow. One way would be to get the latest version from the stable branch: |
Line 28: | Line 44: |
$ hg clone http://selenic.com/hg/ $ cd hg |
$ hg clone http://selenic.com/repo/hg-stable/ $ cd hg-stable |
Line 33: | Line 49: |
This should work for every linux with python. But for rpm based systems it is better for administrative reasons to use it. You can find some via [BinaryPackages]. I got mine like this: {{{ $ cd download-directory $ wget http://repos.opensuse.org/devel:/tools:/scm/openSUSE_10.2/x86_64/mercurial-0.9.3-3.1.x86_64.rpm $ sudo rpm -ihv mercurial-0.9.3-3.1.x86_64.rpm }}} |
/!\ Be sure to check for later versions, these filenames and versions might be out of date. |
Line 44: | Line 52: |
["RHEL4HgWebDirSetup"] | [[RHEL4HgWebDirSetup]] == OpenBSD 4.6 Specific Instructions for chrooted Apache 1.3.29 == OpenBsdWebDirSetup |
Line 47: | Line 58: |
Line 50: | Line 60: |
At least one installer for 0.9.5 uses Python 2.4. (I can't verify all of them.) If you do wish to use Python 2.5, you must build your own Mercurial WindowsInstall. The first line of `hgwebdir.cgi` must point to your Python executeable. Ex: {{{ |
At least one installer for 0.9.5 uses Python 2.4. (I can't verify all of them.) The pre-compiled Windows binaries for Mercurial 1.0.x, 1.1.x, 1.2.x and 1.3.x were compiled with Python 2.5. If you do wish to use Python 2.6, you must build your own Mercurial WindowsInstall. The first line of `hgwebdir.cgi` must point to your Python executable. Ex: {{{#!python |
Line 56: | Line 70: |
}}} | # # An example CGI script to export multiple hgweb repos, edit as necessary ... }}} Some users report for the Mercurial 1.1 installation, Python needs to have the pywin32 package installed. It can be downloaded from: http://sourceforge.net/project/platformdownload.php?group_id=78018 If this package is not installed you will see an error like: "!ImportError: No module named pywintypes". (I didn't need it for Python 1.1.1 though...) |
Line 59: | Line 77: |
Line 62: | Line 79: |
Unzip `library.zip` (located in `MERCURIAL_HOME`) to a path of your choosing. (e.g. `MERCURIAL_HOME\lib`; for example: `c:\dev\Mercurial\lib`.) | Unzip `MERCURIAL_HOME\library.zip` to a path of your choosing. (e.g. `MERCURIAL_HOME\lib`; for example: `c:\dev\Mercurial\lib`.). Winzip and this file may not play nice together so try using a command line unzip utility like: http://stahlforce.com/dev/index.php?tool=zipunzip |
Line 65: | Line 82: |
{{{ | {{{#!python |
Line 70: | Line 88: |
Line 73: | Line 90: |
If you continue to see import errors even after adjusting `sys.path`, you may need to turn on Python's optimize mode so it can import `.pyo` files. You can do this by enabling mod_env and using the following setting in Apache: {{{ SetEnv PYTHONOPTIMIZE x }}} |
|
Line 74: | Line 97: |
Line 79: | Line 101: |
Move the `Templates` folder from my `MERCURAIL_HOME\Templates` to `MERCURIAL_HOME\lib\Templates`. | Move the `Templates` folder from my `MERCURIAL_HOME\Templates` to `MERCURIAL_HOME\lib\Templates`. |
Line 82: | Line 104: |
Line 84: | Line 105: |
Line 89: | Line 111: |
Line 97: | Line 118: |
Line 100: | Line 120: |
I could not get `[collections]` to work properly with drive letters - using them on the left side causes no repositories to show up. But if your repositories are on the same drive as your CGI, you can do: | === Collections of Repositories === The advised way of specifying collection is now the [paths] section. This has been introduced in Mercurial 1.1 For old versions see the next section. ==== Current version ==== {{{ [paths] /trunk = /webdata/hg_repos/trunk/** }}} '''Warning''': Browsing the available repositories '''will be very slow''', as all the files and subdirectories are scanned every time. To avoid scanning more than one subdirectory, use one asterisk (*) instead of two (**). This causes all repositories under `c:/webdata/hg_repos/trunk` to show up (whereas a simple `*` does not look for nested ones). Multiple collections may be specified, however each must have a unique prefix (part before the =). The prefix name may be the root - just the '/'. This will search inside every directory of the repository, this might be extremely slow if executed on a repository containing a working directory. The advice here is to run [[http://mercurial.selenic.com/wiki/Update|`hg update null`]] on the served repository to avoid any superfluous recursive search. ==== Mercurial 1.0 ==== There is a bug with `[collections]` not working with Windows drive letters - Mercurial misinterprets the colon as a variable separator. See [[http://www.selenic.com/mercurial/bts/issue852|this bug tracker issue]] for details. This bug was fixed in Mercurial 1.1.x (see next section). Repository collections still work ''if'' they are on the same drive as your CGI though. Use: |
Line 104: | Line 141: |
\webdata\merc.repos = /webdata/merc.repos }}} The backslashes and forward slashes make a difference. This got all of my repositories to show up that were located in `c:/webdata/merc.repos`. See [http://www.selenic.com/mercurial/bts/issue852 this bug tracker issue] for details. ==== webdir.cgi Windows Bugs ==== '''Subdirecotries don't work in Collections''' Repositories one sub directory below your root cause a 404 Not Found error - the Windows backslash gets converted to a `%5C` in the URL and the script interprets this as a request to a location that doesn't exist. Example: URL `http://myserver/repos/hgwebdir.cgi/web%5Chtdocs/` causes a 404 Not Found. Manually changing the `%5C` to a forward slash causes Mercurial to report that no repository exists: "The specified repository "web" is unknown, sorry." 0.9.5 Update: The 404 error is still present. If you change the backslash to a foward slash the CGI doesn't know how to look into the proper repository. Instead it gives you an "Unknown Repository" type message. See [http://selenic.com/pipermail/mercurial/2007-December/016178.html this mailing list post] for more on the issue. |
\webdata\hg_repos\trunk = /webdata/hg_repos/trunk }}} The backslashes and forward slashes make a difference. This got all of my repositories to show up that were located in `c:/webdata/hg_repos/trunk`. (Repositories located in lower subdirectories will show up ''but'' won't work. You have to add another line for their subdirectories.) |
Line 124: | Line 148: |
Line 126: | Line 149: |
Line 130: | Line 154: |
It's usually a good idea to keep special directories out of the tree served by apache, but for security reasons on openSUSE the cgi scripts only work within the document root. So for openSUSE, which uses user/group wwwrun/www instead of www-data/www-data and does not allow write acces to cgi directories for anyone but the apache user it is |
It's usually a good idea to keep special directories out of the tree served by apache, but for security reasons on openSUSE the cgi scripts only work within the document root. So for openSUSE, which uses user/group wwwrun/www instead of www-data/www-data and does not allow write access to cgi directories for anyone but the apache user it is |
Line 137: | Line 161: |
Line 139: | Line 162: |
Line 148: | Line 170: |
Line 150: | Line 171: |
Line 153: | Line 175: |
To get a look like on http://hg.kublai.com/ with subdirectories? Just create subdirectories with hg repositories in it. To get a look of the toplevel like on kublai, add the following to hgweb.config: |
To get a look like on http://hg.kublai.com/ with subdirectories? Just create subdirectories with hg repositories in it. To get a look of the top level like on kublai, add the following to hgweb.config: |
Line 162: | Line 184: |
You can either use a separate webserver such as Apache or lighttpd, or use the webserver built into hg. === Using Apache or lighttpd with the hgwebdir.cgi script === |
You can either use a separate web server such as Apache, lighttpd or nginx, or use the web server built into hg. === Using Apache, lighttpd or nginx with the hgwebdir.cgi script === |
Line 167: | Line 188: |
Line 169: | Line 189: |
Line 171: | Line 192: |
$ sudo -u www-data chmod +x /var/hg/hgwebdir.cgi }}} |
$ sudo -u www-data chmod +x /var/hg/hgwebdir.cgi }}} |
Line 175: | Line 195: |
Line 177: | Line 198: |
$ sudo -u wwwrun chmod +x /srv/www/htdocs/hg/hgwebdir.cgi }}} ==== Configuring apache ==== Ok, now it's time for apache (see at the end of this paragraph for the openSUSE way of doing this). |
$ sudo -u wwwrun chmod +x /srv/www/htdocs/hg/hgwebdir.cgi }}} ==== Configuring apache for use with CGIs ==== Ok, now it's time for apache (see at the end of this paragraph for the openSUSE way of doing this). |
Line 185: | Line 204: |
Line 188: | Line 208: |
Line 190: | Line 209: |
{{{ ScriptAliasMatch ^/hg(.*) /var/hg/hgwebdir.cgi$1 |
{{{ ScriptAliasMatch ^/hg(.*) /var/hg/hgwebdir.cgi$1 |
Line 195: | Line 214: |
Line 199: | Line 217: |
Line 202: | Line 219: |
Now make it really available, by changing your favourite site in `/etc/apache2/sites-enabled`. For this experiment I used `/etc/apache2/sites-enabled/default`: |
Now make it really available, by changing your favorite site in `/etc/apache2/sites-available`. For this experiment I used `/etc/apache2/sites-available/default`: |
Line 209: | Line 226: |
Line 211: | Line 227: |
Line 215: | Line 232: |
Line 217: | Line 233: |
Line 221: | Line 238: |
Check if it works by directing your browser to `<yourhost>/hg/` For openSUSE, just put this in /etc/apache2/conf.d/hg.conf {{{ ScriptAliasMatch ^/hg(.*) /srv/www/htdocs/hg/hgwebdir.cgi$1 |
Check if it works by directing your browser to `<yourhost>/hg/`. For openSUSE, just put this in /etc/apache2/conf.d/hg.conf: {{{ ScriptAliasMatch ^/hg(.*) /srv/www/htdocs/hg/hgwebdir.cgi$1 |
Line 232: | Line 246: |
Line 236: | Line 249: |
Line 242: | Line 254: |
Line 245: | Line 256: |
==== Configuring Apache with mod_wsgi ==== Using mod_wsgi is recommended over using mod_python. It's one of the faster and more efficient ways of serving hgweb(dir). You can use the hgwebdir.wsgi script (it lives where other Mercurial scripts live, and works with Mercurial 1.0 and later), which references a hgwebdir.conf file in the CONFIG variable: {{{ from mercurial.hgweb.hgweb_mod import hgweb from mercurial.hgweb.hgwebdir_mod import hgwebdir CONFIG = '/var/hg/hgweb.config' application = hgwebdir(CONFIG) }}} This is really an ordinary Python module, but it uses a wsgi extension to make it clear what its use is. You then need to add this to your httpd.conf (or the vhost config): {{{ WSGIScriptAlias / /var/hg/script/hgwebdir.wsgi <Directory /var/hg/script> Order deny,allow Allow from all </Directory> }}} Here is an alternative configuration for a non rooted directory of the context path. {{{ WSGIScriptAliasMatch ^/hg(.*) /var/hg/script/hgwebdir.wsgi$1 <Directory /var/hg/script> Order deny,allow Allow from all </Directory> }}} Since you're allowing some permissions to the directory the .wsgi script is in, you probably don't want to put the script in a directory that also contains your repositories. NOTE: the default hgwebdir.wsgi uses 'hgweb.config' as configuration path. This may not be what you expect. If you find yourself with a working but empty installation, try to set this to the full path where your hgweb.config is situated NOTE: I had an issue in Mercurial 1.6.4 with the path where hgweb.wsgi can find the file hgweb.conf. They were in the same directory but this declaration didn't work config='hgweb.conf' but this with the full path worked config='/var/www/root_apache/hgweb.conf'. ==== Configuring apache with mod_python ==== You can also use mod_python, though mod_wsgi is probably better. Here are three howto's: http://www.selenic.com/pipermail/mercurial/2007-May/013222.html http://blog.slucas.fr/en/oss/hgweb-mod_python http://www.aventinesolutions.nl/mediawiki/index.php/Quick_Tip:_Getting_Started_with_Mercurial (on Fedora 6) |
|
Line 246: | Line 304: |
Ok, now it's time for lighttpd (no openSUSE specifics, because I dont use it). You can either update the existing /etc/lighttpd/lighttpd.conf file, or create /etc/lighttpd.conf/hg.conf and include that file from lighttpd.conf. |
Ok, now it's time for lighttpd (no openSUSE specifics, because I don't use it). You can either update the existing /etc/lighttpd/lighttpd.conf file, or create /etc/[[http://lighttpd.conf/hg.conf|lighttpd.conf/hg.conf]] and include that file from lighttpd.conf. |
Line 252: | Line 309: |
Line 256: | Line 314: |
Next, configure rewrite rules that map URLs to the hgwebdir.cgi script. With the following added to your config file, URLs starting with either hg or mercurial will map to hgwebdir.cgi: {{{ url.rewrite-once = ( |
Next, configure rewrite rules that map URLs to the hgwebdir.cgi script. With the following added to your config file, URLs starting with either hg or mercurial will map to hgwebdir.cgi: {{{ url.rewrite-once = ( |
Line 262: | Line 319: |
"^/mercurial([/?].*)?$" => "/hgwebdir.cgi$1" | "^/mercurial([/?].*)?$" => "/hgwebdir.cgi$1" |
Line 265: | Line 322: |
Line 267: | Line 323: |
Line 269: | Line 326: |
server.document-root = "/var/hg/" cgi.assign = ( ".cgi" => "/usr/bin/python" ) |
server.document-root = "/var/hg/" cgi.assign = ( ".cgi" => "/usr/bin/python" ) |
Line 273: | Line 330: |
Line 275: | Line 331: |
{{{ $ sudo lighttpd -t -f /etc/lighttpd/lighttpd.conf |
{{{ $ sudo lighttpd -t -f /etc/lighttpd/lighttpd.conf |
Line 279: | Line 336: |
Line 281: | Line 337: |
Line 284: | Line 341: |
Check if it works by directing your browser to `<yourhost>/hg/` or `<yourhost>/mercurial/` |
Check if it works by directing your browser to `<yourhost>/hg/` or `<yourhost>/mercurial/`. |
Line 288: | Line 344: |
To enable support for pushing to remote repositories, you are required to add an extra $HTTP check to your vhost. The command when pushing that requires authorization is 'unbunble', so what we do is check to see if it is within the URL: {{{ ... |
To enable support for pushing to remote repositories, you are required to add an extra $HTTP check to your vhost. The command when pushing that requires authorization is 'unbundle', so what we do is check to see if it is within the URL: {{{ |
Line 300: | Line 355: |
... }}} This example uses an Apache2 .htpasswd file, please read the Lighttpd documentation for examples of more such as digest. |
}}} This example uses an Apache2 .htpasswd file. You can add the following variables to your lighttpd.conf: {{{ auth.backend = "htpasswd" # auth method auth.backend.htpasswd.userfile = "/path/to/file" # passwd file. Syntax: USERNAME:ENCRYPTED_PASS }}} An easy way to create this file: {{{ htpasswd -c /path/to/file USERNAME }}} You will be prompted for password input. Be sure to add mod_auth to the lighttpd modules: {{{ server.modules += ( "mod_auth" ) }}} === Configuring nginx === Here is a configuration for nginx (newer than 0.8.48, in older versions there was a bug where fastcgi_pass was not inherited inside the limit_except block) which uses fastcgi to talk to the hgwebdir. nginx does not spawn hgwebdir by itself, so you have to take care of that yourself (with for example spawn-fcgi). Once you have done that, you can use something similar to the following configuration. It assumes that you have Mercurial installed in /srv/mercurial/ for static files, probably this is not true for your installation. {{{ server { listen 80 default; server_name example.com; root /srv/www; location / { return 403; } location /hg/ { fastcgi_pass 127.0.0.1:9000; include fastcgi_hg; fastcgi_intercept_errors off; limit_except GET HEAD { auth_basic 'Example'; auth_basic_user_file /srv/hg.htpasswd; } } location /hg/static/ { rewrite /hg/static/(.*) /$1 break; root /srv/mercurial/mercurial/templates/static; expires 30d; } location ~ /\. { deny all; } } }}} This configuration is using TCP on port 9000 to talk to the fastcgi daemon. It requires authentication (for push). And it servers static files directly. fastcgi_hg file is as follows: {{{ include fastcgi_params; fastcgi_split_path_info ^(/hg)(.*)$; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param AUTH_USER $remote_user; fastcgi_param REMOTE_USER $remote_user; }}} You probably need Mercurial with [[http://selenic.com/hg/rev/e5d3c7083d91|this changeset]] to use it with nginx properly. |
Line 306: | Line 431: |
Line 308: | Line 432: |
Line 314: | Line 439: |
Line 318: | Line 442: |
Line 322: | Line 445: |
Line 326: | Line 448: |
Line 328: | Line 449: |
Line 330: | Line 450: |
Line 337: | Line 458: |
Line 339: | Line 459: |
Line 343: | Line 462: |
Line 347: | Line 467: |
Line 349: | Line 468: |
Line 353: | Line 473: |
Line 357: | Line 476: |
Line 359: | Line 477: |
Line 363: | Line 482: |
Line 365: | Line 483: |
Line 369: | Line 486: |
Line 373: | Line 491: |
Line 375: | Line 492: |
Line 377: | Line 493: |
{{{ [web] style = gitweb # looks cleaner from my point of # view :) allow_archive = gz zip bz2 # If you think people should be able # to download snapshots as .tar.gz, # .zip, .tar.bz2 respectively }}} == Disclaimer == Well, it works (worked) for me. Please do not hesitate to update this page to include small bits I've forgotten or just plainly am not aware of. |
{{{ [web] # enable snapshot downloads allow_archive = gz zip bz2 }}} === Change the URL using baseurl and URL rewriting === For example, we might not want the hgwebdir.fcgi in our URLs if we have a dedicated or virtual host for our repositories. In the hgweb.config, add the following: {{{ [web] baseurl = / }}} hgwebdir will now write all links as `/x/y` instead of `/hgwebdir.fcgi/x/y`. Now we only need a rewrite rule. For Lighttpd, add (if hgwebdir.fcgi resides in the server's document root): {{{ url.rewrite-once = ("^(/hgwebdir.fcgi/.*)$" => "$1", "^(/.*)$" => "/hgwebdir.fcgi$1" ) }}} For apache, add this to your .htaccess file. This example is based on hgwebdir.fcgi residing on your server as such "hg.example.com/cgi-bin/hgwebdir.fcgi" {{{ # Taken from http://www.pmwiki.org/wiki/Cookbook/CleanUrls#samedir # Used at http://ggap.sf.net/hg/ Options +ExecCGI RewriteEngine On #write base depending on where the base url lives RewriteBase /cgi-bin RewriteRule ^$ hgwebdir.fcgi [L] # Send requests for files that exist to those files. RewriteCond %{REQUEST_FILENAME} !-f # Send requests for directories that exist to those directories. RewriteCond %{REQUEST_FILENAME} !-d # Send requests to hgwebdir.cgi, appending the rest of url. RewriteRule (.*) /cgi-bin/hgwebdir.fcgi/$1 [QSA,L] }}} == See also == * PublishingRepositories * [[SharedSSH]] |
Line 392: | Line 533: |
See also [:SharedSSH]. |
This page does not meet our wiki style guidelines. Please help improve this page by cleaning up its formatting. |
Note:
This page appears to contain material that is no longer relevant. Please help improve this page by updating its content.
This page's contents belong elsewhere. Please help improve this wiki by reorganizing this content. |
Publishing Repositories with hgwebdir.cgi
The multiple repository CGI server is now described in the Publishing Repositories document together with other related information. However, this guide gives some additional useful details for publishing repositories.
1. Introduction
Starting with version 1.6 of Mercurial, the hgwebdir.cgi script has been unified with the hgweb.cgi script. Wherever hgwebdir.cgi is referred to in these directions, you can substitute the hgweb.cgi script instead.
This page explains how to make a bunch of repositories accessible through CGI using the hgwebdir.cgi-script and a webserver (apache, lighttpd or nginx). Once the script is set up, it is very easy to open new repositories. To quickly serve a single repository, please have a look at CGIinstall.
Contents
2. Pre-requisites
The installed software is:
- A webserver that can run CGI scripts such as apache2 (apache2, apache2-common, apache2-mpm-prefork, apache2-utils), lighttpd or nginx (newer than 0.8.48)
- But it is not necessary (see below)
The free version of Abyss Web Server works well under windows
- some version of mercurial (mine was 0.9 taken from Debian/unstable)
- Python:
- Ubuntu/Edgy comes with python 2.4
- you will need the python2.4-dev package as well
- sudo (in general, I prefer sudo to su)
hgwebdir.cgi (use the one coming with your Mercurial package or download from http://www.selenic.com/repo/hg-stable/raw-file/tip/hgwebdir.cgi)
3. Getting proper Mercurial
If you are on Linux, you probably want to install the Mercurial version packaged by your distribution. Like for RPM-based distributions:
$ cd download-directory $ wget http://download.opensuse.org/repositories/devel:/tools:/scm/openSUSE_10.2/x86_64/mercurial-1.0-1.2.x86_64.rpm $ sudo rpm -ihv mercurial-1.0-1.2.x86_64.rpm
If you can only get a pre-1.0 version from your distribution, you should probably acquire another version somehow. One way would be to get the latest version from the stable branch:
$ cd working-directory $ hg clone http://selenic.com/repo/hg-stable/ $ cd hg-stable $ python setup.py build $ sudo python setup.py install
Be sure to check for later versions, these filenames and versions might be out of date.
4. RHEL4 Specific Instructions
5. OpenBSD 4.6 Specific Instructions for chrooted Apache 1.3.29
6. Windows Specific Instructions
On Windows, your Python version must match the version used to compile Mercurial. Otherwise, you'll get "Invalid Magic Number" errors when trying to run the CGI.
At least one installer for 0.9.5 uses Python 2.4. (I can't verify all of them.)
The pre-compiled Windows binaries for Mercurial 1.0.x, 1.1.x, 1.2.x and 1.3.x were compiled with Python 2.5.
If you do wish to use Python 2.6, you must build your own Mercurial WindowsInstall.
The first line of hgwebdir.cgi must point to your Python executable. Ex:
Some users report for the Mercurial 1.1 installation, Python needs to have the pywin32 package installed. It can be downloaded from: http://sourceforge.net/project/platformdownload.php?group_id=78018 If this package is not installed you will see an error like: "ImportError: No module named pywintypes". (I didn't need it for Python 1.1.1 though...)
6.1. Mercurial Lib Files
Install the Mercurial libraries. The Windows binary puts a .zip file of the libraries in your Mercurial install directory, which I refer to as MERCURIAL_HOME.
Unzip MERCURIAL_HOME\library.zip to a path of your choosing. (e.g. MERCURIAL_HOME\lib; for example: c:\dev\Mercurial\lib.). Winzip and this file may not play nice together so try using a command line unzip utility like: http://stahlforce.com/dev/index.php?tool=zipunzip
Specify the location of the library files in hgwebdir.cgi
If you compiled your own version of Mercurial, you do not need the sys.path.insert line.
If you continue to see import errors even after adjusting sys.path, you may need to turn on Python's optimize mode so it can import .pyo files. You can do this by enabling mod_env and using the following setting in Apache:
SetEnv PYTHONOPTIMIZE x
6.2. Adjust Template Files
The CGI assumes templates are located inside of the lib directory you just created.
(Although you're supposed to be able to specify templates = c:/dev/Mercurial/lib in Mercurial.ini or hgweb.config, neither option worked for me.)
Move the Templates folder from my MERCURIAL_HOME\Templates to MERCURIAL_HOME\lib\Templates.
6.3. Other Gotchas
The path to your Mercurial repositories cannot also contain the name to the path to the Mercurial CGI. Maybe this is just my weird Apache setup, but when my hgwebdir.cgi was installed in c:/webdata/repos, this hgweb.config failed for me:
[paths] repo1 = c:/webdata/repos.merc/images repo2 = c:/webdata/repos.merc/web/htdocs/
and instead I had to change my directory names to
[paths] repo1 = c:/webdata/merc.repos/images repo2 = c:/webdata/merc.repos/web/htdocs/
I don't know if this is a Mercurial/Python issue or an Apache issue. Either way, hopefully this saves you some time.
6.4. Collections of Repositories
The advised way of specifying collection is now the [paths] section. This has been introduced in Mercurial 1.1 For old versions see the next section.
6.4.1. Current version
[paths] /trunk = /webdata/hg_repos/trunk/**
Warning: Browsing the available repositories will be very slow, as all the files and subdirectories are scanned every time. To avoid scanning more than one subdirectory, use one asterisk (*) instead of two (**).
This causes all repositories under c:/webdata/hg_repos/trunk to show up (whereas a simple * does not look for nested ones). Multiple collections may be specified, however each must have a unique prefix (part before the =). The prefix name may be the root - just the '/'.
This will search inside every directory of the repository, this might be extremely slow if executed on a repository containing a working directory. The advice here is to run `hg update null` on the served repository to avoid any superfluous recursive search.
6.4.2. Mercurial 1.0
There is a bug with [collections] not working with Windows drive letters - Mercurial misinterprets the colon as a variable separator. See this bug tracker issue for details. This bug was fixed in Mercurial 1.1.x (see next section).
Repository collections still work if they are on the same drive as your CGI though. Use:
[collections] \webdata\hg_repos\trunk = /webdata/hg_repos/trunk
The backslashes and forward slashes make a difference.
This got all of my repositories to show up that were located in c:/webdata/hg_repos/trunk. (Repositories located in lower subdirectories will show up but won't work. You have to add another line for their subdirectories.)
7. Directory Structure
Create the necessary directories:
$ sudo mkdir -p /var/hg/repos $ sudo chown -R www-data:www-data /var/hg
It's usually a good idea to keep special directories out of the tree served by apache, but for security reasons on openSUSE the cgi scripts only work within the document root. So for openSUSE, which uses user/group wwwrun/www instead of www-data/www-data and does not allow write access to cgi directories for anyone but the apache user it is
$ sudo mkdir -p /srv/www/htdocs/hg/repos $ sudo chown -R wwwrun:www /srv/www/htdocs/hg/repos $ sudo chmod 755 /srv/www/htdocs/hg
8. Preparing the config
$ cat > /tmp/hgweb.config [collections] repos/ = repos/ ^D $ sudo -u www-data cp /tmp/hgweb.config /var/hg $ rm /tmp/hgweb.config
For openSUSE, replace the sudo line above with
$ sudo -u wwwrun cp /tmp/hgweb.config /srv/www/htdocs/hg
To get a look like on http://hg.kublai.com/ with subdirectories? Just create subdirectories with hg repositories in it. To get a look of the top level like on kublai, add the following to hgweb.config:
[web] style = gitweb
This also works in repository hgrc's, which are mentioned below.
9. Two possibilities
You can either use a separate web server such as Apache, lighttpd or nginx, or use the web server built into hg.
9.1. Using Apache, lighttpd or nginx with the hgwebdir.cgi script
9.1.1. Putting the right stuff in place
Put the script in place (remember, we are still in that working-directory/hg :)):
$ sudo -u www-data cp hgwebdir.cgi /var/hg $ sudo -u www-data chmod +x /var/hg/hgwebdir.cgi
And again, some changes for openSUSE
$ sudo -u wwwrun cp /usr/share/doc/packages/mercurial/hgwebdir.cgi /srv/www/htdocs/hg $ sudo -u wwwrun chmod +x /srv/www/htdocs/hg/hgwebdir.cgi
9.1.2. Configuring apache for use with CGIs
Ok, now it's time for apache (see at the end of this paragraph for the openSUSE way of doing this).
First of all, do not really change the config of apache directly:
$ sudo mkdir /etc/apache2/hg
Create the config with the following contents (e.g by using sudo vim /etc/apache2/hg/main.conf):
ScriptAliasMatch ^/hg(.*) /var/hg/hgwebdir.cgi$1 <Directory /var/hg> Options ExecCGI FollowSymLinks AllowOverride None </Directory>
This config says that we are going to serve our repositories through '<yourhost>/hg/'.
Now make it really available, by changing your favorite site in /etc/apache2/sites-available. For this experiment I used /etc/apache2/sites-available/default:
... Include /etc/apache2/hg/main.conf </VirtualHost>
Make sure that everything is OK:
$ sudo apache2ctl configtest Syntax is OK
Restart your web server:
$ sudo apache2ctl stop $ sudo apache2ctl start
Check if it works by directing your browser to <yourhost>/hg/.
For openSUSE, just put this in /etc/apache2/conf.d/hg.conf:
ScriptAliasMatch ^/hg(.*) /srv/www/htdocs/hg/hgwebdir.cgi$1 <Directory /srv/www/htdocs/hg> Options ExecCGI FollowSymLinks AllowOverride None </Directory>
and run
sudo rcapache2 reload
if this does not complain about config errors you should be done.
9.1.3. Configuring Apache with mod_wsgi
Using mod_wsgi is recommended over using mod_python. It's one of the faster and more efficient ways of serving hgweb(dir).
You can use the hgwebdir.wsgi script (it lives where other Mercurial scripts live, and works with Mercurial 1.0 and later), which references a hgwebdir.conf file in the CONFIG variable:
from mercurial.hgweb.hgweb_mod import hgweb from mercurial.hgweb.hgwebdir_mod import hgwebdir CONFIG = '/var/hg/hgweb.config' application = hgwebdir(CONFIG)
This is really an ordinary Python module, but it uses a wsgi extension to make it clear what its use is.
You then need to add this to your httpd.conf (or the vhost config):
WSGIScriptAlias / /var/hg/script/hgwebdir.wsgi <Directory /var/hg/script> Order deny,allow Allow from all </Directory>
Here is an alternative configuration for a non rooted directory of the context path.
WSGIScriptAliasMatch ^/hg(.*) /var/hg/script/hgwebdir.wsgi$1 <Directory /var/hg/script> Order deny,allow Allow from all </Directory>
Since you're allowing some permissions to the directory the .wsgi script is in, you probably don't want to put the script in a directory that also contains your repositories.
NOTE: the default hgwebdir.wsgi uses 'hgweb.config' as configuration path. This may not be what you expect. If you find yourself with a working but empty installation, try to set this to the full path where your hgweb.config is situated
NOTE: I had an issue in Mercurial 1.6.4 with the path where hgweb.wsgi can find the file hgweb.conf. They were in the same directory but this declaration didn't work config='hgweb.conf' but this with the full path worked config='/var/www/root_apache/hgweb.conf'.
9.1.4. Configuring apache with mod_python
You can also use mod_python, though mod_wsgi is probably better. Here are three howto's:
http://www.selenic.com/pipermail/mercurial/2007-May/013222.html
http://blog.slucas.fr/en/oss/hgweb-mod_python
http://www.aventinesolutions.nl/mediawiki/index.php/Quick_Tip:_Getting_Started_with_Mercurial (on Fedora 6)
9.1.5. Configuring lighttpd
Ok, now it's time for lighttpd (no openSUSE specifics, because I don't use it).
You can either update the existing /etc/lighttpd/lighttpd.conf file, or create /etc/lighttpd.conf/hg.conf and include that file from lighttpd.conf.
First, you need to check if mod_rewrite and mod_cgi are enabled in the config file, and add them to server.modules if they haven't already been added:
server.modules += ( "mod_cgi" ) server.modules += ( "mod_rewrite" )
Next, configure rewrite rules that map URLs to the hgwebdir.cgi script. With the following added to your config file, URLs starting with either hg or mercurial will map to hgwebdir.cgi:
url.rewrite-once = ( "^/hg([/?].*)?$" => "/hgwebdir.cgi$1", "^/mercurial([/?].*)?$" => "/hgwebdir.cgi$1" )
Then, configure a URL match that invokes hgwebdir.cgi:
$HTTP["url"] =~ "^/hgwebdir.cgi([/?].*)?$" { server.document-root = "/var/hg/" cgi.assign = ( ".cgi" => "/usr/bin/python" ) }
Make sure that everything is OK:
$ sudo lighttpd -t -f /etc/lighttpd/lighttpd.conf Syntax OK
Restart the web server:
$ sudo /etc/init.d/lighttpd restart
Check if it works by directing your browser to <yourhost>/hg/ or <yourhost>/mercurial/.
9.2. Configuring Lighttpd push support
To enable support for pushing to remote repositories, you are required to add an extra $HTTP check to your vhost. The command when pushing that requires authorization is 'unbundle', so what we do is check to see if it is within the URL:
$HTTP["querystring"] =~ "cmd=unbundle" { auth.require = ( "" => ( "method" => "basic", "realm" => "Mercuial Repo", "require" => "valid-user" ) ) }
This example uses an Apache2 .htpasswd file. You can add the following variables to your lighttpd.conf:
auth.backend = "htpasswd" # auth method auth.backend.htpasswd.userfile = "/path/to/file" # passwd file. Syntax: USERNAME:ENCRYPTED_PASS
An easy way to create this file:
htpasswd -c /path/to/file USERNAME
You will be prompted for password input.
Be sure to add mod_auth to the lighttpd modules:
server.modules += ( "mod_auth" )
9.3. Configuring nginx
Here is a configuration for nginx (newer than 0.8.48, in older versions there was a bug where fastcgi_pass was not inherited inside the limit_except block) which uses fastcgi to talk to the hgwebdir. nginx does not spawn hgwebdir by itself, so you have to take care of that yourself (with for example spawn-fcgi). Once you have done that, you can use something similar to the following configuration.
It assumes that you have Mercurial installed in /srv/mercurial/ for static files, probably this is not true for your installation.
server { listen 80 default; server_name example.com; root /srv/www; location / { return 403; } location /hg/ { fastcgi_pass 127.0.0.1:9000; include fastcgi_hg; fastcgi_intercept_errors off; limit_except GET HEAD { auth_basic 'Example'; auth_basic_user_file /srv/hg.htpasswd; } } location /hg/static/ { rewrite /hg/static/(.*) /$1 break; root /srv/mercurial/mercurial/templates/static; expires 30d; } location ~ /\. { deny all; } }
This configuration is using TCP on port 9000 to talk to the fastcgi daemon. It requires authentication (for push). And it servers static files directly.
fastcgi_hg file is as follows:
include fastcgi_params; fastcgi_split_path_info ^(/hg)(.*)$; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param AUTH_USER $remote_user; fastcgi_param REMOTE_USER $remote_user;
You probably need Mercurial with this changeset to use it with nginx properly.
9.4. Standalone
Simply run
sudo -u www-data hg serve --webdir-conf /var/hg/hgweb.config
and enjoy this speedy method of serving multiple repos. It should be faster than using Apache.
10. You are done
Hooray!
11. Final Bits
No openSUSE specifics here. You should know the differences by now (apache user and doc path).
11.1. Create a new repository
$ sudo -u www-data hg init /var/hg/repos/<repository-name>
11.2. Provide more information about it
Add the following to the /var/hg/repos/<repository-name>/.hg/hgrc file:
[web] contact = Bilbo Baggins # Whom to contact, plain text, # no fancy stuff description = My precious! # Nice description what this is about, # you can include HTML (like <a>)
11.3. Allow pushing to the repository
By default, nobody is allowed pushing.
To allow pushing to everybody, add the following line to the /var/hg/repos/<repository-name>/.hg/hgrc file:
[web] allow_push = *
To allow only selected users to push changes, add the following line to the /var/hg/repos/<repository-name>/.hg/hgrc file:
[web] allow_push = frodo, sam
These are virtual users (for instance, as defined using a .htpasswd file), and not real system users.
11.4. Deny pushing to the repository
Most likely you will want to use it together with allow_push = *. If you want allow pushing to everybody, but a selected list of people, add the following line to the /var/hg/repos/<repository-name>/.hg/hgrc file:
[web] deny_push = saruman
11.5. Allow pushing only over a non-secure channel
(I still need to check how it works )
By default, pushes are allowed only over https. If you are certain and do not want to enforce https for pushes, add the following line to the /var/hg/repos/<repository-name>/.hg/hgrc file:
[web] push_ssl = false
11.6. Customize the look
Add the following to the /var/hg/repos/<repository-name>/.hg/hgrc file:
[web] # enable snapshot downloads allow_archive = gz zip bz2
11.7. Change the URL using baseurl and URL rewriting
For example, we might not want the hgwebdir.fcgi in our URLs if we have a dedicated or virtual host for our repositories. In the hgweb.config, add the following:
[web] baseurl = /
hgwebdir will now write all links as /x/y instead of /hgwebdir.fcgi/x/y. Now we only need a rewrite rule. For Lighttpd, add (if hgwebdir.fcgi resides in the server's document root):
url.rewrite-once = ("^(/hgwebdir.fcgi/.*)$" => "$1", "^(/.*)$" => "/hgwebdir.fcgi$1" )
For apache, add this to your .htaccess file. This example is based on hgwebdir.fcgi residing on your server as such "hg.example.com/cgi-bin/hgwebdir.fcgi"
# Taken from http://www.pmwiki.org/wiki/Cookbook/CleanUrls#samedir # Used at http://ggap.sf.net/hg/ Options +ExecCGI RewriteEngine On #write base depending on where the base url lives RewriteBase /cgi-bin RewriteRule ^$ hgwebdir.fcgi [L] # Send requests for files that exist to those files. RewriteCond %{REQUEST_FILENAME} !-f # Send requests for directories that exist to those directories. RewriteCond %{REQUEST_FILENAME} !-d # Send requests to hgwebdir.cgi, appending the rest of url. RewriteRule (.*) /cgi-bin/hgwebdir.fcgi/$1 [QSA,L]