Paul Joseph Davis

Webby Post-Commit Hook for SVN
==============================

Just finished setting up a post-commit hook for subversion [1] and thought
I'd post it. Its fairly simple. It does emailing etc. when things break.

Basically, it just listens to svn commits and checks to see if it the specified
webby directory was modified, and if so clobber-builds the site and copies the
built version to your web root.

Its not very fantastic, but it appears to get the job done.

Download the script here [2]. I've also included it inline just incase I fail
to maintain my links properly.

    #! /usr/bin/env python

    import os
    import sys
    import subprocess as sp
    import traceback

    # Arguments for post-commit
    PATH = sys.argv[1]
    REV = sys.argv[2]

    # Email Setup
    SENDMAIL = "/usr/sbin/sendmail"
    RECIPIENTS = ["paul.joseph.davis@gmail.com"]
    FROM = "davisp@cavernum.net"

    # SVN Setup
    SVN = "/usr/bin/svn"
    SVNLOOK = "/usr/bin/svnlook"
    WATCH = "www/root"

    # Website Setup
    WEB_ROOT = "/var/www/davispj.com/public"

    # Webby Config
    WEBBY = "/var/lib/gems/1.8/bin/webby"
    WEBBY_ROOT = "/var/www/davispj.com/root"

    # System Utils
    COPY = "/bin/cp"

    class SPError(Exception):
        def __init__(self, command, returncode, stdout, stderr):
            self.command = command
            self.returncode = returncode
            self.stdout = stdout
            self.stderr = stderr
        def __str__(self):
            return repr(self)
        def __repr__(self):
            mesg = """
                COMMAND: %s
                RETURNCODE: %s
                STDOUT:
                %s
                STDERR:
                %s
            """
            mesg = '\n'.join([t.lstrip() for t in mesg.strip().split('\n')])
            return mesg % (self.command, self.returncode, self.stdout, self.stderr)

    def spcall(command, shell=False, input=None):
        pipe = sp.Popen(command, shell=shell, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE)
        (stdout, stderr) = pipe.communicate(input=input)
        if pipe.returncode != 0:
            if isinstance(command, list):
                command = ' '.join(command)
            raise SPError(command, pipe.returncode, stdout, stderr)
        return (stdout, stderr)

    def email(subj, mesg):
        fmt = """
            TO: %s
            FROM: %s
            SUBJECT: %s

            %s
        """
        fmt = '\n'.join([t.lstrip() for t in fmt.strip().split('\n')])
        content = fmt % (','.join(RECIPIENTS), FROM, subj, mesg)
        command = [SENDMAIL]
        command.extend(RECIPIENTS)
        spcall(command, input=content)

    def site_changed():
        (stdout, stderr) = spcall([SVNLOOK, "dirs-changed", PATH])
        for line in stdout.split('\n'):
            if line.startswith(WATCH):
                return True
        return False

    def main():
        try:
            if not site_changed():
                print "No change."
                exit(0)
            os.chdir(WEBBY_ROOT)
            spcall([SVN, 'up'])
            spcall([WEBBY, 'clobber'])
            spcall([WEBBY, 'build'])
            spcall(' '.join([COPY, '-r', os.path.join(WEBBY_ROOT, 'output', '*'), WEB_ROOT]), shell=True)
        except SPError, inst:
            email("Post-Commit Subprocess Failure", repr(inst))
        except:
            mesg = traceback.format_exc()
            email("Post-Commit Unknown Failure", mesg)

    if __name__ == '__main__':
        main()

References
----------

[1]:  http://subversion.tigris.org/
[2]:  http://www.davispj.com/git/?p=webby-svn-hooks.git


Copyright Notice
----------------

Copyright 2008-2010 Paul Joseph Davis

License
-------

http://creativecommons.org/licenses/by/3.0/