mirror of
https://github.com/pyenv/pyenv.git
synced 2026-10-02 23:41:06 +09:00
python-build: show download progress in interactive terminals
--- Co-authored-by: Ivan Pozdeev <vano@mail.mipt.ru> Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
This commit is contained in:
parent
67dbc6e930
commit
8339b9b033
@ -425,6 +425,18 @@ http_head_aria2c() {
|
|||||||
aria2c --dry-run --no-conf=true ${ARIA2_OPTS} "$1" >&4 2>&1
|
aria2c --dry-run --no-conf=true ${ARIA2_OPTS} "$1" >&4 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Shows interactive output of a program
|
||||||
|
# while also logging it.
|
||||||
|
# Usage:
|
||||||
|
# command <switches forcing interactive output to non-terminal> 2>&1 | interactive_output; rc=${PIPESTATUS[0]}
|
||||||
|
interactive_output() {
|
||||||
|
if [ -n "$VERBOSE" ]; then
|
||||||
|
cat >> "$LOG_PATH"
|
||||||
|
else
|
||||||
|
tee -a "$LOG_PATH" >&3
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
http_get_aria2c() {
|
http_get_aria2c() {
|
||||||
# aria2c always treats -o argument as a relative path
|
# aria2c always treats -o argument as a relative path
|
||||||
local out dir_out;
|
local out dir_out;
|
||||||
@ -447,7 +459,26 @@ http_get_aria2c() {
|
|||||||
dir_out="$HOME"
|
dir_out="$HOME"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if aria2c --allow-overwrite=true --no-conf=true -d "${dir_out}" -o "${out}" ${ARIA2_OPTS} "$1" >&4; then
|
local aria2c_progress=
|
||||||
|
# aria2c prints status to stdout rather than stderr.
|
||||||
|
# As a result, when stdout is redirected, it becomes line-buffered,
|
||||||
|
# and status messages (which are divided by CRs) are not seen
|
||||||
|
# until a summary message with some LFs is printed.
|
||||||
|
# So we have to print summaries often as a crutch.
|
||||||
|
# But need to make the interval reasonable because each summary is
|
||||||
|
# several lines long which, made too often, becomes obnoxious.
|
||||||
|
[ -t 3 ] && aria2c_progress="--summary-interval=5"
|
||||||
|
local cmd
|
||||||
|
cmd=(aria2c --allow-overwrite=true --no-conf=true -d "${dir_out}" -o "${out}" ${aria2c_progress} ${ARIA2_OPTS} "$1")
|
||||||
|
|
||||||
|
if [ -t 3 ]; then
|
||||||
|
"${cmd[@]}" 2>&1 | interactive_output
|
||||||
|
ret=${PIPESTATUS[0]}
|
||||||
|
else
|
||||||
|
"${cmd[@]}" >&4
|
||||||
|
ret=$?
|
||||||
|
fi
|
||||||
|
if [ "$ret" -eq 0 ]; then
|
||||||
[ -n "$2" ] || cat "${dir_out:-.}/${out}"
|
[ -n "$2" ] || cat "${dir_out:-.}/${out}"
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
@ -471,7 +502,21 @@ http_get_curl() {
|
|||||||
local curl_is_snap;
|
local curl_is_snap;
|
||||||
if [[ $(command -v curl) == "/snap/"* ]]; then curl_is_snap=1; fi
|
if [[ $(command -v curl) == "/snap/"* ]]; then curl_is_snap=1; fi
|
||||||
if [[ -n $2 && -n $curl_is_snap ]]; then out="$HOME/$(basename "$2")"; else out="$2"; fi
|
if [[ -n $2 && -n $curl_is_snap ]]; then out="$HOME/$(basename "$2")"; else out="$2"; fi
|
||||||
curl -q -o "${out:--}" -sSLf ${CURL_OPTS} "$1" || return $?
|
local curl_progress=
|
||||||
|
if [ -t 3 ]; then
|
||||||
|
curl_progress="--no-silent"
|
||||||
|
fi
|
||||||
|
local cmd
|
||||||
|
cmd=(curl -q -o "${out:--}" -sSLf ${CURL_OPTS} ${curl_progress} "$1")
|
||||||
|
if [ -t 3 ]; then
|
||||||
|
exec 5>&1
|
||||||
|
"${cmd[@]}" 3>&1 1>&5 2>&3 3>&- | interactive_output
|
||||||
|
ret=${PIPESTATUS[0]}
|
||||||
|
exec 5>&-
|
||||||
|
[ "$ret" -eq 0 ] || return "$ret"
|
||||||
|
else
|
||||||
|
"${cmd[@]}" || return $?
|
||||||
|
fi
|
||||||
if [[ -n $out && -n $curl_is_snap ]]; then mv "$out" "$2"; fi
|
if [[ -n $out && -n $curl_is_snap ]]; then mv "$out" "$2"; fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,7 +525,21 @@ http_head_wget() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
http_get_wget() {
|
http_get_wget() {
|
||||||
wget -nv ${WGET_OPTS} -O "${2:--}" "$1"
|
local wget_progress="-nv"
|
||||||
|
if [ -t 3 ]; then
|
||||||
|
wget_progress="-nv --show-progress --progress=bar:force:noscroll"
|
||||||
|
fi
|
||||||
|
local cmd
|
||||||
|
cmd=(wget ${WGET_OPTS} ${wget_progress} -O "${2:--}" "$1")
|
||||||
|
if [ -t 3 ]; then
|
||||||
|
exec 5>&1
|
||||||
|
"${cmd[@]}" 3>&1 1>&5 2>&3 3>&- | interactive_output
|
||||||
|
ret=${PIPESTATUS[0]}
|
||||||
|
exec 5>&-
|
||||||
|
return "$ret"
|
||||||
|
else
|
||||||
|
"${cmd[@]}"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch_tarball() {
|
fetch_tarball() {
|
||||||
@ -1526,7 +1585,7 @@ use_homebrew() {
|
|||||||
if command -v brew &>/dev/null; then
|
if command -v brew &>/dev/null; then
|
||||||
local brew_prefix="$(brew --prefix 2>/dev/null || true)"
|
local brew_prefix="$(brew --prefix 2>/dev/null || true)"
|
||||||
# /usr/local/lib:/usr/lib is the default library search path
|
# /usr/local/lib:/usr/lib is the default library search path
|
||||||
if [[ -n $brew_prefix && ( ( $brew_prefix != "/usr" && $brew_prefix != "/usr/local" )
|
if [[ -n $brew_prefix && ( ( $brew_prefix != "/usr" && $brew_prefix != "/usr/local" )
|
||||||
#when -isysroot is passed to Apple CLang, /usr/(local) are excluded from the default search path
|
#when -isysroot is passed to Apple CLang, /usr/(local) are excluded from the default search path
|
||||||
|| ( is_mac && osx_using_default_compiler && $CFLAGS =~ (^|\ )-isysroot\ ) ) ]]; then
|
|| ( is_mac && osx_using_default_compiler && $CFLAGS =~ (^|\ )-isysroot\ ) ) ]]; then
|
||||||
export CPPFLAGS="${CPPFLAGS:+$CPPFLAGS }-I${brew_prefix}/include"
|
export CPPFLAGS="${CPPFLAGS:+$CPPFLAGS }-I${brew_prefix}/include"
|
||||||
@ -2777,7 +2836,8 @@ else
|
|||||||
BUILD_PATH="$PYTHON_BUILD_BUILD_PATH"
|
BUILD_PATH="$PYTHON_BUILD_BUILD_PATH"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exec 4<> "$LOG_PATH" # open the log file at fd 4
|
# Append mode needed to be able to `tee` to it at the same time
|
||||||
|
exec 4>> "$LOG_PATH"
|
||||||
if [ -n "$VERBOSE" ]; then
|
if [ -n "$VERBOSE" ]; then
|
||||||
tail -f "$LOG_PATH" &
|
tail -f "$LOG_PATH" &
|
||||||
TAIL_PID=$!
|
TAIL_PID=$!
|
||||||
|
|||||||
@ -8,6 +8,21 @@ _setup() {
|
|||||||
mkdir -p "${PYTHON_BUILD_BUILD_PATH}"
|
mkdir -p "${PYTHON_BUILD_BUILD_PATH}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_script_available() {
|
||||||
|
command -v script >/dev/null || skip "'script' not installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_with_script() {
|
||||||
|
local command
|
||||||
|
# `script' outputs CRLF because ttys do so under the hood
|
||||||
|
# https://unix.stackexchange.com/questions/343324/why-in-the-output-of-script-1-the-newline-is-cr-lf-dos-style
|
||||||
|
case "$(uname -s)" in
|
||||||
|
Linux) printf -v command '%q ' "$@"; script -qec "$command" /dev/stdout | tr -d $'\r' ;;
|
||||||
|
*) script -q /dev/stdout "$@" | tr -d $'\r' ;;
|
||||||
|
esac </dev/null
|
||||||
|
return ${PIPESTATUS[0]}
|
||||||
|
}
|
||||||
|
|
||||||
@test "failed download displays error message" {
|
@test "failed download displays error message" {
|
||||||
stub curl false
|
stub curl false
|
||||||
|
|
||||||
@ -17,6 +32,22 @@ _setup() {
|
|||||||
assert_output_contains "error: failed to download package-1.0.0.tar.gz"
|
assert_output_contains "error: failed to download package-1.0.0.tar.gz"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "interactive download progress is both shown and logged" {
|
||||||
|
check_script_available
|
||||||
|
export TMPDIR="$BATS_TEST_TMPDIR"
|
||||||
|
stub curl '** -o * ** --no-silent ** http://example.com/* : "'"$BASH"'" -ec '\''echo download-progress >&2; "$FIXTURE_ROOT/fake_downloader" "$@"'\'' "$@"'
|
||||||
|
|
||||||
|
run run_with_script python-build "$FIXTURE_ROOT/definitions/without-checksum" "$INSTALL_ROOT"
|
||||||
|
assert_success
|
||||||
|
unstub curl
|
||||||
|
|
||||||
|
assert_line download-progress
|
||||||
|
|
||||||
|
run cat "$BATS_TEST_TMPDIR"/python-build.*.log
|
||||||
|
assert_success
|
||||||
|
assert_line download-progress
|
||||||
|
}
|
||||||
|
|
||||||
@test "using aria2c if available" {
|
@test "using aria2c if available" {
|
||||||
export PYTHON_BUILD_ARIA2_OPTS=
|
export PYTHON_BUILD_ARIA2_OPTS=
|
||||||
export -n PYTHON_BUILD_HTTP_CLIENT
|
export -n PYTHON_BUILD_HTTP_CLIENT
|
||||||
@ -33,6 +64,23 @@ OUT
|
|||||||
unstub aria2c
|
unstub aria2c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "interactive aria2c output is emulated by printing summaries" {
|
||||||
|
check_script_available
|
||||||
|
export TMPDIR="$BATS_TEST_TMPDIR"
|
||||||
|
export PYTHON_BUILD_ARIA2_OPTS=
|
||||||
|
export -n PYTHON_BUILD_HTTP_CLIENT
|
||||||
|
stub aria2c '** --summary-interval=* ** http://example.com/* : "'"$BASH"'" -ec '\''echo download-progress; "$FIXTURE_ROOT/fake_downloader" aria2c "$@"'\'' "$@"'
|
||||||
|
|
||||||
|
run run_with_script python-build "$FIXTURE_ROOT/definitions/without-checksum" "$INSTALL_ROOT"
|
||||||
|
assert_success
|
||||||
|
unstub aria2c
|
||||||
|
assert_line download-progress
|
||||||
|
|
||||||
|
run cat "$BATS_TEST_TMPDIR"/python-build.*.log
|
||||||
|
assert_success
|
||||||
|
assert_line download-progress
|
||||||
|
}
|
||||||
|
|
||||||
@test "fetching from git repository" {
|
@test "fetching from git repository" {
|
||||||
stub git "clone --depth 1 --branch master http://example.com/packages/package.git package-dev : mkdir package-dev"
|
stub git "clone --depth 1 --branch master http://example.com/packages/package.git package-dev : mkdir package-dev"
|
||||||
|
|
||||||
|
|||||||
44
plugins/python-build/test/fixtures/fake_downloader
vendored
Executable file
44
plugins/python-build/test/fixtures/fake_downloader
vendored
Executable file
@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
aria2c=
|
||||||
|
wget=
|
||||||
|
src=
|
||||||
|
dest=
|
||||||
|
dir_=
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
aria2c)
|
||||||
|
aria2c=1;;
|
||||||
|
wget)
|
||||||
|
wget=1;;
|
||||||
|
esac
|
||||||
|
while (($#)); do
|
||||||
|
case "$1" in
|
||||||
|
-o)
|
||||||
|
if [[ -z $wget ]]; then
|
||||||
|
dest="$2"
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
-O)
|
||||||
|
if [[ -n $wget ]]; then
|
||||||
|
dest="$2"
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
-d)
|
||||||
|
if [[ -n $aria2c ]]; then
|
||||||
|
dir_="$2/"
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
src="$FIXTURE_ROOT/${1##*/}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
cp "$src" "${dir_}${dest}"
|
||||||
|
|
||||||
@ -138,6 +138,19 @@ assert_output_contains() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert_line() {
|
||||||
|
if [ "$1" -ge 0 ] 2>/dev/null; then
|
||||||
|
assert_equal "$2" "${lines[$1]}"
|
||||||
|
else
|
||||||
|
local line
|
||||||
|
for line in "${lines[@]}"; do
|
||||||
|
if [ "$line" = "$1" ]; then return 0; fi
|
||||||
|
done
|
||||||
|
flunk "expected line \`$1'" $'\n'\
|
||||||
|
"output: $output"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Output a modified PATH that ensures that the given executable is not present,
|
# Output a modified PATH that ensures that the given executable is not present,
|
||||||
# but in which system utils necessary for pyenv operation are still available.
|
# but in which system utils necessary for pyenv operation are still available.
|
||||||
path_without() {
|
path_without() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user