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 — develop ( 6960a7...1d918b )
by
unknown
13:11 queued 06:59
created

create_virtualenv()   C

Complexity

Conditions 8

Size

Total Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
dl 0
loc 55
rs 6.2085
c 1
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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):
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
91
    # 3. Install pack-specific requirements
92
    requirements_file_path = os.path.join(pack_path, 'requirements.txt')
93
    has_requirements = os.path.isfile(requirements_file_path)
94
95
    if has_requirements:
96
        logger.debug('Installing pack specific requirements from "%s"' %
97
                     (requirements_file_path))
98
        install_requirements(virtualenv_path=virtualenv_path,
99
                             requirements_file_path=requirements_file_path)
100
    else:
101
        logger.debug('No pack specific requirements found')
102
103
    action = 'updated' if update else 'created'
104
    logger.debug('Virtualenv for pack "%s" successfully %s in "%s"' %
105
                 (pack_name, action, virtualenv_path))
106
107
108
def create_virtualenv(virtualenv_path, logger=None, include_pip=True, include_setuptools=True,
109
                      include_wheel=True):
110
    """
111
    :param include_pip: Include pip binary and package in the newely created virtual environment.
112
    :type include_pip: ``bool``
113
114
    :param include_setuptools: Include setuptools binary and package in the newely created virtual
115
                               environment.
116
    :type include_setuptools: ``bool``
117
118
    :param include_wheel: Include wheel in the newely created virtual environment.
119
    :type include_wheel : ``bool``
120
    """
121
122
    logger = logger or LOG
123
124
    python_binary = cfg.CONF.actionrunner.python_binary
125
    virtualenv_binary = cfg.CONF.actionrunner.virtualenv_binary
126
    virtualenv_opts = cfg.CONF.actionrunner.virtualenv_opts
127
128
    if not os.path.isfile(python_binary):
129
        raise Exception('Python binary "%s" doesn\'t exist' % (python_binary))
130
131
    if not os.path.isfile(virtualenv_binary):
132
        raise Exception('Virtualenv binary "%s" doesn\'t exist.' % (virtualenv_binary))
133
134
    logger.debug('Creating virtualenv in "%s" using Python binary "%s"' %
135
                 (virtualenv_path, python_binary))
136
137
    cmd = [virtualenv_binary, '-p', python_binary]
138
    cmd.extend(virtualenv_opts)
139
140
    if not include_pip:
141
        cmd.append('--no-pip')
142
143
    if not include_setuptools:
144
        cmd.append('--no-setuptools')
145
146
    if not include_wheel:
147
        cmd.append('--no-wheel')
148
149
    cmd.extend([virtualenv_path])
150
    logger.debug('Running command "%s" to create virtualenv.', ' '.join(cmd))
151
152
    try:
153
        exit_code, _, stderr = run_command(cmd=cmd)
154
    except OSError as e:
155
        raise Exception('Error executing command %s. %s.' % (' '.join(cmd),
156
                                                             e.message))
157
158
    if exit_code != 0:
159
        raise Exception('Failed to create virtualenv in "%s": %s' %
160
                        (virtualenv_path, stderr))
161
162
    return True
163
164
165
def remove_virtualenv(virtualenv_path, logger=None):
166
    """
167
    Remove the provided virtualenv.
168
    """
169
    logger = logger or LOG
170
171
    if not os.path.exists(virtualenv_path):
172
        logger.info('Virtualenv path "%s" doesn\'t exist' % virtualenv_path)
173
        return True
174
175
    logger.debug('Removing virtualenv in "%s"' % virtualenv_path)
176
    try:
177
        shutil.rmtree(virtualenv_path)
178
    except Exception as e:
179
        logger.error('Error while removing virtualenv at "%s": "%s"' % (virtualenv_path, e))
180
        raise e
181
182
    return True
183
184
185
def install_requirements(virtualenv_path, requirements_file_path):
186
    """
187
    Install requirements from a file.
188
    """
189
    pip_path = os.path.join(virtualenv_path, 'bin/pip')
190
    cmd = [pip_path, 'install', '-U', '-r', requirements_file_path]
191
    env = get_env_for_subprocess_command()
192
    exit_code, stdout, stderr = run_command(cmd=cmd, env=env)
193
194
    if exit_code != 0:
195
        stdout = to_ascii(stdout)
196
        stderr = to_ascii(stderr)
197
198
        raise Exception('Failed to install requirements from "%s": %s (stderr: %s)' %
199
                        (requirements_file_path, stdout, stderr))
200
201
    return True
202
203
204
def install_requirement(virtualenv_path, requirement):
205
    """
206
    Install a single requirement.
207
208
    :param requirement: Requirement specifier.
209
    """
210
    pip_path = os.path.join(virtualenv_path, 'bin/pip')
211
    cmd = [pip_path, 'install', requirement]
212
    env = get_env_for_subprocess_command()
213
    exit_code, stdout, stderr = run_command(cmd=cmd, env=env)
214
215
    if exit_code != 0:
216
        raise Exception('Failed to install requirement "%s": %s' %
217
                        (requirement, stdout))
218
219
    return True
220
221
222
def get_env_for_subprocess_command():
223
    """
224
    Retrieve environment to be used with the subprocess command.
225
226
    Note: We remove PYTHONPATH from the environment so the command works
227
    correctly with the newely created virtualenv.
228
    """
229
    env = os.environ.copy()
230
231
    if 'PYTHONPATH' in env:
232
        del env['PYTHONPATH']
233
234
    return env
235