This script enables you to perform a syntax check on your cfengine configuration files in the pre commit phase of a subversion commit. The commit will be rejected by the hook if the syntax check fails. It was written for FreeBSD but should work on any other platform. The script assumes that your cfengine configs live under /config/cfengine in your repository.
#!/usr/local/bin/perl #Copyright (C) 2009, Tom Judge # ---------------------------------------------------------------------------- # "THE BEER-WARE LICENSE" (Revision 42): # <tom@tomjudge.com> wrote this file. As long as you retain this notice you # can do whatever you want with this stuff. If we meet some day, and you think # this stuff is worth it, you can buy me a beer in return Tom Judge. # ---------------------------------------------------------------------------- use strict; use warnings; my $REPOS = $ARGV[0]; my $TXN = $ARGV[1]; my $SVNLOOK ="/usr/local/bin/svnlook"; my $SVN = "/usr/local/bin/svn"; my $PATCH = "/usr/bin/patch"; my $CFAGENT = "/usr/local/sbin/cfagent"; my $CFSERVD = "/usr/local/sbin/cfservd"; my $DEBUG =1; my $exit_status=0; ### Setup a tempory working directory. $ENV{'TMPDIR'} = "/var/tmp"; my $WORKDIR = `/usr/bin/mktemp -d -t cfengine-svn-commit`; if ($? != 0) { print STDERR "Failed to make temp working dir.\n"; exit 1; } chomp $WORKDIR; print STDERR "Temp Working Dir: $WORKDIR\n\n"; ### ### Get the list of directories that have changed ### my @CHANGED_DIRS = `$SVNLOOK dirs-changed -t $TXN $REPOS`; if ($? != 0) { $exit_status = 1; print STDERR "Failed to get changed dirs\n"; goto cleanup; } my $cfengine_changed =0; foreach my $dir (@CHANGED_DIRS) { chomp $dir; print STDERR "Changed Dir: $dir\n"; if ($dir =~ m#^config/cfengine/inputs/#) { $cfengine_changed =1; } } print STDERR "\n"; ## Check if the config changed that we are insterested in ## If nothing changed jump to cleanup and delete the temp folder. goto cleanup if ($cfengine_changed ==0); ### ### Get the diff of the commit ### my @DIFF = `$SVNLOOK diff -t $TXN $REPOS > $WORKDIR/diff`; if ($? != 0) { $exit_status = 1; print STDERR "Failed to get diff\n"; goto cleanup; } ### ### Check out a working copy to run the tests on. ### print STDERR "Checking out working copy from $REPOS ...."; `$SVN co --quiet --ignore-externals file://$REPOS $WORKDIR/wc 1>&2`; if ($? != 0) { $exit_status = 1; print STDERR "Failed to get fresh working copy\n"; goto cleanup; } print STDERR "OK.\n\n"; ### ### Change cwd to working copy to apply patch. ### chdir "$WORKDIR/wc"; ### ### Apply the patch ### print STDERR "Applying commited changes to working copy....\n"; `patch -p0 < $WORKDIR/diff 1>/dev/null`; if ($? != 0) { $exit_status = 1; print STDERR "Failed to patch working copy\n"; goto cleanup; } print STDERR "Patched OK.\n\n"; ### ### Test the configuration for syntax errors ### $ENV{'CFINPUTS'} = "$WORKDIR/wc/config/cfengine/inputs"; $ENV{'HOME'} = "/home/system/svn"; print STDERR "Running Cfagent against new configuration....\n\n"; my @cfagent_output = `$CFAGENT --no-splay --verbose --parse-only 2>&1`; if ($? != 0) { foreach my $line (@cfagent_output) { print STDERR $line; } print STDERR "\n\n\n##### Syntax error in CFAgent Config\n\n\n\n"; print STDERR "#####\n"; print STDERR "#####\n"; print STDERR "#####\n"; print STDERR "##### YOUR COMMIT FAILED THE SANITY CHECK AND HAS BEEN REJECTED.\n"; print STDERR "#####\n"; print STDERR "##### THE OUTPUT OF THE CFENGINE RUN IS ABOVE THIS MESSAGE.\n"; print STDERR "#####\n"; print STDERR "#####\n"; print STDERR "#####\n"; $exit_status=1; goto cleanup; } print STDERR "Cfagent completed successfully\n\n"; print STDERR "Running Cfservd against new configuration....\n\n"; my @cfservd_output = `$CFSERVD --verbose --parse-only 1>&2`; if ($? != 0) { foreach my $line (@cfservd_output) { print STDERR $line; } print STDERR "\n\n\n##### Syntax error in CFServD Config\n\n\n\n"; print STDERR "#####\n"; print STDERR "#####\n"; print STDERR "#####\n"; print STDERR "##### YOUR COMMIT FAILED THE SANITY CHECK AND HAS BEEN REJECTED.\n"; print STDERR "#####\n"; print STDERR "##### THE OUTPUT OF THE CFENGINE RUN IS ABOVE THIS MESSAGE.\n"; print STDERR "#####\n"; print STDERR "#####\n"; print STDERR "#####\n"; $exit_status=1; goto cleanup; } cleanup: `/bin/rm -Rf $WORKDIR`; exit $exit_status;