GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — plexxi-v2.3.2 ( 5d46fe )
by
unknown
06:59
created

install_requirement()   B

Complexity

Conditions 6

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 6
dl 0
loc 35
rs 7.5384
c 5
b 0
f 0
1
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
2
# contributor license agreements.  See the NOTICE file distributed with
3
# this work for additional information regarding copyright ownership.
4
# The ASF licenses this file to You under the Apache License, Version 2.0
5
# (the "License"); you may not use this file except in compliance with
6
# the License.  You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15
16
"""
17
Pack virtual environment related utility functions.
18
"""
19
20
import os
21
import re
22
import shutil
23
24
from oslo_config import cfg
25
26
from st2common import log as logging
27
from st2common.constants.pack import PACK_REF_WHITELIST_REGEX
28
from st2common.constants.pack import BASE_PACK_REQUIREMENTS
29
from st2common.util.shell import run_command
30
from st2common.util.shell import quote_unix
31
from st2common.util.compat import to_ascii
32
from st2common.content.utils import get_packs_base_paths
33
from st2common.content.utils import get_pack_directory
34
35
__all__ = [
36
    'setup_pack_virtualenv'
37
]
38
39
LOG = logging.getLogger(__name__)
40
41
42
def setup_pack_virtualenv(pack_name, update=False, logger=None, include_pip=True,
43
                          include_setuptools=True, include_wheel=True, proxy_config=None):
44
45
    """
46
    Setup virtual environment for the provided pack.
47
48
    :param pack_name: Name of the pack to setup the virtualenv for.
49
    :type pack_name: ``str``
50
51
    :param update: True to update dependencies inside the virtual environment.
52
    :type update: ``bool``
53
54
    :param logger: Optional logger instance to use. If not provided it defaults to the module
55
                   level logger.
56
    """
57
    logger = logger or LOG
58
59
    if not re.match(PACK_REF_WHITELIST_REGEX, pack_name):
60
        raise ValueError('Invalid pack name "%s"' % (pack_name))
61
62
    base_virtualenvs_path = os.path.join(cfg.CONF.system.base_path, 'virtualenvs/')
63
    virtualenv_path = os.path.join(base_virtualenvs_path, quote_unix(pack_name))
64
65
    # Ensure pack directory exists in one of the search paths
66
    pack_path = get_pack_directory(pack_name=pack_name)
67
68
    logger.debug('Setting up virtualenv for pack "%s" (%s)' % (pack_name, pack_path))
69
70
    if not pack_path:
71
        packs_base_paths = get_packs_base_paths()
72
        search_paths = ', '.join(packs_base_paths)
73
        msg = 'Pack "%s" is not installed. Looked in: %s' % (pack_name, search_paths)
74
        raise Exception(msg)
75
76
    # 1. Create virtualenv if it doesn't exist
77
    if not update or not os.path.exists(virtualenv_path):
78
        # 0. Delete virtual environment if it exists
79
        remove_virtualenv(virtualenv_path=virtualenv_path, logger=logger)
80
81
        # 1. Create virtual environment
82
        logger.debug('Creating virtualenv for pack "%s" in "%s"' % (pack_name, virtualenv_path))
83
        create_virtualenv(virtualenv_path=virtualenv_path, logger=logger, include_pip=include_pip,
84
                          include_setuptools=include_setuptools, include_wheel=include_wheel)
85
86
    # 2. Install base requirements which are common to all the packs
87
    logger.debug('Installing base requirements')
88
    for requirement in BASE_PACK_REQUIREMENTS:
89
        install_requirement(virtualenv_path=virtualenv_path, requirement=requirement,
90
                            proxy_config=proxy_config, logger=logger)
91
92
    # 3. Install pack-specific requirements
93
    requirements_file_path = os.path.join(pack_path, 'requirements.txt')
94
    has_requirements = os.path.isfile(requirements_file_path)
95
96
    if has_requirements:
97
        logger.debug('Installing pack specific requirements from "%s"' %
98
                     (requirements_file_path))
99
        install_requirements(virtualenv_path=virtualenv_path,
100
                             requirements_file_path=requirements_file_path,
101
                             proxy_config=proxy_config,
102
                             logger=logger)
103
    else:
104
        logger.debug('No pack specific requirements found')
105
106
    action = 'updated' if update else 'created'
107
    logger.debug('Virtualenv for pack "%s" successfully %s in "%s"' %
108
                 (pack_name, action, virtualenv_path))
109
110
111
def create_virtualenv(virtualenv_path, logger=None, include_pip=True, include_setuptools=True,
112
                      include_wheel=True):
113
    """
114
    :param include_pip: Include pip binary and package in the newely created virtual environment.
115
    :type include_pip: ``bool``
116
117
    :param include_setuptools: Include setuptools binary and package in the newely created virtual
118
                               environment.
119
    :type include_setuptools: ``bool``
120
121
    :param include_wheel: Include wheel in the newely created virtual environment.
122
    :type include_wheel : ``bool``
123
    """
124
125
    logger = logger or LOG
126
127
    python_binary = cfg.CONF.actionrunner.python_binary
128
    virtualenv_binary = cfg.CONF.actionrunner.virtualenv_binary
129
    virtualenv_opts = cfg.CONF.actionrunner.virtualenv_opts
130
131
    if not os.path.isfile(python_binary):
132
        raise Exception('Python binary "%s" doesn\'t exist' % (python_binary))
133
134
    if not os.path.isfile(virtualenv_binary):
135
        raise Exception('Virtualenv binary "%s" doesn\'t exist.' % (virtualenv_binary))
136
137
    logger.debug('Creating virtualenv in "%s" using Python binary "%s"' %
138
                 (virtualenv_path, python_binary))
139
140
    cmd = [virtualenv_binary, '-p', python_binary]
141
    cmd.extend(virtualenv_opts)
142
143
    if not include_pip:
144
        cmd.append('--no-pip')
145
146
    if not include_setuptools:
147
        cmd.append('--no-setuptools')
148
149
    if not include_wheel:
150
        cmd.append('--no-wheel')
151
152
    cmd.extend([virtualenv_path])
153
    logger.debug('Running command "%s" to create virtualenv.', ' '.join(cmd))
154
155
    try:
156
        exit_code, _, stderr = run_command(cmd=cmd)
157
    except OSError as e:
158
        raise Exception('Error executing command %s. %s.' % (' '.join(cmd),
159
                                                             e.message))
160
161
    if exit_code != 0:
162
        raise Exception('Failed to create virtualenv in "%s": %s' %
163
                        (virtualenv_path, stderr))
164
165
    return True
166
167
168
def remove_virtualenv(virtualenv_path, logger=None):
169
    """
170
    Remove the provided virtualenv.
171
    """
172
    logger = logger or LOG
173
174
    if not os.path.exists(virtualenv_path):
175
        logger.info('Virtualenv path "%s" doesn\'t exist' % virtualenv_path)
176
        return True
177
178
    logger.debug('Removing virtualenv in "%s"' % virtualenv_path)
179
    try:
180
        shutil.rmtree(virtualenv_path)
181
    except Exception as e:
182
        logger.error('Error while removing virtualenv at "%s": "%s"' % (virtualenv_path, e))
183
        raise e
184
185
    return True
186
187
188
def install_requirements(virtualenv_path, requirements_file_path, proxy_config=None, logger=None):
189
    """
190
    Install requirements from a file.
191
    """
192
    logger = logger or LOG
193
    pip_path = os.path.join(virtualenv_path, 'bin/pip')
194
    cmd = [pip_path]
195
196
    if proxy_config:
197
        cert = proxy_config.get('proxy_ca_bundle_path', None)
198
        https_proxy = proxy_config.get('https_proxy', None)
199
        http_proxy = proxy_config.get('http_proxy', None)
200
201
        if http_proxy:
202
            cmd.extend(['--proxy', http_proxy])
203
204
        if https_proxy:
205
            cmd.extend(['--proxy', https_proxy])
206
207
        if cert:
208
            cmd.extend(['--cert', cert])
209
210
    cmd.extend(['install', '-U', '-r', requirements_file_path])
211
    env = get_env_for_subprocess_command()
212
213
    logger.debug('Installing requirements from file %s with command %s.',
214
                 requirements_file_path, ' '.join(cmd))
215
    exit_code, stdout, stderr = run_command(cmd=cmd, env=env)
216
217
    if exit_code != 0:
218
        stdout = to_ascii(stdout)
219
        stderr = to_ascii(stderr)
220
221
        raise Exception('Failed to install requirements from "%s": %s (stderr: %s)' %
222
                        (requirements_file_path, stdout, stderr))
223
224
    return True
225
226
227
def install_requirement(virtualenv_path, requirement, proxy_config=None, logger=None):
228
    """
229
    Install a single requirement.
230
231
    :param requirement: Requirement specifier.
232
    """
233
    logger = logger or LOG
234
    pip_path = os.path.join(virtualenv_path, 'bin/pip')
235
    cmd = [pip_path]
236
237
    if proxy_config:
238
        cert = proxy_config.get('proxy_ca_bundle_path', None)
239
        https_proxy = proxy_config.get('https_proxy', None)
240
        http_proxy = proxy_config.get('http_proxy', None)
241
242
        if http_proxy:
243
            cmd.extend(['--proxy', http_proxy])
244
245
        if https_proxy:
246
            cmd.extend(['--proxy', https_proxy])
247
248
        if cert:
249
            cmd.extend(['--cert', cert])
250
251
    cmd.extend(['install', requirement])
252
    env = get_env_for_subprocess_command()
253
    logger.debug('Installing requirement %s with command %s.',
254
                 requirement, ' '.join(cmd))
255
    exit_code, stdout, stderr = run_command(cmd=cmd, env=env)
256
257
    if exit_code != 0:
258
        raise Exception('Failed to install requirement "%s": %s' %
259
                        (requirement, stdout))
260
261
    return True
262
263
264
def get_env_for_subprocess_command():
265
    """
266
    Retrieve environment to be used with the subprocess command.
267
268
    Note: We remove PYTHONPATH from the environment so the command works
269
    correctly with the newely created virtualenv.
270
    """
271
    env = os.environ.copy()
272
273
    if 'PYTHONPATH' in env:
274
        del env['PYTHONPATH']
275
276
    return env
277