# HG changeset patch # User Tero Marttila # Date 1331899166 -7200 # Node ID dab145ee3f81d4ee75226c1afa73265bfb13438e # Parent f4457348faa01b9885a52f8cec529eefc6e2a297 update: mad bash wizardry diff -r f4457348faa0 -r dab145ee3f81 bin/update --- a/bin/update Thu Mar 15 18:34:57 2012 +0200 +++ b/bin/update Fri Mar 16 13:59:26 2012 +0200 @@ -22,7 +22,15 @@ ## options IS_TTY= + +LOG=y +LOG_INFO= +LOG_DEBUG= +LOG_CMD= + UPDATE_FORCE= +UPDATE_NOOP= +UPDATE_DIFF= SERIAL_NOUPDATE= function help_args { @@ -32,7 +40,15 @@ Usage: $prog [options] -h display this help text + + -q quiet + -v verbose + -D debug + + -d show changes + -F force-updates without checking src mtime + -n no-op/mock-update; do not actually change anything; implies -S -S do not update serial END } @@ -40,16 +56,32 @@ function parse_args { OPTIND=1 - while getopts 'hFS' opt "$@"; do + while getopts 'hqvDdFnS' opt "$@"; do case $opt in h) help_args $1 exit 0 ;; + q) LOG= ;; + v) LOG_INFO=y ;; + D) + LOG_DEBUG=y + LOG_CMD=y + + ;; + + d) UPDATE_DIFF=y ;; F) UPDATE_FORCE=y ;; S) SERIAL_NOUPDATE=y ;; - + + n) + # implies -S + UPDATE_NOOP=y + SERIAL_NOUPDATE=y + ;; + + ?) die ;; @@ -78,19 +110,40 @@ } function log { - log_msg "$*" + [ $LOG ] && log_msg "$*" || true } function log_info { - log_color 36 " $*" + [ $LOG_INFO ] && log_color 36 " $*" || true } function log_debug { - log_color 32 " $*" + [ $LOG_DEBUG ] && log_color 32 " $*" || true } function log_cmd { - log_color 35 " \$ $*" + [ $LOG_CMD ] && log_color 35 " \$ $*" || true +} + +# XXX: broken +function log_stack { + local level=1 + + while info=$(caller $level); do + echo $info | read line sub file + + log_msg "$file:$lineno $sub()" + + level=$(($level + 1)) + done +} + +function fail { + func=$(caller 1 | cut -d ' ' -f 2) + + log_error "$func: $*" + + exit 2 } function die { @@ -113,9 +166,11 @@ } function indent () { + local indent=$1; shift + "$@" | ( while read line; do - echo " $line" + echo "$indent$line" done ) || exit $? } @@ -126,49 +181,116 @@ [ -d $ZONES ] || die "Missing zones: $ZONES" ## functions -function update { - local dst=$1 - local src=$2 +function check_update { + # target + local dst=$1; shift + + log_debug "$dst:" + + # need update? + local update= + + if [ ! -e $dst ] || [ $UPDATE_FORCE ]; then + log_debug " update forced" + update=y + fi + + # check deps + for dep in "$@"; do + # don't bother checking if already figured out + [ $update ] && continue + + # check + + if [ $dst -ot $dep ]; then + log_debug " changed: $dep" + update=y + fi + done + + [ ! $update ] && log_debug " up-to-date" + + # return + [ $update ] +} + +function do_update { + local dst=$1; shift local tmp=$dst.new - shift 2 - - if [ -z $src ] || [ $UPDATE_FORCE ] || [ $dst -ot $src ]; then - log_debug "update: $dst <- $src" - cmd "$@" $src > $tmp + log_debug " update: $dst" + cmd "$@" > $tmp - # compare - if [ -e $dst ]; then - # terse - indent diff --unified=1 $dst $tmp + # compare + if [ -e $dst ] && [ $UPDATE_DIFF ]; then + log_debug " changes:" + + # terse + indent " " diff --unified=1 $dst $tmp + fi + + if [ $UPDATE_NOOP ]; then + # cleanup + log_debug " no-op:" + + cmd rm $tmp + else + # commit + log_debug " done:" + + cmd mv $tmp $dst + fi +} + +function update { + local dst=$1; shift; + + local sep= + local dep=() + local cmd=() + + for arg in "$@"; do + if [ $arg == '--' ]; then + sep=y fi - - # overwrite - mv $tmp $dst - else - log_debug "$dst <- $src: up-to-date" - fi + if [ $sep ]; then + cmd=("${cmd[@]:-}" "$arg") + else + dep=("${dep[@]:-}" "$arg") + fi + done + + [ ! $sep ] && fail "Invalid args given: $@" + + check_update $dst "${dep[@]}" && do_update $dst "${cmd[@]}" || true } ## bin wrappers function update_serial { - cmd $UPDATE_SERIAL $* + local serial=$1; shift + local old=$(cat $serial) + + log_info "Updating serial: $serial" + + cmd $UPDATE_SERIAL $* $serial + + local new=$(cat $serial) + + log_debug " $old -> $new" } function expand_zone { local output=$1; shift local src=$1; shift - - update $output $src $EXPAND_ZONE "$@" } function process_zone { local output=$1; shift local src=$1; shift - update $output $src $PROCESS_ZONE $PROCESS_ARGS "$@" + check_update $output $src && update $output $PROCESS_ZONE $PROCESS_ARGS "$@" $src } ## actions @@ -177,21 +299,38 @@ local part=$2 local name=$zone.zone.$part + local src=$SETTINGS/$name + local dst=$ZONES/$name - log_info "Copying zone $zone/$part: zones/$name" - update $ZONES/$name $SETTINGS/$name cat + if check_update $dst $src; then + log_info "Copying zone $zone.$part..." + + do_update $output cat $src + else + log_info "Copying zone $zone.$part: not changed" + fi } function update_zone { local zone=$1 + local name=$zone.zone - log_info "Generating $zone zone headers: zones/$name" + local out=$ZONES/$name + local in=$SETTINGS/$zone.zone + local serial=$SERIALS/$zone.serial - expand_zone $ZONES/$name $SETTINGS/$zone.zone \ - --serial $SERIALS/$zone.serial \ - --expand zones=$ROOT/$ZONES + if check_update $out $in $serial; then + log_info "Generating $zone zone headers..." + + do_update $out \ + $EXPAND_ZONE $SETTINGS/$zone.zone \ + --serial $SERIALS/$zone.serial \ + --expand zones=$ROOT/$ZONES + else + log_info "Generating $zone zone headers: not changed" + fi } function update_zone_view { @@ -200,12 +339,35 @@ local name=$view/$zone.zone - log_info "Generating $zone:$view zone headers: zones/$name" + local out=$ZONES/$name + local in=$SETTINGS/$zone.zone + local serial=$SERIALS/$zone.serial - expand_zone $ZONES/$name $SETTINGS/$zone.zone \ - --serial $SERIALS/$zone.serial \ - --expand zones=$ROOT/$ZONES \ - --expand view=$view + if check_update $out $in $serial; then + log_info "Generating $zone:$view zone headers..." + + do_update $out \ + $EXPAND_ZONE $SETTINGS/$zone.zone \ + --serial $SERIALS/$zone.serial \ + --expand zones=$ROOT/$ZONES \ + --expand view=$view + else + log_info "Generating $zone:$view zone headers: not changed" + fi +} + +function update_hosts { + local dst=$1; shift + local src=$1; shift + + + if check_update $dst $src; then + log_info "Generating $dst..." + + do_update $dst $PROCESS_ZONE $PROCESS_ARGS $src "$@" + else + log_info "Generating $dst: not changed" + fi } function main { @@ -214,18 +376,19 @@ parse_args "$@" + log "Updating serials..." + if [ $SERIAL_NOUPDATE ]; then - log_debug "skipping serial-update" + log_debug "skipping" else - log "Updating serials..." - update_serial $SERIALS/paivola.serial - update_serial $SERIALS/paivola-reverse.serial + update_serial $SERIALS/paivola.serial + update_serial $SERIALS/paivola-reverse.serial fi log "Generating host zones..." - process_zone $ZONES/external/paivola.zone.hosts $SETTINGS/paivola.txt --forward-zone - process_zone $ZONES/internal/paivola.zone.hosts $SETTINGS/paivola.txt --forward-zone --forward-txt --forward-mx $FORWARD_MX - process_zone $ZONES/paivola-reverse.zone.hosts $SETTINGS/paivola.txt --reverse-zone $REVERSE_ZONE --reverse-domain $REVERSE_DOMAIN + update_hosts $ZONES/external/paivola.zone.hosts $SETTINGS/paivola.txt --forward-zone + update_hosts $ZONES/internal/paivola.zone.hosts $SETTINGS/paivola.txt --forward-zone --forward-txt --forward-mx $FORWARD_MX + update_hosts $ZONES/paivola-reverse.zone.hosts $SETTINGS/paivola.txt --reverse-zone $REVERSE_ZONE --reverse-domain $REVERSE_DOMAIN log "Copying zone parts..." copy_zone_part paivola auto @@ -233,7 +396,7 @@ copy_zone_part paivola internal copy_zone_part paivola external - log "Updating zones..." + log "Updating zones headers..." update_zone paivola-reverse update_zone_view paivola internal update_zone_view paivola external