~ursinha/ubuntu-ci-services-itself/401-copying-di-check

« back to all changes in this revision

Viewing changes to juju-deployer/deploy.py

  • Committer: Vincent Ladeuil
  • Date: 2014-03-05 16:43:49 UTC
  • mto: This revision was merged to the branch mainline in revision 327.
  • Revision ID: vila+ci@canonical.com-20140305164349-jr7w6gq23ja3szdl
Use local branches instead of temporary ones for dependencies we run from source.

Put the dependency dirs in front of PYTHONPATH and PATH to ensure we use them instead of local ones.

Using local branches allows local debugging of said dependencies from a branch and avoid re-installing them at each deployment.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
from distutils import spawn
15
15
from itertools import chain
16
16
 
 
17
import bzrlib
 
18
from bzrlib import (
 
19
    builtins,
 
20
    plugin,
 
21
)
 
22
 
 
23
 
 
24
HERE = os.path.abspath(os.path.dirname(__file__))
 
25
 
17
26
# the juju-deployer/ directory.
18
27
deployer_dir = os.path.abspath(os.path.dirname(sys.argv[0]))
19
28
# ci-utils probably isn't in our pythonpath
21
30
from ci_utils import dump_stack
22
31
 
23
32
 
 
33
bzrlib.initialize()
 
34
plugin.load_plugins()
 
35
 
 
36
 
24
37
def check_environment():
25
38
    '''Cheetah requires environment variables for populating our templates'''
26
39
    cheetah_vars = {
108
121
        yield ('-c', os.path.join(d, f))
109
122
 
110
123
 
111
 
def append_python_path(path):
112
 
    path = os.path.abspath(path)
113
 
    if os.environ.get('PYTHONPATH'):
114
 
        os.environ['PYTHONPATH'] += ':%s' % path
115
 
    else:
116
 
        os.environ['PYTHONPATH'] = '%s' % path
117
 
 
118
 
 
119
 
def install(branch, revno=0):
120
 
    """Put a copy of a bzr branch in a temporary directory."""
121
 
 
122
 
    temp_dir = tempfile.mkdtemp()
123
 
    try:
124
 
        cmd = ['bzr', 'co', '--lightweight']
125
 
        if revno > 0:
126
 
            cmd.append('-r%d' % revno)
127
 
        cmd += [branch, temp_dir]
128
 
        subprocess.check_call(cmd)
129
 
        append_python_path(temp_dir)
130
 
    except:
131
 
        shutil.rmtree(temp_dir)
132
 
        raise
133
 
 
134
 
    return temp_dir
135
 
 
136
 
 
137
 
def install_jujuclient():
 
124
def prepend_path(env_var, path):
 
125
    """Put our dependencies paths first so they don't get hidden."""
 
126
    val = os.environ.get(env_var, None)
 
127
    paths = (val and val.split(os.path.pathsep)) or []
 
128
    paths.insert(0, path)
 
129
    os.environ[env_var] = os.path.pathsep.join(paths)
 
130
 
 
131
 
 
132
def get_or_pull_branch(src, dst, revision=None, out=None, err=None):
 
133
    """Get a branch at a given revision.
 
134
 
 
135
    If the branch already exists, pulls the given revision.
 
136
 
 
137
    :param src: The url to get the branch from (any url recognized by bzr).
 
138
 
 
139
    :param dst: The directory where the branch will reside.
 
140
 
 
141
    :param revision: The optional revision to set the branch to.
 
142
    """
 
143
    with bzrlib.initialize(stdout=out, stderr=err):
 
144
        if os.path.exists(dst):
 
145
            cmd = builtins.cmd_pull()
 
146
            args = [src, '-d', dst, '--overwrite']
 
147
        else:
 
148
            cmd = builtins.cmd_branch()
 
149
            args = [src, dst]
 
150
        if revision is not None:
 
151
            args.extend(['--revision', revision])
 
152
        cmd.run_argv_aliases(args)
 
153
 
 
154
 
 
155
def install_jujuclient(where=None):
138
156
    """Install python-jujuclient from bzr. Revision r23 works around problems
139
157
    we were seeing with env watches (LP: #1284183)."""
140
 
    return install('lp:python-jujuclient', revno=24)
141
 
 
142
 
 
143
 
def install_deployer():
144
 
    """Install juju-deployer from bzr. We need juju-deployer from tip to have
145
 
    JUJU_REPOSITORY work properly (r87)."""
146
 
 
147
 
    deployer = install('lp:juju-deployer', revno=103)
148
 
    os.environ['PATH'] = '%s:%s' % (deployer, os.environ['PATH'])
149
 
    deployer_bin = os.path.join(deployer, 'juju-deployer')
 
158
    if where is None:
 
159
        where = os.path.join(HERE, '..', 'branches')
 
160
    dest = os.path.abspath(os.path.join(where, 'charmworldlib'))
 
161
    get_or_pull_branch('lp:python-jujuclient', dest, 'revno:24')
 
162
    prepend_path('PYTHONPATH', dest)
 
163
    return dest
 
164
 
 
165
 
 
166
def install_deployer(where=None):
 
167
    """Install juju-deployer from bzr."""
 
168
    if where is None:
 
169
        where = os.path.join(HERE, '..', 'branches')
 
170
    dest = os.path.abspath(os.path.join(where, 'juju-deployer'))
 
171
    # For an obscure reason tag:0.3.1 is not in lp:juju-deployer
 
172
    get_or_pull_branch('lp:juju-deployer', dest, revision='revno:103')
 
173
    prepend_path('PYTHONPATH', dest)
 
174
    # FIXME: This duplicates setup.py and shouldn't be needed. This specific
 
175
    # piece (juju-deployer) is a weird beast, it installs from source (not pip
 
176
    # nor package), it requires amulet which itself requires urllib3 (among
 
177
    # others), it's used both in unit tests that are executed in a venv and in
 
178
    # ./tests/run.py which is not executed in venv. My head hurts -- vila
 
179
    # 2014-02-12
 
180
    deployer_bin = os.path.join(dest, 'juju-deployer')
150
181
    with open(deployer_bin, 'w') as fp:
151
 
        tmpl = '#!/bin/sh\nPYTHONPATH=%s\nexec python %s/deployer/cli.py $*'
152
 
        fp.write(tmpl % (os.environ['PYTHONPATH'], deployer))
 
182
        tmpl = '#!/bin/sh\nPYTHONPATH={}\nexec python {}/deployer/cli.py $*'
 
183
        fp.write(tmpl.format(os.environ['PYTHONPATH'], dest))
153
184
    st = os.stat(deployer_bin)
154
185
    mode = st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
155
186
    os.chmod(deployer_bin, mode)
156
 
    return deployer
 
187
    prepend_path('PATH', dest)
 
188
    return dest
157
189
 
158
190
 
159
191
def remove_branch(branch_dir):
196
228
            local_charms[release].append(charm)
197
229
            charmdir = os.path.join(charmsdir, release, charm)
198
230
            if os.path.exists(os.path.join(charmdir, 'Makefile')):
199
 
                print('Building charm: %s' % charm)
 
231
                print('Building charm: {}'.format(charm))
200
232
                subprocess.check_call(['make'], cwd=charmdir)
201
233
    return clean_func
202
234
 
252
284
    check_bootstrapped()
253
285
    check_dependencies()
254
286
 
255
 
    temp_dir = install_jujuclient()
256
 
    atexit.register(lambda: remove_branch(temp_dir))
257
 
 
258
 
    temp_dir = install_deployer()
259
 
    atexit.register(lambda: remove_branch(temp_dir))
 
287
    install_jujuclient()
 
288
    install_deployer()
260
289
 
261
290
    # A place to put our generated .yaml files.
262
291
    temp_dir = tempfile.mkdtemp()
263
 
    atexit.register(lambda: shutil.rmtree(temp_dir))
 
292
    atexit.register(shutil.rmtree, temp_dir)
264
293
    working_dir = os.path.join(temp_dir, 'deployer')
 
294
    # Copy all existing .yaml files, they don't need to be populated but
 
295
    # juju-deployer expect them in 'working_dir'.
265
296
    shutil.copytree(deployer_dir, working_dir)
266
297
 
267
298
    if not args.branch_payload and not args.reuse_payload: