commit:     fa90907e9d23cbbaa15567eb9924b604740aacd6
Author:     Florian Schmaus <flow <AT> gentoo <DOT> org>
AuthorDate: Thu Apr  4 15:22:25 2024 +0000
Commit:     Florian Schmaus <flow <AT> gentoo <DOT> org>
CommitDate: Tue May 14 07:58:12 2024 +0000
URL:        https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=fa90907e

edo.eclass: enhance edob for usage with noisy commands

Normally, edob can, or rather should, not be used with noisy commands,
i.e., commands that produce an output. This is because the output
destroys the concept of ebegin and eend, where the eend marker is shown
on the same line that is produced by ebegin.

However, it sometimes would be nice to use edob with noisy commands, but
this means to redirect stdout and stderr of those commands. Instead of
redirecting the output to /dev/null, we save the output in a log file
under T. This allows us to present the output to the user in case the
command fails, making it furthermore part of the build.log, which we
expect users to attach to bug reports.

Closes: https://github.com/gentoo/gentoo/pull/36117
Signed-off-by: Florian Schmaus <flow <AT> gentoo.org>

 eclass/edo.eclass   |  68 ++++++++++++++++++++++++++-----
 eclass/tests/edo.sh | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 171 insertions(+), 10 deletions(-)

diff --git a/eclass/edo.eclass b/eclass/edo.eclass
index c2e7ed60083f..ed8ec8d3201e 100644
--- a/eclass/edo.eclass
+++ b/eclass/edo.eclass
@@ -1,4 +1,4 @@
-# Copyright 2022 Gentoo Authors
+# Copyright 2022-2024 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 # @ECLASS: edo.eclass
@@ -12,10 +12,16 @@
 # This eclass provides the 'edo' command, and an 'edob' variant for 
ebegin/eend,
 # which logs the command used verbosely and dies (exits) on failure.
 #
-# This eclass should be used only where needed to give a more verbose log, e.g.
-# for invoking non-standard ./configure scripts, or building objects/binaries
-# directly within ebuilds via compiler invocations. It is NOT to be used
-# in place of generic 'command || die' where verbosity is unnecessary.
+# The 'edo' command should be used only where needed to give a more verbose 
log,
+# e.g. for invoking non-standard ./configure scripts, or building
+# objects/binaries directly within ebuilds via compiler invocations.  It is NOT
+# to be used in place of generic 'command || die' where verbosity is
+# unnecessary.
+#
+# The 'edob' command can be used for long running commands, even if
+# those commands produce output.  The 'edob' command will suppress the
+# command's output and only present it if the command returned with a
+# non-zero exit status.
 case ${EAPI} in
        7|8) ;;
        *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
@@ -35,14 +41,56 @@ edo() {
 }
 
 # @FUNCTION: edob
-# @USAGE: <command> [<args>...]
+# @USAGE: [-l <log-name>] [-m <message>] <command> [<args>...]
 # @DESCRIPTION:
 # Executes 'command' with ebegin & eend with any given arguments and exits
-# on failure unless called under 'nonfatal'.
+# on failure unless called under 'nonfatal'.  This function redirects
+# stdout and stderr to a log file.  The content of the log file is shown
+# if the command returns with a non-zero exit status.
+#
+# If -m <message> is provided, then invokes ebegin with <message>, otherwise
+# a default message is used.  If -l <log-name> is provided, then <log-name> is
+# used to construct the name of the log file where stdout and stderr of the
+# command is redirected to.
 edob() {
-       ebegin "Running $@"
-       "$@"
-       eend $? || die -n "Failed to run command: $@"
+       local message
+       local log_name
+
+       while true; do
+               case "${1}" in
+                       -l|-m)
+                               [[ $# -lt 2 ]] && die "Must provide an argument 
to ${1}"
+                               case "${1}" in
+                                       -l)
+                                               log_name="${2}"
+                                               ;;
+                                       -m)
+                                               message="${2}"
+                                               ;;
+                               esac
+                               shift 2
+                               ;;
+                       *)
+                               break
+                               ;;
+               esac
+       done
+
+       [[ -z ${message} ]] && message="Running $@"
+       [[ -z ${log_name} ]] && log_name="$(basename ${1})"
+
+       local log_file="${T}/${log_name}.log"
+       [[ -f ${log_file} ]] && die "Log file ${log_file} exists. Consider 
using \"edob -l\""
+
+       ebegin "${message}"
+
+       "$@" &> "${log_file}"
+       local ret=$?
+
+       if ! eend $ret; then
+               cat "${log_file}"
+               die -n "Command \"$@\" failed with exit status $ret"
+       fi
 }
 
 fi

diff --git a/eclass/tests/edo.sh b/eclass/tests/edo.sh
new file mode 100755
index 000000000000..cac03e0401ba
--- /dev/null
+++ b/eclass/tests/edo.sh
@@ -0,0 +1,113 @@
+#!/bin/bash
+# Copyright 1999-2024 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=8
+source tests-common.sh || exit
+
+inherit edo
+
+make_some_noise() {
+       echo "Here is some noise:"
+       echo "${1:?Must provide some noise}"
+       echo "EoN"
+}
+
+test_edob_simple() {
+       tbegin "edob with output test"
+       (
+               edob make_some_noise foo
+               eend $?
+       ) &> "${T}/edob.out"
+       local res=$?
+       if [[ $res -ne 0 ]]; then
+               tend $res
+               return 0
+       fi
+
+       local log_file="${T}/make_some_noise.log"
+       local second_line="$(sed -n '2p' "${log_file}")"
+    [[ "${second_line}" == "foo" ]];
+       tend $? "Unexpected output, found \"${second_line}\", expected \"foo\""
+
+       rm "${log_file}" || die
+}
+
+test_edob_explicit_log_name() {
+       tbegin "edob with explicit logfile name"
+       (
+               edob -l mylog make_some_noise bar
+               eend $?
+       ) &> "${T}/edob.out"
+       local res=$?
+       if [[ $res -ne 0 ]]; then
+               cat "${T}/edob.out"
+               tend $res
+               return 0
+       fi
+
+       local log_file="${T}/mylog.log"
+       local second_line="$(sed -n '2p' "${log_file}")"
+    [[ "${second_line}" == "bar" ]];
+       tend $? "Unexpected output, found \"${second_line}\", expected \"foo\""
+
+       rm "${log_file}" || die
+}
+
+test_edob_explicit_message() {
+       tbegin "edob with explicit message"
+       (
+               edob -m "Making some noise" make_some_noise baz
+               eend $?
+       ) &> "${T}/edob.out"
+       local res=$?
+       if [[ $res -ne 0 ]]; then
+               cat "${T}/edob.out"
+               tend $res
+               return 0
+       fi
+
+       local log_file="${T}/make_some_noise.log"
+       local second_line="$(sed -n '2p' "${log_file}")"
+    [[ "${second_line}" == "baz" ]];
+       tend $? "Unexpected output, found \"${second_line}\", expected \"baz\""
+
+       rm "${log_file}" || die
+}
+
+test_edob_failure() {
+       make_some_noise_and_fail() {
+               make_some_noise "$@"
+               return 1
+       }
+
+       tbegin "edob with failing command"
+       (
+               edob -m "Making some noise" make_some_noise_and_fail quz
+               eend $?
+       ) &> "${T}/edob.out"
+       local res=$?
+       # Now, this time we expect res to be exactly '1'.
+       if [[ $res -ne 1 ]]; then
+               tend 1
+               return 1
+       fi
+
+       local log_file="${T}/make_some_noise_and_fail.log"
+       local second_line="$(sed -n '2p' "${log_file}")"
+    [[ "${second_line}" == "quz" ]];
+       tend $? "Unexpected output, found \"${second_line}\", expected \"quz\""
+
+       rm "${log_file}" || die
+
+       local fourth_line_of_edob_out="$(sed -n '4p' "${T}/edob.out")"
+       [[ "${fourth_line_of_edob_out}" == "quz" ]];
+       tend $? "Unexpected output, found \"${fourth_line_of_edob_out}\", 
expected \"quz\""
+}
+
+test_edob_simple
+test_edob_explicit_log_name
+test_edob_explicit_message
+test_edob_failure
+
+texit

Reply via email to