| Index: bootstrap/build_deps.py
|
| diff --git a/bootstrap/build_deps.py b/bootstrap/build_deps.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..2a261437781dc2c03ed477bdb7b478e8238de68f
|
| --- /dev/null
|
| +++ b/bootstrap/build_deps.py
|
| @@ -0,0 +1,187 @@
|
| +#!/usr/bin/env python
|
| +# Copyright 2014 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +import argparse
|
| +import contextlib
|
| +import hashlib
|
| +import os
|
| +import shutil
|
| +import subprocess
|
| +import sys
|
| +import tempfile
|
| +
|
| +import bootstrap
|
| +
|
| +
|
| +ROOT = os.path.dirname(os.path.abspath(__file__))
|
| +WHEELHOUSE = os.path.join(ROOT, 'wheelhouse')
|
| +
|
| +GIT_REPO = 'git+https://chromium.googlesource.com/infra/third_party/{}'
|
| +SOURCE_URL = 'gs://{}/sources/{{}}'.format(bootstrap.BUCKET)
|
| +WHEELS_URL = 'gs://{}/wheels/'.format(bootstrap.BUCKET)
|
| +
|
| +
|
| +@contextlib.contextmanager
|
| +def tempdir(*args, **kwargs):
|
| + tdir = None
|
| + try:
|
| + tdir = tempfile.mkdtemp(*args, **kwargs)
|
| + yield tdir
|
| + finally:
|
| + if tdir:
|
| + shutil.rmtree(tdir, ignore_errors=True)
|
| +
|
| +
|
| +@contextlib.contextmanager
|
| +def tempname(*args, **kwargs):
|
| + tmp = None
|
| + try:
|
| + tmp = tempfile.mktemp(*args, **kwargs)
|
| + yield tmp
|
| + finally:
|
| + if tmp:
|
| + try:
|
| + os.unlink(tmp)
|
| + except OSError:
|
| + pass
|
| +
|
| +
|
| +def has_custom_build(name):
|
| + return os.path.exists(os.path.join(ROOT, 'custom_builds', name + '.py'))
|
| +
|
| +
|
| +def pip(*args, **kwargs):
|
| + subprocess.check_call(
|
| + (os.path.join(sys.prefix, 'bin', 'pip'),) + args, **kwargs)
|
| +
|
| +
|
| +def wheel(arg, source_sha, build):
|
| + with tempdir() as tdir:
|
| + pip('wheel', '--no-index', '--no-deps', '--wheel-dir', tdir, arg)
|
| + grab_wheel(tdir, WHEELHOUSE, source_sha, build)
|
| +
|
| +
|
| +def grab_wheel(src, dst, source_sha, build):
|
| + # late import lets us grab the virtualenv pip
|
| + from pip.wheel import Wheel
|
| +
|
| + items = os.listdir(src)
|
| + assert len(items) == 1, 'Wrong number of files in wheel directory: %r' % items
|
| +
|
| + wheelfile = items[0]
|
| + wheel_info = Wheel.wheel_file_re.match(wheelfile)
|
| +
|
| + assert wheel_info is not None, 'Not a wheel file? %r' % wheelfile
|
| +
|
| + os.rename(os.path.join(src, wheelfile),
|
| + os.path.join(dst, '%s-%s_%s%s' % (
|
| + wheel_info.group('namever'),
|
| + build,
|
| + source_sha,
|
| + wheel_info.group(4)
|
| + )))
|
| +
|
| +
|
| +def run_custom_build(name, link, sha, build):
|
| + from pip.index import Link
|
| + from pip.download import unpack_file_url, unpack_vcs_link, is_vcs_url
|
| +
|
| + assert has_custom_build(name)
|
| +
|
| + link = Link(link, trusted=True)
|
| + unpack = unpack_vcs_link if is_vcs_url(link) else unpack_file_url
|
| +
|
| + with tempdir() as tmpd, tempdir() as wheeld: # pylint: disable=C0321
|
| + unpack(link, tmpd)
|
| + m = getattr(__import__('custom_builds.%s' % (name,)), name)
|
| + m.Build(tmpd, wheeld)
|
| + grab_wheel(wheeld, WHEELHOUSE, sha, build)
|
| +
|
| +
|
| +def process_git(name, rev, build):
|
| + print
|
| + print 'Processing (git)', name, rev
|
| +
|
| + url = GIT_REPO.format(name) + '@' + rev
|
| +
|
| + if not has_custom_build(name):
|
| + wheel(url, rev, build)
|
| + else:
|
| + run_custom_build(name, url, rev, build)
|
| +
|
| +
|
| +def process_gs(name, sha_ext, build):
|
| + print
|
| + print 'Processing (gs)', name, sha_ext
|
| +
|
| + sha, ext = sha_ext.split('.', 1)
|
| + with tempname(ext) as tmp:
|
| + link = 'file://' + tmp
|
| + subprocess.check_call(['gsutil', 'cp', SOURCE_URL.format(sha_ext), tmp])
|
| + with open(tmp, 'rb') as f:
|
| + assert hashlib.sha1(f.read()).hexdigest() == sha
|
| + if not has_custom_build(name):
|
| + wheel(link, sha, build)
|
| + else:
|
| + run_custom_build(name, link, sha, build)
|
| +
|
| +
|
| +def clear_wheelhouse():
|
| + shutil.rmtree(WHEELHOUSE, ignore_errors=True)
|
| + try:
|
| + os.makedirs(WHEELHOUSE)
|
| + except OSError:
|
| + pass
|
| +
|
| +
|
| +def push_wheelhouse():
|
| + return subprocess.call(['gsutil', '-m', 'cp', WHEELHOUSE + '/*', WHEELS_URL])
|
| +
|
| +
|
| +def main(args):
|
| + parser = argparse.ArgumentParser()
|
| + parser.add_argument(
|
| + 'to_build', nargs='*',
|
| + help='Names of packages to build. Defaults to all packages.')
|
| + opts = parser.parse_args(args)
|
| + to_build = set(opts.to_build)
|
| +
|
| + build_env = os.path.join(ROOT, 'BUILD_ENV')
|
| +
|
| + print 'Parsing deps.pyl'
|
| + deps = bootstrap.read_deps(os.path.join(ROOT, 'deps.pyl'))
|
| + bootstrap.activate_env(build_env, {'wheel': deps.pop('wheel')})
|
| +
|
| + print 'Finding missing deps'
|
| + missing_deps = {}
|
| + for name, entry in deps.iteritems():
|
| + if to_build and name not in to_build:
|
| + continue
|
| + try:
|
| + bootstrap.get_links({name: entry})
|
| + except bootstrap.NoWheelException:
|
| + missing_deps[name] = entry
|
| +
|
| + if not missing_deps:
|
| + print 'Nothing to process'
|
| + return
|
| +
|
| + print 'Processing deps:'
|
| + bootstrap.print_deps(missing_deps)
|
| +
|
| + for name, options in missing_deps.iteritems():
|
| + clear_wheelhouse()
|
| + # TODO(iannucci): skip entries which already exist in gs
|
| + if 'rev' in options:
|
| + process_git(name, options['rev'], options['build'])
|
| + elif 'gs' in options:
|
| + process_gs(name, options['gs'], options['build'])
|
| + else:
|
| + raise Exception('Invalid options %r for %r' % (options, name))
|
| + push_wheelhouse()
|
| +
|
| +
|
| +if __name__ == '__main__':
|
| + sys.exit(main(sys.argv[1:]))
|
|
|