~ubuntu-repository-cache-charmers/ubuntu-repository-cache/trunk

« back to all changes in this revision

Viewing changes to lib/charmhelpers/fetch/python/packages.py

  • Committer: mergebot at canonical
  • Author(s): "Barry Price"
  • Date: 2019-05-08 15:32:38 UTC
  • mfrom: (250.1.3 ubuntu-repository-cache)
  • Revision ID: mergebot@juju-139df4-prod-is-toolbox-0.canonical.com-20190508153238-osgo1v8tcexwbjp6
Sync charm-helpers from upstream

Reviewed-on: https://code.launchpad.net/~barryprice/ubuntu-repository-cache/charmhelpers-sync/+merge/366887
Reviewed-by: Stuart Bishop <stuart.bishop@canonical.com>

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
# coding: utf-8
 
3
 
 
4
# Copyright 2014-2015 Canonical Limited.
 
5
#
 
6
# Licensed under the Apache License, Version 2.0 (the "License");
 
7
# you may not use this file except in compliance with the License.
 
8
# You may obtain 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,
 
14
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
15
# See the License for the specific language governing permissions and
 
16
# limitations under the License.
 
17
 
 
18
import os
 
19
import six
 
20
import subprocess
 
21
import sys
 
22
 
 
23
from charmhelpers.fetch import apt_install, apt_update
 
24
from charmhelpers.core.hookenv import charm_dir, log
 
25
 
 
26
__author__ = "Jorge Niedbalski <jorge.niedbalski@canonical.com>"
 
27
 
 
28
 
 
29
def pip_execute(*args, **kwargs):
 
30
    """Overriden pip_execute() to stop sys.path being changed.
 
31
 
 
32
    The act of importing main from the pip module seems to cause add wheels
 
33
    from the /usr/share/python-wheels which are installed by various tools.
 
34
    This function ensures that sys.path remains the same after the call is
 
35
    executed.
 
36
    """
 
37
    try:
 
38
        _path = sys.path
 
39
        try:
 
40
            from pip import main as _pip_execute
 
41
        except ImportError:
 
42
            apt_update()
 
43
            if six.PY2:
 
44
                apt_install('python-pip')
 
45
            else:
 
46
                apt_install('python3-pip')
 
47
            from pip import main as _pip_execute
 
48
        _pip_execute(*args, **kwargs)
 
49
    finally:
 
50
        sys.path = _path
 
51
 
 
52
 
 
53
def parse_options(given, available):
 
54
    """Given a set of options, check if available"""
 
55
    for key, value in sorted(given.items()):
 
56
        if not value:
 
57
            continue
 
58
        if key in available:
 
59
            yield "--{0}={1}".format(key, value)
 
60
 
 
61
 
 
62
def pip_install_requirements(requirements, constraints=None, **options):
 
63
    """Install a requirements file.
 
64
 
 
65
    :param constraints: Path to pip constraints file.
 
66
    http://pip.readthedocs.org/en/stable/user_guide/#constraints-files
 
67
    """
 
68
    command = ["install"]
 
69
 
 
70
    available_options = ('proxy', 'src', 'log', )
 
71
    for option in parse_options(options, available_options):
 
72
        command.append(option)
 
73
 
 
74
    command.append("-r {0}".format(requirements))
 
75
    if constraints:
 
76
        command.append("-c {0}".format(constraints))
 
77
        log("Installing from file: {} with constraints {} "
 
78
            "and options: {}".format(requirements, constraints, command))
 
79
    else:
 
80
        log("Installing from file: {} with options: {}".format(requirements,
 
81
                                                               command))
 
82
    pip_execute(command)
 
83
 
 
84
 
 
85
def pip_install(package, fatal=False, upgrade=False, venv=None,
 
86
                constraints=None, **options):
 
87
    """Install a python package"""
 
88
    if venv:
 
89
        venv_python = os.path.join(venv, 'bin/pip')
 
90
        command = [venv_python, "install"]
 
91
    else:
 
92
        command = ["install"]
 
93
 
 
94
    available_options = ('proxy', 'src', 'log', 'index-url', )
 
95
    for option in parse_options(options, available_options):
 
96
        command.append(option)
 
97
 
 
98
    if upgrade:
 
99
        command.append('--upgrade')
 
100
 
 
101
    if constraints:
 
102
        command.extend(['-c', constraints])
 
103
 
 
104
    if isinstance(package, list):
 
105
        command.extend(package)
 
106
    else:
 
107
        command.append(package)
 
108
 
 
109
    log("Installing {} package with options: {}".format(package,
 
110
                                                        command))
 
111
    if venv:
 
112
        subprocess.check_call(command)
 
113
    else:
 
114
        pip_execute(command)
 
115
 
 
116
 
 
117
def pip_uninstall(package, **options):
 
118
    """Uninstall a python package"""
 
119
    command = ["uninstall", "-q", "-y"]
 
120
 
 
121
    available_options = ('proxy', 'log', )
 
122
    for option in parse_options(options, available_options):
 
123
        command.append(option)
 
124
 
 
125
    if isinstance(package, list):
 
126
        command.extend(package)
 
127
    else:
 
128
        command.append(package)
 
129
 
 
130
    log("Uninstalling {} package with options: {}".format(package,
 
131
                                                          command))
 
132
    pip_execute(command)
 
133
 
 
134
 
 
135
def pip_list():
 
136
    """Returns the list of current python installed packages
 
137
    """
 
138
    return pip_execute(["list"])
 
139
 
 
140
 
 
141
def pip_create_virtualenv(path=None):
 
142
    """Create an isolated Python environment."""
 
143
    if six.PY2:
 
144
        apt_install('python-virtualenv')
 
145
    else:
 
146
        apt_install('python3-virtualenv')
 
147
 
 
148
    if path:
 
149
        venv_path = path
 
150
    else:
 
151
        venv_path = os.path.join(charm_dir(), 'venv')
 
152
 
 
153
    if not os.path.exists(venv_path):
 
154
        subprocess.check_call(['virtualenv', venv_path])