You might know that the software behind gitorious.org is open source, and therefore it’s possible to set up gitorious on your own server for private use. I spent almost the whole Saturday on that and would like to share some information and pitfalls that I ran into.
Basic information can be found in upstream’s gitorious project wiki:
Gitorious Components is a must-read before the actual installation in order to understand how gitorious works.
Git Authentication is worth a glance unless you already know how gitosis authenticates its users.
There is also a guide available on how to install gitorious on Gentoo using some ebuilds from an overlay, but the gitorious ebuild in there has a few shortcomings (e.g. some hardcoded paths, passwordless login to mysql). Since I want to install gitorious by hand in order to understand how all the components work together, I decided to follow the guide at cjohansen.no, which performs the installation step-by-step.
The latter is an excellent read, so I won’t repeat the steps mentioned there. You can skip the prerequisites as the actual installation starts at “Get the Gitorious source code”. You can then skip another two paragraphs and continue with “Creating a home for Git repositories”. Since you then skipped the installation of ActiveMQ, you can just emerge stompserver and start that. Following (and adjusting e.g. paths) the rest of the guide is left as an exercise to the reader.
Just some pitfalls:
When you attempt to run the application (for testing purposes, in development mode) using the mongrel server, you usually get the following output:
$ script/server
=> Booting Mongrel
=> Rails 2.3.5 application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
This cries for a click on the URL to easily open gitorious in your browser. This, however, leads to some very weird behaviour when you want to log in: You enter your credentials, click “Log in”, and then you’re redirected to the index page, still being logged out. What happened here? It took me some time to find the answer: Gitorious uses the gitorious_host variable from $RAILS_ROOT/config/gitorious.yml (following the tutorial that’s “git.localhost”) to set the cookie domain when you log in. However, the browser will then just discard this cookie because it receives a cookie for “git.localhost” from 0.0.0.0. In other words: To perform a successful login, the host name you type into your browser’s address bar needs to match the value of gitorious_host.
Another pitfall: If you run the mongrel server in the production environment, the login action will redirect you to the SSL equivalent, running on port 443, meaning your browser won’t be able to find the server and spitting out “Server not found”. You can disable this by putting
SslRequirement.disable_ssl_check = true
in your config/environment/production.rb file.
And the last issue, that took me some hours to investigate: As soon as everything is running and you try to “git push”, you get “bash: gitorious: No such file or directory”. Why the hack is this? We symlinked the gitorious executable earlier:
$ sudo ln -s /var/www/git.myserver.com/gitorious/script/gitorious /usr/local/bin/gitorious
This obviously means that /usr/local/bin is not in $PATH by default on Gentoo. Let’s check this:
keytoaster@veda ~ $ sudo su - gitorious
gitorious@veda ~ $ echo $PATH
/usr/local/bin:/usr/bin:/bin:/opt/bin:/usr/x86_64-pc-linux-gnu/gcc-bin/4.4.3:/opt/blackdown-jdk-1.4.2.03/bin:/opt/blackdown-jdk-1.4.2.03/jre/bin:/usr/qt/3/bin:/usr/games/bin:/opt/vmware/server/console/bin
gitorious@veda ~ $
It’s there?! Oh wait, that’s a login shell, so /etc/profile and the likes are being processed. Let’s take a look at that:
if [ "$EUID" = "0" ] || [ "$USER" = "root" ] ; then
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${ROOTPATH}"
else
PATH="/usr/local/bin:/usr/bin:/bin:${PATH}"
fi
Yup, that’s clearly where it comes from. This suggests that when we try git push, it won’t be run as a login shell (obviously). So let’s see how $PATH looks like when we pass an empty environment and run a new bash:
gitorious@veda ~ $ env -i bash
gitorious@veda /var/gitorious/home $ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
gitorious@veda /var/gitorious/home $
Ahem, yeah. sbin stuff? That’s certainly surprising at first, but after some research, we find that that is the default value for $PATH unless it gets overwritten (by e.g. /etc/profile).
But hang on, /usr/local/bin is in there, too. So why isn’t it there when we git push? Probably the environment is modified when we log in via ssh. Let’s see:
keytoaster@veda ~ $ ssh test@localhost bash -i
Password:
bash: cannot set terminal process group (-1): Invalid argument
bash: no job control in this shell
test@veda ~ $ echo $PATH
/usr/bin:/bin:/usr/sbin:/sbin
echo $PATH
(I’ve used another unix account here, as gitorious is configured to use SSH keys.)
Yay, there we go, no /usr/local/bin in there. A look into the ssh man page reveals the following:
ENVIRONMENT
ssh will normally set the following environment variables:
PATH Set to the default PATH, as specified when compiling ssh.
So apparently the value of the default PATH when you log in via SSH without a login shell depends on what is was set to at compile time. Let’s confirm this by looking at configure of the openssh source code:
veda openssh-5.3p1 # ./configure --help | grep default-path
--with-default-path= Specify default \$PATH environment for server
veda openssh-5.3p1 #
Yup, that’s it. The default $PATH is set by the SSH server. This explains why the gitorious installation guide symlinks it to /usr/local/bin: /usr/local/bin is in the default path for SSH on whatever distro the author used. It’s just that Gentoo behaves different: The default –prefix for configure is /usr/local. As such, configure makes sure that /usr/local/bin is in the default $PATH in order to make scp work (see below). However, econf in Gentoo ebuilds pass –prefix=/usr. As /usr/bin is already in STDPATH (see /usr/include/paths.h), nothing else happens, no /usr/local stuff is involved. The code from configure.ac that handles this is as follows:
# Whether to mess with the default path
[...]
[ user_path=`cat conftest.stdpath` ],
[ user_path="/usr/bin:/bin:/usr/sbin:/sbin" ],
[ user_path="/usr/bin:/bin:/usr/sbin:/sbin" ]
)
# make sure $bindir is in USER_PATH so scp will work
t_bindir=`eval echo ${bindir}`
case $t_bindir in
NONE/*) t_bindir=`echo $t_bindir | sed "s~NONE~$prefix~"` ;;
esac
case $t_bindir in
NONE/*) t_bindir=`echo $t_bindir | sed "s~NONE~$ac_default_prefix~"` ;;
esac
echo $user_path | grep ":$t_bindir" > /dev/null 2>&1
if test $? -ne 0 ; then
echo $user_path | grep "^$t_bindir" > /dev/null 2>&1
if test $? -ne 0 ; then
user_path=$user_path:$t_bindir
AC_MSG_RESULT(Adding $t_bindir to USER_PATH so scp will work)
fi
fi
fi ]
)
The question is: Do we consider this a bug? I for one would expect that the default $PATH in an SSH environment is similar to the default $PATH set by /etc/profile. As such I would at least expect it to contain /usr/local/bin:/usr/bin:/bin.
Thanks go to Christian Ruppert for helping me.