diff options
Diffstat (limited to 'wrappers/shadow-ar.sh')
-rwxr-xr-x | wrappers/shadow-ar.sh | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/wrappers/shadow-ar.sh b/wrappers/shadow-ar.sh new file mode 100755 index 00000000..b363034c --- /dev/null +++ b/wrappers/shadow-ar.sh @@ -0,0 +1,246 @@ +#!/bin/bash + +set -euf -o pipefail + +top="#TOP#" +shadow_top="#SHADOW_TOP#" + +orig_ar="#ORIG_TOOL#" +shadow_ar="#SHADOW_TOOL#" + +errors=() +warnings=() +skips=() + +orig_out=() +shadow_out=() +orig_input=() +shadow_input=() +orig_opts=() +shadow_opts=() + +dump_log () +{ + ( + set +u + IFS=";" + cat <<EOF +errors=(${errors[@]}) +warnings=(${warnings[@]}) +skips=(${skips[@]}) +orig_out=(${orig_out[@]}) +shadow_out=(${shadow_out[@]}) +orig_input=(${orig_input[@]}) +shadow_input=(${shadow_input[@]}) +orig_opts=($0 ${orig_opts[@]}) +shadow_opts=(${shadow_opts[@]}) + +EOF + ) +} + +report_errors () { + res=$? + if [ $res != 0 ]; then + errors+=("wrapper failed with $res") + fi + if [ ${#errors[@]} != 0 ] \ + || [ ${#warnings[@]} != 0 ] \ + || [ ${#skips[@]} != 0 ]; then + ( + /usr/bin/flock -e 9 + + if [ ${#errors[@]} != 0 ]; then + log=$shadow_top.errors + elif [ ${#warnings[@]} != 0 ]; then + log=$shadow_top.warnings + else + log=$shadow_top.skips + fi + dump_log >>$log + ) 9>>$shadow_top.lock + fi +} + +trap report_errors EXIT + +if [ "$#" -gt 0 ] && [ ${#orig_opts[@]} = 0 ]; then + opt="$1" + shift + + orig_opts+=("$opt") + + case "$opt" in + "-M") skips+=("mri-script unsupported") ;; + "c"*) ;; + *) errors+=("orig expecting: crsPD, cqsL, etc.; got: $opt") ;; + esac +else + errors+=("orig missing: action") +fi + +while [ "$#" -gt 0 ]; do + opt="$1" + shift + + orig_opts+=("$opt") + + case "$opt" in + "-"*) + ;; + *) + if [ ${#orig_out[@]} = 0 ]; then + orig_out+=("$opt") + else + orig_input+=("$opt") + fi + ;; + esac +done + +# orig_out is used only if command is not skipped +if [ "${#orig_out[@]}" = 0 ] && [ ${#skips[@]} = 0 ]; then + errors+=("orig missing: orig_out") +fi + +print_shadow_path () +{ + local path="$1" + local prefix="${2-}" + + case "$path" in + "/dev/null") echo "$path"; return ;; + "/"*) errors+=("Absolute path: $path") ;; + esac + + # Check that we are under $top + case "$(pwd -P | sed -e "s#^$top##")" in + "/"*) errors+=("Running outside of $top") ;; + esac + + echo "$(pwd -P)/$path" | sed -e "s#$top#$shadow_top${prefix}#" +} + +generate_shadow_rsp () +{ + local orig_rsp="$1" + + local shadow_rsp orig_file shadow_file + + shadow_rsp=$(print_shadow_path "$orig_rsp") + mkdir -p "$(dirname "$shadow_rsp")" + rm -f "$shadow_rsp" + + if [ "$(stat --format=%s "$orig_rsp")" = 0 ]; then + touch "$shadow_rsp" + else + local quote delim="" + while read -d '' -r orig_file; do + # unquote orig + case "$orig_file" in + \'*\') quote="'"; orig_file=${orig_file:1:-1} ;; + *) quote="" ;; + esac + shadow_file=$(print_shadow_path "$orig_file") + if ! [ -e "$shadow_file" ]; then + shadow_file="$orig_file" + fi + # quote shadow + echo -ne "$delim$quote$shadow_file$quote" >> "$shadow_rsp" + delim=" " + done < <({ cat "$orig_rsp"; echo; } | xargs printf '%s\0') + fi + + echo "$shadow_rsp" +} + +make_shadow_opts () +{ + local opt + local shadow_file + + if [ "$#" -gt 0 ] && [ ${#shadow_opts[@]} = 0 ]; then + opt="$1" + shift + + shadow_opts+=("$opt") + + case "$opt" in + "c"*) ;; + *) errors+=("shadow expecting: crsPD, cqsL, etc.; got: $opt") ;; + esac + else + errors+=("shadow missing: action") + fi + + while [ "$#" -gt 0 ]; do + opt="$1" + shift + + case "$opt" in + "-"*) ;; + "@"*".rsp") + opt="${opt#@}" + if [ x"$(basename "$opt" .rsp)" = x"$(basename "${orig_out[*]}")" ]; then + opt=$(generate_shadow_rsp "$opt") + else + errors+=("RSP file $opt does not match orig_out ${orig_out[*]}") + fi + opt="@$opt" + ;; + "@"*) + errors+=("Unexpected option: $opt") + opt="${opt#@}" + # shellcheck disable=SC2046 + make_shadow_opts $(cat "$opt") + continue + ;; + *) + shadow_file=$(print_shadow_path "$opt") + if [ ${#shadow_out[@]} = 0 ]; then + opt="$shadow_file" + shadow_out+=("$shadow_file") + elif [ -e "$shadow_file" ]; then + opt="$shadow_file" + shadow_input+=("$shadow_file") + fi + ;; + esac + shadow_opts+=("$opt") + done +} + +if [ ${#errors[@]} = 0 ] && [ ${#skips[@]} = 0 ]; then + make_shadow_opts "${orig_opts[@]}" +fi + +if [ ${#errors[@]} = 0 ] && [ ${#skips[@]} = 0 ]; then + shadow_log=$(print_shadow_path "${orig_out[*]}" "-logs") + + mkdir -p "$(dirname "${shadow_out[*]}")" + mkdir -p "$(dirname "$shadow_log")" + + dump_log > "$shadow_log" + echo "$shadow_ar" "${shadow_opts[@]}" >> "$shadow_log" + "$shadow_ar" "${shadow_opts[@]}" >> "$shadow_log" 2>&1 & + shadow_res=0 && wait $! || shadow_res=$? + + if [ $shadow_res != 0 ]; then + errors+=("shadow_ar failed with $shadow_res") + elif ! [ -e "${shadow_out[*]}" ]; then + errors+=("shadow_ar failed to generate output") + else + shadow_link=$(IFS=""; print_shadow_path "${orig_out[*]}" "-default-A") + mkdir -p "$(dirname "$shadow_link")" + ln -s -f "${shadow_out[*]}" "$shadow_link" + fi +fi + +"$orig_ar" "${orig_opts[@]}" < /dev/stdin & +orig_res=0 && wait $! || orig_res=$? + +if [ $orig_res != 0 ]; then + errors+=("orig_ar failed with $orig_res") +fi + +exit $orig_res |