# /bin/sh # $Id$ # vim:et:ft=sh:sts=2:sw=2 # # Copyright 2010 Kate Ward. All Rights Reserved. # Author: kate.ward@forestent.com (Kate Ward) # # Continuous build script for shell library testing. # # Sample usages: # $ blah # treat unset variables as an error set -u # global constants setglobal ARGV0 = $[basename $0] setglobal ARGV0_DIR = $[dirname $0] setglobal SHLIB_DIR = ""$(ARGV0_DIR)/../lib"" # load libraries source ${SHFLAGS_LIB:-${SHLIB_DIR}/shflags} \ || shell {echo 'unable to load shflags library' > !2; exit 1} source ${VERSIONS_LIB:-${SHLIB_DIR}/versions} \ || shell {echo 'unable to load versions library' > !2; exit 1} setglobal OUTPUT_FILE = ""$(VERSIONS_OS_NAME)_$(VERSIONS_OS_RELEASE)"" # define flags DEFINE_string 'command' '' 'the command to start a build' 'c' DEFINE_string 'watch' '' 'file to watch for changes' 'w' DEFINE_string 'watch_from' '' 'file containing filenames to watch' 'W' DEFINE_string 'output' $(OUTPUT_FILE) 'output file to write to' 'o' DEFINE_string 'output_dir' '.' 'directory to write output file' 'O' DEFINE_integer 'pause' 60 'pause between successive runs (sec)' 'p' setglobal FLAGS_HELP = ""USAGE: $(ARGV0) [flags]"" #------------------------------------------------------------------------------ # functions # # This function exits the script, optionally printing a message # # Args: # message: string: an error message to be output (optional) # Output: # string: usable flags proc die { test $Argc -ne 0 && echo @Argv > !2 flags_help exit 1 } # Function to give the current date in ISO format # # Args: # none # Output: # string: isodate proc isodate { date -u '+%Y%m%dT%H%M%SZ' } proc age { setglobal awkScript = '''' match $(VERSIONS_OS_NAME) { with FreeBSD|Solaris setglobal awkScript = ''{print $6,$7,$8}'' with Linux setglobal awkScript = ''{print $6,$7}'' with * echo "unrecognized OS name ($(VERSIONS_OS_NAME))" > !2 } ls -l $1 |awk $(awkScript) } #------------------------------------------------------------------------------ # main # proc main { # checks test -n $(FLAGS_command) || die 'command required' test -z $(FLAGS_watch) -a -z $(FLAGS_watch_from) \ && die 'one of watch or watch_from required' test -n $(FLAGS_watch) -a -n $(FLAGS_watch_from) \ && die 'only one of watch or watch_from can be specified' test -r $(FLAGS_watch) || die 'unable to read watch file' test -w $(FLAGS_output_dir) || die 'unable to write to output directory' setglobal watchAge = $[age $(FLAGS_watch)] setglobal watchAgePrev = $(watchAge) # build while true { if test ! $(watchAge) == $(watchAgePrev) { setglobal date = $[isodate] echo "building $(VERSIONS_OS_NAME)-$(VERSIONS_OS_RELEASE) @ $(date)" setglobal outputFileDated = ""$(FLAGS_output)-$(date)"" $(FLAGS_command) >"$(FLAGS_output_dir)/$(outputFileDated)" !2 > !1 shell { cd $(FLAGS_output_dir); rm -f $(FLAGS_output); ln -s $(outputFileDated) $(FLAGS_output); grep FAIL $(FLAGS_output); } setglobal watchAgePrev = $(watchAge) } setglobal watchAge = $[age $(FLAGS_watch)] if test $(watchAge) == $(watchAgePrev) { echo 'sleeping...' while test $(watchAge) == $(watchAgePrev) { sleep $(FLAGS_pause) setglobal watchAge = $[age $(FLAGS_watch)] } } } } # execute main() if this is run in standalone mode (i.e. not in a unit test) setglobal argv0 = $[echo $(ARGV0) |sed 's/_test$//;s/_test\.sh$//] if test $(ARGV0) = $(argv0) { FLAGS @Argv || exit $? eval set -- $(FLAGS_ARGV) if test $Argc -gt 0 { main @Argv; } else { main; } }