blob: 39684b6fc5317c1ccf191af5454cd46e7dbe1486 [file] [log] [blame]
Dean Troyer490430d2015-01-30 14:38:35 -06001#!/bin/bash
2#
3# **inc/python** - Python-related functions
4#
5# Support for pip/setuptools interfaces and virtual environments
6#
7# External functions used:
8# - GetOSVersion
9# - is_fedora
10# - is_suse
11# - safe_chown
12
13# Save trace setting
14INC_PY_TRACE=$(set +o | grep xtrace)
15set +o xtrace
16
17
Dean Troyer8c2ce6e2015-02-18 14:47:54 -060018# Global Config Variables
19
20# PROJECT_VENV contains the name of the virtual enviromnet for each
21# project. A null value installs to the system Python directories.
22declare -A PROJECT_VENV
23
24
Dean Troyer490430d2015-01-30 14:38:35 -060025# Python Functions
26# ================
27
28# Get the path to the pip command.
29# get_pip_command
30function get_pip_command {
31 which pip || which pip-python
32
33 if [ $? -ne 0 ]; then
34 die $LINENO "Unable to find pip; cannot continue"
35 fi
36}
37
38# Get the path to the direcotry where python executables are installed.
39# get_python_exec_prefix
40function get_python_exec_prefix {
Dean Troyer2b564762015-02-11 17:01:02 -060041 local xtrace=$(set +o | grep xtrace)
42 set +o xtrace
43 if [[ -z "$os_PACKAGE" ]]; then
44 GetOSVersion
45 fi
46 $xtrace
47
Dean Troyer490430d2015-01-30 14:38:35 -060048 if is_fedora || is_suse; then
49 echo "/usr/bin"
50 else
51 echo "/usr/local/bin"
52 fi
53}
54
55# Wrapper for ``pip install`` to set cache and proxy environment variables
Dean Troyer41d6f852015-03-25 22:42:46 -050056# Uses globals ``OFFLINE``, ``PIP_VIRTUAL_ENV``,
Chris Dentebdd9ac2015-03-04 12:35:14 +000057# ``PIP_UPGRADE``, ``TRACK_DEPENDS``, ``*_proxy``
Dean Troyer490430d2015-01-30 14:38:35 -060058# pip_install package [package ...]
59function pip_install {
60 local xtrace=$(set +o | grep xtrace)
61 set +o xtrace
Chris Dentebdd9ac2015-03-04 12:35:14 +000062 local upgrade=""
Dean Troyer490430d2015-01-30 14:38:35 -060063 local offline=${OFFLINE:-False}
64 if [[ "$offline" == "True" || -z "$@" ]]; then
65 $xtrace
66 return
67 fi
68
Chris Dentebdd9ac2015-03-04 12:35:14 +000069 PIP_UPGRADE=$(trueorfalse False PIP_UPGRADE)
70 if [[ "$PIP_UPGRADE" = "True" ]] ; then
71 upgrade="--upgrade"
72 fi
73
Dean Troyer490430d2015-01-30 14:38:35 -060074 if [[ -z "$os_PACKAGE" ]]; then
75 GetOSVersion
76 fi
77 if [[ $TRACK_DEPENDS = True && ! "$@" =~ virtualenv ]]; then
78 # TRACK_DEPENDS=True installation creates a circular dependency when
79 # we attempt to install virtualenv into a virualenv, so we must global
80 # that installation.
81 source $DEST/.venv/bin/activate
82 local cmd_pip=$DEST/.venv/bin/pip
83 local sudo_pip="env"
84 else
Dean Troyer2b564762015-02-11 17:01:02 -060085 if [[ -n ${PIP_VIRTUAL_ENV:=} && -d ${PIP_VIRTUAL_ENV} ]]; then
86 local cmd_pip=$PIP_VIRTUAL_ENV/bin/pip
87 local sudo_pip="env"
88 else
89 local cmd_pip=$(get_pip_command)
90 local sudo_pip="sudo -H"
91 fi
Dean Troyer490430d2015-01-30 14:38:35 -060092 fi
93
94 local pip_version=$(python -c "import pip; \
95 print(pip.__version__.strip('.')[0])")
96 if (( pip_version<6 )); then
97 die $LINENO "Currently installed pip version ${pip_version} does not" \
98 "meet minimum requirements (>=6)."
99 fi
100
101 $xtrace
102 $sudo_pip \
Eli Qiao6a83c422015-03-17 16:54:16 +0800103 http_proxy="${http_proxy:-}" \
104 https_proxy="${https_proxy:-}" \
105 no_proxy="${no_proxy:-}" \
Joe Gordoncd8824a2015-03-04 16:40:19 -0800106 PIP_FIND_LINKS=$PIP_FIND_LINKS \
Chris Dentebdd9ac2015-03-04 12:35:14 +0000107 $cmd_pip install $upgrade \
Dean Troyer490430d2015-01-30 14:38:35 -0600108 $@
109
Sean Dagueeeb7bda2015-03-25 11:55:32 -0400110 # Also install test requirements
111 local test_req="$@/test-requirements.txt"
112 if [[ -e "$test_req" ]]; then
113 echo "Installing test-requirements for $test_req"
114 $sudo_pip \
115 http_proxy=${http_proxy:-} \
116 https_proxy=${https_proxy:-} \
117 no_proxy=${no_proxy:-} \
118 PIP_FIND_LINKS=$PIP_FIND_LINKS \
Chris Dentebdd9ac2015-03-04 12:35:14 +0000119 $cmd_pip install $upgrade \
Sean Dagueeeb7bda2015-03-25 11:55:32 -0400120 -r $test_req
Dean Troyer490430d2015-01-30 14:38:35 -0600121 fi
122}
123
Joe Gordond5ac7852015-02-06 19:29:23 -0800124# get version of a package from global requirements file
125# get_from_global_requirements <package>
126function get_from_global_requirements {
127 local package=$1
128 local required_pkg=$(grep -h ${package} $REQUIREMENTS_DIR/global-requirements.txt | cut -d\# -f1)
129 if [[ $required_pkg == "" ]]; then
130 die $LINENO "Can't find package $package in requirements"
131 fi
132 echo $required_pkg
133}
134
Dean Troyer490430d2015-01-30 14:38:35 -0600135# should we use this library from their git repo, or should we let it
136# get pulled in via pip dependencies.
137function use_library_from_git {
138 local name=$1
139 local enabled=1
140 [[ ,${LIBS_FROM_GIT}, =~ ,${name}, ]] && enabled=0
141 return $enabled
142}
143
144# setup a library by name. If we are trying to use the library from
145# git, we'll do a git based install, otherwise we'll punt and the
146# library should be installed by a requirements pull from another
147# project.
148function setup_lib {
149 local name=$1
150 local dir=${GITDIR[$name]}
151 setup_install $dir
152}
153
154# setup a library by name in editiable mode. If we are trying to use
155# the library from git, we'll do a git based install, otherwise we'll
156# punt and the library should be installed by a requirements pull from
157# another project.
158#
159# use this for non namespaced libraries
160function setup_dev_lib {
161 local name=$1
162 local dir=${GITDIR[$name]}
163 setup_develop $dir
164}
165
166# this should be used if you want to install globally, all libraries should
167# use this, especially *oslo* ones
168function setup_install {
169 local project_dir=$1
170 setup_package_with_req_sync $project_dir
171}
172
173# this should be used for projects which run services, like all services
174function setup_develop {
175 local project_dir=$1
176 setup_package_with_req_sync $project_dir -e
177}
178
179# determine if a project as specified by directory is in
180# projects.txt. This will not be an exact match because we throw away
181# the namespacing when we clone, but it should be good enough in all
182# practical ways.
183function is_in_projects_txt {
184 local project_dir=$1
185 local project_name=$(basename $project_dir)
186 return grep "/$project_name\$" $REQUIREMENTS_DIR/projects.txt >/dev/null
187}
188
189# ``pip install -e`` the package, which processes the dependencies
190# using pip before running `setup.py develop`
191#
192# Updates the dependencies in project_dir from the
193# openstack/requirements global list before installing anything.
194#
195# Uses globals ``TRACK_DEPENDS``, ``REQUIREMENTS_DIR``, ``UNDO_REQUIREMENTS``
196# setup_develop directory
197function setup_package_with_req_sync {
198 local project_dir=$1
199 local flags=$2
200
201 # Don't update repo if local changes exist
202 # Don't use buggy "git diff --quiet"
203 # ``errexit`` requires us to trap the exit code when the repo is changed
204 local update_requirements=$(cd $project_dir && git diff --exit-code >/dev/null || echo "changed")
205
206 if [[ $update_requirements != "changed" ]]; then
207 if [[ "$REQUIREMENTS_MODE" == "soft" ]]; then
208 if is_in_projects_txt $project_dir; then
209 (cd $REQUIREMENTS_DIR; \
210 python update.py $project_dir)
211 else
212 # soft update projects not found in requirements project.txt
213 (cd $REQUIREMENTS_DIR; \
214 python update.py -s $project_dir)
215 fi
216 else
217 (cd $REQUIREMENTS_DIR; \
218 python update.py $project_dir)
219 fi
220 fi
221
222 setup_package $project_dir $flags
223
224 # We've just gone and possibly modified the user's source tree in an
225 # automated way, which is considered bad form if it's a development
226 # tree because we've screwed up their next git checkin. So undo it.
227 #
228 # However... there are some circumstances, like running in the gate
229 # where we really really want the overridden version to stick. So provide
230 # a variable that tells us whether or not we should UNDO the requirements
231 # changes (this will be set to False in the OpenStack ci gate)
232 if [ $UNDO_REQUIREMENTS = "True" ]; then
233 if [[ $update_requirements != "changed" ]]; then
234 (cd $project_dir && git reset --hard)
235 fi
236 fi
237}
238
239# ``pip install -e`` the package, which processes the dependencies
240# using pip before running `setup.py develop`
241# Uses globals ``STACK_USER``
242# setup_develop_no_requirements_update directory
243function setup_package {
244 local project_dir=$1
245 local flags=$2
246
247 pip_install $flags $project_dir
248 # ensure that further actions can do things like setup.py sdist
249 if [[ "$flags" == "-e" ]]; then
250 safe_chown -R $STACK_USER $1/*.egg-info
251 fi
252}
253
254
255# Restore xtrace
256$INC_PY_TRACE
257
258# Local variables:
259# mode: shell-script
260# End: