Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # Copyright (C) 2015 The Android Open Source Project |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # See the License for the specific language governing permissions and |
| 14 | # limitations under the License. |
| 15 | |
Chad Horohoe | 6914232 | 2018-05-17 10:19:22 -0700 | [diff] [blame] | 16 | """ |
| 17 | Suggested call sequence: |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 18 | |
Chad Horohoe | 6914232 | 2018-05-17 10:19:22 -0700 | [diff] [blame] | 19 | python tools/js/bower2bazel.py -w lib/js/bower_archives.bzl \ |
| 20 | -b lib/js/bower_components.bzl |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 21 | """ |
| 22 | |
| 23 | from __future__ import print_function |
| 24 | |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 25 | import collections |
| 26 | import json |
| 27 | import hashlib |
| 28 | import optparse |
| 29 | import os |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 30 | import subprocess |
| 31 | import sys |
| 32 | import tempfile |
| 33 | import glob |
| 34 | import bowerutil |
| 35 | |
Chad Horohoe | 6914232 | 2018-05-17 10:19:22 -0700 | [diff] [blame] | 36 | # list of licenses for packages that don't specify one in their bower.json file |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 37 | package_licenses = { |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 38 | "codemirror-minified": "codemirror-minified", |
| 39 | "es6-promise": "es6-promise", |
| 40 | "fetch": "fetch", |
| 41 | "font-roboto": "polymer", |
| 42 | "iron-a11y-announcer": "polymer", |
| 43 | "iron-a11y-keys-behavior": "polymer", |
| 44 | "iron-autogrow-textarea": "polymer", |
| 45 | "iron-behaviors": "polymer", |
| 46 | "iron-dropdown": "polymer", |
| 47 | "iron-fit-behavior": "polymer", |
| 48 | "iron-flex-layout": "polymer", |
| 49 | "iron-form-element-behavior": "polymer", |
| 50 | "iron-icon": "polymer", |
| 51 | "iron-iconset-svg": "polymer", |
| 52 | "iron-input": "polymer", |
| 53 | "iron-menu-behavior": "polymer", |
| 54 | "iron-meta": "polymer", |
| 55 | "iron-overlay-behavior": "polymer", |
| 56 | "iron-resizable-behavior": "polymer", |
| 57 | "iron-selector": "polymer", |
| 58 | "iron-validatable-behavior": "polymer", |
| 59 | "moment": "moment", |
| 60 | "neon-animation": "polymer", |
| 61 | "page": "page.js", |
| 62 | "paper-button": "polymer", |
| 63 | "paper-icon-button": "polymer", |
| 64 | "paper-input": "polymer", |
| 65 | "paper-item": "polymer", |
| 66 | "paper-listbox": "polymer", |
| 67 | "paper-toggle-button": "polymer", |
| 68 | "paper-styles": "polymer", |
| 69 | "paper-tabs": "polymer", |
| 70 | "polymer": "polymer", |
| 71 | "polymer-resin": "polymer", |
| 72 | "promise-polyfill": "promise-polyfill", |
| 73 | "web-animations-js": "Apache2.0", |
| 74 | "webcomponentsjs": "polymer", |
| 75 | "paper-material": "polymer", |
| 76 | "paper-styles": "polymer", |
| 77 | "paper-behaviors": "polymer", |
| 78 | "paper-ripple": "polymer", |
| 79 | "iron-checked-element-behavior": "polymer", |
| 80 | "font-roboto": "polymer", |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 81 | } |
| 82 | |
| 83 | |
Han-Wen Nienhuys | 3dede16 | 2017-02-01 13:33:19 +0100 | [diff] [blame] | 84 | def build_bower_json(version_targets, seeds): |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 85 | """Generate bower JSON file, return its path. |
Han-Wen Nienhuys | 3dede16 | 2017-02-01 13:33:19 +0100 | [diff] [blame] | 86 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 87 | Args: |
| 88 | version_targets: bazel target names of the versions.json file. |
| 89 | seeds: an iterable of bower package names of the seed packages, ie. |
| 90 | the packages whose versions we control manually. |
| 91 | """ |
| 92 | bower_json = collections.OrderedDict() |
| 93 | bower_json['name'] = 'bower2bazel-output' |
| 94 | bower_json['version'] = '0.0.0' |
Chad Horohoe | 6914232 | 2018-05-17 10:19:22 -0700 | [diff] [blame] | 95 | bower_json['description'] = 'Auto-generated bower.json for dependency ' + \ |
| 96 | 'management' |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 97 | bower_json['private'] = True |
| 98 | bower_json['dependencies'] = {} |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 99 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 100 | seeds = set(seeds) |
| 101 | for v in version_targets: |
Chad Horohoe | 6914232 | 2018-05-17 10:19:22 -0700 | [diff] [blame] | 102 | path = os.path.join("bazel-out/*-fastbuild/bin", |
| 103 | v.lstrip("/").replace(":", "/")) |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 104 | fs = glob.glob(path) |
Chad Horohoe | 6914232 | 2018-05-17 10:19:22 -0700 | [diff] [blame] | 105 | err_msg = '%s: file not found or multiple files found: %s' % (path, fs) |
| 106 | assert len(fs) == 1, err_msg |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 107 | with open(fs[0]) as f: |
| 108 | j = json.load(f) |
| 109 | if "" in j: |
| 110 | # drop dummy entries. |
| 111 | del j[""] |
Han-Wen Nienhuys | 3dede16 | 2017-02-01 13:33:19 +0100 | [diff] [blame] | 112 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 113 | trimmed = {} |
| 114 | for k, v in j.items(): |
| 115 | if k in seeds: |
| 116 | trimmed[k] = v |
Han-Wen Nienhuys | 3dede16 | 2017-02-01 13:33:19 +0100 | [diff] [blame] | 117 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 118 | bower_json['dependencies'].update(trimmed) |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 119 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 120 | tmpdir = tempfile.mkdtemp() |
| 121 | ret = os.path.join(tmpdir, 'bower.json') |
| 122 | with open(ret, 'w') as f: |
| 123 | json.dump(bower_json, f, indent=2) |
| 124 | return ret |
| 125 | |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 126 | |
Paladox none | 0fb28c1 | 2018-03-28 13:34:51 +0000 | [diff] [blame] | 127 | def decode(input): |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 128 | try: |
| 129 | return input.decode("utf-8") |
| 130 | except TypeError: |
| 131 | return input |
| 132 | |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 133 | |
| 134 | def bower_command(args): |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 135 | base = subprocess.check_output(["bazel", "info", "output_base"]).strip() |
| 136 | exp = os.path.join(decode(base), "external", "bower", "*npm_binary.tgz") |
| 137 | fs = sorted(glob.glob(exp)) |
Chad Horohoe | 6914232 | 2018-05-17 10:19:22 -0700 | [diff] [blame] | 138 | err_msg = "bower tarball not found or have multiple versions %s" % fs |
| 139 | assert len(fs) == 1, err_msg |
| 140 | return ["python", |
| 141 | os.getcwd() + "/tools/js/run_npm_binary.py", sorted(fs)[0]] + args |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 142 | |
| 143 | |
| 144 | def main(args): |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 145 | opts = optparse.OptionParser() |
| 146 | opts.add_option('-w', help='.bzl output for WORKSPACE') |
| 147 | opts.add_option('-b', help='.bzl output for //lib:BUILD') |
| 148 | opts, args = opts.parse_args() |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 149 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 150 | target_str = subprocess.check_output([ |
| 151 | "bazel", "query", "kind(bower_component_bundle, //polygerrit-ui/...)"]) |
Chad Horohoe | 6914232 | 2018-05-17 10:19:22 -0700 | [diff] [blame] | 152 | seed_str = subprocess.check_output( |
| 153 | ["bazel", "query", |
| 154 | "attr(seed, 1, kind(bower_component, deps(//polygerrit-ui/...)))"]) |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 155 | targets = [s for s in decode(target_str).split('\n') if s] |
| 156 | seeds = [s for s in decode(seed_str).split('\n') if s] |
| 157 | prefix = "//lib/js:" |
| 158 | non_seeds = [s for s in seeds if not s.startswith(prefix)] |
| 159 | assert not non_seeds, non_seeds |
| 160 | seeds = set([s[len(prefix):] for s in seeds]) |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 161 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 162 | version_targets = [t + "-versions.json" for t in targets] |
| 163 | subprocess.check_call(['bazel', 'build'] + version_targets) |
| 164 | bower_json_path = build_bower_json(version_targets, seeds) |
| 165 | dir = os.path.dirname(bower_json_path) |
| 166 | cmd = bower_command(["install"]) |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 167 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 168 | build_out = sys.stdout |
| 169 | if opts.b: |
| 170 | build_out = open(opts.b + ".tmp", 'w') |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 171 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 172 | ws_out = sys.stdout |
| 173 | if opts.b: |
| 174 | ws_out = open(opts.w + ".tmp", 'w') |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 175 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 176 | header = """# DO NOT EDIT |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 177 | # generated with the following command: |
| 178 | # |
| 179 | # %s |
| 180 | # |
| 181 | |
| 182 | """ % ' '.join(sys.argv) |
| 183 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 184 | ws_out.write(header) |
| 185 | build_out.write(header) |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 186 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 187 | oldwd = os.getcwd() |
| 188 | os.chdir(dir) |
| 189 | subprocess.check_call(cmd) |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 190 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 191 | interpret_bower_json(seeds, ws_out, build_out) |
| 192 | ws_out.close() |
| 193 | build_out.close() |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 194 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 195 | os.chdir(oldwd) |
| 196 | os.rename(opts.w + ".tmp", opts.w) |
| 197 | os.rename(opts.b + ".tmp", opts.b) |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 198 | |
| 199 | |
| 200 | def dump_workspace(data, seeds, out): |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 201 | out.write('load("//tools/bzl:js.bzl", "bower_archive")\n\n') |
| 202 | out.write('def load_bower_archives():\n') |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 203 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 204 | for d in data: |
| 205 | if d["name"] in seeds: |
| 206 | continue |
Paladox none | d2bc63c | 2019-04-07 21:47:26 +0000 | [diff] [blame] | 207 | out.write(""" bower_archive( |
| 208 | name = "%(name)s", |
| 209 | package = "%(normalized-name)s", |
| 210 | version = "%(version)s", |
| 211 | sha1 = "%(bazel-sha1)s", |
| 212 | ) |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 213 | """ % d) |
| 214 | |
| 215 | |
| 216 | def dump_build(data, seeds, out): |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 217 | out.write('load("//tools/bzl:js.bzl", "bower_component")\n\n') |
| 218 | out.write('def define_bower_components():\n') |
| 219 | for d in data: |
Paladox none | d2bc63c | 2019-04-07 21:47:26 +0000 | [diff] [blame] | 220 | out.write(" bower_component(\n") |
| 221 | out.write(" name = \"%s\",\n" % d["name"]) |
| 222 | out.write(" license = \"//lib:LICENSE-%s\",\n" % d["bazel-license"]) |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 223 | deps = sorted(d.get("dependencies", {}).keys()) |
| 224 | if deps: |
| 225 | if len(deps) == 1: |
Paladox none | d2bc63c | 2019-04-07 21:47:26 +0000 | [diff] [blame] | 226 | out.write(" deps = [\":%s\"],\n" % deps[0]) |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 227 | else: |
Paladox none | d2bc63c | 2019-04-07 21:47:26 +0000 | [diff] [blame] | 228 | out.write(" deps = [\n") |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 229 | for dep in deps: |
Paladox none | d2bc63c | 2019-04-07 21:47:26 +0000 | [diff] [blame] | 230 | out.write(" \":%s\",\n" % dep) |
| 231 | out.write(" ],\n") |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 232 | if d["name"] in seeds: |
Paladox none | d2bc63c | 2019-04-07 21:47:26 +0000 | [diff] [blame] | 233 | out.write(" seed = True,\n") |
| 234 | out.write(" )\n") |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 235 | # done |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 236 | |
| 237 | |
| 238 | def interpret_bower_json(seeds, ws_out, build_out): |
Chad Horohoe | 6914232 | 2018-05-17 10:19:22 -0700 | [diff] [blame] | 239 | out = subprocess.check_output(["find", "bower_components/", "-name", |
| 240 | ".bower.json"]) |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 241 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 242 | data = [] |
| 243 | for f in sorted(decode(out).split('\n')): |
| 244 | if not f: |
| 245 | continue |
| 246 | pkg = json.load(open(f)) |
| 247 | pkg_name = pkg["name"] |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 248 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 249 | pkg["bazel-sha1"] = bowerutil.hash_bower_component( |
| 250 | hashlib.sha1(), os.path.dirname(f)).hexdigest() |
| 251 | license = package_licenses.get(pkg_name, "DO_NOT_DISTRIBUTE") |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 252 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 253 | pkg["bazel-license"] = license |
| 254 | pkg["normalized-name"] = pkg["_originalSource"] |
| 255 | data.append(pkg) |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 256 | |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 257 | dump_workspace(data, seeds, ws_out) |
| 258 | dump_build(data, seeds, build_out) |
Han-Wen Nienhuys | 28e7a6d | 2016-09-21 15:03:54 +0200 | [diff] [blame] | 259 | |
| 260 | |
| 261 | if __name__ == '__main__': |
Chad Horohoe | dd22470 | 2018-05-16 22:33:06 -0400 | [diff] [blame] | 262 | main(sys.argv[1:]) |