#!/bin/bash
# vim: set ft=sh :
#
# Dependency-based updates + utils
## Compare the given output file with all given source files:
#
# check_update $out ${deps[@]} && do_update $out ... || ...
#
# Returns true if the output file needs to be updated.
function check_update {
# target
local out="$1"; shift
debug "$out"
# need update?
local update=
if [ ${#@} == 0 ]; then
debug " update: unknown deps"
update=y
elif [ ! -e "$out" ]; then
debug " update: dest missing"
update=y
elif [ $UPDATE_FORCE ]; then
debug " update: forced"
update=y
fi
# check deps
for dep in "$@"; do
# don't bother checking if already figured out
[ $update ] && continue
# check
if [ ! -e "$dep" ]; then
warn "$out: Missing source: $dep"
elif [ "$out" -ot "$dep" ]; then
debug " update: $dep"
update=y
else
debug " check: $dep"
fi
done
[ ! $update ] && debug " up-to-date"
# return
[ $update ]
}
## Generate updated output file from given command's stdout:
#
# do_update $out $BIN/cmd --args
#
# Writes output to a temporary .new file, optionally shows a diff of changes, and commits
# the new version to $out (unless noop'd).
function do_update {
local out="$1"; shift
local tmp="$out.new"
debug "$out"
cmd "$@" > "$tmp"
# compare
if [ -e "$out" ] && [ $UPDATE_DIFF ]; then
debug " changes:"
# terse
indent " " diff --unified=1 "$out" "$tmp" || true
fi
# deploy
if [ $UPDATE_NOOP ]; then
# cleanup
debug " no-op"
cmd rm "$tmp"
else
# commit
debug " deploy"
cmd mv "$tmp" "$out"
fi
}
## Compare symlink to target:
#
# check_link $lnk $tgt && do_link $lnk $tgt || ...
#
# Tests if the symlink exists, and the target matches.
# Fails if the target does not exist.
function check_link {
local lnk="$1"
local tgt="$2"
[ ! -e "$tgt" ] && fail "$tgt: target does not exist"
[ ! -e "$lnk" ] || [ $(readlink "$lnk") != "$tgt" ]
}
## Update symlink to point to target:
#
# do_link $lnk $tgt
#
function do_link {
local lnk="$1"
local tgt="$2"
cmd ln -sf "$tgt" "$lnk"
}
## Read include paths from file
function read_zone_includes {
cmd sed -n -E 's/^\$INCLUDE\s+"(.+)"/\1/p' "$@"
}
## (cached) include paths for zone file
function zone_includes {
local cache="$1"
local src="$2"
local prefix="${3:-}"
if [ ! -e "$cache" -o "$cache" -ot "$src" ]; then
read_zone_includes "$src" > "$cache"
fi
while read include; do
echo -n "$prefix$include "
done < "$cache"
}
## Search for prefix-matching includes in zone file
function zone_includes_grep {
local cache="$1"
local src="$2"
local prefix="$3"
for include in $(zone_includes $cache $src); do
if [ "${include#$prefix}" != "$include" ]; then
echo -n " ${include#$prefix}"
fi
done
}