2020-12-01 19:32:25 +00:00
#!/usr/bin/env bash
2019-04-26 09:57:49 +00:00
# ------------------------------------------------------------------------------
# vim:ts=4:et
# This file is part of solidity.
#
# solidity 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.
#
# solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>
#
# (c) 2016-2019 solidity contributors.
# ------------------------------------------------------------------------------
2021-10-14 16:39:59 +00:00
# The fail() function defined below requires set -e to be enabled.
set -e
2021-10-14 16:43:04 +00:00
# Save the initial working directory so that printStackTrace() can access it even if the sourcing
# changes directory. The paths returned by `caller` are relative to it.
_initial_work_dir = $( pwd )
2022-11-24 15:16:16 +00:00
if [ [ -n ${ CIRCLECI :- } ] ]
2019-04-26 09:57:49 +00:00
then
export TERM = " ${ TERM :- xterm } "
2022-11-24 15:16:16 +00:00
function printTask { echo -e " $( tput bold) $( tput setaf 2) $1 $( tput setaf 7) " ; }
function printError { >& 2 echo -e " $( tput setaf 1) $1 $( tput setaf 7) " ; }
function printWarning { >& 2 echo -e " $( tput setaf 11) $1 $( tput setaf 7) " ; }
function printLog { echo -e " $( tput setaf 3) $1 $( tput setaf 7) " ; }
2019-04-26 09:57:49 +00:00
else
2022-11-24 15:16:16 +00:00
function printTask { echo -e " $( tput bold) $( tput setaf 2) $1 $( tput sgr0) " ; }
function printError { >& 2 echo -e " $( tput setaf 1) $1 $( tput sgr0) " ; }
function printWarning { >& 2 echo -e " $( tput setaf 11) $1 $( tput sgr0) " ; }
function printLog { echo -e " $( tput setaf 3) $1 $( tput sgr0) " ; }
2019-04-26 09:57:49 +00:00
fi
2022-08-22 14:09:38 +00:00
function checkDputEntries
{
local pattern = " $1 "
grep " ${ pattern } " /etc/dput.cf --quiet || \
fail " Error: Missing ${ pattern // \\ / } section in /etc/dput.cf (check top comment in release_ppa.sh for more information). "
}
function sourcePPAConfig
{
[ [ " $LAUNCHPAD_KEYID " = = "" && " $LAUNCHPAD_EMAIL " = = "" ] ] || fail
# source keyid and email from .release_ppa_auth
if [ [ -e .release_ppa_auth ] ]
then
# shellcheck source=/dev/null
source " ${ REPO_ROOT } /.release_ppa_auth "
fi
[ [ " $LAUNCHPAD_KEYID " != "" && " $LAUNCHPAD_EMAIL " != "" ] ] || \
fail " Error: Couldn't find variables \$LAUNCHPAD_KEYID or \$LAUNCHPAD_EMAIL in sourced file .release_ppa_auth (check top comment in $0 for more information). "
}
2021-10-14 14:25:07 +00:00
function printStackTrace
{
printWarning ""
printWarning "Stack trace:"
local frame = 1
while caller " $frame " > /dev/null
do
2021-10-14 16:43:04 +00:00
local lineNumber line file function
2021-10-14 14:25:07 +00:00
# `caller` returns something that could already be printed as a stacktrace but we can make
# it more readable by rearranging the components.
# NOTE: This assumes that paths do not contain spaces.
2022-11-24 15:16:16 +00:00
lineNumber = $( caller " $frame " | cut -d " " -f 1)
function = $( caller " $frame " | cut -d " " -f 2)
file = $( caller " $frame " | cut -d " " -f 3)
2021-10-14 16:43:04 +00:00
# Paths in the output from `caller` can be relative or absolute (depends on how the path
# with which the script was invoked) and if they're relative, they're not necessarily
# relative to the current working dir. This is a heuristic that will work if they're absolute,
# relative to current dir, or relative to the dir that was current when the script started.
# If neither works, it gives up.
line = $(
{
tail " --lines=+ ${ lineNumber } " " $file " ||
tail " --lines=+ ${ lineNumber } " " ${ _initial_work_dir } / ${ file } "
} 2> /dev/null |
head --lines= 1 |
sed -e 's/^[[:space:]]*//'
) || line = "<failed to find source line>"
2021-10-14 14:25:07 +00:00
>& 2 printf " %s:%d in function %s()\n" " $file " " $lineNumber " " $function "
2021-10-14 16:43:04 +00:00
>& 2 printf " %s\n" " $line "
2021-10-14 14:25:07 +00:00
( ( frame++) )
done
}
2021-10-28 09:58:47 +00:00
function fail
2021-10-01 15:21:11 +00:00
{
printError " $@ "
2021-10-14 16:39:59 +00:00
# Using return rather than exit lets the invoking code handle the failure by suppressing the exit code.
2021-10-01 15:21:11 +00:00
return 1
}
2021-10-28 09:58:47 +00:00
function assertFail
2021-10-14 14:25:07 +00:00
{
printError ""
( ( $# = = 0 ) ) && printError "Assertion failed."
( ( $# = = 1 ) ) && printError " Assertion failed: $1 "
printStackTrace
# Intentionally using exit here because assertion failures are not supposed to be handled.
exit 2
}
2021-10-28 09:58:47 +00:00
function msg_on_error
2021-10-01 15:27:09 +00:00
{
local error_message
local no_stdout = false
local no_stderr = false
while [ [ $1 = ~ ^-- ] ]
do
case " $1 " in
--msg)
error_message = " $2 "
shift
shift
; ;
--no-stdout)
no_stdout = true
shift
; ;
--no-stderr)
no_stderr = true
shift
; ;
--silent)
no_stdout = true
no_stderr = true
shift
; ;
*)
2021-10-14 16:39:59 +00:00
assertFail " Invalid option for msg_on_error: $1 "
2021-10-01 15:27:09 +00:00
; ;
esac
done
local command = ( " $@ " )
local stdout_file stderr_file
stdout_file = " $( mktemp -t cmdline_test_command_stdout_XXXXXX.txt) "
stderr_file = " $( mktemp -t cmdline_test_command_stderr_XXXXXX.txt) "
if " ${ command [@] } " > " $stdout_file " 2> " $stderr_file "
then
[ [ $no_stdout = = "true" ] ] || cat " $stdout_file "
[ [ $no_stderr = = "true" ] ] || >& 2 cat " $stderr_file "
rm " $stdout_file " " $stderr_file "
return 0
else
2021-10-14 14:50:14 +00:00
printError ""
printError " Command failed: ${ error_message } "
printError " command: $SOLC ${ command [*] } "
2021-10-01 15:27:09 +00:00
if [ [ -s " $stdout_file " ] ]
then
2021-10-14 14:50:14 +00:00
printError "--- stdout ---"
printError "-----------"
2021-10-01 15:27:09 +00:00
>& 2 cat " $stdout_file "
2021-10-14 14:50:14 +00:00
printError "--------------"
2021-10-01 15:27:09 +00:00
else
2021-10-14 14:50:14 +00:00
printError " stdout: <EMPTY>"
2021-10-01 15:27:09 +00:00
fi
if [ [ -s " $stderr_file " ] ]
then
2021-10-14 14:50:14 +00:00
printError "--- stderr ---"
2021-10-01 15:27:09 +00:00
>& 2 cat " $stderr_file "
2021-10-14 14:50:14 +00:00
printError "--------------"
2021-10-01 15:27:09 +00:00
else
2021-10-14 14:50:14 +00:00
printError " stderr: <EMPTY>"
2021-10-01 15:27:09 +00:00
fi
rm " $stdout_file " " $stderr_file "
2021-10-14 14:50:14 +00:00
printStackTrace
2021-10-01 15:27:09 +00:00
return 1
fi
}
2022-11-24 15:16:16 +00:00
2021-10-14 15:30:13 +00:00
function diff_values
{
( ( $# >= 2 ) ) || fail "diff_values requires at least 2 arguments."
local value1 = " $1 "
local value2 = " $2 "
2022-11-24 15:16:16 +00:00
shift 2
2021-10-14 15:30:13 +00:00
2022-11-24 15:16:16 +00:00
if ! diff --unified= 0 <( echo " $value1 " ) <( echo " $value2 " ) " $@ "
then
if [ [ -n ${ DIFFVIEW :- } ] ]
then
# Use user supplied diff view binary
" $DIFFVIEW " <( echo " $value1 " ) <( echo " $value2 " )
fi
return 1
fi
}
function diff_files
{
( ( $# >= 2 ) ) || fail "diff_files requires at least 2 arguments."
local file1 = " $1 "
local file2 = " $2 "
if ! diff " ${ file1 } " " ${ file2 } "
then
if [ [ -n ${ DIFFVIEW :- } ] ]
then
# Use user supplied diff view binary
" $DIFFVIEW " " ${ file1 } " " ${ file2 } "
fi
return 1
fi
2021-10-14 15:30:13 +00:00
}
2021-10-28 09:58:47 +00:00
function safe_kill
2019-04-26 09:57:49 +00:00
{
local PID = ${ 1 }
local NAME = ${ 2 :- ${ 1 } }
local n = 1
# only proceed if $PID does exist
2020-12-01 19:31:30 +00:00
kill -0 " $PID " 2>/dev/null || return
2019-04-26 09:57:49 +00:00
echo " Sending SIGTERM to ${ NAME } ( ${ PID } ) ... "
2020-12-01 19:31:30 +00:00
kill " $PID "
2019-04-26 09:57:49 +00:00
# wait until process terminated gracefully
2020-12-01 19:31:30 +00:00
while kill -0 " $PID " 2>/dev/null && [ [ $n -le 4 ] ] ; do
2019-04-26 09:57:49 +00:00
echo " Waiting ( $n ) ... "
sleep 1
2020-12-01 19:32:12 +00:00
n = $(( n + 1 ))
2019-04-26 09:57:49 +00:00
done
# process still alive? then hard-kill
2020-12-01 19:31:30 +00:00
if kill -0 " $PID " 2>/dev/null; then
2019-04-26 09:57:49 +00:00
echo " Sending SIGKILL to ${ NAME } ( ${ PID } ) ... "
2020-12-01 19:31:30 +00:00
kill -9 " $PID "
2019-04-26 09:57:49 +00:00
fi
}
2021-10-28 10:32:53 +00:00
function circleci_select_steps
{
2021-12-09 13:37:21 +00:00
# We expect multiple lines in $all_steps, one step per line
2021-10-28 10:32:53 +00:00
local all_steps = " $1 "
( ( $# = = 1 ) ) || assertFail
if ( ( CIRCLE_NODE_TOTAL ) ) && ( ( CIRCLE_NODE_TOTAL > 1 ) )
then
echo " $all_steps " | circleci tests split | xargs
else
echo " $all_steps " | xargs
fi
}
2021-12-09 13:37:21 +00:00
function circleci_select_steps_multiarg
{
# We expect multiple arguments, one step per argument.
circleci_select_steps " $( printf '%s\n' " $@ " ) "
}
2021-10-28 10:32:53 +00:00
function circleci_step_selected
{
local selected_steps = " $1 "
local step = " $2 "
2021-12-09 13:10:14 +00:00
( ( $# = = 2 ) ) || assertFail
2021-10-28 10:32:53 +00:00
[ [ $step != *" " * ] ] || assertFail "Step names must not contain spaces."
[ [ " $selected_steps " = = *" $step " * ] ] || return 1
}
2021-12-09 13:10:14 +00:00
function first_word
{
local words = " $1 "
( ( $# = = 1 ) ) || assertFail
echo " $words " | cut -d " " -f 1
}
2022-04-05 07:06:04 +00:00
# Function reads from stdin. Therefore it has to be used with pipes.
function split_on_empty_lines_into_numbered_files
{
path_prefix = " ${ 1 } "
path_suffix = " ${ 2 } "
awk -v RS = " {print > (\" ${ path_prefix } _\"NR \" ${ path_suffix } \")} "
}
2022-11-24 15:16:16 +00:00
function command_available
{
local program = " $1 "
local parameters = ${ * : 2 }
if ! " ${ program } " " ${ parameters } " > /dev/null 2>& 1
then
fail " ' ${ program } ' not found or not executed successfully with parameter(s) ' ${ parameters } '. aborting. "
fi
}