setup-php 2.36.0 → 2.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,6 +9,8 @@ Function Get-SqlsrvReleaseVersion() {
9
9
  return '5.10.1'
10
10
  } elseif ($version -eq '8.0') {
11
11
  return '5.11.1'
12
+ } elseif ($version -match '8.[1-2]') {
13
+ return '5.12.0'
12
14
  } else {
13
15
  return 'latest'
14
16
  }
@@ -6,6 +6,8 @@ get_sqlsrv_version() {
6
6
  echo '5.10.1'
7
7
  elif [[ "${version:?}" =~ 8.0 ]]; then
8
8
  echo '5.11.1'
9
+ elif [[ "${version:?}" =~ 8.[1-2] ]]; then
10
+ echo '5.12.0'
9
11
  else
10
12
  # Return an empty string so that pecl will install the latest version.
11
13
  echo ''
@@ -127,6 +127,51 @@ setup_cached_versions() {
127
127
  run_script "php-ubuntu" "$version" "${debug:?}" "${ts:?}"
128
128
  }
129
129
 
130
+ # Function to get the link path for an alternative.
131
+ alternative_link() {
132
+ case "$1" in
133
+ php-cgi-bin) echo "/usr/lib/cgi-bin/php" ;;
134
+ php-fpm) echo "/usr/sbin/php-fpm" ;;
135
+ php-fpm.sock) echo "/run/php/php-fpm.sock" ;;
136
+ *) echo "/usr/bin/$1" ;;
137
+ esac
138
+ }
139
+
140
+ # Function to get the target path for an alternative.
141
+ alternative_target() {
142
+ case "$1" in
143
+ php-cgi-bin) echo "/usr/lib/cgi-bin/php$version" ;;
144
+ php-fpm) echo "/usr/sbin/php-fpm$version" ;;
145
+ php-fpm.sock) echo "/run/php/php$version-fpm.sock" ;;
146
+ *) echo "/usr/bin/$1$version" ;;
147
+ esac
148
+ }
149
+
150
+ # Function to register an alternative if the versioned binary exists but is missing.
151
+ register_alternative() {
152
+ local tool=$1
153
+ local link target priority state_file
154
+ target="$(alternative_target "$tool")"
155
+ [ -e "$target" ] || return 0
156
+ state_file="/var/lib/dpkg/alternatives/$tool"
157
+ if sudo test -r "$state_file" && sudo grep -Fxq "$target" "$state_file"; then
158
+ return 0
159
+ fi
160
+ link="$(alternative_link "$tool")"
161
+ priority="${version//./}"
162
+ sudo update-alternatives --install "$link" "$tool" "$target" "$priority" >/dev/null 2>&1
163
+ }
164
+
165
+ # Function to register and switch an alternative.
166
+ set_alternative() {
167
+ local tool=$1
168
+ local target
169
+ target="$(alternative_target "$tool")"
170
+ [ -e "$target" ] || return 0
171
+ register_alternative "$tool" || return 1
172
+ sudo update-alternatives --set "$tool" "$target" >/dev/null 2>&1
173
+ }
174
+
130
175
  # Function to add PECL.
131
176
  add_pecl() {
132
177
  add_devtools phpize >/dev/null 2>&1
@@ -143,16 +188,11 @@ switch_version() {
143
188
  tools=("$@")
144
189
  to_wait=()
145
190
  if ! (( ${#tools[@]} )); then
146
- tools+=(pear pecl php phar phar.phar php-cgi php-config phpize phpdbg)
147
- [ -e /usr/lib/cgi-bin/php"$version" ] && sudo update-alternatives --set php-cgi-bin /usr/lib/cgi-bin/php"$version" & to_wait+=($!)
148
- [ -e /usr/sbin/php-fpm"$version" ] && sudo update-alternatives --set php-fpm /usr/sbin/php-fpm"$version" & to_wait+=($!)
149
- [ -e /run/php/php"$version"-fpm.sock ] && sudo update-alternatives --set php-fpm.sock /run/php/php"$version"-fpm.sock & to_wait+=($!)
191
+ tools+=(php-cgi-bin php-fpm php-fpm.sock pear pecl php phar phar.phar php-cgi php-config phpize phpdbg)
150
192
  fi
151
193
  for tool in "${tools[@]}"; do
152
- if [ -e "/usr/bin/$tool$version" ]; then
153
- sudo update-alternatives --set "$tool" /usr/bin/"$tool$version" &
154
- to_wait+=($!)
155
- fi
194
+ set_alternative "$tool" &
195
+ to_wait+=($!)
156
196
  done
157
197
  wait "${to_wait[@]}"
158
198
  }
@@ -187,7 +227,7 @@ update_php() {
187
227
  # Function to install PHP.
188
228
  add_php() {
189
229
  if [ "${runner:?}" = "self-hosted" ] || [ "${use_package_cache:-true}" = "false" ]; then
190
- if [[ "$version" =~ ${nightly_versions:?} || "$ts" = "zts" ]]; then
230
+ if [[ "$version" =~ ${php_builder_versions:?} || "$ts" = "zts" ]]; then
191
231
  setup_php_builder
192
232
  else
193
233
  add_packaged_php
@@ -115,6 +115,18 @@ Function Set-ComposerEnv() {
115
115
  }
116
116
  }
117
117
 
118
+ # Function to identify latest-like URLs that should bypass the persistent cache.
119
+ Function Test-MutableToolUrl() {
120
+ Param(
121
+ [Parameter(Position = 0, Mandatory = $true)]
122
+ [string]
123
+ $Url
124
+ )
125
+ $mutableUrlRegex = '(^|[/?#._=-])(latest|stable|preview|snapshot|nightly|master)([/?#._=-]|$)|/releases/latest/download/'
126
+ $versionLikeRegex = '(^|[^0-9])[0-9]+\.[0-9]+([.-][0-9A-Za-z]+)*'
127
+ return ($Url -match $mutableUrlRegex) -or (($Url -match '\.phar([?#].*)?$') -and -not ($Url -match $versionLikeRegex))
128
+ }
129
+
118
130
  # Function to extract tool version.
119
131
  Function Get-ToolVersion() {
120
132
  Param (
@@ -158,12 +170,7 @@ Function Add-ToolsHelper() {
158
170
  } elseif($tool -eq "cs2pr") {
159
171
  (Get-Content $bin_dir/cs2pr).replace('exit(9)', 'exit(0)') | Set-Content $bin_dir/cs2pr
160
172
  } elseif($tool -eq "deployer") {
161
- if(Test-Path $composer_bin\deployer.phar.bat) {
162
- Copy-Item $composer_bin\deployer.phar.bat -Destination $composer_bin\dep.bat
163
- }
164
- if(Test-Path $composer_bin\dep.bat) {
165
- Copy-Item $composer_bin\dep.bat -Destination $composer_bin\deployer.bat
166
- }
173
+ Copy-Item $bin_dir\deployer.bat -Destination $bin_dir\dep.bat
167
174
  } elseif($tool -eq "phan") {
168
175
  $extensions += @('fileinfo', 'ast')
169
176
  } elseif($tool -eq "phinx") {
@@ -205,30 +212,51 @@ Function Add-Tool() {
205
212
  [Parameter(Position = 2, Mandatory = $false)]
206
213
  $ver_param
207
214
  )
208
- if (Test-Path $bin_dir\$tool) {
209
- Copy-Item $bin_dir\$tool -Destination $bin_dir\$tool.old -Force
210
- }
215
+ $urls = $urls -split ','
211
216
  $tool_path = "$bin_dir\$tool"
212
- foreach ($url in $urls){
213
- if (($url | Split-Path -Extension) -eq ".exe") {
214
- $tool_path = "$tool_path.exe"
215
- }
216
- try {
217
- $status_code = (Invoke-WebRequest -Passthru -Uri $url -OutFile $tool_path).StatusCode
218
- } catch {
219
- if($url -match '.*github.com.*releases.*latest.*') {
220
- try {
221
- $url = $url.replace("releases/latest/download", "releases/download/" + ([regex]::match((Get-File -Url ($url.split('/release')[0] + "/releases")).Content, "([0-9]+\.[0-9]+\.[0-9]+)/" + ($url.Substring($url.LastIndexOf("/") + 1))).Groups[0].Value).split('/')[0])
222
- $status_code = (Invoke-WebRequest -Passthru -Uri $url -OutFile $tool_path).StatusCode
223
- } catch { }
217
+ $is_exe = ((($urls[0] | Split-Path -Extension).ToLowerInvariant()) -eq '.exe')
218
+ if ($is_exe) { $tool_path = "$tool_path.exe" }
219
+ $tool_ext = if ($is_exe) { '.exe' } else { '' }
220
+ $url_stream = [System.IO.MemoryStream]::New([System.Text.Encoding]::UTF8.GetBytes($urls[0]))
221
+ $cache_key = (Get-FileHash -InputStream $url_stream -Algorithm SHA256).Hash.Substring(0, 16)
222
+ $cache_path = "$env:TEMP\$tool-$cache_key$tool_ext"
223
+ $use_cache = -not (Test-MutableToolUrl $urls[0])
224
+ $status_code = 200
225
+ if ($use_cache -and (Test-Path $cache_path -PathType Leaf)) {
226
+ Copy-Item $cache_path -Destination $tool_path -Force
227
+ } else {
228
+ $backup_path = "$tool_path.bak"
229
+ if (Test-Path $tool_path) { Copy-Item $tool_path -Destination $backup_path -Force }
230
+ foreach ($url in $urls){
231
+ try {
232
+ $status_code = (Invoke-WebRequest -Passthru -Uri $url -OutFile $tool_path).StatusCode
233
+ } catch {
234
+ if($url -match '.*github.com.*releases.*latest.*') {
235
+ try {
236
+ $url = $url.replace("releases/latest/download", "releases/download/" + ([regex]::match((Get-File -Url ($url.split('/release')[0] + "/releases")).Content, "([0-9]+\.[0-9]+\.[0-9]+)/" + ($url.Substring($url.LastIndexOf("/") + 1))).Groups[0].Value).split('/')[0])
237
+ $status_code = (Invoke-WebRequest -Passthru -Uri $url -OutFile $tool_path).StatusCode
238
+ } catch {
239
+ $status_code = 0
240
+ }
241
+ } else {
242
+ $status_code = 0
243
+ }
244
+ }
245
+ if($status_code -eq 200 -and (Test-Path $tool_path)) {
246
+ if ($use_cache) {
247
+ Copy-Item $tool_path -Destination $cache_path -Force
248
+ }
249
+ break
224
250
  }
225
251
  }
226
- if($status_code -eq 200 -and (Test-Path $tool_path)) {
227
- break
252
+ if ($status_code -ne 200 -and (Test-Path $backup_path)) {
253
+ Copy-Item $backup_path -Destination $tool_path -Force
228
254
  }
255
+ Remove-Item $backup_path -Force -ErrorAction SilentlyContinue
229
256
  }
230
257
 
231
- if (((Get-ChildItem -Path $bin_dir/* | Where-Object Name -Match "^$tool(.exe|.phar)*$").Count -gt 0)) {
258
+ $escaped_tool = [regex]::Escape($tool)
259
+ if (((Get-ChildItem -Path $bin_dir/* | Where-Object Name -Match "^$escaped_tool(\.exe|\.phar)?$").Count -gt 0)) {
232
260
  $bat_content = @()
233
261
  $bat_content += "@ECHO off"
234
262
  $bat_content += "setlocal DISABLEDELAYEDEXPANSION"
@@ -242,8 +270,6 @@ Function Add-Tool() {
242
270
  } else {
243
271
  if($tool -eq "composer") {
244
272
  $env:fail_fast = 'true'
245
- } elseif (Test-Path $bin_dir\$tool.old) {
246
- Copy-Item $bin_dir\$tool.old -Destination $bin_dir\$tool -Force
247
273
  }
248
274
  Add-Log $cross $tool "Could not add $tool"
249
275
  }
@@ -113,6 +113,16 @@ set_composer_env() {
113
113
  fi
114
114
  }
115
115
 
116
+ # Function to identify latest-like URLs that should bypass the persistent cache.
117
+ is_mutable_tool_url() {
118
+ local tool_url=$1
119
+ local mutable_url_regex='(^|[/?#._=-])(latest|stable|preview|snapshot|nightly|master)([/?#._=-]|$)|/releases/latest/download/'
120
+ local version_like_regex='(^|[^0-9])[0-9]+\.[0-9]+([.-][0-9A-Za-z]+)*'
121
+ [[ "$tool_url" =~ $mutable_url_regex ]] && return 0
122
+ [[ "$tool_url" =~ \.phar([?#].*)?$ && ! "$tool_url" =~ $version_like_regex ]] && return 0
123
+ return 1
124
+ }
125
+
116
126
  # Helper function to configure tools.
117
127
  add_tools_helper() {
118
128
  tool=$1
@@ -123,19 +133,15 @@ add_tools_helper() {
123
133
  extensions+=(iconv mbstring phar sodium)
124
134
  elif [ "$tool" = "codeception" ]; then
125
135
  extensions+=(json mbstring)
126
- sudo ln -s "$scoped_dir"/vendor/bin/codecept "$scoped_dir"/vendor/bin/codeception
136
+ sudo ln -s "$scoped_dir"/vendor/bin/codecept "$scoped_dir"/vendor/bin/codeception 2>/dev/null || true
127
137
  elif [ "$tool" = "composer" ]; then
128
138
  configure_composer "$tool_path"
129
139
  elif [ "$tool" = "cs2pr" ]; then
130
140
  sudo sed -i 's/\r$//; s/exit(9)/exit(0)/' "$tool_path" 2>/dev/null ||
131
141
  sudo sed -i '' 's/\r$//; s/exit(9)/exit(0)/' "$tool_path"
132
142
  elif [ "$tool" = "deployer" ]; then
133
- if [ -e "$composer_bin"/deployer.phar ]; then
134
- sudo ln -s "$composer_bin"/deployer.phar "$composer_bin"/dep
135
- fi
136
- if [ -e "$composer_bin"/dep ]; then
137
- sudo ln -s "$composer_bin"/dep "$composer_bin"/deployer
138
- fi
143
+ sudo ln -s "$tool_path" "$tool_path_dir"/deployer 2>/dev/null || true
144
+ sudo ln -s "$tool_path" "$tool_path_dir"/dep 2>/dev/null || true
139
145
  elif [ "$tool" = "phan" ]; then
140
146
  extensions+=(fileinfo ast)
141
147
  elif [ "$tool" = "phinx" ]; then
@@ -151,7 +157,7 @@ add_tools_helper() {
151
157
  elif [ "$tool" = "phpDocumentor" ]; then
152
158
  extensions+=(ctype hash json fileinfo iconv mbstring simplexml xml)
153
159
  sudo ln -s "$tool_path" "$tool_path_dir"/phpdocumentor 2>/dev/null || true
154
- sudo ln -s "$tool_path" "$tool_path_dir"/phpdoc
160
+ sudo ln -s "$tool_path" "$tool_path_dir"/phpdoc 2>/dev/null || true
155
161
  elif [ "$tool" = "phpunit" ]; then
156
162
  extensions+=(dom json libxml mbstring xml xmlwriter)
157
163
  elif [ "$tool" = "phpunit-bridge" ]; then
@@ -162,9 +168,9 @@ add_tools_helper() {
162
168
  fi
163
169
  elif [ "$tool" = "vapor-cli" ]; then
164
170
  extensions+=(fileinfo json mbstring zip simplexml)
165
- sudo ln -s "$scoped_dir"/vendor/bin/vapor "$scoped_dir"/vendor/bin/vapor-cli
171
+ sudo ln -s "$scoped_dir"/vendor/bin/vapor "$scoped_dir"/vendor/bin/vapor-cli 2>/dev/null || true
166
172
  elif [ "$tool" = wp-cli ]; then
167
- sudo ln -s "$tool_path" "$tool_path_dir"/"${tool%-*}"
173
+ sudo ln -s "$tool_path" "$tool_path_dir"/"${tool%-*}" 2>/dev/null || true
168
174
  fi
169
175
  for extension in "${extensions[@]}"; do
170
176
  add_extension "$extension" extension >/dev/null 2>&1
@@ -180,25 +186,41 @@ add_tool() {
180
186
  if ! [ -d "$tool_path_dir" ]; then
181
187
  sudo mkdir -p "$tool_path_dir"
182
188
  fi
183
- add_path "$tool_path_dir"
184
- if [ -e "$tool_path" ]; then
185
- sudo cp -aL "$tool_path" /tmp/"$tool"
189
+ if ! [ -d "$tool_cache_path_dir" ]; then
190
+ sudo mkdir -p "$tool_cache_path_dir"
186
191
  fi
192
+ add_path "$tool_path_dir" verify
193
+ add_path "$tool_cache_path_dir"
187
194
  IFS="," read -r -a url <<<"$url"
188
- status_code=$(get -v -e "$tool_path" "${url[@]}")
189
- if [ "$status_code" != "200" ] && [[ "${url[0]}" =~ .*github.com.*releases.*latest.* ]]; then
190
- url[0]="${url[0]//releases\/latest\/download/releases/download/$(get -s -n "" "$(echo "${url[0]}" | cut -d '/' -f '1-5')/releases" | grep -Eo -m 1 "([0-9]+\.[0-9]+\.[0-9]+)/$(echo "${url[0]}" | sed -e "s/.*\///")" | cut -d '/' -f 1)}"
191
- status_code=$(get -v -e "$tool_path" "${url[0]}")
195
+ cache_key=$(get_sha256 "${url[0]}" | head -c 16)
196
+ cache_path="$tool_cache_path_dir/${tool}-${cache_key}"
197
+ use_cache=true
198
+ is_mutable_tool_url "${url[0]}" && use_cache=false
199
+ status_code="200"
200
+ if [ "$use_cache" = "true" ] && [ -f "$cache_path" ]; then
201
+ sudo cp -a "$cache_path" "$tool_path"
202
+ else
203
+ [ -f "$tool_path" ] && sudo cp -a "$tool_path" "$tool_path.bak"
204
+ status_code=$(get -v -e "$tool_path" "${url[@]}")
205
+ if [ "$status_code" != "200" ] && [[ "${url[0]}" =~ .*github.com.*releases.*latest.* ]]; then
206
+ url[0]="${url[0]//releases\/latest\/download/releases/download/$(get -s -n "" "$(echo "${url[0]}" | cut -d '/' -f '1-5')/releases" | grep -Eo -m 1 "([0-9]+\.[0-9]+\.[0-9]+)/$(echo "${url[0]}" | sed -e "s/.*\///")" | cut -d '/' -f 1)}"
207
+ status_code=$(get -v -e "$tool_path" "${url[0]}")
208
+ fi
209
+ if [ "$status_code" = "200" ] && [ "$use_cache" = "true" ]; then
210
+ sudo cp -a "$tool_path" "$cache_path"
211
+ elif [ -f "$tool_path.bak" ]; then
212
+ sudo mv "$tool_path.bak" "$tool_path"
213
+ fi
214
+ sudo rm -f "$tool_path.bak"
192
215
  fi
193
216
  if [ "$status_code" = "200" ]; then
194
217
  add_tools_helper "$tool"
218
+ [ -L "$tool_cache_path_dir/$tool" ] || sudo ln -s "$tool_path" "$tool_cache_path_dir/$tool" 2>/dev/null || true
195
219
  tool_version=$(get_tool_version "$tool" "$ver_param")
196
220
  add_log "${tick:?}" "$tool" "Added $tool $tool_version"
197
221
  else
198
222
  if [ "$tool" = "composer" ]; then
199
223
  export fail_fast=true
200
- elif [ -e /tmp/"$tool" ]; then
201
- sudo cp -a /tmp/"$tool" "$tool_path"
202
224
  fi
203
225
  if [ "$status_code" = "404" ]; then
204
226
  add_log "$cross" "$tool" "Failed to download $tool from ${url[*]}"
@@ -8,7 +8,7 @@ add_blackfire_linux() {
8
8
  add_blackfire_darwin() {
9
9
  sudo mkdir -p /usr/local/var/run
10
10
  add_brew_tap blackfireio/homebrew-blackfire
11
- brew install blackfire
11
+ safe_brew install blackfire
12
12
  }
13
13
 
14
14
  blackfire_config() {
@@ -44,6 +44,135 @@ add_brew_bins_to_path() {
44
44
  add_path "$brew_prefix"/sbin
45
45
  }
46
46
 
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 stdout_fifo stderr_fifo stdout_log stderr_log timeout_file
78
+ local command_pid stdout_reader_pid stderr_reader_pid monitor_pid exit_code
79
+ tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/setup-php-brew.XXXXXX")" || return 1
80
+ stdout_fifo="$tmp_dir/stdout.fifo"
81
+ stderr_fifo="$tmp_dir/stderr.fifo"
82
+ stdout_log="$tmp_dir/stdout.log"
83
+ stderr_log="$tmp_dir/stderr.log"
84
+ timeout_file="$tmp_dir/timed_out"
85
+ mkfifo "$stdout_fifo" "$stderr_fifo" || {
86
+ rm -rf "$tmp_dir"
87
+ return 1
88
+ }
89
+ : >"$stdout_log"
90
+ : >"$stderr_log"
91
+
92
+ ("$@" >"$stdout_fifo" 2>"$stderr_fifo") &
93
+ command_pid=$!
94
+
95
+ (
96
+ while IFS= read -r line || [ -n "$line" ]; do
97
+ printf '%s\n' "$line"
98
+ printf '%s\n' "$line" >>"$stdout_log"
99
+ done <"$stdout_fifo"
100
+ ) &
101
+ stdout_reader_pid=$!
102
+
103
+ (
104
+ while IFS= read -r line || [ -n "$line" ]; do
105
+ printf '%s\n' "$line" >&2
106
+ printf '%s\n' "$line" >>"$stderr_log"
107
+ done <"$stderr_fifo"
108
+ ) &
109
+ stderr_reader_pid=$!
110
+
111
+ (
112
+ local last_activity current_activity current_err_activity now
113
+ last_activity=$(get_file_mtime "$stdout_log")
114
+ current_err_activity=$(get_file_mtime "$stderr_log")
115
+ [ "$current_err_activity" -gt "$last_activity" ] && last_activity="$current_err_activity"
116
+ while kill -0 "$command_pid" >/dev/null 2>&1; do
117
+ sleep "$poll_secs"
118
+ current_activity=$(get_file_mtime "$stdout_log")
119
+ [ "$current_activity" -gt "$last_activity" ] && last_activity="$current_activity"
120
+ current_err_activity=$(get_file_mtime "$stderr_log")
121
+ [ "$current_err_activity" -gt "$last_activity" ] && last_activity="$current_err_activity"
122
+ now=$(date +%s)
123
+ if [ $((now - last_activity)) -ge "$timeout_secs" ]; then
124
+ printf "\nsetup-php: brew produced no output for %ss; terminating and retrying...\n" "$timeout_secs" >&2
125
+ : >"$timeout_file"
126
+ terminate_process_tree "$command_pid"
127
+ break
128
+ fi
129
+ done
130
+ ) &
131
+ monitor_pid=$!
132
+
133
+ wait "$command_pid"
134
+ exit_code=$?
135
+ wait "$stdout_reader_pid" 2>/dev/null || true
136
+ wait "$stderr_reader_pid" 2>/dev/null || true
137
+ kill "$monitor_pid" >/dev/null 2>&1 || true
138
+ wait "$monitor_pid" 2>/dev/null || true
139
+
140
+ if [ -e "$timeout_file" ]; then
141
+ rm -rf "$tmp_dir"
142
+ return 124
143
+ fi
144
+
145
+ rm -rf "$tmp_dir"
146
+ return "$exit_code"
147
+ }
148
+
149
+ # Function to run brew with retries and an inactivity watchdog.
150
+ safe_brew() {
151
+ local max_attempts="${SETUP_PHP_BREW_RETRY_ATTEMPTS:-3}"
152
+ local attempt=1
153
+ local exit_code=0
154
+
155
+ if [ "${SETUP_PHP_BREW_WATCHDOG:-true}" = "false" ]; then
156
+ brew "$@"
157
+ return $?
158
+ fi
159
+
160
+ while [ "$attempt" -le "$max_attempts" ]; do
161
+ run_with_inactivity_watchdog brew "$@" && return 0
162
+ exit_code=$?
163
+
164
+ if [ "$attempt" -ge "$max_attempts" ]; then
165
+ return "$exit_code"
166
+ fi
167
+
168
+ printf "setup-php: retrying brew command (attempt %s/%s, exit %s)\n" "$((attempt + 1))" "$max_attempts" "$exit_code" >&2
169
+ sleep "$((attempt * 5))"
170
+ attempt=$((attempt + 1))
171
+ done
172
+
173
+ return "$exit_code"
174
+ }
175
+
47
176
  # Function to add brew.
48
177
  add_brew() {
49
178
  brew_prefix="$(get_brew_prefix)"
@@ -74,6 +203,7 @@ configure_brew() {
74
203
  export HOMEBREW_NO_ENV_HINTS=1
75
204
  export HOMEBREW_NO_INSTALL_CLEANUP=1
76
205
  export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
206
+ export HOMEBREW_DOWNLOAD_CONCURRENCY="${HOMEBREW_DOWNLOAD_CONCURRENCY:-6}"
77
207
  export brew_opts
78
208
  export brew_path
79
209
  export brew_path_dir
@@ -4,7 +4,7 @@ add_bazel() {
4
4
  add_list bazel/apt https://storage.googleapis.com/bazel-apt https://bazel.build/bazel-release.pub.gpg stable jdk1.8
5
5
  install_packages bazel
6
6
  else
7
- brew install bazel
7
+ safe_brew install bazel
8
8
  fi
9
9
  fi
10
10
  }
@@ -25,7 +25,7 @@ add_grpc_php_plugin_brew() {
25
25
  . "${0%/*}"/tools/brew.sh
26
26
  configure_brew
27
27
  [ -e /usr/local/bin/protoc ] && sudo mv /usr/local/bin/protoc /tmp/protoc && sudo mv /usr/local/include/google /tmp
28
- brew install grpc
28
+ safe_brew install grpc
29
29
  brew link --force --overwrite grpc >/dev/null 2>&1
30
30
  [ -e /tmp/protoc ] && sudo mv /tmp/protoc /usr/local/bin/protoc && sudo mv /tmp/google /usr/local/include/
31
31
  grpc_tag="v$(brew info grpc | grep "grpc:" | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+")"
@@ -246,7 +246,11 @@ check_lists() {
246
246
  match_file=$(grep -Elr "$primary" "$list_dir" 2>/dev/null | head -n 1)
247
247
  fi
248
248
  if [ -z "$match_file" ] && [ -n "$secondary" ]; then
249
- match_file=$(grep -Elr "$secondary" "$list_dir" 2>/dev/null | head -n 1)
249
+ local candidate
250
+ candidate=$(grep -Elr "$secondary" "$list_dir" 2>/dev/null | head -n 1)
251
+ if [ -n "$candidate" ] && { [ -z "$primary" ] || grep -Eq "$primary" "$candidate"; }; then
252
+ match_file="$candidate"
253
+ fi
250
254
  fi
251
255
  if [ -n "$match_file" ]; then
252
256
  local list_count
@@ -4,6 +4,7 @@ export cross="✗"
4
4
  export curl_opts=(-sL)
5
5
  export old_versions="5.[3-5]"
6
6
  export jit_versions="8.[0-9]"
7
+ export php_builder_versions="8.[3-9]"
7
8
  export nightly_versions="8.[6-9]"
8
9
  export xdebug3_versions="7.[2-4]|8.[0-9]"
9
10
  export latest="releases/latest/download"
@@ -58,6 +59,7 @@ read_env() {
58
59
  -n "$ACT" || -n "$CONTAINER" ]] && _runner=self-hosted || _runner=github
59
60
  runner="${runner:-${RUNNER:-$_runner}}"
60
61
  tool_path_dir="${setup_php_tools_dir:-${SETUP_PHP_TOOLS_DIR:-/usr/local/bin}}"
62
+ tool_cache_path_dir="${setup_php_tool_cache_dir:-${SETUP_PHP_TOOL_CACHE_DIR:-${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}/setup-php/tools}}"
61
63
 
62
64
  if [[ "$runner" = "github" && $_runner = "self-hosted" ]]; then
63
65
  fail_fast=true
@@ -79,6 +81,7 @@ read_env() {
79
81
  export update
80
82
  export ts
81
83
  export tool_path_dir
84
+ export tool_cache_path_dir
82
85
  }
83
86
 
84
87
  # Function to create a lock.
@@ -169,14 +172,15 @@ get_shell_profile() {
169
172
  # Function to add a path to the PATH variable.
170
173
  add_path() {
171
174
  path_to_add=$1
172
- [[ ":$PATH:" == *":$path_to_add:"* ]] && return
175
+ action=$2
176
+ [[ "$action" == "verify" && ":$PATH:" == *":$path_to_add:"* ]] && return
173
177
  if [[ -n "$GITHUB_PATH" ]]; then
174
- echo "$path_to_add" | tee -a "$GITHUB_PATH" >/dev/null 2>&1
178
+ printf '%s\n%s' "$path_to_add" "$(grep -v "^${path_to_add}$" "$GITHUB_PATH" 2>/dev/null)" > "$GITHUB_PATH"
175
179
  else
176
180
  profile=$(get_shell_profile)
177
181
  ([ -e "$profile" ] && grep -q ":$path_to_add\"" "$profile" 2>/dev/null) || echo "export PATH=\"\${PATH:+\${PATH}:}\"$path_to_add" | sudo tee -a "$profile" >/dev/null 2>&1
178
182
  fi
179
- export PATH="${PATH:+${PATH}:}$path_to_add"
183
+ [[ ":$PATH:" == *":$path_to_add:"* ]] || export PATH="${PATH:+${PATH}:}$path_to_add"
180
184
  }
181
185
 
182
186
  # Function to add environment variables using a PATH.
@@ -81,9 +81,10 @@ Function Get-PathFromRegistry {
81
81
  # Function to add a location to PATH.
82
82
  Function Add-Path {
83
83
  param(
84
- [string]$PathItem
84
+ [string]$PathItem,
85
+ [switch]$Force
85
86
  )
86
- if("$env:PATH;".contains("$PathItem;")) {
87
+ if(-not($Force) -and "$env:PATH;".contains("$PathItem;")) {
87
88
  return
88
89
  }
89
90
  if ($env:GITHUB_PATH) {
@@ -375,6 +376,7 @@ if(-not($env:ImageOS) -and -not($env:ImageVersion)) {
375
376
  if(-not(Test-Path -LiteralPath $current_profile)) {
376
377
  New-Item -Path $current_profile -ItemType "file" -Force >$null 2>&1
377
378
  }
379
+ Add-Path -PathItem $bin_dir -Force
378
380
  }
379
381
 
380
382
  $src = Join-Path -Path $PSScriptRoot -ChildPath \..