Compare commits

..

17 Commits

Author SHA1 Message Date
Ivan Pozdeev
b52a8e3f52 python-build scripts: Switch to jc release
They finally made a release with our fix
2026-06-19 08:36:53 +03:00
Ayush
f122a9d764
CI: add_version enhancements (#3475)
- Prevent OpenSSL from bumping across major versions
- Skip adding versions that already have pending PRs
- Copy/move patches when adding new releases in the same series
2026-06-14 21:46:48 +03:00
native-api
3323ba3ed9
README: clarify shell setup instructions using the new --install option 2026-06-12 15:34:14 +03:00
Ivan Pozdeev
b43c9e5d42 2.7.2 2026-06-10 23:16:50 +03:00
pyenv-bot[bot]
532b659ca2
Add CPython 3.13.14 (#3473)
---------

Co-authored-by: Ivan Pozdeev <vano@mail.mipt.ru>
2026-06-10 23:12:21 +03:00
pyenv-bot[bot]
7565df6eab
Add CPython 3.14.6 (#3472)
---------

Co-authored-by: native-api <2670332+native-api@users.noreply.github.com>
Co-authored-by: Ivan Pozdeev <vano@mail.mipt.ru>
2026-06-10 23:11:56 +03:00
Ivan Pozdeev
e55613a267 CI: Don't trigger push checks on a pull request 2026-06-10 22:03:22 +03:00
Ivan Pozdeev
6c0c5cfa96 Fix verify_* calls in 3.6.x
Fixes #3470
2026-06-10 21:56:41 +03:00
Anup Das
cf6f3c3200
fix(rehash): prevent terminal hang caused by stale or sandbox-blocked lock file (#3469)
* reduce stale lock TTL to 2 min, check for stale lock before acquiring and each time -- to hold up new shell sessions for as little as possible

---------

Co-authored-by: Ivan Pozdeev <vano@mail.mipt.ru>
2026-06-04 22:36:11 +03:00
Ivan Pozdeev
45180928d3
2.7.1 2026-06-03 09:09:54 +03:00
native-api
c12fd3ae6b
realpath.c: fix obsolete syntax warning (#3468) 2026-06-03 08:42:53 +03:00
Ayush
455d1a31db
init: add --install for shell setup (#3454) 2026-06-03 01:13:07 +03:00
pyenv-bot[bot]
efc77132f7
Add CPython 3.15.0b2 (#3467)
Co-authored-by: native-api <2670332+native-api@users.noreply.github.com>
2026-06-03 00:55:40 +03:00
native-api
c425c9ec3a
Update URLs for PyPy nightly; Remove pypy3.5 and pypy3.7 nightly (#3466)
pypy3.5-c-jit-latest and pypy3.7-c-jit-latest are no longer available
2026-06-02 13:16:51 +03:00
native-api
95ddd7d479
Support 3.9 EOL Pip URL, consolidate tests (#3465) 2026-06-02 10:29:59 +03:00
Ivan Pozdeev
29057a6c69
2.6.32 2026-05-31 06:20:35 +03:00
native-api
23eb9a9ee3
Merge pull request #3463 from native-api/3.14_openssl_4_r2
3.14.0-5: Support building against OpenSSL 4
2026-05-31 05:59:43 +03:00
35 changed files with 10576 additions and 378 deletions

View File

@ -1,5 +1,8 @@
name: macos_build
on: [pull_request, push]
on:
push:
branches: [master]
pull_request: {}
permissions:
contents: read # to fetch code (actions/checkout)

View File

@ -1,5 +1,8 @@
name: pyenv_tests
on: [pull_request, push]
on:
push:
branches: [master]
pull_request: {}
permissions:
contents: read # to fetch code (actions/checkout)

View File

@ -1,5 +1,8 @@
name: ubuntu_build
on: [pull_request, push]
on:
push:
branches: [master]
pull_request: {}
permissions:
contents: read # to fetch code (actions/checkout)

View File

@ -1,5 +1,18 @@
# Version History
## Release v2.7.2
* fix(rehash): prevent terminal hang caused by stale or sandbox-blocked lock file by @anupddas in https://github.com/pyenv/pyenv/pull/3469
* 3.6.x: Fix verify_* calls by @native-api in https://github.com/pyenv/pyenv/commit/6c0c5cfa9619e4a7a90102d8bee6c771c4739836
* Add CPython 3.14.6 by @pyenv-bot[bot] in https://github.com/pyenv/pyenv/pull/3472
* Add CPython 3.13.14 by @pyenv-bot[bot] in https://github.com/pyenv/pyenv/pull/3473
## Release v2.7.1
* Support 3.9 EOL Pip URL, consolidate tests by @native-api in https://github.com/pyenv/pyenv/pull/3465
* Update URLs for PyPy nightly; Remove pypy3.5 and pypy3.7 nightly by @native-api in https://github.com/pyenv/pyenv/pull/3466
* Add CPython 3.15.0b2 by @pyenv-bot[bot] in https://github.com/pyenv/pyenv/pull/3467
* init: add --install for shell setup by @macayu17 in https://github.com/pyenv/pyenv/pull/3454
* realpath.c: fix obsolete syntax warning by @native-api in https://github.com/pyenv/pyenv/pull/3468
## Release v2.6.32
* Add miniconda3 26.3.2-2, miniforge3 26.3.2-0, 26.3.2-1 by @native-api in https://github.com/pyenv/pyenv/pull/3445
* miniforge3 26.1, 26.3, add_miniforge: exclude .pkg installers by @native-api in https://github.com/pyenv/pyenv/pull/3446

View File

@ -393,11 +393,15 @@ List existing pyenv shims.
Configure the shell environment for pyenv
Usage: eval "$(pyenv init [-|--path] [--no-push-path] [--no-rehash] [<shell>])"
pyenv init --install [<shell>]
pyenv init --detect-shell [<shell>]
- Initialize shims directory, print PYENV_SHELL variable, completions path
and shell function
--path Print shims path
--install Configure detected shell startup files
--no-push-path Do not push shim to the start of PATH if they're already there
--detect-shell Print shell startup files detected for the current shell
--no-rehash Add no rehash command to output
## `pyenv completions`

241
README.md
View File

@ -69,6 +69,7 @@ This project was forked from [rbenv](https://github.com/rbenv/rbenv) and
* [Using Pyenv without shims](#using-pyenv-without-shims)
* [Running nested shells from Python-based programs](#running-nested-shells-from-python-based-programs)
* [Environment variables](#environment-variables)
* [Manual shell setup](#manual-shell-setup)
* **[Development](#development)**
* [Contributing](#contributing)
* [Version History](#version-history)
@ -177,115 +178,28 @@ which does install native Windows Python versions.
----
The below setup should work for the vast majority of users for common use cases.
See [Advanced configuration](#advanced-configuration) for details and more configuration options.
See [Advanced configuration](#advanced-configuration)
and specifically [Manual shell setup](#manual-shell-setup) for details and more configuration options.
#### Bash
<details>
To add the suggested setup code to the startup files of the running shell,
run `<path/to/pyenv> --install`.
Specifically:
Stock Bash startup files vary widely between distributions in which of them source
which, under what circumstances, in what order and what additional configuration they perform.
As such, the most reliable way to get Pyenv in all environments is to append Pyenv
configuration commands to both `.bashrc` (for interactive shells)
and the profile file that Bash would use (for login shells).
* If you installed Pyenv with the installer script:
1. First, add the commands to `~/.bashrc` by running the following in your terminal:
```sh
~/.pyenv/bin/pyenv init --install
```
```bash
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init - bash)"' >> ~/.bashrc
```
2. Then, if you have `~/.profile`, `~/.bash_profile` or `~/.bash_login`, add the commands there as well.
If you have none of these, create a `~/.profile` and add the commands there.
* If you installed Pyenv with Homebrew:
* to add to `~/.profile`:
``` bash
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
echo 'eval "$(pyenv init - bash)"' >> ~/.profile
```
* to add to `~/.bash_profile`:
```bash
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init - bash)"' >> ~/.bash_profile
```
```sh
pyenv init --install
```
**Bash warning**: There are some systems where the `BASH_ENV` variable is configured
to point to `.bashrc`. On such systems, you should almost certainly put the
`eval "$(pyenv init - bash)"` line into `.bash_profile`, and **not** into `.bashrc`. Otherwise, you
may observe strange behaviour, such as `pyenv` getting into an infinite loop.
See [#264](https://github.com/pyenv/pyenv/issues/264) for details.
</details>
#### Zsh
<details>
Add Pyenv startup commands to `~/.zshrc` by running the following in your terminal:
```zsh
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init - zsh)"' >> ~/.zshrc
```
If you wish to get Pyenv in noninteractive login shells as well, also add the commands to `~/.zprofile` or `~/.zlogin`.
</details>
#### Fish
<details>
1. If you have Fish 3.2.0 or newer, execute this interactively:
```fish
set -Ux PYENV_ROOT $HOME/.pyenv
test -d $PYENV_ROOT/bin; and fish_add_path $PYENV_ROOT/bin
```
2. Otherwise, execute the snippet below:
```fish
set -Ux PYENV_ROOT $HOME/.pyenv
test -d $PYENV_ROOT/bin; and set -U fish_user_paths $PYENV_ROOT/bin $fish_user_paths
```
3. Now, add this to `~/.config/fish/config.fish`:
```fish
pyenv init - fish | source
```
</details>
#### Nushell
<details>
Add the following lines to your `config.nu` to add Pyenv and its shims to your `PATH`.
Shell integration (completions and subcommands changing the shell's state)
isn't currently supported.
~~~ nu
$env.PYENV_ROOT = "~/.pyenv" | path expand
if (( $"($env.PYENV_ROOT)/bin" | path type ) == "dir") {
$env.PATH = $env.PATH | prepend $"($env.PYENV_ROOT)/bin" }
$env.PATH = $env.PATH | prepend $"(pyenv root)/shims"
~~~
</details>
#### Microsoft PowerShell
<details>
Add the commands to `$profile.CurrentUserAllHosts` by running the following in your terminal:
~~~ pwsh
echo '$Env:PYENV_ROOT="$Env:HOME/.pyenv"' >> $profile.CurrentUserAllHosts
echo 'if (Test-Path -LP "$Env:PYENV_ROOT/bin" -PathType Container) {
$Env:PATH="$Env:PYENV_ROOT/bin:$Env:PATH" }' >> $profile.CurrentUserAllHosts
echo 'iex ((pyenv init -) -join "`n")' >> $profile.CurrentUserAllHosts
~~~
</details>
For Bash, avoid the automatic `--install` path if your `BASH_ENV` points to
`.bashrc`; use the manual Bash instructions below so the `eval "$(pyenv init - bash)"`
line only goes in your login startup file.
### C. Restart your shell
----
@ -797,6 +711,127 @@ name | default | description
See also [_Special environment variables_ in Python-Build's README](plugins/python-build/README.md#special-environment-variables)
for environment variables that can be used to customize the build.
### Manual shell setup
Below is the suggested shell setup added to shell startup files by `pyenv init --install`.
* To automatically install Pyenv for a shell different than the running shell, run
```sh
path/to/pyenv --install <shell executable name>
```
e.g. `~/.pyenv --install bash`.
#### Bash
<details>
Stock Bash startup files vary widely between distributions in which of them source
which, under what circumstances, in what order and what additional configuration they perform.
As such, the most reliable way to get Pyenv in all environments is to append Pyenv
configuration commands to both `.bashrc` (for interactive shells)
and the profile file that Bash would use (for login shells).
1. First, add the commands to `~/.bashrc` by running the following in your terminal:
```bash
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init - bash)"' >> ~/.bashrc
```
2. Then, if you have `~/.profile`, `~/.bash_profile` or `~/.bash_login`, add the commands there as well.
If you have none of these, create a `~/.profile` and add the commands there.
* to add to `~/.profile`:
``` bash
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
echo 'eval "$(pyenv init - bash)"' >> ~/.profile
```
* to add to `~/.bash_profile`:
```bash
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init - bash)"' >> ~/.bash_profile
```
**Bash warning**: There are some systems where the `BASH_ENV` variable is configured
to point to `.bashrc`. On such systems, you should almost certainly put the
`eval "$(pyenv init - bash)"` line into `.bash_profile`, and **not** into `.bashrc`. Otherwise, you
may observe strange behaviour, such as `pyenv` getting into an infinite loop.
See [#264](https://github.com/pyenv/pyenv/issues/264) for details.
</details>
#### Zsh
<details>
Add Pyenv startup commands to `~/.zshrc` by running the following in your terminal:
```zsh
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init - zsh)"' >> ~/.zshrc
```
If you wish to get Pyenv in noninteractive login shells as well, also add the commands to `~/.zprofile` or `~/.zlogin`.
</details>
#### Fish
<details>
1. If you have Fish 3.2.0 or newer, execute this interactively:
```fish
set -Ux PYENV_ROOT $HOME/.pyenv
test -d $PYENV_ROOT/bin; and fish_add_path $PYENV_ROOT/bin
```
2. Otherwise, execute the snippet below:
```fish
set -Ux PYENV_ROOT $HOME/.pyenv
test -d $PYENV_ROOT/bin; and set -U fish_user_paths $PYENV_ROOT/bin $fish_user_paths
```
3. Now, add this to `~/.config/fish/config.fish`:
```fish
pyenv init - fish | source
```
</details>
#### Nushell
<details>
Add the following lines to your `config.nu` to add Pyenv and its shims to your `PATH`.
Shell integration (completions and subcommands changing the shell's state)
isn't currently supported.
~~~ nu
$env.PYENV_ROOT = "~/.pyenv" | path expand
if (( $"($env.PYENV_ROOT)/bin" | path type ) == "dir") {
$env.PATH = $env.PATH | prepend $"($env.PYENV_ROOT)/bin" }
$env.PATH = $env.PATH | prepend $"(pyenv root)/shims"
~~~
</details>
#### Microsoft PowerShell
<details>
Add the commands to `$profile.CurrentUserAllHosts` by running the following in your terminal:
~~~ pwsh
echo '$Env:PYENV_ROOT="$Env:HOME/.pyenv"' >> $profile.CurrentUserAllHosts
echo 'if (Test-Path -LP "$Env:PYENV_ROOT/bin" -PathType Container) {
$Env:PATH="$Env:PYENV_ROOT/bin:$Env:PATH" }' >> $profile.CurrentUserAllHosts
echo 'iex ((pyenv init -) -join "`n")' >> $profile.CurrentUserAllHosts
~~~
</details>
----
## Development

View File

@ -12,7 +12,7 @@
set -e
[ -n "$PYENV_DEBUG" ] && set -x
version="2.6.32"
version="2.7.2"
git_revision=""
if cd "${BASH_SOURCE%/*}" 2>/dev/null && git remote -v 2>/dev/null | grep -q pyenv; then

View File

@ -1,6 +1,8 @@
#!/usr/bin/env bash
# Summary: Configure the shell environment for pyenv
# Usage: eval "$(pyenv init [-|--path] [--no-push-path] [--detect-shell] [--no-rehash] [<shell>])"
# Usage: eval "$(pyenv init [-|--path] [--no-push-path] [--no-rehash] [<shell>])"
# pyenv init --install [<shell>]
# pyenv init --detect-shell [<shell>]
set -e
[ -n "$PYENV_DEBUG" ] && set -x
@ -9,6 +11,7 @@ set -e
if [ "$1" = "--complete" ]; then
echo -
echo --path
echo --install
echo --no-push-path
echo --no-rehash
echo --detect-shell
@ -30,6 +33,9 @@ while [ "$#" -gt 0 ]; do
--path)
mode="path"
;;
--install)
mode="install"
;;
--detect-shell)
mode="detect-shell"
;;
@ -81,21 +87,23 @@ function main() {
exit 0
;;
"detect-shell")
detect_profile 1
detect_profile
print_detect_shell
exit 0
;;
"install")
install_shell_startup_files
exit 0
;;
esac
# should never get here
exit 2
}
function detect_profile() {
local detect_for_detect_shell="$1"
case "$shell" in
bash )
if [ -e '~/.bash_profile' ]; then
if [ -e "${HOME}/.bash_profile" ]; then
profile='~/.bash_profile'
else
profile='~/.profile'
@ -103,6 +111,10 @@ function detect_profile() {
profile_explain="~/.bash_profile if it exists, otherwise ~/.profile"
rc='~/.bashrc'
;;
fish )
profile='~/.config/fish/config.fish'
rc='~/.config/fish/config.fish'
;;
pwsh )
profile='~/.config/powershell/profile.ps1'
rc='~/.config/powershell/profile.ps1'
@ -121,13 +133,10 @@ function detect_profile() {
rc='~/.profile'
;;
* )
if [ -n "$detect_for_detect_shell" ]; then
profile=
rc=
else
profile='your shell'\''s login startup file'
rc='your shell'\''s interactive startup file'
fi
profile_explain='your shell'\''s login startup file'
rc_explain='your shell'\''s interactive startup file'
;;
esac
}
@ -146,38 +155,32 @@ function help_() {
echo "# Add pyenv executable to PATH by running"
echo "# the following interactively:"
echo
echo 'set -Ux PYENV_ROOT $HOME/.pyenv'
echo 'set -U fish_user_paths $PYENV_ROOT/bin $fish_user_paths'
print_fish_user_path_setup
echo
echo "# Load pyenv automatically by appending"
echo "# the following to ~/.config/fish/config.fish:"
echo
echo 'pyenv init - fish | source'
print_fish_shell_setup
echo
;;
pwsh )
echo '# Load pyenv automatically by appending'
echo "# the following to $profile :"
echo
echo '$Env:PYENV_ROOT="$Env:HOME/.pyenv"'
echo 'if (Test-Path -LP "$Env:PYENV_ROOT/bin" -PathType Container) {'
echo ' $Env:PATH="$Env:PYENV_ROOT/bin:$Env:PATH" }'
echo 'iex ((pyenv init -) -join "`n")'
print_pwsh_shell_setup
;;
* )
echo '# Load pyenv automatically by appending'
echo -n "# the following to "
if [ "$profile" == "$rc" ]; then
echo "$profile :"
if [[ "$profile" == "$rc" && -z $rc_explain ]]; then
echo "${profile_explain:-$profile} :"
else
echo
echo "# ${profile_explain:-$profile} (for login shells)"
echo "# and $rc (for interactive shells) :"
echo "# and ${rc_explain:-$rc} (for interactive shells) :"
fi
echo
echo 'export PYENV_ROOT="$HOME/.pyenv"'
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"'
echo 'eval "$(pyenv init - '$shell')"'
print_posix_shell_setup
;;
esac
echo
@ -186,6 +189,154 @@ function help_() {
} >&2
}
function print_posix_shell_setup() {
echo 'export PYENV_ROOT="$HOME/.pyenv"'
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"'
echo 'eval "$(pyenv init - '$shell')"'
}
function print_fish_shell_setup() {
echo 'pyenv init - fish | source'
}
function print_fish_user_path_setup() {
echo 'set -Ux PYENV_ROOT $HOME/.pyenv'
echo 'if functions -q fish_add_path'
echo ' test -d $PYENV_ROOT/bin; and fish_add_path $PYENV_ROOT/bin'
echo 'else'
echo ' test -d $PYENV_ROOT/bin; and set -U fish_user_paths $PYENV_ROOT/bin $fish_user_paths'
echo 'end'
}
function print_pwsh_shell_setup() {
echo '$Env:PYENV_ROOT="$Env:HOME/.pyenv"'
echo 'if (Test-Path -LP "$Env:PYENV_ROOT/bin" -PathType Container) {'
echo ' $Env:PATH="$Env:PYENV_ROOT/bin:$Env:PATH" }'
echo 'iex ((pyenv init -) -join "`n")'
}
function expand_home_path() {
local path="$1"
printf '%s\n' "${path/#\~/$HOME}"
}
function install_shell_startup_files() {
if [[ -z $HOME ]]; then
echo "pyenv: HOME must be set to configure shell startup files" >&2
return 1
fi
detect_profile
local files=()
local lines=()
local profile_path rc_path setup
case "$shell" in
bash | zsh | ksh | ksh93 | mksh )
rc_path="$(expand_home_path "$rc")"
profile_path="$(expand_home_path "$profile")"
setup="$(print_posix_shell_setup)"
files=("$rc_path")
lines=("$setup")
if [[ $profile_path != "$rc_path" ]]; then
files+=("$profile_path")
lines+=("$setup")
fi
;;
fish )
rc_path="$(expand_home_path "$rc")"
files=("$rc_path")
lines=("$(print_fish_shell_setup)")
;;
pwsh )
rc_path="$(expand_home_path "$rc")"
files=("$rc_path")
lines=("$(print_pwsh_shell_setup)")
;;
* )
echo "pyenv: cannot automatically configure startup files for $shell" >&2
return 1
;;
esac
local index
for ((index = 0; index < ${#files[@]}; index++)); do
check_startup_file "${files[$index]}" || return 1
done
if [[ $shell == fish ]]; then
install_fish_user_paths || return 1
fi
for ((index = 0; index < ${#files[@]}; index++)); do
append_lines "${files[$index]}" "${lines[$index]}"
done
}
function check_startup_file() {
local file="$1"
local grep_status
if [[ ! -e $file ]]; then
return 0
fi
if [[ ! -f $file || ! -r $file ]]; then
echo "pyenv: failed to inspect $file" >&2
return 1
fi
if grep -Fi pyenv "$file" >/dev/null; then
echo "pyenv: cannot automatically apply changes to $file: it appears to already contain Pyenv-related code." >&2
echo "pyenv: review the file's contents and apply changes manually if necessary." >&2
echo "pyenv: run \`pyenv init $shell\` to see the suggested setup." >&2
return 1
else
grep_status=$?
if [[ $grep_status == 1 ]]; then
return 0
fi
echo "pyenv: failed to inspect $file" >&2
return "$grep_status"
fi
}
function install_fish_user_paths() {
local fish_setup
if ! command -v fish >/dev/null; then
echo "pyenv: fish is not available to configure fish universal variables" >&2
return 1
fi
fish_setup="$(print_fish_user_path_setup)"
if ! fish -c "$fish_setup"; then
echo "pyenv: failed to configure fish universal variables" >&2
return 1
fi
}
function append_lines() {
local file="$1"
local lines="$2"
local dir last_char
dir="${file%/*}"
if [[ $dir != "$file" ]]; then
mkdir -p "$dir"
fi
if [[ -s $file ]]; then
last_char="$(tail -c 1 "$file")" || return 1
if [[ -n $last_char ]]; then
echo >> "$file"
fi
fi
printf '%s\n' "$lines" >> "$file"
}
function init_dirs() {
mkdir -p "${PYENV_ROOT}/"{shims,versions}
}

View File

@ -13,15 +13,29 @@ mkdir -p "$SHIM_PATH"
declare last_acquire_error
acquire_lock() {
# Ensure only one instance of pyenv-rehash is running at a time by
# setting the shell's `noclobber` option and attempting to write to
# the prototype shim file.
local ret
# An old lock file is presumed stale. We assume no healthy rehash takes this long.
# The time is picked very small so that a killed rehash holds up new shell sessions
# for as little as possible
find "$PROTOTYPE_SHIM_PATH" -mmin +2 -exec rm -f {} \; 2>/dev/null || true
set -o noclobber
# Assuming an old lockfile is stale
# Unknown why this happens for some users but this at least unblocks them
last_acquire_error="$( { ( echo -n > "$PROTOTYPE_SHIM_PATH"; ) 2>&1 1>&3 3>&1-; } 3>&1)" \
|| { find "$PROTOTYPE_SHIM_PATH" -mmin +10 -exec rm -f {} \; ; ret=1; }
&& trap release_lock EXIT \
|| {
# Linux Landlock and MacOS Seatbelt sandbox subsystems return false information in access(),
# making -w "$SHIM_PATH" not catch the fact that the shims dir is not writable in this case.
# Bash doesn't provide access to errno to check for non-EEXIST error code in `echo >'.
# So check for writablity by trying to write to a different file,
# in a way that taxes the usual use case as little as possible.
if [[ -z $tested_for_other_write_errors ]]; then
( t="$(TMPDIR="$SHIM_PATH" mktemp)" && rm "$t" ) \
&& tested_for_other_write_errors=1 \
|| { echo "pyenv: cannot rehash: $SHIM_PATH isn't writable" >&2
set +o noclobber
exit 1; }
fi
ret=1
}
set +o noclobber
[[ -z "${ret}" ]]
}
@ -32,6 +46,7 @@ remove_prototype_shim() {
release_lock() {
remove_prototype_shim
trap - EXIT
}
if [ ! -w "$SHIM_PATH" ]; then
@ -45,22 +60,8 @@ PYENV_REHASH_TIMEOUT=${PYENV_REHASH_TIMEOUT:-60}
while (( SECONDS <= start + PYENV_REHASH_TIMEOUT )); do
if acquire_lock; then
acquired=1
# If we were able to obtain a lock, register a trap to clean up the
# prototype shim when the process exits.
trap release_lock EXIT
break
else
#Landlock sandbox subsystem in the Linux kernel returns false information in access() as of 6.14.0,
# making -w "$SHIM_PATH" not catch the fact that the shims dir is not writable in this case.
#Bash doesn't provide access to errno to check for non-EEXIST error code in acquire_lock.
#So check for writablity by trying to write to a different file,
# in a way that taxes the usual use case as little as possible.
if [[ -z $tested_for_other_write_errors ]]; then
( t="$(TMPDIR="$SHIM_PATH" mktemp)" && rm "$t" ) && tested_for_other_write_errors=1 ||
{ echo "pyenv: cannot rehash: $SHIM_PATH isn't writable" >&2; break; }
fi
# POSIX sleep(1) doesn't provide subsecond precision, but many others do
sleep 0.1 2>/dev/null || sleep 1
fi

View File

@ -14,7 +14,7 @@
# -g/--debug Build a debug version
#
PYTHON_BUILD_VERSION="2.6.32"
PYTHON_BUILD_VERSION="2.7.2"
OLDIFS="$IFS"
@ -2678,7 +2678,7 @@ if [ -z "${GET_PIP_URL}" ]; then
2.6 | 2.6.* )
GET_PIP_URL="https://bootstrap.pypa.io/pip/2.6/get-pip.py"
;;
2.7 | 2.7.* | pypy2.7 | pypy2.7-* )
2.7 | 2.7.* | pypy2.7 | pypy2.7-* | pypy-c-jit-* )
GET_PIP_URL="https://bootstrap.pypa.io/pip/2.7/get-pip.py"
;;
3.2 | 3.2.* )
@ -2702,6 +2702,9 @@ if [ -z "${GET_PIP_URL}" ]; then
3.8 | 3.8.* | pypy3.8 | pypy3.8-* | pyston* )
GET_PIP_URL="https://bootstrap.pypa.io/pip/3.8/get-pip.py"
;;
3.9 | 3.9.* | pypy3.9 | pypy3.9-* )
GET_PIP_URL="https://bootstrap.pypa.io/pip/3.9/get-pip.py"
;;
* )
GET_PIP_URL="https://bootstrap.pypa.io/get-pip.py"
;;

View File

@ -17,6 +17,7 @@ import os.path
import pathlib
import pprint
import re
import shutil
import subprocess
import sys
import typing
@ -46,6 +47,14 @@ EXCLUDED_VERSIONS= {
here = pathlib.Path(__file__).resolve()
OUT_DIR: pathlib.Path = here.parent.parent / "share" / "python-build"
AUTO_ADD_VERSION_REF_RE = re.compile(
r"^(?P<object_id>[0-9a-f]{40,64})\t"
r"refs/heads/auto_add_version/(?P<versions>\S+)$"
)
OPENSSL_RELEASE_TAG_RE = re.compile(
r"^openssl-(?P<major>\d+)\.\d+(?:\.\d+)*(?:[a-z]+\d*)?$"
)
T_THUNK=\
'''export PYTHON_BUILD_FREE_THREADING=1
source "${BASH_SOURCE[0]%t}"
@ -83,10 +92,13 @@ def adapt_script(version: packaging.version.Version,
url=new_package_url+'#'+new_package_hash,
verify_py_suffix=verify_py_suffix)
elif m:=re.match(r'\s*install_package\s+"(?P<package>openssl-\S+)"\s+'
elif m:=re.match(r'\s*install_package\s+'
r'"(?P<package>openssl-(?P<openssl_major>\d+)\.\S+)"\s+'
r'"(?P<url>\S+)"\s.*$',
line):
item = VersionDirectory.openssl.get_store_latest_release()
item = VersionDirectory.openssl.get_store_latest_release(
int(m.group('openssl_major'))
)
line = Re.sub_groups(m,
package=item.package_name,
@ -129,6 +141,8 @@ def add_version(version: packaging.version.Version):
return False
VersionDirectory.existing.append(_CPythonExistingScriptInfo(version,str(new_path)))
handle_version_patches(version, previous_version, is_prerelease_upgrade)
cleanup_prerelease_upgrade(is_prerelease_upgrade, previous_version, version)
handle_t_thunks(version, previous_version, is_prerelease_upgrade)
@ -137,6 +151,51 @@ def add_version(version: packaging.version.Version):
return True
def handle_version_patches(
version: packaging.version.Version,
previous_version: packaging.version.Version,
is_prerelease_upgrade: bool)\
-> None:
if (previous_version.major, previous_version.minor) != (version.major, version.minor):
return
patches_dir = OUT_DIR / "patches"
previous_patches = patches_dir / str(previous_version)
if not previous_patches.exists():
return
new_patches = patches_dir / str(version)
if is_prerelease_upgrade:
logger.info(f"Git moving patches from {previous_version} to {version}")
subprocess.check_call((
"git", "-C", OUT_DIR, "mv",
f"patches/{previous_version}",
f"patches/{version}",
))
else:
logger.info(f"Copying patches from {previous_version} to {version}")
shutil.copytree(previous_patches, new_patches)
previous_package_patches = new_patches / f"Python-{previous_version}"
new_package_patches = new_patches / f"Python-{version}"
if is_prerelease_upgrade:
subprocess.check_call((
"git", "-C", OUT_DIR, "mv",
f"patches/{version}/Python-{previous_version}",
f"patches/{version}/Python-{version}",
))
else:
previous_package_patches.rename(new_package_patches)
previous_t_patches = patches_dir / f"{previous_version}t"
if previous_t_patches.exists() or previous_t_patches.is_symlink():
if is_prerelease_upgrade:
previous_t_patches.unlink()
(patches_dir / f"{version}t").symlink_to(
str(version), target_is_directory=True
)
def cleanup_prerelease_upgrade(
is_prerelease_upgrade: bool,
previous_version: packaging.version.Version,
@ -211,7 +270,11 @@ def main():
VersionDirectory.available.get_store_available_source_downloads(release, True)
del release
versions_to_add = sorted(VersionDirectory.available.keys() - VersionDirectory.existing.keys())
versions_to_add = sorted(
VersionDirectory.available.keys()
- VersionDirectory.existing.keys()
- get_pending_versions()
)
logger.info("Versions to add:\n"+pprint.pformat(versions_to_add))
result = False
@ -219,6 +282,27 @@ def main():
result = add_version(version_to_add) or result
return int(not result)
def get_pending_versions() -> typing.Set[packaging.version.Version]:
ls_remote = subprocess.check_output(
("git", "-C", OUT_DIR, "ls-remote", "origin",
"refs/heads/auto_add_version/*"),
text=True,
timeout=30,
)
pending_versions = set()
for line in ls_remote.splitlines():
match = AUTO_ADD_VERSION_REF_RE.fullmatch(line)
if not match:
raise ValueError(f"Unexpected git ls-remote output: {line!r}")
pending_versions.update(
packaging.version.Version(version)
for version in match.group("versions").split("_")
)
return pending_versions
def parse_args():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
@ -440,18 +524,41 @@ class _OpenSSLVersionInfo(typing.NamedTuple):
class OpenSSLVersionsDirectory(KeyedList[_OpenSSLVersionInfo, packaging.version.Version]):
key_field = "version"
def get_store_latest_release(self) \
def get_store_latest_release(self, major: int) \
-> _OpenSSLVersionInfo:
if self:
#already retrieved
return self[max(self.keys())]
matching = [
release for release in self
if release.version.major == major
]
if matching:
return max(matching, key=lambda release: release.version)
url = "https://api.github.com/repos/openssl/openssl/releases?per_page=100"
while url:
response = requests.get(url, timeout=30)
response.raise_for_status()
matching = [
release
for release in response.json()
if not release['draft']
and not release['prerelease']
and (match := OPENSSL_RELEASE_TAG_RE.fullmatch(
release['tag_name']
))
and int(match.group('major')) == major
]
if matching:
j_release = matching[0]
break
url = response.links.get('next', {}).get('url')
else:
raise ValueError(f"No OpenSSL {major}.x release found")
j = requests.get("https://api.github.com/repos/openssl/openssl/releases/latest", timeout=30).json()
# noinspection PyTypeChecker
# urlparse can parse str as well as bytes
shasum_url = more_itertools.one(
asset['browser_download_url']
for asset in j['assets']
for asset in j_release['assets']
if urllib.parse.urlparse(asset['browser_download_url']).path.split('/')[-1].endswith('.sha256')
)
shasum_text = requests.get(shasum_url, timeout=30).text
@ -467,7 +574,7 @@ class OpenSSLVersionsDirectory(KeyedList[_OpenSSLVersionInfo, packaging.version.
package_url = more_itertools.one(
asset['browser_download_url']
for asset in j['assets']
for asset in j_release['assets']
if urllib.parse.urlparse(asset['browser_download_url']).path.split('/')[-1] == package_filename
)

View File

@ -6,4 +6,4 @@ packaging
requests
sortedcontainers
tqdm
jc @ git+https://github.com/native-api/jc@haslib_mode
jc

View File

@ -0,0 +1,11 @@
prefer_openssl3
export PYTHON_BUILD_CONFIGURE_WITH_OPENSSL=1
export PYTHON_BUILD_CONFIGURE_WITH_OPENSSL_RPATH=1
export PYTHON_BUILD_TCLTK_USE_PKGCONFIG=1
install_package "openssl-3.6.3" "https://github.com/openssl/openssl/releases/download/openssl-3.6.3/openssl-3.6.3.tar.gz#243a86649cf6f23eeb6a2ff2456e09e5d77dd9018a54d3d96b0c6bdd6ba6c7f1" mac_openssl --if has_broken_mac_openssl
install_package "readline-8.3" "https://ftpmirror.gnu.org/readline/readline-8.3.tar.gz#fe5383204467828cd495ee8d1d3c037a7eba1389c22bc6a041f627976f9061cc" mac_readline --if has_broken_mac_readline
if has_tar_xz_support; then
install_package "Python-3.13.14" "https://www.python.org/ftp/python/3.13.14/Python-3.13.14.tar.xz#639e43243c620a308f968213df9e00f2f8f62332f7adbaa7a7eeb9783057c690" standard verify_py313 copy_python_gdb ensurepip
else
install_package "Python-3.13.14" "https://www.python.org/ftp/python/3.13.14/Python-3.13.14.tgz#5ae535a36af0ebca6fca176ecb8197f5db9c1cb8c8f0cd12cdf1787046db1f41" standard verify_py313 copy_python_gdb ensurepip
fi

View File

@ -0,0 +1,11 @@
prefer_openssl3_to_4
export PYTHON_BUILD_CONFIGURE_WITH_OPENSSL=1
export PYTHON_BUILD_CONFIGURE_WITH_OPENSSL_RPATH=1
export PYTHON_BUILD_TCLTK_USE_PKGCONFIG=1
install_package "openssl-4.0.1" "https://github.com/openssl/openssl/releases/download/openssl-4.0.1/openssl-4.0.1.tar.gz#2db3f3a0d6ea4b59e1f094ace2c8cd536dffb87cdc39084c5afa1e6f7f37dd09" mac_openssl --if has_broken_mac_openssl
install_package "readline-8.3" "https://ftpmirror.gnu.org/readline/readline-8.3.tar.gz#fe5383204467828cd495ee8d1d3c037a7eba1389c22bc6a041f627976f9061cc" mac_readline --if has_broken_mac_readline
if has_tar_xz_support; then
install_package "Python-3.14.6" "https://www.python.org/ftp/python/3.14.6/Python-3.14.6.tar.xz#143b1dddefaec3bd2e21e3b839b34a2b7fb9842272883c576420d605e9f30c63" standard verify_py314 copy_python_gdb ensurepip
else
install_package "Python-3.14.6" "https://www.python.org/ftp/python/3.14.6/Python-3.14.6.tgz#74d0d71d0600e477651a077101d6e62d1e2e69b8e992ba18c993dd643b7ba222" standard verify_py314 copy_python_gdb ensurepip
fi

View File

@ -0,0 +1,2 @@
export PYTHON_BUILD_FREE_THREADING=1
source "${BASH_SOURCE[0]%t}"

View File

@ -1,11 +0,0 @@
prefer_openssl3
export PYTHON_BUILD_CONFIGURE_WITH_OPENSSL=1
export PYTHON_BUILD_CONFIGURE_WITH_OPENSSL_RPATH=1
export PYTHON_BUILD_TCLTK_USE_PKGCONFIG=1
install_package "openssl-3.6.2" "https://github.com/openssl/openssl/releases/download/openssl-3.6.2/openssl-3.6.2.tar.gz#aaf51a1fe064384f811daeaeb4ec4dce7340ec8bd893027eee676af31e83a04f" mac_openssl --if has_broken_mac_openssl
install_package "readline-8.3" "https://ftpmirror.gnu.org/readline/readline-8.3.tar.gz#fe5383204467828cd495ee8d1d3c037a7eba1389c22bc6a041f627976f9061cc" mac_readline --if has_broken_mac_readline
if has_tar_xz_support; then
install_package "Python-3.15.0b1" "https://www.python.org/ftp/python/3.15.0/Python-3.15.0b1.tar.xz#d4d52ccfa1d727ef5235fbb7d70fa1dbacf10b8b3760db622875da05acbe437c" standard verify_py315 copy_python_gdb ensurepip
else
install_package "Python-3.15.0b1" "https://www.python.org/ftp/python/3.15.0/Python-3.15.0b1.tgz#9b41271890067875db7f0f5cb2fdcb944b90c473f272a18a13b93c059d84c68e" standard verify_py315 copy_python_gdb ensurepip
fi

View File

@ -0,0 +1,11 @@
prefer_openssl3
export PYTHON_BUILD_CONFIGURE_WITH_OPENSSL=1
export PYTHON_BUILD_CONFIGURE_WITH_OPENSSL_RPATH=1
export PYTHON_BUILD_TCLTK_USE_PKGCONFIG=1
install_package "openssl-4.0.0" "https://github.com/openssl/openssl/releases/download/openssl-4.0.0/openssl-4.0.0.tar.gz#c32cf49a959c4f345f9606982dd36e7d28f7c58b19c2e25d75624d2b3d2f79ac" mac_openssl --if has_broken_mac_openssl
install_package "readline-8.3" "https://ftpmirror.gnu.org/readline/readline-8.3.tar.gz#fe5383204467828cd495ee8d1d3c037a7eba1389c22bc6a041f627976f9061cc" mac_readline --if has_broken_mac_readline
if has_tar_xz_support; then
install_package "Python-3.15.0b2" "https://www.python.org/ftp/python/3.15.0/Python-3.15.0b2.tar.xz#d14f474ab679e90bc734b02ff58447b6ec99a821af61d6ff0c1da0f86e341a71" standard verify_py315 copy_python_gdb ensurepip
else
install_package "Python-3.15.0b2" "https://www.python.org/ftp/python/3.15.0/Python-3.15.0b2.tgz#781f4bcdef48d1d38b335fdc7a156b4e5fe9738b14456121f949257ff5cce77c" standard verify_py315 copy_python_gdb ensurepip
fi

View File

@ -0,0 +1,2 @@
export PYTHON_BUILD_FREE_THREADING=1
source "${BASH_SOURCE[0]%t}"

View File

@ -2,7 +2,7 @@ prefer_openssl11
install_package "openssl-1.1.0j" "https://www.openssl.org/source/old/1.1.0/openssl-1.1.0j.tar.gz#31bec6c203ce1a8e93d5994f4ed304c63ccf07676118b6634edded12ad1b3246" mac_openssl --if has_broken_mac_openssl
install_package "readline-8.0" "https://ftpmirror.gnu.org/readline/readline-8.0.tar.gz#e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461" mac_readline --if has_broken_mac_readline
if has_tar_xz_support; then
install_package "Python-3.6.10" "https://www.python.org/ftp/python/3.6.10/Python-3.6.10.tar.xz#0a833c398ac8cd7c5538f7232d8531afef943c60495c504484f308dac3af40de" standard verify_py37 copy_python_gdb ensurepip
install_package "Python-3.6.10" "https://www.python.org/ftp/python/3.6.10/Python-3.6.10.tar.xz#0a833c398ac8cd7c5538f7232d8531afef943c60495c504484f308dac3af40de" standard verify_py36 copy_python_gdb ensurepip
else
install_package "Python-3.6.10" "https://www.python.org/ftp/python/3.6.10/Python-3.6.10.tgz#7034dd7cba98d4f94c74f9edd7345bac71c8814c41672c64d9044fa2f96f334d" standard verify_py37 copy_python_gdb ensurepip
install_package "Python-3.6.10" "https://www.python.org/ftp/python/3.6.10/Python-3.6.10.tgz#7034dd7cba98d4f94c74f9edd7345bac71c8814c41672c64d9044fa2f96f334d" standard verify_py36 copy_python_gdb ensurepip
fi

View File

@ -2,7 +2,7 @@ prefer_openssl11
install_package "openssl-1.1.0j" "https://www.openssl.org/source/old/1.1.0/openssl-1.1.0j.tar.gz#31bec6c203ce1a8e93d5994f4ed304c63ccf07676118b6634edded12ad1b3246" mac_openssl --if has_broken_mac_openssl
install_package "readline-8.0" "https://ftpmirror.gnu.org/readline/readline-8.0.tar.gz#e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461" mac_readline --if has_broken_mac_readline
if has_tar_xz_support; then
install_package "Python-3.6.11" "https://www.python.org/ftp/python/3.6.11/Python-3.6.11.tar.xz#741ebdcbc4e3937a5ff23517dd455ebf7d543ea9fef6f5cf6f46e575d6c4fda4" standard verify_py37 copy_python_gdb ensurepip
install_package "Python-3.6.11" "https://www.python.org/ftp/python/3.6.11/Python-3.6.11.tar.xz#741ebdcbc4e3937a5ff23517dd455ebf7d543ea9fef6f5cf6f46e575d6c4fda4" standard verify_py36 copy_python_gdb ensurepip
else
install_package "Python-3.6.11" "https://www.python.org/ftp/python/3.6.11/Python-3.6.11.tgz#96621902f89746fffc22f39749c07da7c2917b232e72352e6837d41850f7b90c" standard verify_py37 copy_python_gdb ensurepip
install_package "Python-3.6.11" "https://www.python.org/ftp/python/3.6.11/Python-3.6.11.tgz#96621902f89746fffc22f39749c07da7c2917b232e72352e6837d41850f7b90c" standard verify_py36 copy_python_gdb ensurepip
fi

View File

@ -2,7 +2,7 @@ prefer_openssl11
install_package "openssl-1.1.0j" "https://www.openssl.org/source/old/1.1.0/openssl-1.1.0j.tar.gz#31bec6c203ce1a8e93d5994f4ed304c63ccf07676118b6634edded12ad1b3246" mac_openssl --if has_broken_mac_openssl
install_package "readline-8.0" "https://ftpmirror.gnu.org/readline/readline-8.0.tar.gz#e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461" mac_readline --if has_broken_mac_readline
if has_tar_xz_support; then
install_package "Python-3.6.12" "https://www.python.org/ftp/python/3.6.12/Python-3.6.12.tar.xz#70953a9b5d6891d92e65d184c3512126a15814bee15e1eff2ddcce04334e9a99" standard verify_py37 copy_python_gdb ensurepip
install_package "Python-3.6.12" "https://www.python.org/ftp/python/3.6.12/Python-3.6.12.tar.xz#70953a9b5d6891d92e65d184c3512126a15814bee15e1eff2ddcce04334e9a99" standard verify_py36 copy_python_gdb ensurepip
else
install_package "Python-3.6.12" "https://www.python.org/ftp/python/3.6.12/Python-3.6.12.tgz#12dddbe52385a0f702fb8071e12dcc6b3cb2dde07cd8db3ed60e90d90ab78693" standard verify_py37 copy_python_gdb ensurepip
install_package "Python-3.6.12" "https://www.python.org/ftp/python/3.6.12/Python-3.6.12.tgz#12dddbe52385a0f702fb8071e12dcc6b3cb2dde07cd8db3ed60e90d90ab78693" standard verify_py36 copy_python_gdb ensurepip
fi

View File

@ -2,7 +2,7 @@ prefer_openssl11
install_package "openssl-1.1.0j" "https://www.openssl.org/source/old/1.1.0/openssl-1.1.0j.tar.gz#31bec6c203ce1a8e93d5994f4ed304c63ccf07676118b6634edded12ad1b3246" mac_openssl --if has_broken_mac_openssl
install_package "readline-8.0" "https://ftpmirror.gnu.org/readline/readline-8.0.tar.gz#e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461" mac_readline --if has_broken_mac_readline
if has_tar_xz_support; then
install_package "Python-3.6.13" "https://www.python.org/ftp/python/3.6.13/Python-3.6.13.tar.xz#a47a43a53abb42286a2c11965343ff56711b9e64e8d11bf2c6701a4fb8ce1a0f" standard verify_py37 copy_python_gdb ensurepip
install_package "Python-3.6.13" "https://www.python.org/ftp/python/3.6.13/Python-3.6.13.tar.xz#a47a43a53abb42286a2c11965343ff56711b9e64e8d11bf2c6701a4fb8ce1a0f" standard verify_py36 copy_python_gdb ensurepip
else
install_package "Python-3.6.13" "https://www.python.org/ftp/python/3.6.13/Python-3.6.13.tgz#614950d3d54f6e78dac651b49c64cfe2ceefea5af3aff3371a9e4b27a53b2669" standard verify_py37 copy_python_gdb ensurepip
install_package "Python-3.6.13" "https://www.python.org/ftp/python/3.6.13/Python-3.6.13.tgz#614950d3d54f6e78dac651b49c64cfe2ceefea5af3aff3371a9e4b27a53b2669" standard verify_py36 copy_python_gdb ensurepip
fi

View File

@ -2,7 +2,7 @@ prefer_openssl11
install_package "openssl-1.1.0j" "https://www.openssl.org/source/old/1.1.0/openssl-1.1.0j.tar.gz#31bec6c203ce1a8e93d5994f4ed304c63ccf07676118b6634edded12ad1b3246" mac_openssl --if has_broken_mac_openssl
install_package "readline-8.0" "https://ftpmirror.gnu.org/readline/readline-8.0.tar.gz#e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461" mac_readline --if has_broken_mac_readline
if has_tar_xz_support; then
install_package "Python-3.6.7" "https://www.python.org/ftp/python/3.6.7/Python-3.6.7.tar.xz#81fd1401a9d66533b0a3e9e3f4ea1c7c6702d57d5b90d659f971e6f1b745f77d" standard verify_py37 copy_python_gdb ensurepip
install_package "Python-3.6.7" "https://www.python.org/ftp/python/3.6.7/Python-3.6.7.tar.xz#81fd1401a9d66533b0a3e9e3f4ea1c7c6702d57d5b90d659f971e6f1b745f77d" standard verify_py36 copy_python_gdb ensurepip
else
install_package "Python-3.6.7" "https://www.python.org/ftp/python/3.6.7/Python-3.6.7.tgz#b7c36f7ed8f7143b2c46153b7332db2227669f583ea0cce753facf549d1a4239" standard verify_py37 copy_python_gdb ensurepip
install_package "Python-3.6.7" "https://www.python.org/ftp/python/3.6.7/Python-3.6.7.tgz#b7c36f7ed8f7143b2c46153b7332db2227669f583ea0cce753facf549d1a4239" standard verify_py36 copy_python_gdb ensurepip
fi

View File

@ -2,7 +2,7 @@ prefer_openssl11
install_package "openssl-1.1.0j" "https://www.openssl.org/source/old/1.1.0/openssl-1.1.0j.tar.gz#31bec6c203ce1a8e93d5994f4ed304c63ccf07676118b6634edded12ad1b3246" mac_openssl --if has_broken_mac_openssl
install_package "readline-8.0" "https://ftpmirror.gnu.org/readline/readline-8.0.tar.gz#e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461" mac_readline --if has_broken_mac_readline
if has_tar_xz_support; then
install_package "Python-3.6.8" "https://www.python.org/ftp/python/3.6.8/Python-3.6.8.tar.xz#35446241e995773b1bed7d196f4b624dadcadc8429f26282e756b2fb8a351193" standard verify_py37 copy_python_gdb ensurepip
install_package "Python-3.6.8" "https://www.python.org/ftp/python/3.6.8/Python-3.6.8.tar.xz#35446241e995773b1bed7d196f4b624dadcadc8429f26282e756b2fb8a351193" standard verify_py36 copy_python_gdb ensurepip
else
install_package "Python-3.6.8" "https://www.python.org/ftp/python/3.6.8/Python-3.6.8.tgz#7f5b1f08b3b0a595387ef6c64c85b1b13b38abef0dd871835ee923262e4f32f0" standard verify_py37 copy_python_gdb ensurepip
install_package "Python-3.6.8" "https://www.python.org/ftp/python/3.6.8/Python-3.6.8.tgz#7f5b1f08b3b0a595387ef6c64c85b1b13b38abef0dd871835ee923262e4f32f0" standard verify_py36 copy_python_gdb ensurepip
fi

View File

@ -2,7 +2,7 @@ prefer_openssl11
install_package "openssl-1.1.0j" "https://www.openssl.org/source/old/1.1.0/openssl-1.1.0j.tar.gz#31bec6c203ce1a8e93d5994f4ed304c63ccf07676118b6634edded12ad1b3246" mac_openssl --if has_broken_mac_openssl
install_package "readline-8.0" "https://ftpmirror.gnu.org/readline/readline-8.0.tar.gz#e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461" mac_readline --if has_broken_mac_readline
if has_tar_xz_support; then
install_package "Python-3.6.9" "https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tar.xz#5e2f5f554e3f8f7f0296f7e73d8600c4e9acbaee6b2555b83206edf5153870da" standard verify_py37 copy_python_gdb ensurepip
install_package "Python-3.6.9" "https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tar.xz#5e2f5f554e3f8f7f0296f7e73d8600c4e9acbaee6b2555b83206edf5153870da" standard verify_py36 copy_python_gdb ensurepip
else
install_package "Python-3.6.9" "https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tgz#47fc92a1dcb946b9ed0abc311d3767b7215c54e655b17fd1d3f9b538195525aa" standard verify_py37 copy_python_gdb ensurepip
install_package "Python-3.6.9" "https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tgz#47fc92a1dcb946b9ed0abc311d3767b7215c54e655b17fd1d3f9b538195525aa" standard verify_py36 copy_python_gdb ensurepip
fi

View File

@ -0,0 +1 @@
3.14.6

View File

@ -1,30 +1,21 @@
case "$(pypy_architecture 2>/dev/null || true)" in
"linux" )
install_nightly_package "pypy-c-jit-latest-linux" "http://buildbot.pypy.org/nightly/trunk/pypy-c-jit-latest-linux.tar.bz2" "pypy-c-jit-*-linux" "pypy" verify_py27 ensurepip
;;
"linux-armel" )
install_nightly_package "pypy-c-jit-latest-linux-armel" "http://buildbot.pypy.org/nightly/trunk/pypy-c-jit-latest-linux-armel.tar.bz2" "pypy-c-jit-*-linux-armel" "pypy" verify_py27 ensurepip
;;
"linux-armhf" )
if [[ "$(cat /etc/issue 2>/dev/null || true)" == "Raspbian"* ]]; then
install_nightly_package "pypy-c-jit-latest-linux-armhf-raspbian" "http://buildbot.pypy.org/nightly/trunk/pypy-c-jit-latest-linux-armhf-raspbian.tar.bz2" "pypy-c-jit-*-linux-armhf-raspbian" "pypy" verify_py27 ensurepip
else
{ echo
colorize 1 "ERROR"
echo ": The binary distribution of PyPy is not available for $(pypy_architecture 2>/dev/null || true)."
echo
} >&2
exit 1
fi
install_nightly_package "pypy-c-jit-latest-linux" "https://buildbot.pypy.org/nightly/main/pypy-c-jit-latest-linux.tar.bz2" "pypy-c-jit-*-linux" "pypy" verify_py27 ensurepip_lt21
;;
"linux64" )
install_nightly_package "pypy-c-jit-latest-linux64" "http://buildbot.pypy.org/nightly/trunk/pypy-c-jit-latest-linux64.tar.bz2" "pypy-c-jit-*-linux64" "pypy" verify_py27 ensurepip
install_nightly_package "pypy-c-jit-latest-linux64" "https://buildbot.pypy.org/nightly/main/pypy-c-jit-latest-linux64.tar.bz2" "pypy-c-jit-*-linux64" "pypy" verify_py27 ensurepip_lt21
;;
"linux-aarch64" )
install_nightly_package "pypy-c-jit-latest-aarch64" "https://buildbot.pypy.org/nightly/main/pypy-c-jit-latest-aarch64.tar.bz2" "pypy-c-jit-*-aarch64" "pypy" verify_py27 ensurepip_lt21
;;
"osarm64" )
install_nightly_package "pypy-c-jit-latest-macos_arm64" "https://buildbot.pypy.org/nightly/main/pypy-c-jit-latest-macos_arm64.tar.bz2" "pypy-c-jit-*-macos_arm64" "pypy" verify_py27 ensurepip_lt21
;;
"osx64" )
install_nightly_package "pypy-c-jit-latest-osx64" "http://buildbot.pypy.org/nightly/trunk/pypy-c-jit-latest-osx64.tar.bz2" "pypy-c-jit-*-osx64" "pypy" verify_py27 ensurepip
install_nightly_package "pypy-c-jit-latest-macos_x86_64" "https://buildbot.pypy.org/nightly/main/pypy-c-jit-latest-macos_x86_64.tar.bz2" "pypy-c-jit-*-macos_x86_64" "pypy" verify_py27 ensurepip_lt21
;;
"win32" )
install_zip "pypy-c-jit-latest-win32" "http://buildbot.pypy.org/nightly/trunk/pypy-c-jit-latest-win32.zip" "pypy" verify_py27 ensurepip
install_zip "pypy-c-jit-latest-win32" "https://buildbot.pypy.org/nightly/main/pypy-c-jit-latest-win32.zip" "pypy" verify_py27 ensurepip_lt21
;;
* )
{ echo

View File

@ -1,49 +0,0 @@
echo
colorize 1 "WARNING"
echo ": This may eat your kittens/ affect timespace in alternate dimensions/"
echo "cause you to complain more. Nightly builds are meant for testing only."
echo
echo "To report bugs/regressions, please see:"
echo
echo "http://doc.pypy.org/en/latest/faq.html#how-should-i-report-a-bug"
echo
case "$(pypy_architecture 2>/dev/null || true)" in
"linux" )
install_nightly_package "pypy-c-jit-latest-linux" "http://buildbot.pypy.org/nightly/py3.5/pypy-c-jit-latest-linux.tar.bz2" "pypy-c-jit-*-linux" "pypy" verify_py27 ensurepip
;;
"linux-armel" )
install_nightly_package "pypy-c-jit-latest-linux-armel" "http://buildbot.pypy.org/nightly/py3.5/pypy-c-jit-latest-linux-armel.tar.bz2" "pypy-c-jit-*-linux-armel" "pypy" verify_py27 ensurepip
;;
"linux-armhf" )
if [[ "$(cat /etc/issue 2>/dev/null || true)" == "Raspbian"* ]]; then
install_nightly_package "pypy-c-jit-latest-linux-armhf-raspbian" "http://buildbot.pypy.org/nightly/py3.5/pypy-c-jit-latest-linux-armhf-raspbian.tar.bz2" "pypy-c-jit-*-linux-armhf-raspbian" "pypy" verify_py27 ensurepip
else
{ echo
colorize 1 "ERROR"
echo ": The latest nightly build of PyPy 3.5 is not available for $(pypy_architecture 2>/dev/null || true),"
echo "Please check http://buildbot.pypy.org/nightly/py3.5/ for previous builds."
echo
} >&2
exit 1
fi
;;
"linux64" )
install_nightly_package "pypy3.5-c-jit-latest-linux64" "http://buildbot.pypy.org/nightly/py3.5/pypy-c-jit-latest-linux64.tar.bz2" "pypy-c-jit-*-linux64" "pypy" verify_py35 ensurepip
;;
"osx64" )
install_nightly_package "pypy-c-jit-latest-osx64" "http://buildbot.pypy.org/nightly/py3.5/pypy-c-jit-latest-osx64.tar.bz2" "pypy-c-jit-*-osx64" "pypy" verify_py27 ensurepip
;;
"win32" )
install_zip "pypy-c-jit-latest-win32" "http://buildbot.pypy.org/nightly/py3.5/pypy-c-jit-latest-win32.zip" "pypy" verify_py27 ensurepip
;;
* )
{ echo
colorize 1 "ERROR"
echo ": The latest nightly build of PyPy 3.5 is not available for $(pypy_architecture 2>/dev/null || true),"
echo "Please check http://buildbot.pypy.org/nightly/py3.5/ for previous builds."
echo
} >&2
exit 1
;;
esac

View File

@ -1,39 +0,0 @@
echo
colorize 1 "WARNING"
echo ": This may eat your kittens/ affect timespace in alternate dimensions/"
echo "cause you to complain more. Nightly builds are meant for testing only."
echo "Current pypy py3.7 development status:"
echo
echo "https://foss.heptapod.net/pypy/pypy/-/wikis/py3.7%20status"
echo
echo "for the latest status updates. To report bugs/regressions, please see:"
echo
echo "https://doc.pypy.org/en/latest/faq.html#how-should-i-report-a-bug"
echo
case "$(pypy_architecture 2>/dev/null || true)" in
"linux" )
install_nightly_package "pypy-c-jit-latest-linux" "https://buildbot.pypy.org/nightly/py3.7/pypy-c-jit-latest-linux.tar.bz2" "pypy-c-jit-*-linux" "pypy" verify_py27 ensurepip
;;
"linux64" )
install_nightly_package "pypy3.7-c-jit-latest-linux64" "https://buildbot.pypy.org/nightly/py3.7/pypy-c-jit-latest-linux64.tar.bz2" "pypy-c-jit-*-linux64" "pypy" verify_py35 ensurepip
;;
"linux-aarch64" )
install_nightly_package "pypy3.7-c-jit-latest-aarch64" "https://buildbot.pypy.org/nightly/py3.7/pypy-c-jit-latest-aarch64.tar.bz2" "pypy-c-jit-*-aarch64" "pypy" verify_py35 ensurepip
;;
"osx64" )
install_nightly_package "pypy-c-jit-latest-osx64" "https://buildbot.pypy.org/nightly/py3.7/pypy-c-jit-latest-osx64.tar.bz2" "pypy-c-jit-*-osx64" "pypy" verify_py27 ensurepip
;;
"win32" )
install_zip "pypy-c-jit-latest-win32" "https://buildbot.pypy.org/nightly/py3.7/pypy-c-jit-latest-win32.zip" "pypy" verify_py27 ensurepip
;;
* )
{ echo
colorize 1 "ERROR"
echo ": The latest nightly build of PyPy 3.7 is not available for $(pypy_architecture 2>/dev/null || true),"
echo "Please check https://buildbot.pypy.org/nightly/py3.7/ for previous builds."
echo
} >&2
exit 1
;;
esac

View File

@ -388,82 +388,39 @@ OUT
assert_success
}
@test "use the custom GET_PIP_URL for 2.6 versions" {
run_inline_definition_with_name --name=2.6 <<OUT
echo "\${GET_PIP_URL}"
OUT
assert_output "https://bootstrap.pypa.io/pip/2.6/get-pip.py"
assert_success
}
@test "use custom GET_PIP_URLs" {
@test "use the custom GET_PIP_URL for 2.7 versions" {
run_inline_definition_with_name --name=2.7 <<OUT
echo "\${GET_PIP_URL}"
OUT
assert_output "https://bootstrap.pypa.io/pip/2.7/get-pip.py"
assert_success
}
declare -a name_subdir=(\
2.6
2.7
3.2
3.3
3.4
3.5
3.6
3.7
3.8
3.9
@test "use the custom GET_PIP_URL for 3.2 versions" {
run_inline_definition_with_name --name=3.2 <<OUT
echo "\${GET_PIP_URL}"
OUT
assert_output "https://bootstrap.pypa.io/pip/3.2/get-pip.py"
assert_success
}
"pypy2.7-7.3.12 2.7"
"pypy-c-jit-latest-linux 2.7"
"pypy3.5-7.0.0 3.5"
"pypy3.6-7.3.3 3.6"
"pypy3.7-7.3.3 3.7"
"pypy3.8-7.3.8 3.8"
"pypy3.9-7.3.16 3.9"
@test "use the custom GET_PIP_URL for 3.3 versions" {
run_inline_definition_with_name --name=3.3 <<OUT
echo "\${GET_PIP_URL}"
OUT
assert_output "https://bootstrap.pypa.io/pip/3.3/get-pip.py"
assert_success
}
"pyston-2.3.5 3.8"
)
@test "use the custom GET_PIP_URL for 3.4 versions" {
run_inline_definition_with_name --name=3.4 <<OUT
echo "\${GET_PIP_URL}"
for item_s in "${name_subdir[@]}"; do
item=($item_s)
name="${item[0]}"
subdir="${item[1]:-$name}"
run_inline_definition_with_name --name="$name" <<OUT
echo "\${DEFINITION_PATH##*/}:\${GET_PIP_URL}"
OUT
assert_output "https://bootstrap.pypa.io/pip/3.4/get-pip.py"
assert_success
}
@test "use the custom GET_PIP_URL for 3.5 versions" {
run_inline_definition_with_name --name=3.5 <<OUT
echo "\${GET_PIP_URL}"
OUT
assert_output "https://bootstrap.pypa.io/pip/3.5/get-pip.py"
assert_success
}
@test "use the custom GET_PIP_URL for 3.6 versions" {
run_inline_definition_with_name --name=3.6 <<OUT
echo "\${GET_PIP_URL}"
OUT
assert_output "https://bootstrap.pypa.io/pip/3.6/get-pip.py"
assert_success
}
@test "use the custom GET_PIP_URL for pypy2.7 versions" {
run_inline_definition_with_name --name=pypy2.7-7.3.12 <<OUT
echo "\${GET_PIP_URL}"
OUT
assert_output "https://bootstrap.pypa.io/pip/2.7/get-pip.py"
assert_success
}
@test "use the custom GET_PIP_URL for pypy3.5 versions" {
run_inline_definition_with_name --name=pypy3.5-7.0.0 <<OUT
echo "\${GET_PIP_URL}"
OUT
assert_output "https://bootstrap.pypa.io/pip/3.5/get-pip.py"
assert_success
}
@test "use the custom GET_PIP_URL for pypy3.6 versions" {
run_inline_definition_with_name --name=pypy3.6-7.3.3 <<OUT
echo "\${GET_PIP_URL}"
OUT
assert_output "https://bootstrap.pypa.io/pip/3.6/get-pip.py"
assert_output "$name:https://bootstrap.pypa.io/pip/$subdir/get-pip.py"
assert_success
done
}

View File

@ -2,8 +2,7 @@
#include <stdlib.h>
#include <stdio.h>
int realpath_builtin(list)
WORD_LIST *list;
int realpath_builtin(WORD_LIST *list)
{
int es;
char *realbuf, *p;

View File

@ -79,6 +79,134 @@ OUT
assert_line "PYENV_SHELL_DETECT=bash"
}
@test "shell detection for fish startup file" {
run pyenv-init --detect-shell fish
assert_success
assert_line "PYENV_SHELL_DETECT=fish"
assert_line "PYENV_PROFILE_DETECT=~/.config/fish/config.fish"
assert_line "PYENV_RC_DETECT=~/.config/fish/config.fish"
}
@test "completion includes install option" {
run pyenv-init --complete
assert_success
assert_line "--install"
}
@test "install setup for detected shell startup files" {
mkdir -p "$HOME"
run pyenv-init --install
assert_success
expected_setup=$'export PYENV_ROOT="$HOME/.pyenv"\n[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"\neval "$(pyenv init - bash)"'
assert_equal "$expected_setup" "$(cat "$HOME/.bashrc")"
assert_equal "$expected_setup" "$(cat "$HOME/.profile")"
}
@test "install setup for bash uses existing bash_profile" {
mkdir -p "$HOME"
touch "$HOME/.bash_profile"
run pyenv-init --install bash
assert_success
expected_setup=$'export PYENV_ROOT="$HOME/.pyenv"\n[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"\neval "$(pyenv init - bash)"'
assert_equal "$expected_setup" "$(cat "$HOME/.bashrc")"
assert_equal "$expected_setup" "$(cat "$HOME/.bash_profile")"
assert [ ! -e "$HOME/.profile" ]
}
@test "install setup for zsh startup files" {
mkdir -p "$HOME"
run pyenv-init --install zsh
assert_success
expected_setup=$'export PYENV_ROOT="$HOME/.pyenv"\n[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"\neval "$(pyenv init - zsh)"'
assert_equal "$expected_setup" "$(cat "$HOME/.zshrc")"
assert_equal "$expected_setup" "$(cat "$HOME/.zprofile")"
}
@test "install setup for fish startup file" {
mkdir -p "$HOME"
create_stub fish <<OUT
printf '%s\n' "\$2" > "$PYENV_TEST_DIR/fish-script"
OUT
run pyenv-init --install fish
assert_success
expected_fish_script=$'set -Ux PYENV_ROOT $HOME/.pyenv\nif functions -q fish_add_path\n test -d $PYENV_ROOT/bin; and fish_add_path $PYENV_ROOT/bin\nelse\n test -d $PYENV_ROOT/bin; and set -U fish_user_paths $PYENV_ROOT/bin $fish_user_paths\nend'
expected_setup='pyenv init - fish | source'
assert_equal "$expected_fish_script" "$(cat "$PYENV_TEST_DIR/fish-script")"
assert_equal "$expected_setup" "$(cat "$HOME/.config/fish/config.fish")"
}
@test "install setup for pwsh startup file" {
mkdir -p "$HOME"
run pyenv-init --install pwsh
assert_success
expected_setup=$'$Env:PYENV_ROOT="$Env:HOME/.pyenv"\nif (Test-Path -LP "$Env:PYENV_ROOT/bin" -PathType Container) {\n $Env:PATH="$Env:PYENV_ROOT/bin:$Env:PATH" }\niex ((pyenv init -) -join "`n")'
assert_equal "$expected_setup" "$(cat "$HOME/.config/powershell/profile.ps1")"
}
@test "install refuses to modify files with pyenv-related code" {
mkdir -p "$HOME"
echo 'eval "$(pyenv init -)"' > "$HOME/.bashrc"
run pyenv-init --install bash
assert_failure
assert_line "pyenv: cannot automatically apply changes to $HOME/.bashrc: it appears to already contain Pyenv-related code."
assert_line "pyenv: review the file's contents and apply changes manually if necessary."
assert_line "pyenv: run \`pyenv init bash\` to see the suggested setup."
assert_equal 'eval "$(pyenv init -)"' "$(cat "$HOME/.bashrc")"
assert [ ! -e "$HOME/.profile" ]
}
@test "install treats PYENV_ROOT as pyenv-related code" {
mkdir -p "$HOME"
echo 'export PYENV_ROOT="$HOME/tools/python-env"' > "$HOME/.bashrc"
run pyenv-init --install bash
assert_failure
assert_line "pyenv: cannot automatically apply changes to $HOME/.bashrc: it appears to already contain Pyenv-related code."
}
@test "install refuses unreadable startup file without partial writes" {
mkdir -p "$HOME/.bashrc"
run pyenv-init --install bash
assert_failure
assert_line "pyenv: failed to inspect $HOME/.bashrc"
assert [ ! -e "$HOME/.profile" ]
}
@test "install setup keeps fish block intact when generic lines already exist" {
mkdir -p "$HOME/.config/fish"
create_stub fish <<OUT
exit 0
OUT
echo "end" > "$HOME/.config/fish/config.fish"
run pyenv-init --install fish
assert_success
expected_setup=$'end\npyenv init - fish | source'
assert_equal "$expected_setup" "$(cat "$HOME/.config/fish/config.fish")"
}
@test "install setup fails gracefully for unsupported shell" {
mkdir -p "$HOME"
run pyenv-init --install nu
assert_failure "pyenv: cannot automatically configure startup files for nu"
}
@test "option to skip rehash" {
run pyenv-init - --no-rehash
assert_success

View File

@ -38,18 +38,17 @@ pyenv: cannot rehash: couldn't acquire lock ${PYENV_ROOT}/shims/.pyenv-shim for
assert_success
}
@test "stale lockfile is removed" {
@test "removes stale lockfile" {
mkdir -p "${PYENV_ROOT}/shims"
#GNU and BSD `date` support generating relative dates via different syntax
# but BusyBox `date` used in Bash Docker images doesn't
# A portable code to set mtime to "N minutes ago" is long and unwieldy,
# see https://unix.stackexchange.com/questions/806015/portably-set-a-files-time-to-n-minutes-ago
# Using a fixed timestamp far in the past is infinitely simpler and good enough for the test
touch -t 200001010000.00 "${PYENV_ROOT}/shims/.pyenv-shim"
run pyenv-rehash
assert_success ""
assert [ ! -e "${PYENV_ROOT}/shims/.pyenv-shim" ]
}
@test "creates shims" {
create_alt_executable_in_version "2.7" "python"
create_alt_executable_in_version "2.7" "fab"