1 # /bin/sh 2 # $Id$ 3 # vim:et:ft=sh:sts=2:sw=2 4 # 5 # Copyright 2010 Kate Ward. All Rights Reserved. 6 # Author: kate.ward (at] forestent.com (Kate Ward) 7 # 8 # Continuous build script for shell library testing. 9 # 10 # Sample usages: 11 # $ blah 12 13 # treat unset variables as an error 14 set -u 15 16 # global constants 17 ARGV0=`basename "$0"` 18 ARGV0_DIR=`dirname "$0"` 19 SHLIB_DIR="${ARGV0_DIR}/../lib" 20 21 # load libraries 22 . ${SHFLAGS_LIB:-${SHLIB_DIR}/shflags} \ 23 || (echo 'unable to load shflags library' >&2; exit 1) 24 . ${VERSIONS_LIB:-${SHLIB_DIR}/versions} \ 25 || (echo 'unable to load versions library' >&2; exit 1) 26 27 OUTPUT_FILE="${VERSIONS_OS_NAME}_${VERSIONS_OS_RELEASE}" 28 29 # define flags 30 DEFINE_string 'command' '' 'the command to start a build' 'c' 31 DEFINE_string 'watch' '' 'file to watch for changes' 'w' 32 DEFINE_string 'watch_from' '' 'file containing filenames to watch' 'W' 33 DEFINE_string 'output' "${OUTPUT_FILE}" 'output file to write to' 'o' 34 DEFINE_string 'output_dir' '.' 'directory to write output file' 'O' 35 DEFINE_integer 'pause' 60 'pause between successive runs (sec)' 'p' 36 37 FLAGS_HELP="USAGE: ${ARGV0} [flags]" 38 39 #------------------------------------------------------------------------------ 40 # functions 41 # 42 43 # This function exits the script, optionally printing a message 44 # 45 # Args: 46 # message: string: an error message to be output (optional) 47 # Output: 48 # string: usable flags 49 die() { 50 [ $# -ne 0 ] && echo "$@" >&2 51 flags_help 52 exit 1 53 } 54 55 # Function to give the current date in ISO format 56 # 57 # Args: 58 # none 59 # Output: 60 # string: isodate 61 isodate() { 62 date -u '+%Y%m%dT%H%M%SZ' 63 } 64 65 age() { 66 awkScript='' 67 case ${VERSIONS_OS_NAME} in 68 FreeBSD|Solaris) awkScript='{print $6,$7,$8}' ;; 69 Linux) awkScript='{print $6,$7}' ;; 70 *) echo "unrecognized OS name (${VERSIONS_OS_NAME})" >&2 ;; 71 esac 72 ls -l "$1" |awk "${awkScript}" 73 } 74 75 #------------------------------------------------------------------------------ 76 # main 77 # 78 79 main() 80 { 81 # checks 82 [ -n "${FLAGS_command}" ] || die 'command required' 83 [ -z "${FLAGS_watch}" -a -z "${FLAGS_watch_from}" ] \ 84 && die 'one of watch or watch_from required' 85 [ -n "${FLAGS_watch}" -a -n "${FLAGS_watch_from}" ] \ 86 && die 'only one of watch or watch_from can be specified' 87 [ -r "${FLAGS_watch}" ] || die 'unable to read watch file' 88 [ -w "${FLAGS_output_dir}" ] || die 'unable to write to output directory' 89 90 watchAge=`age "${FLAGS_watch}"` 91 watchAgePrev=${watchAge} 92 93 # build 94 while true; do 95 if [ ! "${watchAge}" == "${watchAgePrev}" ]; then 96 date=`isodate` 97 echo "building ${VERSIONS_OS_NAME}-${VERSIONS_OS_RELEASE} @ ${date}" 98 outputFileDated="${FLAGS_output}-${date}" 99 ${FLAGS_command} >"${FLAGS_output_dir}/${outputFileDated}" 2>&1 100 101 ( cd "${FLAGS_output_dir}"; 102 rm -f "${FLAGS_output}"; 103 ln -s "${outputFileDated}" "${FLAGS_output}"; 104 grep FAIL "${FLAGS_output}"; ) 105 106 watchAgePrev=${watchAge} 107 fi 108 109 watchAge=`age "${FLAGS_watch}"` 110 if [ "${watchAge}" == "${watchAgePrev}" ]; then 111 echo 'sleeping...' 112 while [ "${watchAge}" == "${watchAgePrev}" ]; do 113 sleep ${FLAGS_pause} 114 watchAge=`age "${FLAGS_watch}"` 115 done 116 fi 117 done 118 } 119 120 # execute main() if this is run in standalone mode (i.e. not in a unit test) 121 argv0=`echo "${ARGV0}" |sed 's/_test$//;s/_test\.sh$//'` 122 if [ "${ARGV0}" = "${argv0}" ]; then 123 FLAGS "$@" || exit $? 124 eval set -- "${FLAGS_ARGV}" 125 if [ $# -gt 0 ]; then main "$@"; else main; fi 126 fi 127