Added wrapper for os.makedirs

I found myself making the same code over and over again: os.makedirs with
a try/except block around to catch if the leaf directory already exists.

This wrapper creates the directory if it doesn't exist, but doesn't throw
an exception if it already does exist. It does throw exceptions for everything
else, so you can still use try/except for other exceptions.

Also added a unittest for this code.
Make '.ssh' dir if it doesn't exist yet (fixes #342)
Enable post-receive multiplexer (refs #341)

There used to be only one post-receive script: the email script. But for
Trac Sync to work, we need to run two post-receive scripts. This is
difficult because the post-receive script read standard input, thus the
first script will deplete all the data before the second (etc.) script
had a change to run.

This changeset adds support to run multiple scripts. The API between
"submin2" and "submin2-admin . git admin" has changed. Instead of the
'post-receive-hook' command, there are now two commands called
'commit-email-hook' and 'trac-sync-hook'.

Instead of one post-receive-hook script, the new layout in the git
'hooks' directory will now be:

 [...]
 post-receive-hook -> [...]/hook-mux # the multiplexing script
 post-receive.d/                     # directory that contains hooks to run
 post-receive.d/001-commit-email.hook # exists iff commit emails are enabled
 post-receive.d/002-trac-sync.hook   # exists iff trac sync is enabled
 [...]

This hook-mux can be used for other hooks that receive data on stdin.

The diagnostics is not updated yet, so for the moment, this will give a
warning that new post-receive-hooks are not up to date (but the old ones
will be shown as up-to-date).
Don't follow symlinks when updating ownership (refs #341)

The previous changeset introduced a multiplexer with a symlink to the script.
This script should not be changed in any way, but the 'fix_perms' command did.
The code now checks if the file is a symlink, and if it is, skips it.
Update diagnostics for post-receive-hook (refs #341)

The diagnostics now checks if the symlink is correct and if there is a
post-commit-hook, if it is up-to-date.
Removed cruft
Initial support for trac/git sync hook (refs #341)

Unfortunately, we had to make a lot of changes, because the hook
is run as the git user, while the trac environment is write-only
for the web user. Both need write access, so this is not trivial.

There are several options to continue:
 * run trac as the same user as git/ssh (easy, but not secure)
 * run something setuid (not easy, and difficult to get secure,
   especially with scripts).
 * do something through sudo (not that ugly, but creates a dependency
   on sudo).
 * let the post-receive write something in the database, and connect to
   the webserver to trigger an action. You can either wait for that
   action, or shoot-and-forget. (this will add another layer of
   complexity, and points of failure)

I have chosen to implement the last option, since I thought it was the
least ugly one. Putting the data in the database in the mean time will
help with robustness, so I'm confident this will work smoothly.

The status is that commit messages are stored in the database, and they
are automatically synced, but the machine of the git user should be in the
IP ACL. If it is not in the IP ACL, it will simply dump the error page as
HTML on your git client output. This is not nice.
Allow 'False' in template

The handling of booleans was not symmetrical in the template module.
When a True boolean value was encountered, it would show up as a string
'True'. However, when this boolean value was False, this resulted in the
string value '' (instead of 'False').

This is now changed. Both 'True' as 'False' show up in the final string,
and the value None still results in '', as before.
Clearer error message when IP denied (refs #341)

Whenever someone pushes changesets, the information about these changesets
are temporarily saved in the database and a URL is retrieved so the web
user can update Trac.

This URL is protected to prevent abuse, so an IP-address has to be
configured. If this is not configured correctly, the git client will
receive an error message. This error message is now clearer.

Instead of letting the dispatcher take care of the exception that is
raised in this case, we only set the acl_required decorator on the
trac-sync handler so we can catch the exception and return an
XMLTemplateResponse instead. This is much less output, and allows the
other side to interpret this programmatically. That last part is not done
yet, but at least it is more readable than a backtrace.
New diagnostic: trac hook access (refs #341)

There is a new diagnostics, to check if submin has access to the sync hook.
This check will connect to submin (itself!) to see if the IP address has
access.

Because it will connect to itself, this check will not work for web servers
where there can only be one single connection simultaneously (our development
server for example!). In those cases, it will timeout.

A new hook is introduced for this, but I don't like this, so I'm going to
rewrite this.
Code cleanup (refs #341)

Instead of checking a separate 'test-acl' hook, we now check the hook
directly. This is possible because the XML now returns an 'inacl' attribute
if the IP address is in the ACL (so we can programmatically check if we are).

Also the internal REST API has changed; the order of directories is different.
Instead of /<vcs_type>/<repo>/<hook_type>, a request is now made by:
/<hook_type>/<vcs_type>/<repo>. This makes it possible to have different
parameters for each hook (I should've done this in the first place anyway).

There were other code cleanups as well.
Added check on trac-sync hook version (refs #341)

Besides checking for the trac-sync hook version, the versions for the
different post-receive hooks were split.

Also added diagnostics hint to update all repositorie hooks at once.
Improve diagnostics and trac-sync robustness (refs #341)

Trac sync uses a different default if 'acl_hook' is not set. It now uses not
only localhost IP-addresses, it also tries to resolve the hostname that
belongs to the vhost of submin and uses those IP-address. Since the default
of 'acl_hook' is unset, this should work for most people.

Diagnostics will check if the acl_hook is set, and will -warn- if it's not
set, but it will also check if trac-sync has access. If the variable is not
set, it will suggest the same setting as it will use by default. By
explicitly setting this to the IP-addresses means that there will be no DNS
lookups at every (git?) push.

Also changed diagnostics to give commands more emphasis. They now have their
own box, so it's clear what you need to copy past if you want to run commands.
Should have used variable here
Don't forget about the old style commit hook (refs #341)

During tests we found the old email commit hooks were lost during an
'submin2-admin ... git hook update [...]' operation. This was due to the
old hook not being recognised, so when the post-receive-mux was put into
place, the commit-email hook was not destroyed.

This fix will correctly show old-style hooks and preserve them on
upgrades.
More pythonic check on symlink (refs #341)
Pythonify and optimize

The usage of samefile will work better than readlink, because readlink
does not resolve chained symlinks, samefile does.

The extra continue's are to break off the checking if one instance of
outdated scripts are found
Call hook-mux like update script (refs #341)

The symlink to hook-mux didn't work in all cases, because the executable bit
was not always set. This is because setuptools does not enforce this (unless
your script should be moved to /bin or /usr/bin, which is not what we want).

To prevent problems, we now call the hook-mux script for post-receive like
the update script. This allows us to update the hook-mux script (or the update
script) by just installing a new version of submin, while at the same time
ensuring that it is always executable (submin controls permission bits in
the repository, but not in the install directory).

To debug all of this, diagnostics is now more verbose as to WHY hooks are
outdated.

Because similar code was needed in the post_receive_hook.py module, the
git hook code was refactored as well. Big code changes for such a small
change in functionality, but I think the code is a bit cleaner now.
Sigh. Fix interpreter (refs #341)

Of course a shell script should not be called with python, but with bash.
And this is why you should test (refs #341)

So, I forgot that the hook-mux script worked by checking how it was
linked to the hook-mux script and uses that as hook name. Of course
it doesn't work if you just call it.

I've changed the hook-mux script to accept an argument, which is
interpreted as the hook name (if no argument is found, it will try
to get it via the old way).

Then I found some .git extension inconsistensies (refs #296), and
worked around it for now (since we haven't decided yet what we're
going to do).