@@ -29,30 +29,38 @@ function uv::install_uv() {
2929 gnu_arch=$( arch)
3030 local uv_url=" https://github.com/astral-sh/uv/releases/download/${UV_VERSION} /uv-${gnu_arch} -unknown-linux-gnu.tar.gz"
3131
32+ local error_log
33+ error_log=$( mktemp)
34+
35+ # shellcheck disable=SC2310 # This function is invoked in an 'if' condition so set -e will be disabled.
3236 if ! {
33- # We set max-time for improved UX/metrics for hanging downloads compared to relying on the build
34- # system timeout. We don't use `--speed-limit` since it gives worse error messages when used with
35- # retries and piping to tar. The Python archives are ~10 MB so only take ~1s to download on Heroku,
36- # so we set low timeouts to reduce delays before retries. However, we allow customising the timeouts
37- # to support non-Heroku environments that may be far from `us-east-1` or have a slower connection.
38- # We use `--no-progress-meter` rather than `--silent` so that retry status messages are printed.
39- # We have to use `--strip-components` since the uv binary is nested under a subdirectory.
40- curl \
41- --connect-timeout " ${CURL_CONNECT_TIMEOUT:- 3} " \
42- --fail \
43- --location \
44- --max-time " ${CURL_TIMEOUT:- 60} " \
45- --no-progress-meter \
46- --retry-max-time " ${CURL_TIMEOUT:- 60} " \
47- --retry 5 \
48- --retry-connrefused \
49- " ${uv_url} " \
50- | tar \
51- --directory " ${uv_dir} " \
52- --extract \
53- --gzip \
54- --no-anchored \
55- --strip-components 1
37+ {
38+ # We set max-time for improved UX/metrics for hanging downloads compared to relying on the build
39+ # system timeout. We don't use `--speed-limit` since it gives worse error messages when used with
40+ # retries and piping to tar. The uv archives are ~20 MB so only take ~1s to download on Heroku,
41+ # so we set low timeouts to reduce delays before retries. However, we allow customising the timeouts
42+ # to support non-Heroku environments that may be far from `us-east-1` or have a slower connection.
43+ # We use `--no-progress-meter` rather than `--silent` so that retry status messages are printed.
44+ # We have to use `--strip-components` since the uv binary is nested under a subdirectory.
45+ curl \
46+ --connect-timeout " ${CURL_CONNECT_TIMEOUT:- 3} " \
47+ --fail \
48+ --location \
49+ --max-time " ${CURL_TIMEOUT:- 60} " \
50+ --no-progress-meter \
51+ --retry-max-time " ${CURL_TIMEOUT:- 60} " \
52+ --retry 5 \
53+ --retry-connrefused \
54+ " ${uv_url} " \
55+ | tar \
56+ --directory " ${uv_dir} " \
57+ --extract \
58+ --gzip \
59+ --no-anchored \
60+ --strip-components 1
61+ } \
62+ | & tee " ${error_log} " \
63+ | & output::indent
5664 }; then
5765 output::error << -EOF
5866 Error: Unable to install uv.
@@ -69,6 +77,8 @@ function uv::install_uv() {
6977 https://www.githubstatus.com
7078 EOF
7179 build_data::set_string " failure_reason" " install-package-manager::uv"
80+ # e.g.: 'curl: (56) Recv failure: Connection reset by peer'
81+ build_data::set_string " failure_detail" " $( head --lines=1 " ${error_log} " || true) "
7282 exit 1
7383 fi
7484 fi
0 commit comments