11#! /usr/bin/env bash
22
3- set -e
3+ set -euo pipefail
44
55venv_python=" ${PYTHON_WHEEL_TEST_EXECUTABLE:- } "
66if [[ -z " $venv_python " ]]; then
@@ -29,33 +29,110 @@ python -m pip install -U pip
2929pip install pytest
3030
3131cleanup=true
32+ background_pids=()
33+ failed_pids=()
34+ cleanup_done=false
3235
33- trap '
34- failed_pids=()
35- for pid in $(jobs -p); do
36- if kill -0 $pid >/dev/null 2>&1; then
37- # Background process is still running - kill it.
38- kill $pid
36+ is_windows_shell=false
37+ case " ${OSTYPE:- } " in
38+ msys* |cygwin* )
39+ is_windows_shell=true
40+ ;;
41+ esac
42+ if [[ " ${OS:- } " == " Windows_NT" ]]; then
43+ is_windows_shell=true
44+ fi
45+
46+ terminate_pid_tree () {
47+ local pid=" $1 "
48+
49+ if ! kill -0 " $pid " > /dev/null 2>&1 ; then
50+ return 0
51+ fi
52+
53+ if [[ " $is_windows_shell " == true ]] && command -v taskkill > /dev/null 2>&1 ; then
54+ taskkill //PID " $pid " //T //F > /dev/null 2>&1 || true
55+ else
56+ kill -TERM " -$pid " > /dev/null 2>&1 || kill " $pid " > /dev/null 2>&1 || true
57+ fi
58+
59+ local deadline=$(( SECONDS + 20 ))
60+ while kill -0 " $pid " > /dev/null 2>&1 ; do
61+ if (( SECONDS >= deadline )) ; then
62+ if [[ " $is_windows_shell " == true ]] && command -v taskkill > /dev/null 2>&1 ; then
63+ taskkill //PID " $pid " //T //F > /dev/null 2>&1 || true
64+ else
65+ kill -KILL " -$pid " > /dev/null 2>&1 || kill -9 " $pid " > /dev/null 2>&1 || true
66+ fi
67+ break
68+ fi
69+ sleep 1
70+ done
71+
72+ wait " $pid " 2> /dev/null || true
73+ }
74+
75+ run_command () {
76+ local cmd=" $1 "
77+ if [[ " $cmd " == * .py ]] && [[ " $cmd " != * [[:space:]]* ]]; then
78+ python " $cmd "
79+ else
80+ bash -lc " $cmd "
81+ fi
82+ }
83+
84+ launch_background_command () {
85+ local cmd=" $1 "
86+ if [[ " $is_windows_shell " == true ]]; then
87+ bash -lc " $cmd " &
88+ elif command -v setsid > /dev/null 2>&1 ; then
89+ setsid bash -lc " $cmd " &
90+ else
91+ bash -lc " $cmd " &
92+ fi
93+ }
94+
95+ cleanup_background_jobs () {
96+ local pid=" "
97+ for pid in " ${background_pids[@]} " ; do
98+ if kill -0 " $pid " > /dev/null 2>&1 ; then
99+ terminate_pid_tree " $pid "
39100 else
40- exit_status=$?
41- if [[ $exit_status -eq 0 ]]; then
101+ if wait " $pid " ; then
42102 echo " Background task $pid already exited with zero status."
43103 else
104+ local exit_status=$?
44105 echo " Background task $pid exited with nonzero status ($exit_status )."
45106 failed_pids+=(" $pid " )
46107 fi
47108 fi
48109 done
110+ }
49111
112+ cleanup_virtualenv () {
50113 if [[ " $cleanup " == " true" ]]; then
51- echo "→ Removing $venv"; rm -rf "$venv"
114+ echo " → Removing $venv "
115+ rm -rf " $venv "
52116 fi
117+ }
118+
119+ on_exit () {
120+ if [[ " $cleanup_done " == " true" ]]; then
121+ return 0
122+ fi
123+ cleanup_done=true
124+ set +e
125+ cleanup_background_jobs
126+ cleanup_virtualenv
53127
54128 if [[ ${# failed_pids[@]} -gt 0 ]]; then
55129 echo " The following background processes exited with nonzero status: ${failed_pids[@]} "
56- exit 1
130+ return 1
57131 fi
58- ' EXIT
132+ return 0
133+ }
134+
135+ trap on_exit EXIT
59136
60137while [[ $# -gt 0 ]]; do
61138 case $1 in
@@ -67,19 +144,16 @@ while [[ $# -gt 0 ]]; do
67144 ;;
68145 -b|--background)
69146 echo " → Launching background task: $2 "
70- $2 &
147+ launch_background_command " $2 "
148+ background_pids+=(" $! " )
71149 echo " ... started with PID: $! "
72150 sleep 5
73151 shift
74152 shift
75153 ;;
76154 -f|--foreground)
77155 echo " → Starting foreground task: $2 "
78- if [[ " $2 " == * .py ]] && [[ " $2 " != * [[:space:]]* ]]; then
79- python " $2 "
80- else
81- $2
82- fi
156+ run_command " $2 "
83157 shift
84158 shift
85159 ;;
@@ -91,3 +165,8 @@ while [[ $# -gt 0 ]]; do
91165 ;;
92166 esac
93167done
168+
169+ cleanup_status=0
170+ on_exit || cleanup_status=$?
171+ trap - EXIT
172+ exit " $cleanup_status "
0 commit comments