#!/usr/bin/env bash # # sage-logger [-p] [-P PREFIX] COMMAND [LOGFILE] # # Evaluate shell command COMMAND while logging stdout and stderr to # LOGFILE (if given). If either the command or the logging failed, return a # non-zero exit status. # # If the -p argument is given, each line printed to stdout is prefixed # with the name of the log file. # # If the -P PREFIX argument is given, each line printed to stdout is # prefixed with PREFIX. # # AUTHOR: # # - Jeroen Demeyer (2015-07-26): initial version based on old pipestatus # script (#18953) # #***************************************************************************** # Copyright (C) 2015 Jeroen Demeyer <[email protected]> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** use_prefix=false prefix="" case "$1" in -p) use_prefix=true shift ;; -P) use_prefix=true prefix="[$2] " shift 2 ;; esac cmd="$1" logfile="$2" export SAGE_LOGFILE="$logfile" logname="$(basename $logfile .log)" logdir=`dirname "$logfile"` if [[ $use_prefix = true && -z "$prefix" ]]; then prefix="[${logname}] " fi # Use sed option to reduce buffering, to make the output appear more # smoothly. For GNU sed, this is the --unbuffered option. # For BSD sed (which is also on OS X), this is the -l option. if [ -n "$prefix" ]; then if sed </dev/null 2>/dev/null --unbuffered ""; then SED="sed --unbuffered" elif sed </dev/null 2>/dev/null -l ""; then SED="sed -l" else SED="sed" fi # eval needed to get the quoting around the regexp right SED="eval $SED 's/^/$prefix/'" else # Make SED a useless use of cat SED=cat fi if [ -z "$logfile" ]; then # Just prefix, nothing else ( exec 2>&1; sh -c "$cmd" ) | \ ( trap '' SIGINT; if [ -n "$GITHUB_ACTIONS" -a -n "$prefix" ]; then echo "::group::${logname}"; fi; $SED; if [ -n "$GITHUB_ACTIONS" -a -n "$prefix" ]; then echo "::endgroup::"; fi ) pipestatus=(${PIPESTATUS[*]}) if [ ${pipestatus[1]} -ne 0 ]; then exit ${pipestatus[1]} else exit ${pipestatus[0]} fi fi # Remainder of the script is with logging to "$logfile" and timing. timefile="$logdir/$logname.time" rm -f "$timefile" time_cmd() { local max=$(($SECONDS+10)) exec 3>&1 4>&2 local time_output time_output=$((time 1>&3 2>&4 sh -c "$1") 2>&1) local retstat=$? [ "$SECONDS" -lt "$max" ] || echo "$time_output" > "$timefile" return $retstat } report_time () { [ -r "$timefile" ] && echo $(< $timefile) } mkdir -p "$logdir" # Do all logging of child processes with V=1 to ensure that no # information is lost. export MAKEFLAGS="$MAKEFLAGS V=1" if [ "$V" = 0 ]; then export SAGE_SILENT_BUILD=yes fi if [ -n "$SAGE_SILENT_BUILD" -a ${use_prefix} = true ]; then # Silent build. # Similar to https://www.gnu.org/software/automake/manual/html_node/Automake-Silent-Rules.html#Automake-Silent-Rules echo "[$logname] installing. Log file: $logfile" ( exec>> $logfile 2>&1; time_cmd "$cmd"; status=$?; report_time; exit $status ) status=$? if [[ $status != 0 ]]; then if [ -n "$GITHUB_ACTIONS" ]; then echo " [$logname] error installing, exit status $status. Log file:" sed "s;^; [$logname] ;" "$logfile" >&2 else echo " [$logname] error installing, exit status $status. End of log file:" tail -n 120 "$logfile" | sed "/Please email sage-devel/,$ d;s;^; [$logname] ;" >&2 echo " [$logname] Full log file: $logfile" fi else time=$(report_time) if [ -n "$time" ]; then echo " [$logname] successfully installed ($time)." else echo " [$logname] successfully installed." fi fi exit $status else # Redirect stdout and stderr to a subprocess running tee. # We trap SIGINT such that SIGINT interrupts the main process being # run, not the logging. ( exec 2>&1; time_cmd "$cmd"; status=$?; report_time; exit $status ) | \ ( trap '' SIGINT; if [ -n "$GITHUB_ACTIONS" -a -n "$prefix" ]; then echo "::group::${logname}"; fi; tee -a "$logfile" | $SED; if [ -n "$GITHUB_ACTIONS" -a -n "$prefix" ]; then echo "::endgroup::"; fi ) pipestatus=(${PIPESTATUS[*]}) if [ ${pipestatus[1]} -ne 0 ]; then exit ${pipestatus[1]} else exit ${pipestatus[0]} fi fi