Skip to content

Instantly share code, notes, and snippets.

@pujianto
Last active December 17, 2021 07:29
Show Gist options
  • Save pujianto/7df2413d64480f7797e1f0c434841283 to your computer and use it in GitHub Desktop.
Save pujianto/7df2413d64480f7797e1f0c434841283 to your computer and use it in GitHub Desktop.
Lazy solution to reinstall your Python libraries inside your PEW virtualenv wrapper or plain virtualenv
#!/bin/sh
# THIS SCRIPT IS INTENDED FOR ROLLING RELEASE DISTRO USERS.
# Sometimes my local libraries didn't work after upgrading my Python, so I decided to write this helper script.
#
# Usage:
# venv_upgrade [options]
#
# Options:
# -h, --help Show this help message.
# -p, --path Path to your virtualenv.
# -n, --name Name of your virtualenv (PEW ONLY).
# -l, --list List all virtual environments (PEW ONLY).
# --dry-run Run without actually upgrading your virtualenv.
#
# Some libraries may be not compatible to your new Python version. Be sure to add --dry-run to check it.
# This script can also be sourced from your favorite shell as long as it POSIX compatible (bash, zsh, etc.).
venv_upgrade() {
usage() {
printf "Usage: \n"
printf " venv_upgrade [options]\n\n\n"
printf "Options:\n"
printf " -h, --help\t\t Show this help message.\n"
printf " -p, --path\t\t Path to your virtualenv.\n"
printf " -n, --name\t\t Name of your virtualenv (PEW ONLY).\n"
printf " -l, --list\t\t List all virtual environments (PEW ONLY).\n"
printf " --dry-run\t Run without actually upgrading your virtualenv.\n\n\n"
}
if ! command -v pip >/dev/null 2>&1; then
printf "pip is not installed"
return 1
fi
if ! command -v virtualenv >/dev/null 2>&1; then
printf "virtualenv is not installed"
return 1
fi
VENV_DRY_RUN=0
while [ $# -gt 0 ]; do
case "${1}" in
-h | --help)
usage
shift
return 0
;;
-p | --path)
VENV_DIR_PATH="${2}"
VENV_ENV_NAME=$(basename "${VENV_DIR_PATH}")
if [ ! -d "${VENV_DIR_PATH}" ]; then
printf "Path does not exist"
return 1
fi
shift
shift
;;
-n | --name)
VENV_ENV_NAME="${2}"
if ! command -V pew >/dev/null 2>&1; then
printf "pew is not installed"
return 1
fi
VENV_DIR_PATH=$(python -m pew dir "${VENV_ENV_NAME}")
VENV_RETVAL=$?
if [ $VENV_RETVAL -ne 0 ]; then
return $VENV_RETVAL
fi
shift
shift
;;
-l | --list)
if ! command -V pew >/dev/null 2>&1; then
printf "pew is not installed"
return 1
fi
python -m pew ls
return 0
;;
--dry-run)
printf "\nDry run mode.\n"
VENV_DRY_RUN=1
shift
;;
\
*)
shift
;;
esac
done
if [ -z "${VENV_DIR_PATH}" ] || [ -z "${VENV_ENV_NAME}" ]; then
usage
return 1
fi
VENV_LIB_PATH="${VENV_DIR_PATH}/lib"
VENV_PYTHON_VERSION=$(python -V | awk 'BEGIN{FS=OFS="."} NF--' | sed 's/\s//g' | tr '[:upper:]' '[:lower:]')
VENV_DETECTED_PYTHON_RUNTIMES=$(find "${VENV_LIB_PATH}" -maxdepth 1 ! -path "${VENV_LIB_PATH}" -type d -name "python*" -printf '%f\n' | sort -k1)
VENV_DETECTED_PYTHON_RUNTIMES_COUNT=$(echo "${VENV_DETECTED_PYTHON_RUNTIMES}" | wc -l)
if [ "${VENV_DETECTED_PYTHON_RUNTIMES_COUNT}" -gt 1 ]; then
printf "%d Python runtimes detected: \nPlease specify the one you want to upgrade to: (default 1) \n" "${VENV_DETECTED_PYTHON_RUNTIMES_COUNT}"
VENV_IDX=1
for VENV_PY in ${VENV_DETECTED_PYTHON_RUNTIMES}; do
printf "\t%s. %s\n" "${VENV_IDX}" "${VENV_PY}"
VENV_IDX=$((VENV_IDX + 1))
done
read -r "VENV_RESPONSE"
while true; do
case "${VENV_RESPONSE}" in
*[!0-9]* | '') ;;
*)
if [ "${VENV_RESPONSE}" -gt 0 ] && [ "${VENV_RESPONSE}" -le "${VENV_DETECTED_PYTHON_RUNTIMES_COUNT}" ]; then
VENV_PYTHONLIB_VERSION=$(echo "${VENV_DETECTED_PYTHON_RUNTIMES}" | awk "NR==${VENV_RESPONSE}")
break
fi
;;
esac
printf "Please enter a valid number between 1 and %d\n" "${VENV_DETECTED_PYTHON_RUNTIMES_COUNT}"
read -r "VENV_RESPONSE"
done
else
VENV_PYTHONLIB_VERSION="${VENV_DETECTED_PYTHON_RUNTIMES}"
fi
printf "Upgrading python runtime from %s to %s on %s\n" "${VENV_PYTHONLIB_VERSION}" "${VENV_PYTHON_VERSION}" "${VENV_ENV_NAME}"
if [ "${VENV_PYTHON_VERSION}" = "${VENV_PYTHONLIB_VERSION}" ]; then
printf "(%s) runtime is detected in your virtual environment. Do you want to recreate the virtual environment instead? [y/N]\n" "${VENV_PYTHONLIB_VERSION}"
read -r "VENV_RESPONSE"
case "$VENV_RESPONSE" in
y | Y) ;;
\
*)
printf "Upgrade cancelled. \n"
return 0
;;
esac
fi
VENV_SITE_PACKAGE_PATH="${VENV_LIB_PATH}/${VENV_PYTHONLIB_VERSION}/site-packages"
VENV_PACKAGES=$(python -m pip freeze --path "${VENV_SITE_PACKAGE_PATH}")
if [ -z "${VENV_PACKAGES}" ]; then
printf "No packages found in %s. Aborting.. \n" "${VENV_SITE_PACKAGE_PATH}"
return 1
else
printf "Packages to be installed: \n\n\n%s \n\nContinue? [y/N]?\n" "${VENV_PACKAGES}"
read -r "VENV_RESPONSE"
case "$VENV_RESPONSE" in
y | Y)
printf "Installing..\n"
vENV_TMP_DIR=$(mktemp -d -t venv_upgrade.XXXXXXXXXX)
VENV_TMP_REQUIREMENTS=$(mktemp -t venv_upgrade.requirements.XXXXXXXXXX.txt)
printf "%s" "${VENV_PACKAGES}" >"${VENV_TMP_REQUIREMENTS}"
if [ "${VENV_DRY_RUN}" -eq 0 ]; then
mv "${VENV_DIR_PATH}" "${vENV_TMP_DIR}"
virtualenv "${VENV_DIR_PATH}"
VENV_CMD_INSTALL="${VENV_DIR_PATH}/bin/python -m pip install -r ${VENV_TMP_REQUIREMENTS}"
eval "${VENV_CMD_INSTALL}"
printf "\n\n\nYour packages were installed in %s. \n" "${VENV_DIR_PATH}"
printf "Your old virtual environment moved to %s temporary folder. \n" "${vENV_TMP_DIR}"
printf "If you want to restore the old virtual environment, run mv %s %s \n" "${vENV_TMP_DIR}" "${VENV_DIR_PATH}"
else
printf "Dry run enabled. Trying to install your packages in %s (temporary folder) then delete it.\n" "${vENV_TMP_DIR}"
virtualenv "${vENV_TMP_DIR}"
VENV_CMD_INSTALL="${vENV_TMP_DIR}/bin/python -m pip install -r ${VENV_TMP_REQUIREMENTS}"
eval "${VENV_CMD_INSTALL}"
printf "Cleanup: rm -rf %s \n" "${vENV_TMP_DIR}"
rm -rf "${vENV_TMP_DIR}"
fi
printf "Cleanup tmp requirements file. \n"
rm "${VENV_TMP_REQUIREMENTS}"
;;
*)
printf "Upgrade cancelled. \n"
return 0
;;
esac
return 0
fi
}
return 2>/dev/null || venv_upgrade "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment