diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f33c274b5..0a3b62952 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - - name: Setup Build Env + - name: Install Build Tools run: sudo ./scripts/install-build-tools.sh - name: Setup Local Dependencies run: ./scripts/setup-dependencies.sh @@ -38,7 +38,7 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - - name: Setup Build Env + - name: Install Build Tools run: sudo ./scripts/install-build-tools.sh - name: Setup Local Dependencies run: ./scripts/setup-dependencies.sh @@ -50,7 +50,7 @@ jobs: name: Pylint runs-on: ubuntu-22.04 continue-on-error: true - timeout-minutes: 10 + timeout-minutes: 5 strategy: matrix: python-version: ["3.10"] @@ -62,10 +62,25 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - name: Setup Build Env + - name: Install Build Tools run: sudo ./scripts/install-build-tools.sh - name: Lint with Pylint run: ./scripts/pylint.sh + shellcheck: + name: Shellcheck + runs-on: ubuntu-22.04 + continue-on-error: true + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Install shellcheck + run: | + sudo apt-get update + sudo apt-get install -y shellcheck + - name: Lint with Shellcheck + run: ./scripts/shellcheck.sh unit-and-integration-test: name: Unit and Integration Tests runs-on: ubuntu-22.04 @@ -74,7 +89,7 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - - name: Setup Build Env + - name: Install Build Tools run: sudo ./scripts/install-build-tools.sh - name: Setup Local Dependencies run: ./scripts/setup-dependencies.sh @@ -84,7 +99,7 @@ jobs: run: ./scripts/test.sh - name: Shorten SHA id: vars - run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" + run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_ENV - uses: actions/upload-artifact@v4 if: ${{ !env.ACT }} name: Archive Test Results @@ -114,4 +129,3 @@ jobs: name: OpenCBDC Transaction Processor docs for ${{ steps.vars.outputs.sha_short }} path: ./doxygen_generated/html/* retention-days: 7 - diff --git a/scripts/benchmarks.sh b/scripts/benchmarks.sh index 030f4f901..19ce3afcc 100755 --- a/scripts/benchmarks.sh +++ b/scripts/benchmarks.sh @@ -64,6 +64,7 @@ done # to the location of this script, the user can run this script from any folder. SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" REPO_TOP_DIR="${SCRIPT_DIR}/.." +BUILD_DIR= if [[ -z "${BUILD_DIR+x}" ]] then BUILD_DIR="${REPO_TOP_DIR}/build" @@ -78,7 +79,8 @@ fi # If the build folder is a relative path, convert it to an absolute path # to avoid potential relative path errors and to improve readability # if the path is written to stdout. -export BUILD_DIR=$(cd "$BUILD_DIR"; pwd) +BUILD_DIR=$(cd "$BUILD_DIR"; pwd) +export BUILD_DIR echo "Build folder: '${BUILD_DIR}'" echo diff --git a/scripts/build-docker.sh b/scripts/build-docker.sh index 68ec4b0d0..5e6b414f4 100755 --- a/scripts/build-docker.sh +++ b/scripts/build-docker.sh @@ -12,7 +12,7 @@ DOCKER_IMAGE_TAG_TWOPHASE=${DOCKER_IMAGE_TAG:-opencbdc-tx-twophase} git submodule init && git submodule update # Build docker image -docker build --target base -t $DOCKER_IMAGE_TAG_BASE -f $SCRIPT_DIR/../Dockerfile $SCRIPT_DIR/.. -docker build --target builder --build-arg BASE_IMAGE=base -t $DOCKER_IMAGE_TAG_BUILDER -f $SCRIPT_DIR/../Dockerfile $SCRIPT_DIR/.. -docker build --target twophase --build-arg BASE_IMAGE=base -t $DOCKER_IMAGE_TAG_TWOPHASE -f $SCRIPT_DIR/../Dockerfile $SCRIPT_DIR/.. -docker build --target atomizer --build-arg BASE_IMAGE=base -t $DOCKER_IMAGE_TAG_ATOMIZER -f $SCRIPT_DIR/../Dockerfile $SCRIPT_DIR/.. +docker build --target base -t "$DOCKER_IMAGE_TAG_BASE" -f "$SCRIPT_DIR"/../Dockerfile "$SCRIPT_DIR"/.. +docker build --target builder --build-arg BASE_IMAGE=base -t "$DOCKER_IMAGE_TAG_BUILDER" -f "$SCRIPT_DIR"/../Dockerfile "$SCRIPT_DIR"/.. +docker build --target twophase --build-arg BASE_IMAGE=base -t "$DOCKER_IMAGE_TAG_TWOPHASE" -f "$SCRIPT_DIR"/../Dockerfile "$SCRIPT_DIR"/.. +docker build --target atomizer --build-arg BASE_IMAGE=base -t "$DOCKER_IMAGE_TAG_ATOMIZER" -f "$SCRIPT_DIR"/../Dockerfile "$SCRIPT_DIR"/.. diff --git a/scripts/build.sh b/scripts/build.sh index 90d07991d..3feb7c181 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -27,7 +27,7 @@ if [ $# -gt 0 ]; then Profiling|--profiling|-p) CMAKE_BUILD_TYPE="Profiling";; Debug|--debug|-d) CMAKE_BUILD_TYPE="Debug";; --help|-h) help;; - *) help $1;; + *) help "$1";; esac fi @@ -37,11 +37,12 @@ echo "Building..." PREFIX="$(cd "$(dirname "$0")"/.. && pwd)/prefix" if [ -z ${BUILD_DIR+x} ]; then - export BUILD_DIR=build + BUILD_DIR=build + export BUILD_DIR fi -mkdir -p $BUILD_DIR -cd $BUILD_DIR +mkdir -p "$BUILD_DIR" +cd "$BUILD_DIR" CMAKE_FLAGS=-DCMAKE_PREFIX_PATH="${PREFIX}" CPUS=1 @@ -60,5 +61,4 @@ fi echo "Building $CMAKE_BUILD_TYPE" eval "cmake -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} ${CMAKE_FLAGS} .." -make -j$CPUS - +make -j"$CPUS" diff --git a/scripts/create-e2e-report.sh b/scripts/create-e2e-report.sh index 51214a4d0..17c63f4e5 100755 --- a/scripts/create-e2e-report.sh +++ b/scripts/create-e2e-report.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash set -e -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + TESTRUN_PATH=$1 function readAndFormatLogs() { @@ -11,15 +11,15 @@ function readAndFormatLogs() { return fi - for logfile in $(ls $logdir); do + for logfile in "$logdir"/*; do logfile_path="$logdir/$logfile" - logfile_content=$(cat $logfile_path) + logfile_content=$(<"$logfile_path") message+="\n
\n$logfile\n\n\`\`\`\n$logfile_content\n\`\`\`\n
\n" done echo "$message" } -testrun_logs="\n
\nView Testrun\n\n\`\`\`\n$(cat $TESTRUN_PATH/testrun.log)\n\`\`\`\n
\n\n" -container_logs=$(readAndFormatLogs $TESTRUN_PATH/logs) +testrun_logs="\n
\nView Testrun\n\n\`\`\`\n$(cat "$TESTRUN_PATH"/testrun.log)\n\`\`\`\n
\n\n" +container_logs=$(readAndFormatLogs "$TESTRUN_PATH"/logs) printf "# E2E Results\n# TestRun Logs\n%b\n\n# Container Logs\n%b\n" "$testrun_logs" "$container_logs" diff --git a/scripts/install-build-tools.sh b/scripts/install-build-tools.sh index 523789d99..9e0ca516a 100755 --- a/scripts/install-build-tools.sh +++ b/scripts/install-build-tools.sh @@ -17,7 +17,7 @@ fi # Supporting these versions for buildflow PYTHON_VERSIONS=("3.10" "3.11" "3.12") -echo "Python3 versions supported: ${PYTHON_VERSIONS[@]}" +echo "Python3 versions supported: ${PYTHON_VERSIONS[*]}" # check if supported version of python3 is already installed, and save the version PY_INSTALLED='' @@ -60,7 +60,7 @@ create_venv_install_python() { if ! $SUDO apt install -y python3-pip; then echo "Failed to install python3-pip" wget https://bootstrap.pypa.io/get-pip.py - $SUDO python${PY_VERSION} get-pip.py + $SUDO python"$PY_VERSION" get-pip.py rm get-pip.py fi # add deadsnakes to download the python venv module @@ -112,7 +112,6 @@ if [[ "$OSTYPE" == "darwin"* ]]; then exit 1 fi - CPUS=$(sysctl -n hw.ncpu) # ensure development environment is set correctly for clang $SUDO xcode-select -switch /Library/Developer/CommandLineTools @@ -121,7 +120,8 @@ if [[ "$OSTYPE" == "darwin"* ]]; then exit 1 fi - brew install llvm@14 googletest google-benchmark lcov make wget cmake bash bc + CPUS=$(sysctl -n hw.ncpu) + echo llvm@14 googletest google-benchmark lcov make wget cmake bash bc | xargs -n 1 -P "$CPUS" brew install brew upgrade bash BREW_ROOT=$(brew --prefix) @@ -132,7 +132,7 @@ if [[ "$OSTYPE" == "darwin"* ]]; then fi GMAKE=/usr/local/bin/gmake if [[ ! -L "$GMAKE" ]]; then - $SUDO ln -s $(xcode-select -p)/usr/bin/gnumake /usr/local/bin/gmake + $SUDO ln -s "$(xcode-select -p)"/usr/bin/gnumake /usr/local/bin/gmake fi # install valid python version if not installed yet @@ -172,8 +172,8 @@ elif [[ "$OSTYPE" == "linux-gnu"* ]]; then $SUDO apt update -y $SUDO apt install -y clang-format-14 clang-tidy-14 - $SUDO ln -sf $(which clang-format-14) /usr/local/bin/clang-format - $SUDO ln -sf $(which clang-tidy-14) /usr/local/bin/clang-tidy + $SUDO ln -sf "$(which clang-format-14)" /usr/local/bin/clang-format + $SUDO ln -sf "$(which clang-tidy-14)" /usr/local/bin/clang-tidy # install valid python version if not installed yet if [[ -z "$PY_INSTALLED" ]]; then @@ -194,9 +194,9 @@ elif [[ "$OSTYPE" == "linux-gnu"* ]]; then MAX_RETRIES=2 while [[ $MAX_RETRIES -gt 0 ]]; do # install python3 valid version and venv module - if $SUDO apt install -y ${FULL_PY}; then + if $SUDO apt install -y "$FULL_PY"; then echo "${FULL_PY} installed successfully" - PY_INSTALLED=${PY_VERS} + PY_INSTALLED="$PY_VERS" break fi MAX_RETRIES=$((MAX_RETRIES - 1)) @@ -215,8 +215,8 @@ if ! which "python${PY_INSTALLED}" &> /dev/null; then exit 1 else # create virtual environment and install python packages for the valid python version - PYTHON_PATH=$(which "python${PY_INSTALLED}") - create_venv_install_python "${PYTHON_PATH}" ${PY_INSTALLED} + PYTHON_PATH=$(which python"$PY_INSTALLED") + create_venv_install_python "$PYTHON_PATH" "$PY_INSTALLED" fi echo "To activate the virtual env to run python, run 'source ./scripts/activate-venv.sh'" diff --git a/scripts/lint.sh b/scripts/lint.sh index c6e4b0936..481cd5686 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -14,6 +14,7 @@ if [ -n "$whitespace_files" ]; then printf '%s\n' "${whitespace_files[@]}" fi +# shellcheck disable=SC2016 newline_files=$(printf '%s' "${check_files[@]}" | xargs -r -I {} bash -c 'test "$(tail -c 1 "{}" | wc -l)" -eq 0 && echo {}' | cat) if [ -n "$newline_files" ] ; then @@ -25,9 +26,12 @@ if [ -n "$whitespace_files" ] || [ -n "$newline_files" ] ; then exit 1 fi -check_format_files=$(git ls-files | grep -E "tools|tests|src|cmake-tests" \ - | grep -E "\..*pp") -clang-format --style=file --Werror --dry-run ${check_format_files[@]} +check_format_files=$(git ls-files | \ + grep -E "tools|tests|src|cmake-tests" | \ + grep -E "\..*pp") + +echo "${check_format_files}" | \ + xargs -n1 -I{} clang-format --style=file --Werror --dry-run {} if ! command -v clang-tidy &>/dev/null; then echo "clang-tidy does not appear to be installed" @@ -46,6 +50,6 @@ fi # use python from the virtual environment for clang-tidy if source "./scripts/activate-venv.sh"; then - python /usr/local/bin/run-clang-tidy.py -p ${BUILD_DIR} "tests/.*/.*\.cpp|src/.*/.*\.cpp|tools/.*/.*\.cpp" + python /usr/local/bin/run-clang-tidy.py -p "$BUILD_DIR" "tests/.*/.*\.cpp|src/.*/.*\.cpp|tools/.*/.*\.cpp" deactivate fi diff --git a/scripts/lua_bench.sh b/scripts/lua_bench.sh index d2ab0ced0..4ed3c4a6d 100755 --- a/scripts/lua_bench.sh +++ b/scripts/lua_bench.sh @@ -29,8 +29,8 @@ for arg in "$@"; do fi done ./build/tools/bench/parsec/lua/lua_bench --component_id=0 \ - --ticket_machine0_endpoint=$IP:7777 --ticket_machine_count=1 \ - --shard_count=1 --shard0_count=1 --shard00_endpoint=$IP:5556 \ - --agent_count=1 --agent0_endpoint=$IP:$PORT \ - --loglevel=$LOGLEVEL scripts/gen_bytecode.lua $N_WALLETS -echo done + --ticket_machine0_endpoint="$IP":7777 --ticket_machine_count=1 \ + --shard_count=1 --shard0_count=1 --shard00_endpoint="$IP":5556 \ + --agent_count=1 --agent0_endpoint="$IP":"$PORT" \ + --loglevel="$LOGLEVEL" scripts/gen_bytecode.lua $N_WALLETS +echo "done"; echo diff --git a/scripts/native-system-benchmark.sh b/scripts/native-system-benchmark.sh index 1b7923fa2..89e1a0f28 100755 --- a/scripts/native-system-benchmark.sh +++ b/scripts/native-system-benchmark.sh @@ -107,7 +107,8 @@ case "$DURATION" in esac if [[ -n "$_help" ]]; then - printf "$usage" "$(basename $0)" + # shellcheck disable=SC2059 + printf "$usage" "$(basename "$0")" exit "$_err" fi @@ -151,7 +152,7 @@ on_int() { printf 'Interrupting all components\n' trap '' SIGINT # avoid interrupting ourself for i in $PIDS; do # intentionally unquoted - if [[ -n "RECORD" ]]; then + if [[ -n "$RECORD" ]]; then kill -SIGINT -- "-$i" else kill -SIGINT -- "$i" @@ -178,7 +179,7 @@ on_int() { if [[ -x "$(which flamegraph.pl)" && -x "$(which stackcollapse-perf.pl)" && -n "$(find "$TESTDIR" -maxdepth 1 -name '*.perf' -print -quit)" ]]; then printf 'Generating Flamegraphs\n' for i in "$TESTDIR"/*.perf; do - waitpid -t 5 -e $(lsof -Qt "$i") &>/dev/null + waitpid -t 5 -e "$(lsof -Qt "$i")" &>/dev/null perf script -i "$i" | stackcollapse-perf.pl > "${i/.perf/.folded}" flamegraph.pl "${i/.perf/.folded}" > "${i/.perf/.svg}" rm -- "${i/.perf/.folded}" @@ -194,7 +195,7 @@ on_int() { printf 'Terminating any remaining processes\n' for i in $PIDS; do # intentionally unquoted - if [[ -n "RECORD" ]]; then + if [[ -n "$RECORD" ]]; then kill -SIGTERM -- "-$i" else kill -SIGTERM -- "$i" @@ -253,7 +254,7 @@ run() { COMP= case "$RECORD" in perf) - $@ &> "$PROC_LOG" & + "$@" &> "$PROC_LOG" & COMP="$!" perf record -F 99 -a -g -o "$PNAME".perf -p "$COMP" &> "$PERF_LOG" & PERFS="$PERFS $!";; @@ -261,7 +262,7 @@ run() { ${DBG} "$@" &> "$PROC_LOG" & COMP="$!";; *) - $@ &> "$PROC_LOG" & + "$@" &> "$PROC_LOG" & COMP="$!";; esac @@ -287,9 +288,9 @@ seed() { if test ! -e "$SEEDDIR"/"$preseed_id"; then printf 'Creating %s\n' "$preseed_id" mkdir -p -- "$SEEDDIR"/"$preseed_id" - pushd "$SEEDDIR"/"$preseed_id" &> /dev/null + pushd "$SEEDDIR"/"$preseed_id" &> /dev/null || exit PID=$(PNAME=seeder BLOCK=1 run "$(getpath seeder)" "$CFG") - popd &> /dev/null + popd &> /dev/null || exit fi printf 'Using %s as seed\n' "$preseed_id" @@ -320,12 +321,13 @@ launch() { for node in $(seq 0 $(( "$raft" - 1 )) ); do export PNAME="$1${id}_$node" PID=$(run "$(getpath "$1")" "$CFG" "$id" "$node") + # shellcheck disable=SC2013 for ep in $(awk -F'[":]' "/$PNAME.*endpoint/ { print \$3 }" "$CFG"); do "$RT"/scripts/wait-for-it.sh -q -t 5 -h localhost -p "$ep" done printf 'Launched logical %s %d, replica %d [PID: %d]\n' "$1" "$id" "$node" "$PID" - if [[ -n "RECORD" ]]; then - PIDS="$PIDS $(getpgid $PID)" + if [[ -n "$RECORD" ]]; then + PIDS="$PIDS $(getpgid "$PID")" else PIDS="$PIDS $PID" fi @@ -333,12 +335,13 @@ launch() { else export PNAME="$1${id}" PID=$(run "$(getpath "$1")" "$CFG" "$id") + # shellcheck disable=SC2013 for ep in $(awk -F'[":]' "/$PNAME.*endpoint/ { print \$3 }" "$CFG"); do "$RT"/scripts/wait-for-it.sh -q -t 5 -h localhost -p "$ep" done printf 'Launched %s %d [PID: %d]\n' "$1" "$id" "$PID" - if [[ -n "RECORD" ]]; then - PIDS="$PIDS $(getpgid $PID)" + if [[ -n "$RECORD" ]]; then + PIDS="$PIDS $(getpgid "$PID")" else PIDS="$PIDS $PID" fi diff --git a/scripts/parsec-run-local.sh b/scripts/parsec-run-local.sh index 643cc79e0..4e020c31d 100755 --- a/scripts/parsec-run-local.sh +++ b/scripts/parsec-run-local.sh @@ -37,27 +37,27 @@ for arg in "$@"; do done mkdir -p logs -echo Running agent on $IP:$PORT -echo Log level = $LOGLEVEL +echo Running agent on "$IP":"$PORT" +echo Log level = "$LOGLEVEL" echo Runner type = $RUNNER_TYPE ./build/src/parsec/runtime_locking_shard/runtime_locking_shardd --shard_count=1 \ - --shard0_count=1 --shard00_endpoint=$IP:5556 \ - --shard00_raft_endpoint=$IP:5557 --node_id=0 --component_id=0 \ - --agent_count=1 --agent0_endpoint=$IP:6666 --ticket_machine_count=1 \ - --ticket_machine0_endpoint=$IP:7777 --loglevel=$LOGLEVEL \ + --shard0_count=1 --shard00_endpoint="$IP":5556 \ + --shard00_raft_endpoint="$IP":5557 --node_id=0 --component_id=0 \ + --agent_count=1 --agent0_endpoint="$IP":6666 --ticket_machine_count=1 \ + --ticket_machine0_endpoint="$IP":7777 --loglevel="$LOGLEVEL" \ > logs/shardd.log & sleep 1 -./scripts/wait-for-it.sh -s $IP:5556 -t 60 -- \ +./scripts/wait-for-it.sh -s "$IP":5556 -t 60 -- \ ./build/src/parsec/ticket_machine/ticket_machined --shard_count=1 \ - --shard0_count=1 --shard00_endpoint=$IP:5556 --node_id=0 \ - --component_id=0 --agent_count=1 --agent0_endpoint=$IP:6666 \ - --ticket_machine_count=1 --ticket_machine0_endpoint=$IP:7777 \ - --loglevel=$LOGLEVEL > logs/ticket_machined.log & + --shard0_count=1 --shard00_endpoint="$IP":5556 --node_id=0 \ + --component_id=0 --agent_count=1 --agent0_endpoint="$IP":6666 \ + --ticket_machine_count=1 --ticket_machine0_endpoint="$IP":7777 \ + --loglevel="$LOGLEVEL" > logs/ticket_machined.log & sleep 1 -./scripts/wait-for-it.sh -s $IP:7777 -t 60 -- ./scripts/wait-for-it.sh -s \ - $IP:5556 -t 60 -- ./build/src/parsec/agent/agentd --shard_count=1 \ - --shard0_count=1 --shard00_endpoint=$IP:5556 --node_id=0 --component_id=0 \ - --agent_count=1 --agent0_endpoint=$IP:$PORT --ticket_machine_count=1 \ - --ticket_machine0_endpoint=$IP:7777 --loglevel=$LOGLEVEL \ +./scripts/wait-for-it.sh -s "$IP":7777 -t 60 -- ./scripts/wait-for-it.sh -s \ + "$IP":5556 -t 60 -- ./build/src/parsec/agent/agentd --shard_count=1 \ + --shard0_count=1 --shard00_endpoint="$IP":5556 --node_id=0 --component_id=0 \ + --agent_count=1 --agent0_endpoint="$IP":"$PORT" --ticket_machine_count=1 \ + --ticket_machine0_endpoint="$IP":7777 --loglevel="$LOGLEVEL" \ --runner_type=$RUNNER_TYPE > logs/agentd.log & diff --git a/scripts/pylint.sh b/scripts/pylint.sh index 9c22df164..2c2fd39ec 100755 --- a/scripts/pylint.sh +++ b/scripts/pylint.sh @@ -1,50 +1,50 @@ #!/usr/bin/env bash ROOT="$(cd "$(dirname "$0")"/.. && pwd)" -PREFIX="${ROOT}"/prefix MIN_CODE_QUALITY=8.0 get_code_score() { - if [ -n "$1" ]; then + if [ -n "$1" ]; then # set minimum quality to user input (int/float) if provided and (5.0 <= input <= 10.0) - if [[ $1 =~ ^([0-9]+)*([\.][0-9])?$ ]]; then - if (( $(echo "$1 >= 5.0" | bc -l) )) && (( $(echo "$1 <= 10.0" | bc -l) )); then - MIN_CODE_QUALITY=$1 - else - # In the future, we want code quality to be at minimum 8.0/10.0 - echo "Code quality score must be between 5.0 and 10.0, inclusive." - echo "Recommended code quality score is >= 8.0." - exit 1 - fi - else - echo "Code quality score must be an integer or floating point number." - exit 1 + if [[ $1 =~ ^([0-9]+)*([\.][0-9])?$ ]]; then + if (( $(echo "$1 >= 5.0" | bc -l) )) && (( $(echo "$1 <= 10.0" | bc -l) )); then + MIN_CODE_QUALITY=$1 + else + # In the future, we want code quality to be at minimum 8.0/10.0 + echo "Code quality score must be between 5.0 and 10.0, inclusive." + echo "Recommended code quality score is >= 8.0." + exit 1 + fi + else + echo "Code quality score must be an integer or floating point number." + exit 1 + fi fi - fi - echo "Linting Python code with minimum quality of $MIN_CODE_QUALITY/10.0..." + echo "Linting Python code with minimum quality of $MIN_CODE_QUALITY/10.0..." } check_pylint() { - if ! command -v pylint &>/dev/null; then - echo "pylint is not installed." - echo "Run 'sudo ./scripts/install-build-tools.sh' to install pylint." - exit 1 - fi + if ! command -v pylint &>/dev/null; then + echo "pylint is not installed." + echo "Run 'sudo ./scripts/install-build-tools.sh' to install pylint." + exit 1 + fi } -get_code_score $1 +get_code_score "$1" if source "${ROOT}/scripts/activate-venv.sh"; then - echo "Virtual environment activated." + echo "Virtual environment activated." else - echo "Failed to activate virtual environment." - exit 1 + echo "Failed to activate virtual environment." + exit 1 fi check_pylint +# shellcheck disable=SC2046 if ! pylint scripts src tests tools --rcfile=.pylintrc \ - --fail-under=$MIN_CODE_QUALITY $(git ls-files '*.py'); then + --fail-under="$MIN_CODE_QUALITY" $(git ls-files '*.py'); then echo "Linting failed, please fix the issues and rerun." - exit 1 + exit 1 else - echo "Linting passed." + echo "Linting passed." fi diff --git a/scripts/setup-dependencies.sh b/scripts/setup-dependencies.sh index ea4b4c771..4559b8275 100755 --- a/scripts/setup-dependencies.sh +++ b/scripts/setup-dependencies.sh @@ -3,7 +3,6 @@ echo "Setting up dependencies..." green="\033[0;32m" -cyan="\033[0;36m" end="\033[0m" set -e @@ -35,7 +34,7 @@ rm -rf ${LEVELDB_VERSION}.tar.gz mv leveldb-${LEVELDB_VERSION} "leveldb-${LEVELDB_VERSION}-${CMAKE_BUILD_TYPE}" cd "leveldb-${LEVELDB_VERSION}-${CMAKE_BUILD_TYPE}" cmake -DCMAKE_INSTALL_PREFIX="${PREFIX}" -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DLEVELDB_BUILD_TESTS=0 -DLEVELDB_BUILD_BENCHMARKS=0 -DBUILD_SHARED_LIBS=0 -DHAVE_SNAPPY=0 . -make -j$CPUS +make -j"$CPUS" make install cd .. @@ -59,11 +58,11 @@ fi mkdir -p build cd build cmake -DCMAKE_INSTALL_PREFIX="${PREFIX}" -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DDISABLE_SSL=1 .. -make -j$CPUS static_lib +make -j"$CPUS" static_lib -echo -e "${green}Copying nuraft to $PREFIX/lib and $PREFIX/include${end}" -cp libnuraft.a $PREFIX/lib -cp -r ../include/libnuraft $PREFIX/include +echo -e "${green}Copying nuraft to ${PREFIX}/lib and ${PREFIX}/include${end}" +cp libnuraft.a "$PREFIX"/lib +cp -r ../include/libnuraft "$PREFIX"/include cd ../.. @@ -72,8 +71,8 @@ rm -rf lua-5.4.3 tar zxf lua-5.4.3.tar.gz rm -rf lua-5.4.3.tar.gz cd lua-5.4.3 -make -j$CPUS -make INSTALL_TOP=$PREFIX install +make -j"$CPUS" +make INSTALL_TOP="$PREFIX" install cd .. if [[ "$OSTYPE" != "darwin"* ]]; then @@ -86,7 +85,7 @@ if [[ "$OSTYPE" != "darwin"* ]]; then mkdir -p curl-${CURL_VERSION}/build cd curl-${CURL_VERSION}/build ../configure --prefix="${PREFIX}" --disable-shared --without-ssl --without-libpsl --without-libidn2 --without-brotli --without-zstd --without-zlib - make -j$CPUS + make -j"$CPUS" make install cd ../.. fi @@ -99,7 +98,7 @@ rm -rf ${JSONCPP_VERSION}.tar.gz mkdir -p jsoncpp-${JSONCPP_VERSION}/build cd jsoncpp-${JSONCPP_VERSION}/build cmake .. -DCMAKE_INSTALL_PREFIX="${PREFIX}" -DBUILD_SHARED_LIBS=NO -DBUILD_STATIC_LIBS=YES -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF -make -j$CPUS +make -j"$CPUS" make install cd ../.. @@ -114,7 +113,7 @@ cd evmc-${EVMC_VER} mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX="${PREFIX}" .. -make -j$CPUS +make -j"$CPUS" make install cd ../.. @@ -149,8 +148,8 @@ mkdir build cd build cmake -DETHASH_BUILD_ETHASH=OFF -DETHASH_BUILD_TESTS=OFF .. cmake --build . --parallel -cp ./lib/keccak/libkeccak.a $PREFIX/lib -cp -r ../include/ethash $PREFIX/include +cp ./lib/keccak/libkeccak.a "$PREFIX"/lib +cp -r ../include/ethash "$PREFIX"/include cd ../.. wget https://gnu.askapache.com/libmicrohttpd/libmicrohttpd-0.9.75.tar.gz @@ -161,7 +160,7 @@ cd libmicrohttpd-0.9.75 mkdir build cd build ../configure --prefix="${PREFIX}" --disable-curl --disable-examples --disable-doc --disable-shared --disable-https -make -j $CPUS +make -j "$CPUS" make install cd ../../ rm -rf libmicrohttpd-0.9.75 diff --git a/scripts/shellcheck.sh b/scripts/shellcheck.sh new file mode 100755 index 000000000..135233a2a --- /dev/null +++ b/scripts/shellcheck.sh @@ -0,0 +1,243 @@ +#!/usr/bin/env bash + +ROOT="$(cd "$(dirname "$0")"/.. && pwd)" + +COLOR="auto" +SEVERITY="warning" +# exclude - waive these diagnostic codes at all severity levels +# include - scan for these diagnostic codes at all severity levels +# includes take precedence over excludes +EXCLUDE_CODES="SC1091" +INCLUDE_CODES="SC2086" +# becomes comma separated string for shellcheck input later + +exit_on_error() { + echo; echo -e "${RED}[ERROR]${RST_COLOR} $1" + echo; echo "Exiting..."; echo + exit 1 +} + +check_shellcheck_install() { + if ! command -v shellcheck &>/dev/null; then + exit_on_error "shellcheck is not installed.\n\n\ + Run '# ./scripts/install-build-tools.sh' to install shellcheck." + fi +} + +exit_bad_arg() { + if [[ -z "$1" ]]; then + exit_on_error "No argument passed to exit_bad_arg function" + fi + show_usage + exit_on_error "Invalid argument: $1" +} + +show_usage() { +cat << EOF +Usage: $0 [options] + +Options: + -h, --help print this help and exit + -C, --color colorize the output, default is 'auto' + -e, --exclude-code exclude specific error code, can have multiple, enter one at a time + -i, --include-code include specific error code, can have multiple, enter one at a time + -S, --severity=LEVEL set severity level (style, info, warning, error), default is 'warning' + +Usage: $ ./scripts/shellcheck.sh [-C|--color=MODE] [-S|--severity=LEVEL] [-e|--exclude-code=CODE] [-i|--include-code=CODE] + +example: $ ./scripts/shellcheck.sh -C auto -S info -e SC2059 -e SC2317 -i SC2034 + +EOF +} + +parse_cli_args() { + echo + while [[ $# -gt 0 ]]; do + optarg= + shft_cnt=1 + # if -- is passed then stop parsing + if [[ "$1" = '--' ]]; then + break + # --option=value + elif [[ "$1" =~ ^-- && ! "$1" =~ ^--$ ]]; then + optarg="${1#*=}"; shft_cnt=1 + # -o=value + elif [[ "$1" =~ ^-- && $# -gt 1 && ! "$2" =~ ^- ]]; then + optarg="$2"; shft_cnt=2 + # -o value + elif [[ "$1" =~ ^-[^-] && $# -gt 1 && ! "$2" =~ ^- ]]; then + optarg="$2"; shft_cnt=2 + # -o + elif [[ "$1" =~ ^-[^-] ]]; then + optarg="${1/??/}" + fi + + case "$1" in + -S*|--severity*) + case "${optarg}" in + style|info|warning|error) + SEVERITY="${optarg}" ;; + *) + exit_bad_arg "$optarg" ;; + esac + shift "$shft_cnt" ;; + -C*|--color*) + case "${optarg}" in + always|auto|never) + COLOR="${optarg}" ;; + *) + exit_bad_arg "$optarg" ;; + esac + shift "$shft_cnt" ;; + -e*|--exclude-code*) + # valid if matching format SC1000-SC9999 + if [[ "${optarg}" =~ ^SC[0-9]{4}$ ]]; then + # if empty, fill with error code, else append comma and new code + if [[ -z "$EXCLUDE_CODES" ]]; then + EXCLUDE_CODES+="${optarg}" + # don't add duplicate exclude code to excludes + elif [[ "${EXCLUDE_CODES[*]}" =~ $optarg ]]; then + exit_on_error "Duplicate error code: $optarg" + else + EXCLUDE_CODES+=",${optarg}" + fi + else + exit_bad_arg "$optarg" + fi + shift "$shft_cnt" ;; + -i*|--include-code*) + if [[ "${optarg}" =~ ^SC[0-9]{4}$ ]]; then + # if variable INCLUDE_CODES is empty, fill with error code + if [[ -z "$INCLUDE_CODES" ]]; then + INCLUDE_CODES+="${optarg}" + # includes override excludes if the same code is in both categories + elif [[ "${INCLUDE_CODES[*]}" =~ $optarg ]]; then + exit_on_error "Duplicate error code: $optarg" + else + INCLUDE_CODES+=",${optarg}" + fi + else + exit_bad_arg "$optarg" + fi + shift "$shft_cnt" ;; + -h|--help) + echo; echo "Command line arguments: $0 $*"; echo + show_usage + exit 0 ;; + *) + exit_bad_arg "$optarg" ;; + esac + done +} + +get_num_cores() { + local CORE_COUNT=1 + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + CORE_COUNT=$(grep -c ^processor /proc/cpuinfo) + elif [[ "$OSTYPE" == "darwin"* ]]; then + CORE_COUNT=$(sysctl -n hw.ncpu) + fi + printf "%d\n" "$CORE_COUNT" +} + +show_shellcheck_args() { + echo -e "Running shellcheck with severity level '${CYAN}${SEVERITY}${RST_COLOR}'" + if [[ -n "$EXCLUDE_CODES" ]]; then + echo + echo -e "Excluding error codes: '${YELLOW}${EXCLUDE_CODES}${RST_COLOR}'" + fi + if [[ -n "$INCLUDE_CODES" ]]; then + echo + echo -e "Including error codes: '${YELLOW}${INCLUDE_CODES}${RST_COLOR}'" + fi + echo +} + +run_shellcheck() { + # two runs of shellcheck used since shellcheck doesn't allow for include codes + # to be checked at all levels while using a severity level for all other codes + # + # 1. include codes only all severity levels (if non-empty) + # 2. exclude codes with the include codes added at the entered severity level + RUN_1_STATUS=0 + RUN_2_STATUS=0 + + # this prevents duplicate scanning of the include codes on the excludes run + EXCLUDES_ALL="$EXCLUDE_CODES" + if [[ -n "$INCLUDE_CODES" && -n "$EXCLUDE_CODES" ]]; then + EXCLUDES_ALL+=",${INCLUDE_CODES}" + elif [[ -n "$INCLUDE_CODES" ]]; then + EXCLUDES_ALL="${INCLUDE_CODES}" + fi + + if command -v git &>/dev/null; then + SHELL_SCRIPTS=$(git ls-files '*.sh') + else + # exclude 3rdparty scripts by specifying the scripts directory + SHELL_SCRIPTS=$(find "$ROOT"/scripts -name '*.sh') + fi + + # scan for only include codes, at all severity levels + if [[ -n "$INCLUDE_CODES" ]]; then + xargs -n 1 -P "$NUM_CORES" shellcheck -x -s bash -C"$COLOR" --include="$INCLUDE_CODES" -S "style" <<< "$SHELL_SCRIPTS" + RUN_1_STATUS="$?" + fi + + # blanket severity level scan, omitting any include codes (to not repeat what shellcheck just scanned for) + xargs -n 1 -P "$NUM_CORES" shellcheck -x -s bash -C"$COLOR" --exclude="$EXCLUDES_ALL" -S "$SEVERITY" <<< "$SHELL_SCRIPTS" + RUN_2_STATUS="$?" + + if [[ "$RUN_1_STATUS" -eq 0 && "$RUN_2_STATUS" -eq 0 ]]; then + echo -e "${GREEN}[PASS]${RST_COLOR} Shellcheck did not detect violations" + return 0 + else + echo -e "${RED}[FAIL]${RST_COLOR} Shellcheck found violations" + return 1 + fi +} + +print_final_message() { + if [[ "$#" -ne 1 ]] || [[ "$1" -ne 0 && "$1" -ne 1 ]]; then + exit_on_error "This function needs a decimal status code as input" + fi + + EXIT_STATUS="$1" + # if no errors found given our parameters, then shellcheck passed + if [[ "$EXIT_STATUS" -eq 0 ]]; then + echo -e "${GREEN}[PASS]${RST_COLOR} Shellcheck did not detect violations" + echo; echo -e "${GREEN}Shellcheck passed.${RST_COLOR}"; echo + else + echo -e "${RED}[FAIL]${RST_COLOR} Shellcheck found unexcused violations" + echo; echo -e "${RED}Shellcheck failed. Please fix the issues and try again.${RST_COLOR}" + fi + exit "$EXIT_STATUS" +} + +main() { + check_shellcheck_install + parse_cli_args "$@" + + if [[ "$COLOR" != "never" ]]; then + RED="\e[31m" + GREEN="\e[32m" + YELLOW="\e[33m" + CYAN="\e[36m" + RST_COLOR="\e[0m" + else + RED="" + GREEN="" + YELLOW="" + CYAN="" + RST_COLOR="" + fi + + NUM_CORES=$(get_num_cores) + show_shellcheck_args + + run_shellcheck + STATUS="$?" + + print_final_message "$STATUS" +} + +main "$@" diff --git a/scripts/test-e2e-minikube.sh b/scripts/test-e2e-minikube.sh index d25900163..a3c12b9c0 100755 --- a/scripts/test-e2e-minikube.sh +++ b/scripts/test-e2e-minikube.sh @@ -7,49 +7,49 @@ BUILD_DOCKER=${TESTRUN_BUILD_DOCKER:-1} # Make sure we have the necessary tools installed required_executables=(minikube docker go helm kubectl) -for e in ${required_executables[@]}; do - if ! command -v $e &> /dev/null; then +for e in "${required_executables[@]}"; do + if ! command -v "$e" &> /dev/null; then echo "'$e' command not be found! This is required to run. Please install it." exit 1 fi done # Start minikube cluster with opencbdc profile -minikube_status=$(minikube -p $MINIKUBE_PROFILE status | grep apiserver | awk '{ print $2 }') +minikube_status=$(minikube -p "$MINIKUBE_PROFILE" status | grep apiserver | awk '{ print $2 }') if [ "$minikube_status" != "Running" ]; then echo "🔄 Starting minkube cluster with profile '$MINIKUBE_PROFILE'..." - minikube -p $MINIKUBE_PROFILE start + minikube -p "$MINIKUBE_PROFILE" start else echo "✅ minikube cluster with profile '$MINIKUBE_PROFILE' is currently running." fi # Update Kubernetes context to default to this minikube cluster profile -minikube -p $MINIKUBE_PROFILE update-context +minikube -p "$MINIKUBE_PROFILE" update-context # Connect host docker cli to docker daemon in minikube vm -eval $(minikube -p $MINIKUBE_PROFILE docker-env) +eval "$(minikube -p "$MINIKUBE_PROFILE" docker-env)" # Build docker image if [[ $BUILD_DOCKER -eq 1 ]]; then echo "🔄 Building docker image for 'opencbdc-tx'" - $SCRIPT_DIR/build-docker.sh + "$SCRIPT_DIR"/build-docker.sh fi # Change to the test directory and fetch dependencies -cd $SCRIPT_DIR/../charts/tests +cd "$SCRIPT_DIR"/../charts/tests echo "🔄 Downloading Go dependencies for testing..." go mod download -x # Set testrun_id and path to store logs from testrun and containers TESTRUN_ID=${TESTRUN_ID:-$(uuidgen)} -TESTRUN_PATH=$SCRIPT_DIR/../testruns/$TESTRUN_ID -TESTRUN_LOG_PATH="$TESTRUN_PATH/testrun.log" -mkdir -p $TESTRUN_PATH +TESTRUN_PATH="$SCRIPT_DIR"/../testruns/"$TESTRUN_ID" +TESTRUN_LOG_PATH="$TESTRUN_PATH"/testrun.log +mkdir -p "$TESTRUN_PATH" # Run test and output test logs to console as well as a file for reference later echo "🔄 Running tests..." -TESTRUN_ID=$TESTRUN_ID go test 2>&1 | tee -a $TESTRUN_LOG_PATH +TESTRUN_ID=$TESTRUN_ID go test 2>&1 | tee -a "$TESTRUN_LOG_PATH" # Generate a markdown report of the testrun with logs -$SCRIPT_DIR/create-e2e-report.sh $TESTRUN_PATH >> $TESTRUN_PATH/report.md -echo "View test results at $(realpath $TESTRUN_PATH)" +"$SCRIPT_DIR"/create-e2e-report.sh "$TESTRUN_PATH" >> "$TESTRUN_PATH"/report.md +echo "View test results at $(realpath "$TESTRUN_PATH")" diff --git a/scripts/test-transaction.sh b/scripts/test-transaction.sh index aeb4e3e78..474c904af 100644 --- a/scripts/test-transaction.sh +++ b/scripts/test-transaction.sh @@ -11,27 +11,27 @@ wallet1="wallet1.dat" client1="client1.dat" # Create wallet0 and save wallet id to var, mint -wallet0_id=$($BUILD_DIR/src/uhs/client/client-cli $config_file $client0 $wallet0 mint 10 10 | grep -E '^[^\W]+$') +wallet0_id=$($BUILD_DIR/src/uhs/client/client-cli "$config_file" $client0 $wallet0 mint 10 10 | grep -E '^[^\W]+$') echo "Wallet0_PK: $wallet0_id" # Sync wallet0 -$BUILD_DIR/src/uhs/client/client-cli $config_file $client0 $wallet0 sync +$BUILD_DIR/src/uhs/client/client-cli "$config_file" $client0 $wallet0 sync # Create wallet1 and save to var -wallet1_id=$($BUILD_DIR/src/uhs/client/client-cli $config_file $client1 $wallet1 newaddress | grep -E '^[^\W]+$') +wallet1_id=$($BUILD_DIR/src/uhs/client/client-cli "$config_file" $client1 $wallet1 newaddress | grep -E '^[^\W]+$') echo "Wallet1_PK: $wallet1_id" # Simulate transaction -importinput=$($BUILD_DIR/src/uhs/client/client-cli $config_file $client0 $wallet0 send 33 $wallet1_id | grep -E '^[a-zA-z0-9]{70,}') +importinput=$($BUILD_DIR/src/uhs/client/client-cli "$config_file" $client0 $wallet0 send 33 "$wallet1_id" | grep -E '^[a-zA-z0-9]{70,}') echo "ImportInput: $importinput" -$BUILD_DIR/src/uhs/client/client-cli $config_file $client1 $wallet1 importinput $importinput +$BUILD_DIR/src/uhs/client/client-cli "$config_file" $client1 $wallet1 importinput "$importinput" # Sync wallet1 -$BUILD_DIR/src/uhs/client/client-cli $config_file $client1 $wallet1 sync +$BUILD_DIR/src/uhs/client/client-cli "$config_file" $client1 $wallet1 sync # Sync wallet1 -$BUILD_DIR/src/uhs/client/client-cli $config_file $client1 $wallet1 info +$BUILD_DIR/src/uhs/client/client-cli "$config_file" $client1 $wallet1 info diff --git a/scripts/test.sh b/scripts/test.sh index 615a8acb5..5021f55cd 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -129,7 +129,8 @@ fi # If the build folder is a relative path, convert it to an absolute path # to avoid potential relative path errors and to improve readability # if the path is written to stdout. -export BUILD_DIR=$(cd "$BUILD_DIR"; pwd) +BUILD_DIR=$(cd "$BUILD_DIR"; pwd) +export BUILD_DIR echo "Build folder: '${BUILD_DIR}'" echo diff --git a/scripts/wait-for-it.sh b/scripts/wait-for-it.sh index d990e0d36..25a9dd4b4 100755 --- a/scripts/wait-for-it.sh +++ b/scripts/wait-for-it.sh @@ -33,10 +33,10 @@ wait_for() while : do if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then - nc -z $WAITFORIT_HOST $WAITFORIT_PORT + nc -z "$WAITFORIT_HOST" "$WAITFORIT_PORT" WAITFORIT_result=$? else - (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1 + (echo -n > /dev/tcp/"$WAITFORIT_HOST"/"$WAITFORIT_PORT") >/dev/null 2>&1 WAITFORIT_result=$? fi if [[ $WAITFORIT_result -eq 0 ]]; then @@ -46,25 +46,25 @@ wait_for() fi sleep 1 done - return $WAITFORIT_result + return "$WAITFORIT_result" } wait_for_wrapper() { # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 - if [[ $WAITFORIT_QUIET -eq 1 ]]; then - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & + if [[ "$WAITFORIT_QUIET" -eq 1 ]]; then + timeout "$WAITFORIT_BUSYTIMEFLAG" "$WAITFORIT_TIMEOUT" "$0" --quiet --child --host="$WAITFORIT_HOST" --port="$WAITFORIT_PORT" --timeout="$WAITFORIT_TIMEOUT" & else - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & + timeout "$WAITFORIT_BUSYTIMEFLAG" "$WAITFORIT_TIMEOUT" "$0" --child --host="$WAITFORIT_HOST" --port="$WAITFORIT_PORT" --timeout="$WAITFORIT_TIMEOUT" & fi WAITFORIT_PID=$! - trap "kill -INT -$WAITFORIT_PID" INT - wait $WAITFORIT_PID - WAITFORIT_RESULT=$? + trap 'kill -INT -"$WAITFORIT_PID"' INT + wait "$WAITFORIT_PID" + WAITFORIT_RESULT="$?" if [[ $WAITFORIT_RESULT -ne 0 ]]; then echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" fi - return $WAITFORIT_RESULT + return "$WAITFORIT_RESULT" } # process arguments @@ -72,7 +72,7 @@ while [[ $# -gt 0 ]] do case "$1" in *:* ) - WAITFORIT_hostport=(${1//:/ }) + WAITFORIT_hostport=("${1//:/ }") WAITFORIT_HOST=${WAITFORIT_hostport[0]} WAITFORIT_PORT=${WAITFORIT_hostport[1]} shift 1 @@ -143,14 +143,14 @@ WAITFORIT_QUIET=${WAITFORIT_QUIET:-0} # Check to see if timeout is from busybox? WAITFORIT_TIMEOUT_PATH=$(type -p timeout) -WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH) +WAITFORIT_TIMEOUT_PATH=$(realpath "$WAITFORIT_TIMEOUT_PATH" 2>/dev/null || readlink -f "$WAITFORIT_TIMEOUT_PATH") WAITFORIT_BUSYTIMEFLAG="" -if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then +if [[ "$WAITFORIT_TIMEOUT_PATH" =~ "busybox" ]]; then WAITFORIT_ISBUSY=1 # Check if busybox timeout uses -t flag # (recent Alpine versions don't support -t anymore) - if timeout &>/dev/stdout | grep -q -e '-t '; then + if timeout |& tee /dev/stdout | grep -q -e '-t '; then WAITFORIT_BUSYTIMEFLAG="-t" fi else @@ -171,7 +171,7 @@ else fi fi -if [[ $WAITFORIT_CLI != "" ]]; then +if [[ -n "${WAITFORIT_CLI[*]}" ]]; then if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess" exit $WAITFORIT_RESULT