terom@583: #!/bin/bash terom@575: # vim: set ft=sh : terom@575: # terom@575: # Dependency-based updates + utils terom@575: terom@575: ## Compare the given output file with all given source files: terom@575: # terom@575: # check_update $out ${deps[@]} && do_update $out ... || ... terom@575: # terom@575: # Returns true if the output file needs to be updated. terom@575: function check_update { terom@575: # target terom@575: local out=$1; shift terom@575: terom@575: debug "$out" terom@575: terom@575: # need update? terom@575: local update= terom@575: terom@575: if [ ${#@} == 0 ]; then terom@575: debug " update: unknown deps" terom@575: update=y terom@575: terom@575: elif [ ! -e $out ]; then terom@575: debug " update: dest missing" terom@575: update=y terom@575: terom@575: elif [ $UPDATE_FORCE ]; then terom@575: debug " update: forced" terom@575: update=y terom@575: fi terom@575: terom@575: # check deps terom@575: for dep in "$@"; do terom@575: # don't bother checking if already figured out terom@575: [ $update ] && continue terom@575: terom@575: # check terom@575: if [ ! -e $ROOT/$dep ]; then terom@590: fail "$out: Missing source: $dep" terom@575: terom@575: elif [ $ROOT/$out -ot $ROOT/$dep ]; then terom@575: debug " update: $dep" terom@575: update=y terom@575: else terom@575: debug " check: $dep" terom@575: fi terom@575: done terom@575: terom@575: [ ! $update ] && debug " up-to-date" terom@575: terom@575: # return terom@575: [ $update ] terom@575: } terom@575: terom@575: ## Generate updated output file from given command's stdout: terom@575: # terom@575: # do_update $out $BIN/cmd --args terom@575: # terom@575: # Writes output to a temporary .new file, optionally shows a diff of changes, and commits terom@575: # the new version to $out (unless noop'd). terom@575: function do_update { terom@575: local out=$1; shift terom@575: local tmp=$out.new terom@575: terom@575: debug "$out" terom@575: cmd "$@" > $ROOT/$tmp terom@575: terom@575: # compare terom@575: if [ -e $ROOT/$out ] && [ $UPDATE_DIFF ]; then terom@575: debug " changes:" terom@575: terom@575: # terse terom@575: indent " " diff --unified=1 $ROOT/$out $ROOT/$tmp || true terom@575: fi terom@575: terom@575: # deploy terom@575: if [ $UPDATE_NOOP ]; then terom@575: # cleanup terom@575: debug " no-op" terom@575: terom@575: cmd rm $ROOT/$tmp terom@575: else terom@575: # commit terom@575: debug " deploy" terom@575: terom@575: cmd mv $ROOT/$tmp $ROOT/$out terom@575: fi terom@575: } terom@575: terom@575: ## Look for a link target: terom@575: # terom@575: # find_link $lnk $tgt... terom@575: # terom@575: # Outputs the first given target to exist, skipping any that are the same as the given $lnk. terom@575: # If no $tgt matches, outputs the last one, or '-'. terom@575: function choose_link { terom@575: local lnk=$1; shift terom@575: local tgt=- terom@575: terom@575: for tgt in "$@"; do terom@575: [ $tgt != $out ] && [ -e $ROOT/$tgt ] && break terom@575: done terom@575: terom@575: echo $tgt terom@575: } terom@575: terom@575: terom@575: ## Compare symlink to target: terom@575: # terom@575: # check_link $lnk $tgt && do_link $lnk $tgt || ... terom@575: # terom@575: # Tests if the symlink exists, and the target matches. terom@575: # Fails if the target does not exist. terom@575: function check_link { terom@575: local lnk=$1 terom@575: local tgt=$2 terom@575: terom@575: [ ! -e $ROOT/$tgt ] && fail "$tgt: target does not exist" terom@575: terom@575: [ ! -e $ROOT/$lnk ] || [ $(readlink $ROOT/$lnk) != $ROOT/$tgt ] terom@575: } terom@575: terom@575: ## Update symlink to point to target: terom@575: # terom@575: # do_link $lnk $tgt terom@575: # terom@575: function do_link { terom@575: local lnk=$1 terom@575: local tgt=$2 terom@575: terom@575: cmd ln -sf $ROOT/$tgt $ROOT/$lnk terom@575: } terom@575: