This updates the edo function to behave similar to its possible implementation in the package manager for EAPI 9:
- Backslash-escaping (as einfo does via "echo -e") is not wanted. - Arguments should be printed in a quoted format that could be reused as shell input. We quote arguments using the "@Q" operator of Bash parameter expansion, but avoid excessive quoting by testing each argument for shell metacharacters. The resulting output should be very similar to that of the trace obtained with "set -x". Note that the @Q operator did not exist in Bash 4.2, therefore arguments are printed literally in EAPI 7. Bug: https://bugs.gentoo.org/744880#c13 Suggested-by: Eli Schwartz <eschwa...@gentoo.org> Reviewed-by: Eli Schwartz <eschwa...@gentoo.org> Signed-off-by: Ulrich Müller <u...@gentoo.org> --- Changes in v2: - Test number of arguments - Add some test cases eclass/edo.eclass | 24 +++++++++++++++++++++--- eclass/tests/edo.sh | 25 ++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/eclass/edo.eclass b/eclass/edo.eclass index 5fd77a676a8b..a308851aca7f 100644 --- a/eclass/edo.eclass +++ b/eclass/edo.eclass @@ -1,4 +1,4 @@ -# Copyright 2022-2024 Gentoo Authors +# Copyright 2022-2025 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 # @ECLASS: edo.eclass @@ -36,8 +36,26 @@ _EDO_ECLASS=1 # Executes a short 'command' with any given arguments and exits on failure # unless called under 'nonfatal'. edo() { - einfo "$@" - "$@" || die -n "Failed to run command: $@" + # list of special characters taken from sh_contains_shell_metas + # in shquote.c (bash-5.2) + local a out regex='[] '\''"\|&;()<>!{}*[?^$`]|^[#~]|[=:]~' + + [[ $# -ge 1 ]] || die "edo: at least one argument needed" + + if [[ ${EAPI} = 7 ]]; then + # no @Q in bash-4.2 + out=" $*" + else + for a; do + # quote if (and only if) necessary + [[ ${a} =~ ${regex} || ! ${a} =~ ^[[:print:]]+$ ]] && a=${a@Q} + out+=" ${a}" + done + fi + + einfon + printf '%s\n' "${out:1}" >&2 + "$@" || die -n "Failed to run command: ${1}" } # @FUNCTION: edob diff --git a/eclass/tests/edo.sh b/eclass/tests/edo.sh index cac03e0401ba..1fa8a7a9a026 100755 --- a/eclass/tests/edo.sh +++ b/eclass/tests/edo.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 1999-2024 Gentoo Authors +# Copyright 1999-2025 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 EAPI=8 @@ -13,6 +13,18 @@ make_some_noise() { echo "EoN" } +test_edo() { + local exp_ret=${1} exp_out=${2} cmd=("${@:3}") + local have_ret have_out + tbegin "edo -> ret: ${exp_ret}, out: ${exp_out}" + have_out=$(edo "${cmd[@]}" 2>&1) + have_ret=$? + have_out=${have_out%%$'\n'*} + have_out=${have_out# \* } + [[ ${have_ret} -eq ${exp_ret} && ${have_out} == "${exp_out}" ]] + tend $? "returned: ${have_ret}, output: ${have_out}" +} + test_edob_simple() { tbegin "edob with output test" ( @@ -105,6 +117,17 @@ test_edob_failure() { tend $? "Unexpected output, found \"${fourth_line_of_edob_out}\", expected \"quz\"" } +test_edo 0 "/bin/true foo" /bin/true foo +test_edo 1 "/bin/false bar" /bin/false bar +test_edo 0 "make_some_noise baz" make_some_noise baz +test_edo 0 ": 'foo bar' 'baz quux'" : 'foo bar' 'baz quux' +test_edo 0 ": @%:+,-=._ '\$'" : '@%:+,-=._' '$' +test_edo 0 ": 'foo;bar' 'baz*quux'" : 'foo;bar' 'baz*quux' +test_edo 0 ": '#foo' bar#baz 'qu=~ux'" : '#foo' 'bar#baz' 'qu=~ux' +test_edo 0 ": '\"' \\' 'foo'\\''bar'" : '"' "'" "foo'bar" +test_edo 0 ": '' ' ' \$'\\t' \$'\\001'" : '' ' ' $'\t' $'\x01' +test_edo 0 ": äöü" : 'äöü' + test_edob_simple test_edob_explicit_log_name test_edob_explicit_message -- 2.49.0