Mike Gerwitz 2024-08-09 01:45:14 -04:00
parent bbe775d870
commit b378cbdf6a
Signed by: mikegerwitz
GPG Key ID: 8C917B7F5DC51BA2
5 changed files with 188 additions and 13 deletions

View File

@ -74,7 +74,7 @@ check-docgen:
build-aux/asg-ontviz >/dev/null
.PHONY: check-system
check-system: bin
check-system: bin conf.sh
tests/run-tests
.PHONY: check-lint

View File

@ -1,3 +1,5 @@
#!/bin/bash
# This configuration file is populated by `configure` and is intended to be
# sourced by shell scripts.
@ -62,4 +64,69 @@ fi
declare -r TAMER_PATH_TAMEC="$TAMER_PATH_BIN/tamec"
declare -r TAMER_PATH_TAMELD="$TAMER_PATH_BIN/tameld"
declare -r P_XMLLINT="@XMLLINT@"
# Miscellaneous programs used by shell scripts.
#
# Note that, just because these programs were populated by a configure
# script, that does not mean that they actually exist. In particular, users
# may arbitrarily override these programs during configuration.
#
# To mitigate this issue, we define functions that serve _in place of_ these
# programs. This provides two major benefits: it allows us to display a
# helpful error when the program cannot be found, and it allows shell
# scripts to simply pretend that those programs exist in the environment
# without having to worry about an extra layer of abstraction.
#
# The most notable downside to this approach is that it is not obvious by
# looking at a shell script whether we have considered that a program may be
# missing, but this ought to be caught by a comprehensive test suite.
awk() { __try-run-cfg-prog "@AWK@" "$@"; }
sed() { __try-run-cfg-prog "@SED@" "$@"; }
grep() { __try-run-cfg-prog "@GREP@" "$@"; }
xmllint() { __try-run-cfg-prog "@XMLLINT@" "$@"; }
dot() { __try-run-cfg-prog "@DOT@" "$@"; }
diff() { __try-run-cfg-prog "@DIFF@" "$@"; }
find() { __try-run-cfg-prog "@FIND@" "$@"; }
xargs() { __try-run-cfg-prog "@XARGS@" "$@"; }
# 'time' is a builtin, so we need a different name
time-cmd() { __try-run-cfg-prog "@TIME@" "$@"; }
# Exit code when bash is unable to locate the requested command.
declare -ri EX_CMD_NOT_FOUND=127
# Attempt to run a program that is configurable via the `configure` script.
# If the program cannot be found, then display a helpful error message that
# directs the user to the configure script.
__try-run-cfg-prog() {
local -r prog="${1?Missing program name}"
shift
# The name of the wrapper command is assumed to be the name of the
# function that called us (the above functions).
local -r name="${FUNCNAME[1]}"
local -i ex=0
command "$prog" "$@" || {
ex=$?
if [ "$ex" == "$EX_CMD_NOT_FOUND" ]; then
# The goal is to notify the user of a few things:
# 1. That they should consult 'configure';
# 2. The name of the command that we _tried_ to invoke; and
# 3. The name that is usually used to invoke this command.
#
# That is: '$prog' and '$name' may differ if someone ran
# ./configure DIFF=foo
# which would try to invoke 'foo' for 'diff'.
cat >&2 <<EOF
help: the missing program '$prog' originates from 'configure' as the command
help: for the program '$name'; did you configure from a different
help: environment than the one you are running in now (e.g. a container),
hwlp: or did you explicitly specify this command/path via 'configure'?
EOF
fi
}
return "$ex"
}

View File

@ -146,11 +146,50 @@ test -z "$FEATURES" || {
}
# Other programs used by scripts
AC_ARG_VAR([XMLLINT], [xmllint from libxml2])
AC_CHECK_PROGS(XMLLINT, [xmllint])
test -n "$XMLLINT" || AC_MSG_ERROR([xmllint not found])
AC_ARG_VAR([DOT], [Graphviz filter for directed graphs])
AC_CHECK_PROGS(DOT, [dot])
test -n "$DOT" || AC_MSG_ERROR([Graphviz dot not found])
# These programs are typically available, but may not be in a minimal
# container, so let's check for them early to help container authors get
# their dependencies right and avoid awkward runtime errors.
AC_ARG_VAR([AWK], [Awk (e.g. Gawk, mawk)])
AC_CHECK_PROGS(AWK, [awk])
AC_ARG_VAR([SED], [sed command])
AC_CHECK_PROGS(SED, [sed])
AC_ARG_VAR([GREP], [grep command])
AC_CHECK_PROGS(GREP, [grep])
AC_ARG_VAR([DIFF], [diff utility (e.g. from GNU diffutils)])
AC_CHECK_PROGS(DIFF, [diff])
AC_ARG_VAR([FIND], [find utility (e.g. from GNU findutils)])
AC_CHECK_PROGS(FIND, [find])
AC_ARG_VAR([XARGS], [xargs utility (e.g. from GNU findutils)])
AC_CHECK_PROGS(XARGS, [xargs])
AC_ARG_VAR([TIME], [time utility (non-shell-builtin)])
AC_CHECK_PROGS(TIME, [time])
# Check for missing programs all at once so that a user can foresee what
# other errors may be coming up, rather than having to modify the
# environment and re-run configure and repeat.
test -n "$XMLLINT" || AC_MSG_ERROR([xmllint not found])
test -n "$DOT" || AC_MSG_ERROR([Graphviz dot not found])
test -n "$AWK" || AC_MSG_ERROR([awk not found])
test -n "$SED" || AC_MSG_ERROR([sed not found])
test -n "$GREP" || AC_MSG_ERROR([grep not found])
test -n "$DIFF" || AC_MSG_ERROR([diff not found])
test -n "$FIND" || AC_MSG_ERROR([find not found])
test -n "$XARGS" || AC_MSG_ERROR([xargs not found])
test -n "$TIME" || AC_MSG_ERROR([time (non-builtin) not found])
AC_CONFIG_FILES([Makefile conf.sh])

View File

@ -0,0 +1,72 @@
#!/bin/bash
# Copyright (C) 2014-2024 Ryan Specialty, LLC.
#
# This file is part of TAME.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Assert that, for each AC_CHECK_PROGS in 'configure.ac', there is a
# corresponding shell function defined for use in shell scripts.
# #
set -euo pipefail
declare -r mypath=$(dirname "$0")
# The functions will be defined in here.
. "$mypath/../conf.sh"
declare -r root="$mypath/.."
# These commands appear in configure.ac as AC_CHECK_PROGS, but they are not
# invoked via shell scripts and so should be ignored here.
declare -ra excluded_cmds=(cargo rustc)
expected-fns() {
# note that some programs are exempt (since they are not invoked via shell
# scripts) and 'time' requires renaming because it is a builtin
awk -F'[][ (,]' '/AC_CHECK_PROGS/{print $5}' "$root/configure.ac" \
| sans-excluded \
| sed 's/^time$/time-cmd/'
}
sans-excluded() {
grep -vF "$( IFS=$'\n'; echo "${excluded_cmds[*]}" )"
}
main() {
local -i ex=0
while read prog; do
printf "checking for shell function %-15s" "'$prog'..."
test "$(type -t "$prog")" == function || {
echo '[FAIL]'
ex=1
continue
}
echo '[ OK ]'
done < <( expected-fns )
if [ "$ex" -ne 0 ]; then
echo 'fail: every AC_CHECK_PROGS in configure.ac must appear as a function'
echo ' in conf.sh.in'.
fi
return "$ex"
}
main "$@"

View File

@ -5,12 +5,9 @@
set -euo pipefail
mypath=$(dirname "$0")
declare -r mypath=$(dirname "$0")
. "$mypath/../../conf.sh"
# Performing this check within `<()` below won't cause a failure.
: "${P_XMLLINT?}" # conf.sh
run-test() {
local name="${1?Missing test name}"
local dir="${2?Missing dir}"
@ -48,7 +45,7 @@ timed-tamec() {
objty=xmlo-experimental
fi
command time -f "%F/%Rfault %I/%Oio %Mrss %c/%wctx \n%C" -o "$dir/time.log" \
time-cmd -f "%F/%Rfault %I/%Oio %Mrss %c/%wctx \n%C" -o "$dir/time.log" \
"${TAMER_PATH_TAMEC?}" -o "$dir/$out" --emit "$objty" "$dir/$in" \
&> "$dir/tamec-$out.log" \
|| ret=$?
@ -86,8 +83,8 @@ test-derive-from-src() {
timed-tamec "$dir" src.xml out.xmli || return
diff <("$P_XMLLINT" --format "$dir/expected.xml" || echo 'ERR expected.xml') \
<("$P_XMLLINT" --format "$dir/out.xmli" || echo 'ERR out.xmli') \
diff <(xmllint --format "$dir/expected.xml" || echo 'ERR expected.xml') \
<(xmllint --format "$dir/out.xmli" || echo 'ERR out.xmli') \
&> "$dir/diff.log"
}
@ -111,8 +108,8 @@ test-fixpoint() {
timed-tamec "$dir" out.xmli out-2.xmli || return
diff <("$P_XMLLINT" --format "$dir/expected.xml" || echo 'ERR expected.xml') \
<("$P_XMLLINT" --format "$dir/out-2.xmli" || echo 'ERR out.xmli') \
diff <(xmllint --format "$dir/expected.xml" || echo 'ERR expected.xml') \
<(xmllint --format "$dir/out-2.xmli" || echo 'ERR out.xmli') \
&> "$dir/diff.log"
}