ebdd9ac5b4
Make it possible for someone to config PIP_UPGRADE=True in local.conf and thus force pip_install calls to upgrade. In automated testing this is probably a bad idea, but in manual testing or situations where devstack is being used to spin up proof of concepts having the option to use the latest and greatest Python modules is a useful way of exploring the health of the ecosystem. To help with visibility of the setting, and section has been added in configuration.rst near other similar settings. Change-Id: I484c954f1e1f05ed02c0b08e8e4a9c18558c05ef
261 lines
7.8 KiB
Bash
261 lines
7.8 KiB
Bash
#!/bin/bash
|
|
#
|
|
# **inc/python** - Python-related functions
|
|
#
|
|
# Support for pip/setuptools interfaces and virtual environments
|
|
#
|
|
# External functions used:
|
|
# - GetOSVersion
|
|
# - is_fedora
|
|
# - is_suse
|
|
# - safe_chown
|
|
|
|
# Save trace setting
|
|
INC_PY_TRACE=$(set +o | grep xtrace)
|
|
set +o xtrace
|
|
|
|
|
|
# Global Config Variables
|
|
|
|
# PROJECT_VENV contains the name of the virtual enviromnet for each
|
|
# project. A null value installs to the system Python directories.
|
|
declare -A PROJECT_VENV
|
|
|
|
|
|
# Python Functions
|
|
# ================
|
|
|
|
# Get the path to the pip command.
|
|
# get_pip_command
|
|
function get_pip_command {
|
|
which pip || which pip-python
|
|
|
|
if [ $? -ne 0 ]; then
|
|
die $LINENO "Unable to find pip; cannot continue"
|
|
fi
|
|
}
|
|
|
|
# Get the path to the direcotry where python executables are installed.
|
|
# get_python_exec_prefix
|
|
function get_python_exec_prefix {
|
|
local xtrace=$(set +o | grep xtrace)
|
|
set +o xtrace
|
|
if [[ -z "$os_PACKAGE" ]]; then
|
|
GetOSVersion
|
|
fi
|
|
$xtrace
|
|
|
|
if is_fedora || is_suse; then
|
|
echo "/usr/bin"
|
|
else
|
|
echo "/usr/local/bin"
|
|
fi
|
|
}
|
|
|
|
# Wrapper for ``pip install`` to set cache and proxy environment variables
|
|
# Uses globals ``INSTALL_TESTONLY_PACKAGES``, ``OFFLINE``, ``PIP_VIRTUAL_ENV``,
|
|
# ``PIP_UPGRADE``, ``TRACK_DEPENDS``, ``*_proxy``
|
|
# pip_install package [package ...]
|
|
function pip_install {
|
|
local xtrace=$(set +o | grep xtrace)
|
|
set +o xtrace
|
|
local upgrade=""
|
|
local offline=${OFFLINE:-False}
|
|
if [[ "$offline" == "True" || -z "$@" ]]; then
|
|
$xtrace
|
|
return
|
|
fi
|
|
|
|
PIP_UPGRADE=$(trueorfalse False PIP_UPGRADE)
|
|
if [[ "$PIP_UPGRADE" = "True" ]] ; then
|
|
upgrade="--upgrade"
|
|
fi
|
|
|
|
if [[ -z "$os_PACKAGE" ]]; then
|
|
GetOSVersion
|
|
fi
|
|
if [[ $TRACK_DEPENDS = True && ! "$@" =~ virtualenv ]]; then
|
|
# TRACK_DEPENDS=True installation creates a circular dependency when
|
|
# we attempt to install virtualenv into a virualenv, so we must global
|
|
# that installation.
|
|
source $DEST/.venv/bin/activate
|
|
local cmd_pip=$DEST/.venv/bin/pip
|
|
local sudo_pip="env"
|
|
else
|
|
if [[ -n ${PIP_VIRTUAL_ENV:=} && -d ${PIP_VIRTUAL_ENV} ]]; then
|
|
local cmd_pip=$PIP_VIRTUAL_ENV/bin/pip
|
|
local sudo_pip="env"
|
|
else
|
|
local cmd_pip=$(get_pip_command)
|
|
local sudo_pip="sudo -H"
|
|
fi
|
|
fi
|
|
|
|
local pip_version=$(python -c "import pip; \
|
|
print(pip.__version__.strip('.')[0])")
|
|
if (( pip_version<6 )); then
|
|
die $LINENO "Currently installed pip version ${pip_version} does not" \
|
|
"meet minimum requirements (>=6)."
|
|
fi
|
|
|
|
$xtrace
|
|
$sudo_pip \
|
|
http_proxy="${http_proxy:-}" \
|
|
https_proxy="${https_proxy:-}" \
|
|
no_proxy="${no_proxy:-}" \
|
|
PIP_FIND_LINKS=$PIP_FIND_LINKS \
|
|
$cmd_pip install $upgrade \
|
|
$@
|
|
|
|
# Also install test requirements
|
|
local test_req="$@/test-requirements.txt"
|
|
if [[ -e "$test_req" ]]; then
|
|
echo "Installing test-requirements for $test_req"
|
|
$sudo_pip \
|
|
http_proxy=${http_proxy:-} \
|
|
https_proxy=${https_proxy:-} \
|
|
no_proxy=${no_proxy:-} \
|
|
PIP_FIND_LINKS=$PIP_FIND_LINKS \
|
|
$cmd_pip install $upgrade \
|
|
-r $test_req
|
|
fi
|
|
}
|
|
|
|
# get version of a package from global requirements file
|
|
# get_from_global_requirements <package>
|
|
function get_from_global_requirements {
|
|
local package=$1
|
|
local required_pkg=$(grep -h ${package} $REQUIREMENTS_DIR/global-requirements.txt | cut -d\# -f1)
|
|
if [[ $required_pkg == "" ]]; then
|
|
die $LINENO "Can't find package $package in requirements"
|
|
fi
|
|
echo $required_pkg
|
|
}
|
|
|
|
# should we use this library from their git repo, or should we let it
|
|
# get pulled in via pip dependencies.
|
|
function use_library_from_git {
|
|
local name=$1
|
|
local enabled=1
|
|
[[ ,${LIBS_FROM_GIT}, =~ ,${name}, ]] && enabled=0
|
|
return $enabled
|
|
}
|
|
|
|
# setup a library by name. If we are trying to use the library from
|
|
# git, we'll do a git based install, otherwise we'll punt and the
|
|
# library should be installed by a requirements pull from another
|
|
# project.
|
|
function setup_lib {
|
|
local name=$1
|
|
local dir=${GITDIR[$name]}
|
|
setup_install $dir
|
|
}
|
|
|
|
# setup a library by name in editiable mode. If we are trying to use
|
|
# the library from git, we'll do a git based install, otherwise we'll
|
|
# punt and the library should be installed by a requirements pull from
|
|
# another project.
|
|
#
|
|
# use this for non namespaced libraries
|
|
function setup_dev_lib {
|
|
local name=$1
|
|
local dir=${GITDIR[$name]}
|
|
setup_develop $dir
|
|
}
|
|
|
|
# this should be used if you want to install globally, all libraries should
|
|
# use this, especially *oslo* ones
|
|
function setup_install {
|
|
local project_dir=$1
|
|
setup_package_with_req_sync $project_dir
|
|
}
|
|
|
|
# this should be used for projects which run services, like all services
|
|
function setup_develop {
|
|
local project_dir=$1
|
|
setup_package_with_req_sync $project_dir -e
|
|
}
|
|
|
|
# determine if a project as specified by directory is in
|
|
# projects.txt. This will not be an exact match because we throw away
|
|
# the namespacing when we clone, but it should be good enough in all
|
|
# practical ways.
|
|
function is_in_projects_txt {
|
|
local project_dir=$1
|
|
local project_name=$(basename $project_dir)
|
|
return grep "/$project_name\$" $REQUIREMENTS_DIR/projects.txt >/dev/null
|
|
}
|
|
|
|
# ``pip install -e`` the package, which processes the dependencies
|
|
# using pip before running `setup.py develop`
|
|
#
|
|
# Updates the dependencies in project_dir from the
|
|
# openstack/requirements global list before installing anything.
|
|
#
|
|
# Uses globals ``TRACK_DEPENDS``, ``REQUIREMENTS_DIR``, ``UNDO_REQUIREMENTS``
|
|
# setup_develop directory
|
|
function setup_package_with_req_sync {
|
|
local project_dir=$1
|
|
local flags=$2
|
|
|
|
# Don't update repo if local changes exist
|
|
# Don't use buggy "git diff --quiet"
|
|
# ``errexit`` requires us to trap the exit code when the repo is changed
|
|
local update_requirements=$(cd $project_dir && git diff --exit-code >/dev/null || echo "changed")
|
|
|
|
if [[ $update_requirements != "changed" ]]; then
|
|
if [[ "$REQUIREMENTS_MODE" == "soft" ]]; then
|
|
if is_in_projects_txt $project_dir; then
|
|
(cd $REQUIREMENTS_DIR; \
|
|
python update.py $project_dir)
|
|
else
|
|
# soft update projects not found in requirements project.txt
|
|
(cd $REQUIREMENTS_DIR; \
|
|
python update.py -s $project_dir)
|
|
fi
|
|
else
|
|
(cd $REQUIREMENTS_DIR; \
|
|
python update.py $project_dir)
|
|
fi
|
|
fi
|
|
|
|
setup_package $project_dir $flags
|
|
|
|
# We've just gone and possibly modified the user's source tree in an
|
|
# automated way, which is considered bad form if it's a development
|
|
# tree because we've screwed up their next git checkin. So undo it.
|
|
#
|
|
# However... there are some circumstances, like running in the gate
|
|
# where we really really want the overridden version to stick. So provide
|
|
# a variable that tells us whether or not we should UNDO the requirements
|
|
# changes (this will be set to False in the OpenStack ci gate)
|
|
if [ $UNDO_REQUIREMENTS = "True" ]; then
|
|
if [[ $update_requirements != "changed" ]]; then
|
|
(cd $project_dir && git reset --hard)
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# ``pip install -e`` the package, which processes the dependencies
|
|
# using pip before running `setup.py develop`
|
|
# Uses globals ``STACK_USER``
|
|
# setup_develop_no_requirements_update directory
|
|
function setup_package {
|
|
local project_dir=$1
|
|
local flags=$2
|
|
|
|
pip_install $flags $project_dir
|
|
# ensure that further actions can do things like setup.py sdist
|
|
if [[ "$flags" == "-e" ]]; then
|
|
safe_chown -R $STACK_USER $1/*.egg-info
|
|
fi
|
|
}
|
|
|
|
|
|
# Restore xtrace
|
|
$INC_PY_TRACE
|
|
|
|
# Local variables:
|
|
# mode: shell-script
|
|
# End:
|