edo.eclass: Fix two issues with edo() output

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 <eschwartz@gentoo.org>
Reviewed-by: Eli Schwartz <eschwartz@gentoo.org>
Signed-off-by: Ulrich Müller <ulm@gentoo.org>
This commit is contained in:
Ulrich Müller 2025-05-12 17:39:49 +02:00
parent 405edea239
commit 12508812d0
No known key found for this signature in database
GPG Key ID: 5188335088415E2E
2 changed files with 45 additions and 4 deletions

View File

@ -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 # Distributed under the terms of the GNU General Public License v2
# @ECLASS: edo.eclass # @ECLASS: edo.eclass
@ -36,8 +36,26 @@ _EDO_ECLASS=1
# Executes a short 'command' with any given arguments and exits on failure # Executes a short 'command' with any given arguments and exits on failure
# unless called under 'nonfatal'. # unless called under 'nonfatal'.
edo() { edo() {
einfo "$@" # list of special characters taken from sh_contains_shell_metas
"$@" || die -n "Failed to run command: $@" # 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 # @FUNCTION: edob

View File

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# Copyright 1999-2024 Gentoo Authors # Copyright 1999-2025 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2 # Distributed under the terms of the GNU General Public License v2
EAPI=8 EAPI=8
@ -13,6 +13,18 @@ make_some_noise() {
echo "EoN" 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() { test_edob_simple() {
tbegin "edob with output test" tbegin "edob with output test"
( (
@ -105,6 +117,17 @@ test_edob_failure() {
tend $? "Unexpected output, found \"${fourth_line_of_edob_out}\", expected \"quz\"" 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_simple
test_edob_explicit_log_name test_edob_explicit_log_name
test_edob_explicit_message test_edob_explicit_message