~cjohnston/ubuntu-ci-services-itself/1285302

« back to all changes in this revision

Viewing changes to ci-utils/ci_utils/setup_helper.py

  • Committer: Chris Johnston
  • Author(s): Andy Doan
  • Date: 2014-02-25 14:12:59 UTC
  • mfrom: (266.2.12 setuptools-pinning)
  • Revision ID: chris_johnston-20140225141259-uhf13di2nmb765nc
[r=Chris Johnston, PS Jenkins bot] pin down our local development dependencies

This gets us using fixed dependencies for local development and should help tarmac.sh run more reliably.  from Andy Doan

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Ubuntu CI Engine
 
2
# Copyright 2014 Canonical Ltd.
 
3
 
 
4
# This program is free software: you can redistribute it and/or modify it
 
5
# under the terms of the GNU Affero General Public License version 3, as
 
6
# published by the Free Software Foundation.
 
7
 
 
8
# This program is distributed in the hope that it will be useful, but
 
9
# WITHOUT ANY WARRANTY; without even the implied warranties of
 
10
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
11
# PURPOSE.  See the GNU Affero General Public License for more details.
 
12
 
 
13
# You should have received a copy of the GNU Affero General Public License
 
14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 
 
16
import os
 
17
import subprocess
 
18
import sys
 
19
 
 
20
import setuptools
 
21
from setuptools.package_index import PackageIndex
 
22
 
 
23
# A branch with all the ez-install deps in a single directory, ie:
 
24
#   lp:~canonical-ci-engineering/ubuntu-ci-services-itself/deps
 
25
PINNED_BRANCH = os.environ.get('CI_DEPS_BRANCH', '')
 
26
_deps = os.path.join(os.path.dirname(__file__), '../../.deps')
 
27
PINNED_LOCAL = os.environ.get('CI_DEPS_LOCAL', os.path.abspath(_deps))
 
28
 
 
29
 
 
30
class HackPI(PackageIndex):
 
31
    '''Ensure we download our dependencies from where we want
 
32
 
 
33
    We want to be able to pin down the location we download our easy-install
 
34
    dependencies from. This ensures we pull them from the place we desire.
 
35
    '''
 
36
    def __init__(self, *args, **kwargs):
 
37
        super(HackPI, self).__init__(*args, **kwargs)
 
38
        if len(PINNED_BRANCH):
 
39
            self.info('CI_DEPS_BRANCH({}) requested at {}'.format(
 
40
                PINNED_BRANCH, PINNED_LOCAL))
 
41
            if os.path.exists(PINNED_LOCAL):
 
42
                self.info('local deps exist, checking for updates')
 
43
                subprocess.check_call(['bzr', 'pull'], cwd=PINNED_LOCAL)
 
44
            else:
 
45
                self.info('Creating new branch for deps')
 
46
                subprocess.check_call(
 
47
                    ['bzr', 'branch', PINNED_BRANCH, PINNED_LOCAL])
 
48
 
 
49
    def _download_url(self, scheme, url, tmpdir):
 
50
        err = '_download_url should not be called with CI_DEPS_BRANCH enabled'
 
51
        if len(PINNED_BRANCH):
 
52
            raise RuntimeError(err)
 
53
        return super(HackPI, self)._download_url(scheme, url, tmpdir)
 
54
 
 
55
    def process_url(self, url, retrieve=False):
 
56
        if not len(PINNED_BRANCH):
 
57
            return super(HackPI, self).process_url(url, retrieve)
 
58
        self.process_filename(PINNED_LOCAL)
 
59
 
 
60
 
 
61
# setuptools is built upon the monkey-patching (probably because it has
 
62
# to override distutils in ways it wasn't designed for). So to hack
 
63
# setuptools we have to monkey patch it.
 
64
import setuptools.command.easy_install
 
65
setuptools.command.easy_install.easy_install.create_index = HackPI
 
66
 
 
67
 
 
68
def _local_pip_file(dep, ver):
 
69
    HackPI()  # ensure our local deps are ready
 
70
    for d in os.listdir(PINNED_LOCAL):
 
71
        if d.startswith('%s-%s' % (dep, ver)):
 
72
            return os.path.join(PINNED_LOCAL, d)
 
73
    raise RuntimeError('Missing dependency: %s' % d)
 
74
 
 
75
 
 
76
def _handle_openstack():
 
77
    # this stuff is required because the pbr library has a bug:
 
78
    #  https://bitbucket.org/pypa/setuptools/issue/73/
 
79
    # in addition the openstack packages like python-glanceclient
 
80
    # fail because they use pbr which does dirty things to setuptools
 
81
    # We do a no-deps option to try and keep what we need for local
 
82
    # development down to a minimum
 
83
    output = subprocess.check_output(['pip', 'freeze'])
 
84
    installed = [x.split('==')[0] for x in output.split('\n')]
 
85
    pips = [
 
86
        'Babel==1.3',
 
87
        'pbr==0.6',
 
88
        'iso8601==0.1.8',
 
89
        'prettytable==0.7.2',
 
90
        'python-glanceclient==0.12.0',
 
91
        'python-keystoneclient==0.6.0',
 
92
        'python-novaclient==2.15.0',
 
93
        'python-swiftclient==1.8.0',
 
94
        'requests==2.2.1'
 
95
    ]
 
96
    for p in pips:
 
97
        dep, ver = p.split('==')
 
98
        if dep in installed:
 
99
            continue
 
100
        if len(PINNED_BRANCH):
 
101
            print('using local copy of pip dependency')
 
102
            p = _local_pip_file(dep, ver)
 
103
        subprocess.check_call(['pip', 'install', '--no-deps', p])
 
104
 
 
105
 
 
106
def setup(name, test_suite, install_requires, **kwargs):
 
107
    '''A simple helper for our components to all call setuptools properly'''
 
108
 
 
109
    # ensure find_packages works if our current directory isn't the component
 
110
    component_dir = os.path.abspath(
 
111
        os.path.join(os.path.dirname(__file__), '../..', name))
 
112
    os.chdir(component_dir)
 
113
 
 
114
    if len(sys.argv) > 1 and sys.argv[1] in ('test', 'develop'):
 
115
        if kwargs.get('requires_openstack'):
 
116
            del kwargs['requires_openstack']
 
117
            _handle_openstack()
 
118
 
 
119
    args = {
 
120
        'name': name,
 
121
        'version': '0.1',
 
122
        'description': '%s component of Ubuntu CI Engine' % name,
 
123
        'author': 'Canonical CI Engineering Team',
 
124
        'license': 'AGPL',
 
125
        'packages': setuptools.find_packages(component_dir),
 
126
        'test_suite': test_suite,
 
127
        'install_requires': install_requires,
 
128
    }
 
129
    for key, val in kwargs.iteritems():
 
130
        args[key] = val
 
131
    return setuptools.setup(**args)