OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 import argparse |
| 7 import glob |
| 8 import hashlib |
| 9 import os |
| 10 import shutil |
| 11 import subprocess |
| 12 import sys |
| 13 |
| 14 import bootstrap |
| 15 |
| 16 from util import ROOT, WHEELHOUSE, WHEELS_URL, SOURCE_URL, LOCAL_STORAGE_PATH |
| 17 from util import tempdir, tempname, platform_tag, merge_deps, print_deps |
| 18 |
| 19 |
| 20 REPO_HOST = 'git+https://chromium.googlesource.com/' |
| 21 GSUTIL = os.path.join( |
| 22 os.path.dirname( |
| 23 os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), |
| 24 'depot_tools', 'gsutil.py') |
| 25 |
| 26 |
| 27 def has_custom_build(name): |
| 28 return os.path.exists(os.path.join(ROOT, 'custom_builds', name + '.py')) |
| 29 |
| 30 |
| 31 def pip(*args, **kwargs): |
| 32 bin_dir = 'Scripts' if sys.platform.startswith('win') else 'bin' |
| 33 subprocess.check_call( |
| 34 (os.path.join(sys.prefix, bin_dir, 'pip'),) + args, **kwargs) |
| 35 |
| 36 |
| 37 def wheel(arg, source_sha, build, build_options): |
| 38 with tempdir() as tdir: |
| 39 args = ['wheel', '--no-index', '--no-deps', '--wheel-dir', tdir] |
| 40 for op in build_options: |
| 41 args += ['--global-option', op] |
| 42 args += [arg] |
| 43 pip(*args) |
| 44 grab_wheel(tdir, WHEELHOUSE, source_sha, build) |
| 45 |
| 46 |
| 47 def grab_wheel(src, dst, source_sha, build): |
| 48 # late import lets us grab the virtualenv pip |
| 49 from pip.wheel import Wheel # pylint: disable=E0611 |
| 50 |
| 51 items = os.listdir(src) |
| 52 assert len(items) == 1, 'Wrong number of files in wheel directory: %r' % items |
| 53 |
| 54 wheelfile = items[0] |
| 55 wheel_info = Wheel.wheel_file_re.match(wheelfile) |
| 56 |
| 57 assert wheel_info is not None, 'Not a wheel file? %r' % wheelfile |
| 58 |
| 59 plat_tag = '' |
| 60 if not wheelfile.endswith('none-any.whl'): |
| 61 plat_tag = platform_tag() |
| 62 |
| 63 shutil.copyfile( |
| 64 os.path.join(src, wheelfile), |
| 65 os.path.join(dst, '{}-{}_{}{}{}'.format( |
| 66 wheel_info.group('namever'), |
| 67 build, |
| 68 source_sha, |
| 69 plat_tag, |
| 70 wheel_info.group(4), |
| 71 ))) |
| 72 |
| 73 |
| 74 def run_custom_build(name, link, sha, build): |
| 75 from pip.index import Link |
| 76 from pip.download import unpack_file_url, unpack_vcs_link, is_vcs_url |
| 77 |
| 78 assert has_custom_build(name) |
| 79 |
| 80 link = Link(link, trusted=True) |
| 81 unpack = unpack_vcs_link if is_vcs_url(link) else unpack_file_url |
| 82 |
| 83 with tempdir() as tmpd, tempdir() as wheeld: # pylint: disable=C0321 |
| 84 unpack(link, tmpd) |
| 85 m = getattr(__import__('custom_builds.%s' % (name,)), name) |
| 86 m.Build(tmpd, wheeld) |
| 87 grab_wheel(wheeld, WHEELHOUSE, sha, build) |
| 88 |
| 89 |
| 90 def process_git(name, rev, build, build_options, repo): |
| 91 print |
| 92 print 'Processing (git)', name, rev |
| 93 |
| 94 url = repo + '@' + rev |
| 95 if not url.startswith('git+https://'): |
| 96 url = REPO_HOST + url |
| 97 |
| 98 if not has_custom_build(name): |
| 99 wheel(url, rev, build, build_options) |
| 100 else: |
| 101 run_custom_build(name, url, rev, build) |
| 102 |
| 103 |
| 104 def process_gs(name, sha_ext, build, build_options): |
| 105 print |
| 106 print 'Processing (gs)', name, sha_ext |
| 107 |
| 108 sha, ext = sha_ext.split('.', 1) |
| 109 with tempname(ext) as tmp: |
| 110 link = 'file://' + tmp |
| 111 subprocess.check_call([ |
| 112 sys.executable, GSUTIL, '--force-version', '4.7', 'cp', |
| 113 SOURCE_URL.format(sha_ext), tmp]) |
| 114 with open(tmp, 'rb') as f: |
| 115 assert hashlib.sha1(f.read()).hexdigest() == sha |
| 116 if not has_custom_build(name): |
| 117 wheel(link, sha, build, build_options) |
| 118 else: |
| 119 run_custom_build(name, link, sha, build) |
| 120 |
| 121 |
| 122 def clear_wheelhouse(): |
| 123 shutil.rmtree(WHEELHOUSE, ignore_errors=True) |
| 124 try: |
| 125 os.makedirs(WHEELHOUSE) |
| 126 except OSError: |
| 127 pass |
| 128 |
| 129 |
| 130 def push_wheelhouse(): |
| 131 status = subprocess.call([ |
| 132 sys.executable, GSUTIL, '--force-version', '4.7', '-m', 'cp', |
| 133 os.path.join(WHEELHOUSE, '*'), WHEELS_URL]) |
| 134 if status: |
| 135 print('Failed to upload wheels, falling back to local cache') |
| 136 if not os.path.isdir(LOCAL_STORAGE_PATH): |
| 137 os.makedirs(LOCAL_STORAGE_PATH) |
| 138 for filename in glob.glob(os.path.join(WHEELHOUSE, '*')): |
| 139 shutil.copy(filename, LOCAL_STORAGE_PATH) |
| 140 return status |
| 141 |
| 142 def main(args): |
| 143 parser = argparse.ArgumentParser() |
| 144 parser.add_argument( |
| 145 '--deps_file', action='append', |
| 146 help='Path to deps.pyl file (default: bootstrap/deps.pyl)') |
| 147 parser.add_argument( |
| 148 'to_build', nargs='*', |
| 149 help='Names of packages to build. Defaults to all packages.') |
| 150 opts = parser.parse_args(args) |
| 151 |
| 152 if 'Ubuntu' in platform_tag() and ROOT.startswith('/usr/local/'): |
| 153 print >> sys.stderr, "\n".join([ |
| 154 "Due to a bug in Ubuntu's python distribution, build_deps.py does not", |
| 155 "work when run from under a path beginning with /usr/local/. Please ", |
| 156 "clone to a different path, and try again.", |
| 157 "", |
| 158 "Bug: https://github.com/pypa/virtualenv/issues/118" |
| 159 ]) |
| 160 return 1 |
| 161 |
| 162 deps_files = opts.deps_file or [os.path.join(ROOT, 'deps.pyl')] |
| 163 to_build = set(opts.to_build) |
| 164 |
| 165 build_env = os.path.join(ROOT, 'BUILD_ENV') |
| 166 |
| 167 print 'Parsing deps.pyl' |
| 168 deps = merge_deps(deps_files) |
| 169 bootstrap.activate_env(build_env, {'wheel': deps.pop('wheel')}) |
| 170 |
| 171 print 'Finding missing deps' |
| 172 missing_deps = {} |
| 173 for name, entry in deps.iteritems(): |
| 174 if to_build and name not in to_build: |
| 175 continue |
| 176 try: |
| 177 bootstrap.get_links({name: entry}) |
| 178 except bootstrap.NoWheelException: |
| 179 missing_deps[name] = entry |
| 180 |
| 181 if not missing_deps: |
| 182 print 'Nothing to process' |
| 183 return |
| 184 |
| 185 print 'Processing deps:' |
| 186 print_deps(missing_deps) |
| 187 |
| 188 for name, options in missing_deps.iteritems(): |
| 189 clear_wheelhouse() |
| 190 # TODO(iannucci): skip entries which already exist in gs |
| 191 if 'repo' in options and 'rev' in options: |
| 192 process_git(name, options['rev'], options['build'], |
| 193 options.get('build_options', ()), |
| 194 options['repo']) |
| 195 elif 'gs' in options: |
| 196 process_gs(name, options['gs'], options['build'], |
| 197 options.get('build_options', ())) |
| 198 else: |
| 199 raise Exception('Invalid options %r for %r' % (options, name)) |
| 200 push_wheelhouse() |
| 201 |
| 202 |
| 203 if __name__ == '__main__': |
| 204 sys.exit(main(sys.argv[1:])) |
OLD | NEW |