Skip to content

Instantly share code, notes, and snippets.

@jagmoreira
Created May 13, 2017 21:30
Show Gist options
  • Save jagmoreira/b922d0524a5b7bc9500ea4b8c372e66b to your computer and use it in GitHub Desktop.
Save jagmoreira/b922d0524a5b7bc9500ea4b8c372e66b to your computer and use it in GitHub Desktop.
Updates all pyenv virtual environments to the latest micro version of Python
#!/usr/bin/env bash
#
# update_envs_micro_python.sh
#
# Updates all pyenv virtual environments to the latest micro version of Python
#
# Author: Joao Moreira (jagmoreira)
#
# First update pyenv to get any new python versions
if type pyenv >/dev/null 2>&1; then
# Homebrew pyenv
if type brew >/dev/null 2>&1 && [[ -n "$(brew ls | grep pyenv)" ]]; then
brew upgrade pyenv
# Linux pyenv
else
pyenv update
fi
else
echo "Pyenv does not appear to be installed in your system..."
echo
exit 1
fi
# Exit script if any errors occur (commands return non-zero status)
set -e
# If any command in a pipe returns an error, fail the whole pipe
set -o pipefail
# Get currently installed main pythons with derived virtualenvs
MAIN_PYTHONS="$(pyenv versions --skip-aliases --bare | grep / | cut -f 1 -d / | uniq)"
for VERSION in $MAIN_PYTHONS; do
echo
echo "Checking for micro version updates for python $VERSION."
echo
# Get the latest micro version for each A.B python
MAJOR_MINOR="$(echo $VERSION | cut -f 1,2 -d .)"
LATEST_MICRO=$(pyenv install -l | grep -E "(^| )$MAJOR_MINOR" | sort -b -V | tail -n 1 | sed -e 's/^[ \t]*//')
# If there are no new micro versions we move on to the next main Python
if [[ "$VERSION" = "$LATEST_MICRO" ]]; then
echo
echo -n "Version $VERSION is already the latest version in the"
echo " $MAJOR_MINOR.x series."
echo
continue
fi
echo
echo "Found a new micro version for python $VERSION!"
echo "$VERSION -> $LATEST_MICRO"
echo
# Install the latest micro and upgrade pip
pyenv install -s "$LATEST_MICRO"
pyenv rehash
export PYENV_VERSION="$LATEST_MICRO"
pip install --upgrade pip
# Get all virtual environments for this minor version
VENVS="$(pyenv versions --skip-aliases --bare | grep $VERSION/ | cut -f 3 -d /)"
N_VENVS=$(echo $VENVS| wc -w)
echo
echo "Found $N_VENVS virtual environments built with python $VERSION."
echo
for ENV in $VENVS; do
echo
echo "Upgrading micro python version of '$ENV' virtualenv: $VERSION-> $LATEST_MICRO"
echo
ENV_PIP_REQS="__tmp_${ENV}_requirements.pip"
export PYENV_VERSION="$ENV" # "Activate" the virtualenv
pip freeze > $ENV_PIP_REQS
pyenv uninstall -f "$ENV"
pyenv virtualenv "$LATEST_MICRO" "$ENV"
pyenv rehash
echo
echo "Re-installing $ENV with all its packages."
echo
# PYENV_VERSION is still set. No need to update it since it's just a
# string with the virtualenv name, which did not change.
pip install --upgrade pip
# If numpy is present install it manually, otherwise some package
# installations might fail due to mall-formed installation requirements
set +e # Temporarily disabling error checking to catch empty grep result
NUMPY="$(grep numpy= $ENV_PIP_REQS)"
set -e
if [[ -n $NUMPY ]]; then
pip install $NUMPY
fi
# Installation of old versions of statsmodels may fail due to mall-formed
# installation requirements. To prevent this, we install all other
# packages first then try the full requirements file again
if [[ -n "$(grep statsmodels $ENV_PIP_REQS)" ]]; then
sed -e '/statsmodels/d' $ENV_PIP_REQS | pip install -r /dev/stdin
fi
pip install -r $ENV_PIP_REQS
done
# Check for any existing environments for the old minor version
if [[ -z "$(pyenv versions --skip-aliases --bare | grep $VERSION/)" ]]; then
echo
echo -n "No more virtualenvs for python $VERSION."
echo " Deleting this minor version..."
echo
pyenv uninstall -f "$VERSION"
fi
done
# Final cleanup
unset PYENV_VERSION
rm -f __tmp_*_requirements.pip
@karthicraghupathi
Copy link

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment