#!/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 <>$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