@@ -44,6 +44,118 @@ add_brew_bins_to_path() {
4444 add_path " $brew_prefix " /sbin
4545}
4646
47+ # Function to get file modification time.
48+ get_file_mtime () {
49+ local file=$1
50+ if [ " $( uname -s) " = " Darwin" ]; then
51+ stat -f " %m" " $file " 2> /dev/null || echo 0
52+ else
53+ stat -c " %Y" " $file " 2> /dev/null || echo 0
54+ fi
55+ }
56+
57+ # Function to terminate a process and its direct children.
58+ terminate_process_tree () {
59+ local pid=$1
60+ local children child
61+ children=$( pgrep -P " $pid " 2> /dev/null || true)
62+ kill -TERM " $pid " > /dev/null 2>&1 || true
63+ for child in $children ; do
64+ terminate_process_tree " $child "
65+ done
66+ sleep 2
67+ kill -KILL " $pid " > /dev/null 2>&1 || true
68+ for child in $children ; do
69+ terminate_process_tree " $child "
70+ done
71+ }
72+
73+ # Function to run a command with an inactivity watchdog.
74+ run_with_inactivity_watchdog () {
75+ local timeout_secs=" ${SETUP_PHP_BREW_INACTIVITY_TIMEOUT:- 180} "
76+ local poll_secs=" ${SETUP_PHP_BREW_WATCHDOG_POLL:- 5} "
77+ local tmp_dir fifo log_file timeout_file command_pid reader_pid monitor_pid exit_code
78+ tmp_dir=" $( mktemp -d " ${TMPDIR:-/ tmp} /setup-php-brew.XXXXXX" ) " || return 1
79+ fifo=" $tmp_dir /output.fifo"
80+ log_file=" $tmp_dir /output.log"
81+ timeout_file=" $tmp_dir /timed_out"
82+ mkfifo " $fifo " || {
83+ rm -rf " $tmp_dir "
84+ return 1
85+ }
86+ : > " $log_file "
87+
88+ (" $@ " > " $fifo " 2>&1 ) &
89+ command_pid=$!
90+
91+ (
92+ while IFS= read -r line || [ -n " $line " ]; do
93+ printf ' %s\n' " $line "
94+ printf ' %s\n' " $line " >> " $log_file "
95+ done < " $fifo "
96+ ) &
97+ reader_pid=$!
98+
99+ (
100+ local last_activity current_activity now
101+ last_activity=$( get_file_mtime " $log_file " )
102+ while kill -0 " $command_pid " > /dev/null 2>&1 ; do
103+ sleep " $poll_secs "
104+ current_activity=$( get_file_mtime " $log_file " )
105+ [ " $current_activity " -gt " $last_activity " ] && last_activity=" $current_activity "
106+ now=$( date +%s)
107+ if [ $(( now - last_activity)) -ge " $timeout_secs " ]; then
108+ printf " \nsetup-php: brew produced no output for %ss; terminating and retrying...\n" " $timeout_secs " >&2
109+ : > " $timeout_file "
110+ terminate_process_tree " $command_pid "
111+ break
112+ fi
113+ done
114+ ) &
115+ monitor_pid=$!
116+
117+ wait " $command_pid "
118+ exit_code=$?
119+ wait " $reader_pid " 2> /dev/null || true
120+ kill " $monitor_pid " > /dev/null 2>&1 || true
121+ wait " $monitor_pid " 2> /dev/null || true
122+
123+ if [ -e " $timeout_file " ]; then
124+ rm -rf " $tmp_dir "
125+ return 124
126+ fi
127+
128+ rm -rf " $tmp_dir "
129+ return " $exit_code "
130+ }
131+
132+ # Function to run brew with retries and an inactivity watchdog.
133+ safe_brew () {
134+ local max_attempts=" ${SETUP_PHP_BREW_RETRY_ATTEMPTS:- 3} "
135+ local attempt=1
136+ local exit_code=0
137+
138+ if [ " ${SETUP_PHP_BREW_WATCHDOG:- true} " = " false" ]; then
139+ brew " $@ "
140+ return $?
141+ fi
142+
143+ while [ " $attempt " -le " $max_attempts " ]; do
144+ run_with_inactivity_watchdog brew " $@ " && return 0
145+ exit_code=$?
146+
147+ if [ " $attempt " -ge " $max_attempts " ]; then
148+ return " $exit_code "
149+ fi
150+
151+ printf " setup-php: retrying brew command (attempt %s/%s, exit %s)\n" " $(( attempt + 1 )) " " $max_attempts " " $exit_code " >&2
152+ sleep " $(( attempt * 5 )) "
153+ attempt=$(( attempt + 1 ))
154+ done
155+
156+ return " $exit_code "
157+ }
158+
47159# Function to add brew.
48160add_brew () {
49161 brew_prefix=" $( get_brew_prefix) "
@@ -74,6 +186,7 @@ configure_brew() {
74186 export HOMEBREW_NO_ENV_HINTS=1
75187 export HOMEBREW_NO_INSTALL_CLEANUP=1
76188 export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
189+ export HOMEBREW_DOWNLOAD_CONCURRENCY=" ${HOMEBREW_DOWNLOAD_CONCURRENCY:- 6} "
77190 export brew_opts
78191 export brew_path
79192 export brew_path_dir
0 commit comments