Running cgit on Gentoo

cgit, a web interface for git repositories, allows you to easily share your projects' source code over a web interface. It's running on my desktop right now, so you can see for yourself what it looks like. On Gentoo, the ebuild for this software can be found as www-apps/cgit. However, after installation, a number of configuration steps should be performed to make it accessible on $HOSTNAME/git, and index your repositories. This post will guide you through the steps I took.

Filesystem layout

In my setup, my (bare) git repositories reside in $HOME/.local/git. But, some of the repositories should not be public, such as the pass store. So, a different directory for cgit to look in exists, at $HOME/.local/srv/cgit. This directory contains symlinks to the actual repositories I want publicly available.

Installing the required software

For this to work, there is more than just cgit to install. There are a number of ways to set this up, but I chose for Nginx as web server, and uwsgi as the handler for the fastcgi requests.

emerge dev-python/pygments www-apps/cgit www-servers/nginx www-servers/uwsgi

Configuring all elements

After installation, each of these packages needs to be configured.

cgit

The configuration file for cgit resides in /etc/cgitrc. After removing all the comments, the contents of my /etc/cgitrc can be found below.

# Fixes for running cgit in a subdirectory
css=/git/cgit.css
logo=/git/cgit.png
virtual-root=/git
remove-suffix=1

# Customization
root-desc=All public repos from tyil
enable-index-owner=0
cache-size=1000
snapshots=tar.gz tar.bz2
clone-prefix=https://home.tyil.nl/git
robots=index, follow

readme=master:README.md
readme=master:README.pod6

# Add filters before repos (or filters won't work)
about-filter=/usr/lib64/cgit/filters/about-formatting.sh
source-filter=/usr/lib64/cgit/filters/syntax-highlighting.py

# Scan paths for repos
scan-path=/home/tyil/.local/srv/cgit

You should probably update the values of root-desc, clone-prefix and scan-path. The first describes the small line of text at the top of the web interface. clone-prefix is the prefix URL used for git clone URLs. The scan-path is the directory cgit will look for repositories in.

Additionally, the readme=master:README.pod6 only positively affects your setup if you also use my Raku customizations, outlined in the next section.

For more information on the available settings and their impact, consult man cgitrc.

Raku customizations

Since I love working with Raku, I made some changes and a couple modules to get README.pod6 files rendered on the about tab on projects. You should ensure the cgit user can run raku and has the Pod::To::Anything and Pod::To::HTML::Section modules installed (including any dependencies). How to achieve this depends on how you installed Raku. Feel free to send me an email if you need help on this part!

Once this works, however, the remaining step is quite simple. The about-filter configuration item in /etc/cgitrc points to a small shell script that invokes the required program to convert a document to HTML. In my case, this file is at /usr/lib64/cgit/filters/about-formatting.sh. Open up this file in your favorite $EDITOR and add another entry to the case for Pod6 to call Raku.

case "$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')" in
   *.markdown|*.mdown|*.md|*.mkd) exec ./md2html; ;;
   *.pod6) exec raku --doc=HTML::Section; ;;
   *.rst) exec ./rst2html; ;;
   *.[1-9]) exec ./man2html; ;;
   *.htm|*.html) exec cat; ;;
   *.txt|*) exec ./txt2html; ;;
esac

Highlighting style

The syntax-highlighting.py filter carries the responsibility to get your code highlighted. This uses the Python library pygments, which comes with a number of styles. cgit uses Pastie by default. To change this, open the Python script, and look for the HtmlFormatter, which contains a style='Pastie' bit. You can change Pastie for any other style name. These styles are available in my version (2.4.2):

  • default
  • emacs
  • friendly
  • colorful
  • autumn
  • murphy
  • manni
  • monokai
  • perldoc
  • pastie
  • borland
  • trac
  • native
  • fruity
  • bw
  • vim
  • vs
  • tango
  • rrt
  • xcode
  • igor
  • paraiso-light
  • paraiso-dark
  • lovelace
  • algol
  • algol_nu
  • arduino
  • rainbow_dash
  • abap
  • solarized-dark
  • solarized-light
  • sas
  • stata
  • stata-light
  • stata-dark

For those interested, I use the emacs theme.

uwsgi

Next up, uwsgi. This needs configuration, which on Gentoo exists in /etc/conf.d/uwsgi. However, this file itself shouldn't be altered. Instead, make a copy of it, and call it /etc/conf.d/uwsgi.cgit. The standard file exists solely as a base template. For brevity, I left out all the comments in the contents below.

UWSGI_SOCKET=
UWSGI_THREADS=0
UWSGI_PROGRAM=
UWSGI_XML_CONFIG=
UWSGI_PROCESSES=1
UWSGI_LOG_FILE=
UWSGI_CHROOT=
UWSGI_DIR=/home/tyil
UWSGI_PIDPATH_MODE=0750
UWSGI_USER=
UWSGI_GROUP=
UWSGI_EMPEROR_PATH=
UWSGI_EMPEROR_PIDPATH_MODE=0770
UWSGI_EMPEROR_GROUP=
UWSGI_EXTRA_OPTIONS="--ini /etc/uwsgi.d/cgit.ini"

That covers the service configuration file. When things don't work the way you expect, specify a path in UWSGI_LOG_FILE to see its logs. Additionally, you may want to alter the value of UWSGI_DIR. This specifies the working directory from which the process starts.

Now comes the application configuration, which will be read from /etc/uwsgi.d/cgit.ini, according to UWSGI_EXTRA_OPTIONS. Create that file with the following contents.

[uwsgi]
master = true
plugins = cgi
socket = 127.0.0.1:1234
uid = cgit
gid = cgit
procname-master = uwsgi cgit
processes = 1
threads = 2
cgi = /usr/share/webapps/cgit/1.2.1/hostroot/cgi-bin/cgit.cgi

Note that the cgi value contains the version number of www-apps/cgit. You may need to come back after an upgrade and update it accordingly.

As last step for uwsgi configuration, a service script, to manage it with rc-service. These scripts all exist in /etc/conf.d, and the package installed a script called uwsgi in there. Just like with the conf.d variant, its just a template. This time, however, don't make a copy of it, but a symlink. It does not need to be edited, but the name must be the same as the conf.d entry name. That would be uwsgi.cgit.

cd /etc/conf.d
ln -s uwsgi uwsgi.cgit

Now you can start the service with rc-service uwsgi.cgit start. If a consequent status notes the state as Started, you're all good. If the state says Crashed, you should go back and double-check all configuration files. When those are correct and you can't figure out why, feel free to reach out to me via email.

rc-service uwsgi.cgit start
rc-service uwsgi.cgit service

# Start this after boot
rc-update add uwsgi.cgit

nginx

The final element to make it accessible, the web server, nginx. How you organize the configuration files here is largely up to you. Explaining how to set up nginx from scratch is beyond the scope of this post. Assuming you know how to configure this, add the following location blocks to the server definition for the vhost you want to make cgit available on.

location "/git" {
   alias /usr/share/webapps/cgit/1.2.1/htdocs;
   try_files $uri @cgit;
}

location @cgit {
   include uwsgi_params;

   gzip off;

   uwsgi_modifier1 9;
   uwsgi_pass 127.0.0.1:1234;

   fastcgi_split_path_info ^(/git/?)(.+)$;
   uwsgi_param PATH_INFO $fastcgi_path_info;
}

Once saved, you can reload nginx, and the $HOSTNAME/git endpoint can be reached, and should display an cgit page, detailing there are no repositories. That can be easily solved by making some available in $HOME/.local/srv/cgit, through the power of symlinks.

Symlinking the repositories

Go nuts with making symlinks to the various repositories you have gathered over the years. You don't need to use bare repositories, cgit will also handle regular repositories that you actively work in. As with the nginx configuration, explaining how to make symlinks is out of scope. In dire situations, consult man ln.

git-mkbare

While making the symlinks is easy, I found that it sheepishly boring to do. I go to $HOME/.local/git, make a directory, cd to it, and create a bare repository. Then off to $HOME/.local/srv/cgit to make a symlink back to the newly created bare repository. I think you can see this will get tedious very quickly.

So, to combat this, I made a small shell script to do all of that for me. I called it git-mkbare, and put it somewhere in my $PATH. This allows me to call it as git mkbare repo-name. It will ask for a small description as well, so I that can also be skipped as a manual task. This script may be of use to you if you want to more quickly start a new project.

You can find this script in my dotfiles repository.

Wrapping up

Now you should have cgit available from your site, allowing you to share the sources of all your projects easily with the world. No need to make use of a (proprietary) third-party service!

If you have questions or comments on my setup, or the post in general, please contact me through email or irc.