blob: f428c1e02118bb466aadac8af0a407695d3d6fe2 [file] [log] [blame]
Matthew Treinish51dfee72013-01-28 15:50:29 -05001# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
Dirk Mueller74af42c2013-06-23 20:50:22 +02003# Copyright 2013 OpenStack Foundation
Matthew Treinish51dfee72013-01-28 15:50:29 -05004# Copyright 2013 IBM Corp.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17
18"""Provides methods needed by installation script for OpenStack development
19virtual environments.
20
Dirk Mueller74af42c2013-06-23 20:50:22 +020021Since this script is used to bootstrap a virtualenv from the system's Python
22environment, it should be kept strictly compatible with Python 2.6.
23
Matthew Treinish51dfee72013-01-28 15:50:29 -050024Synced in from openstack-common
25"""
26
Dirk Mueller74af42c2013-06-23 20:50:22 +020027from __future__ import print_function
28
29import optparse
Matthew Treinish51dfee72013-01-28 15:50:29 -050030import os
31import subprocess
32import sys
33
Matthew Treinish7682cde2013-02-06 16:34:40 -050034
Matthew Treinish51dfee72013-01-28 15:50:29 -050035class InstallVenv(object):
36
Monty Taylor7a3c3792013-07-05 22:15:06 -040037 def __init__(self, root, venv, requirements,
38 test_requirements, py_version,
Matthew Treinish51dfee72013-01-28 15:50:29 -050039 project):
40 self.root = root
41 self.venv = venv
Monty Taylor7a3c3792013-07-05 22:15:06 -040042 self.requirements = requirements
43 self.test_requirements = test_requirements
Matthew Treinish51dfee72013-01-28 15:50:29 -050044 self.py_version = py_version
45 self.project = project
46
47 def die(self, message, *args):
Dirk Mueller74af42c2013-06-23 20:50:22 +020048 print(message % args, file=sys.stderr)
Matthew Treinish51dfee72013-01-28 15:50:29 -050049 sys.exit(1)
50
51 def check_python_version(self):
52 if sys.version_info < (2, 6):
53 self.die("Need Python Version >= 2.6")
54
55 def run_command_with_code(self, cmd, redirect_output=True,
56 check_exit_code=True):
57 """Runs a command in an out-of-process shell.
58
Joe Gordon2b0591d2013-02-14 23:18:39 +000059 Returns the output of that command. Working directory is self.root.
Matthew Treinish51dfee72013-01-28 15:50:29 -050060 """
61 if redirect_output:
62 stdout = subprocess.PIPE
63 else:
64 stdout = None
65
66 proc = subprocess.Popen(cmd, cwd=self.root, stdout=stdout)
67 output = proc.communicate()[0]
68 if check_exit_code and proc.returncode != 0:
69 self.die('Command "%s" failed.\n%s', ' '.join(cmd), output)
70 return (output, proc.returncode)
71
72 def run_command(self, cmd, redirect_output=True, check_exit_code=True):
73 return self.run_command_with_code(cmd, redirect_output,
74 check_exit_code)[0]
75
76 def get_distro(self):
77 if (os.path.exists('/etc/fedora-release') or
78 os.path.exists('/etc/redhat-release')):
Monty Taylor7a3c3792013-07-05 22:15:06 -040079 return Fedora(
80 self.root, self.venv, self.requirements,
81 self.test_requirements, self.py_version, self.project)
Matthew Treinish51dfee72013-01-28 15:50:29 -050082 else:
Monty Taylor7a3c3792013-07-05 22:15:06 -040083 return Distro(
84 self.root, self.venv, self.requirements,
85 self.test_requirements, self.py_version, self.project)
Matthew Treinish51dfee72013-01-28 15:50:29 -050086
87 def check_dependencies(self):
88 self.get_distro().install_virtualenv()
89
90 def create_virtualenv(self, no_site_packages=True):
91 """Creates the virtual environment and installs PIP.
92
93 Creates the virtual environment and installs PIP only into the
94 virtual environment.
95 """
96 if not os.path.isdir(self.venv):
Dirk Mueller74af42c2013-06-23 20:50:22 +020097 print('Creating venv...', end=' ')
Matthew Treinish51dfee72013-01-28 15:50:29 -050098 if no_site_packages:
99 self.run_command(['virtualenv', '-q', '--no-site-packages',
100 self.venv])
101 else:
102 self.run_command(['virtualenv', '-q', self.venv])
Dirk Mueller74af42c2013-06-23 20:50:22 +0200103 print('done.')
Matthew Treinish51dfee72013-01-28 15:50:29 -0500104 else:
Dirk Mueller74af42c2013-06-23 20:50:22 +0200105 print("venv already exists...")
Matthew Treinish51dfee72013-01-28 15:50:29 -0500106 pass
107
108 def pip_install(self, *args):
109 self.run_command(['tools/with_venv.sh',
110 'pip', 'install', '--upgrade'] + list(args),
111 redirect_output=False)
112
113 def install_dependencies(self):
Dirk Mueller74af42c2013-06-23 20:50:22 +0200114 print('Installing dependencies with pip (this can take a while)...')
Matthew Treinish51dfee72013-01-28 15:50:29 -0500115
116 # First things first, make sure our venv has the latest pip and
Monty Taylor7a3c3792013-07-05 22:15:06 -0400117 # setuptools.
118 self.pip_install('pip>=1.3')
119 self.pip_install('setuptools')
Matthew Treinish51dfee72013-01-28 15:50:29 -0500120
Monty Taylor7a3c3792013-07-05 22:15:06 -0400121 self.pip_install('-r', self.requirements)
122 self.pip_install('-r', self.test_requirements)
Matthew Treinish51dfee72013-01-28 15:50:29 -0500123
124 def post_process(self):
125 self.get_distro().post_process()
126
127 def parse_args(self, argv):
128 """Parses command-line arguments."""
Dirk Mueller74af42c2013-06-23 20:50:22 +0200129 parser = optparse.OptionParser()
130 parser.add_option('-n', '--no-site-packages',
131 action='store_true',
132 help="Do not inherit packages from global Python "
133 "install")
134 return parser.parse_args(argv[1:])[0]
Matthew Treinish51dfee72013-01-28 15:50:29 -0500135
136
137class Distro(InstallVenv):
138
139 def check_cmd(self, cmd):
140 return bool(self.run_command(['which', cmd],
141 check_exit_code=False).strip())
142
143 def install_virtualenv(self):
144 if self.check_cmd('virtualenv'):
145 return
146
147 if self.check_cmd('easy_install'):
Dirk Mueller74af42c2013-06-23 20:50:22 +0200148 print('Installing virtualenv via easy_install...', end=' ')
Matthew Treinish51dfee72013-01-28 15:50:29 -0500149 if self.run_command(['easy_install', 'virtualenv']):
Dirk Mueller74af42c2013-06-23 20:50:22 +0200150 print('Succeeded')
Matthew Treinish51dfee72013-01-28 15:50:29 -0500151 return
152 else:
Dirk Mueller74af42c2013-06-23 20:50:22 +0200153 print('Failed')
Matthew Treinish51dfee72013-01-28 15:50:29 -0500154
155 self.die('ERROR: virtualenv not found.\n\n%s development'
156 ' requires virtualenv, please install it using your'
157 ' favorite package management tool' % self.project)
158
159 def post_process(self):
160 """Any distribution-specific post-processing gets done here.
161
162 In particular, this is useful for applying patches to code inside
163 the venv.
164 """
165 pass
166
167
168class Fedora(Distro):
169 """This covers all Fedora-based distributions.
170
171 Includes: Fedora, RHEL, CentOS, Scientific Linux
172 """
173
174 def check_pkg(self, pkg):
175 return self.run_command_with_code(['rpm', '-q', pkg],
176 check_exit_code=False)[1] == 0
177
Matthew Treinish51dfee72013-01-28 15:50:29 -0500178 def apply_patch(self, originalfile, patchfile):
Dirk Mueller74af42c2013-06-23 20:50:22 +0200179 self.run_command(['patch', '-N', originalfile, patchfile],
180 check_exit_code=False)
Matthew Treinish51dfee72013-01-28 15:50:29 -0500181
182 def install_virtualenv(self):
183 if self.check_cmd('virtualenv'):
184 return
185
186 if not self.check_pkg('python-virtualenv'):
Dirk Mueller74af42c2013-06-23 20:50:22 +0200187 self.die("Please install 'python-virtualenv'.")
Matthew Treinish51dfee72013-01-28 15:50:29 -0500188
189 super(Fedora, self).install_virtualenv()
190
191 def post_process(self):
192 """Workaround for a bug in eventlet.
193
194 This currently affects RHEL6.1, but the fix can safely be
195 applied to all RHEL and Fedora distributions.
196
197 This can be removed when the fix is applied upstream.
198
199 Nova: https://bugs.launchpad.net/nova/+bug/884915
Dirk Mueller74af42c2013-06-23 20:50:22 +0200200 Upstream: https://bitbucket.org/eventlet/eventlet/issue/89
201 RHEL: https://bugzilla.redhat.com/958868
Matthew Treinish51dfee72013-01-28 15:50:29 -0500202 """
203
204 # Install "patch" program if it's not there
205 if not self.check_pkg('patch'):
Dirk Mueller74af42c2013-06-23 20:50:22 +0200206 self.die("Please install 'patch'.")
Matthew Treinish51dfee72013-01-28 15:50:29 -0500207
208 # Apply the eventlet patch
209 self.apply_patch(os.path.join(self.venv, 'lib', self.py_version,
210 'site-packages',
211 'eventlet/green/subprocess.py'),
212 'contrib/redhat-eventlet.patch')