
The 'seed' packages are the ones whose versions are set by us in WORKSPACE. We should not set the versions for the rest of the packages in the bower input JSON, so bower can suggest the right versions to use. Change-Id: I9b75f16655d049e2064726862980a339c91dd534
232 lines
6.9 KiB
Python
Executable File
232 lines
6.9 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# Copyright (C) 2015 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Suggested call sequence:
|
|
|
|
python tools/js/bower2bazel.py -w lib/js/bower_archives.bzl -b lib/js/bower_components.bzl
|
|
"""
|
|
|
|
from __future__ import print_function
|
|
|
|
import collections
|
|
import json
|
|
import hashlib
|
|
import optparse
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import glob
|
|
import bowerutil
|
|
|
|
# list of licenses for packages that don't specify one in their bower.json file.
|
|
package_licenses = {
|
|
"es6-promise": "es6-promise",
|
|
"fetch": "fetch",
|
|
"iron-a11y-announcer": "polymer",
|
|
"iron-a11y-keys-behavior": "polymer",
|
|
"iron-autogrow-textarea": "polymer",
|
|
"iron-behaviors": "polymer",
|
|
"iron-dropdown": "polymer",
|
|
"iron-fit-behavior": "polymer",
|
|
"iron-flex-layout": "polymer",
|
|
"iron-form-element-behavior": "polymer",
|
|
"iron-input": "polymer",
|
|
"iron-meta": "polymer",
|
|
"iron-overlay-behavior": "polymer",
|
|
"iron-resizable-behavior": "polymer",
|
|
"iron-selector": "polymer",
|
|
"iron-validatable-behavior": "polymer",
|
|
"moment": "moment",
|
|
"neon-animation": "polymer",
|
|
"page": "page.js",
|
|
"polymer": "polymer",
|
|
"promise-polyfill": "promise-polyfill",
|
|
"web-animations-js": "Apache2.0",
|
|
"webcomponentsjs": "polymer",
|
|
}
|
|
|
|
|
|
def build_bower_json(version_targets, seeds):
|
|
"""Generate bower JSON file, return its path.
|
|
|
|
Args:
|
|
version_targets: bazel target names of the versions.json file.
|
|
seeds: an iterable of bower package names of the seed packages, ie.
|
|
the packages whose versions we control manually.
|
|
"""
|
|
bower_json = collections.OrderedDict()
|
|
bower_json['name'] = 'bower2bazel-output'
|
|
bower_json['version'] = '0.0.0'
|
|
bower_json['description'] = 'Auto-generated bower.json for dependency management'
|
|
bower_json['private'] = True
|
|
bower_json['dependencies'] = {}
|
|
|
|
seeds = set(seeds)
|
|
for v in version_targets:
|
|
fn = os.path.join("bazel-out/local-fastbuild/bin", v.lstrip("/").replace(":", "/"))
|
|
with open(fn) as f:
|
|
j = json.load(f)
|
|
if "" in j:
|
|
# drop dummy entries.
|
|
del j[""]
|
|
|
|
trimmed = {}
|
|
for k, v in j.items():
|
|
if k in seeds:
|
|
trimmed[k] = v
|
|
|
|
bower_json['dependencies'].update(trimmed)
|
|
|
|
tmpdir = tempfile.mkdtemp()
|
|
ret = os.path.join(tmpdir, 'bower.json')
|
|
with open(ret, 'w') as f:
|
|
json.dump(bower_json, f, indent=2)
|
|
return ret
|
|
|
|
|
|
def bower_command(args):
|
|
base = subprocess.check_output(["bazel", "info", "output_base"]).strip()
|
|
exp = os.path.join(base, "external", "bower", "*npm_binary.tgz")
|
|
fs = sorted(glob.glob(exp))
|
|
assert len(fs) == 1, "bower tarball not found or have multiple versions %s" % fs
|
|
return ["python", os.getcwd() + "/tools/js/run_npm_binary.py", sorted(fs)[0]] + args
|
|
|
|
|
|
def main(args):
|
|
opts = optparse.OptionParser()
|
|
opts.add_option('-w', help='.bzl output for WORKSPACE')
|
|
opts.add_option('-b', help='.bzl output for //lib:BUILD')
|
|
opts, args = opts.parse_args()
|
|
|
|
target_str = subprocess.check_output([
|
|
"bazel", "query", "kind(bower_component_bundle, //polygerrit-ui/...)"])
|
|
seed_str = subprocess.check_output([
|
|
"bazel", "query", "attr(seed, 1, kind(bower_component, deps(//polygerrit-ui/...)))"])
|
|
targets = [s for s in target_str.split('\n') if s]
|
|
seeds = [s for s in seed_str.split('\n') if s]
|
|
prefix = "//lib/js:"
|
|
non_seeds = [s for s in seeds if not s.startswith(prefix)]
|
|
assert not non_seeds, non_seeds
|
|
seeds = set([s[len(prefix):] for s in seeds])
|
|
|
|
version_targets = [t + "-versions.json" for t in targets]
|
|
subprocess.check_call(['bazel', 'build'] + version_targets)
|
|
bower_json_path = build_bower_json(version_targets, seeds)
|
|
dir = os.path.dirname(bower_json_path)
|
|
cmd = bower_command(["install"])
|
|
|
|
build_out = sys.stdout
|
|
if opts.b:
|
|
build_out = open(opts.b + ".tmp", 'w')
|
|
|
|
ws_out = sys.stdout
|
|
if opts.b:
|
|
ws_out = open(opts.w + ".tmp", 'w')
|
|
|
|
header = """# DO NOT EDIT
|
|
# generated with the following command:
|
|
#
|
|
# %s
|
|
#
|
|
|
|
""" % ' '.join(sys.argv)
|
|
|
|
ws_out.write(header)
|
|
build_out.write(header)
|
|
|
|
oldwd = os.getcwd()
|
|
os.chdir(dir)
|
|
subprocess.check_call(cmd)
|
|
|
|
interpret_bower_json(seeds, ws_out, build_out)
|
|
ws_out.close()
|
|
build_out.close()
|
|
|
|
os.chdir(oldwd)
|
|
os.rename(opts.w + ".tmp", opts.w)
|
|
os.rename(opts.b + ".tmp", opts.b)
|
|
|
|
|
|
def dump_workspace(data, seeds, out):
|
|
out.write('load("//tools/bzl:js.bzl", "bower_archive")\n\n')
|
|
out.write('def load_bower_archives():\n')
|
|
|
|
for d in data:
|
|
if d["name"] in seeds:
|
|
continue
|
|
out.write(""" bower_archive(
|
|
name = "%(name)s",
|
|
package = "%(normalized-name)s",
|
|
version = "%(version)s",
|
|
sha1 = "%(bazel-sha1)s")
|
|
""" % d)
|
|
|
|
|
|
def dump_build(data, seeds, out):
|
|
out.write('load("//tools/bzl:js.bzl", "bower_component")\n\n')
|
|
out.write('def define_bower_components():\n')
|
|
for d in data:
|
|
out.write(" bower_component(\n")
|
|
out.write(" name = \"%s\",\n" % d["name"])
|
|
out.write(" license = \"//lib:LICENSE-%s\",\n" % d["bazel-license"])
|
|
deps = sorted(d.get("dependencies", {}).keys())
|
|
if deps:
|
|
if len(deps) == 1:
|
|
out.write(" deps = [ \":%s\" ],\n" % deps[0])
|
|
else:
|
|
out.write(" deps = [\n")
|
|
for dep in deps:
|
|
out.write(" \":%s\",\n" % dep)
|
|
out.write(" ],\n")
|
|
if d["name"] in seeds:
|
|
out.write(" seed = True,\n")
|
|
out.write(" )\n")
|
|
# done
|
|
|
|
|
|
def interpret_bower_json(seeds, ws_out, build_out):
|
|
out = subprocess.check_output(["find", "bower_components/", "-name", ".bower.json"])
|
|
|
|
data = []
|
|
for f in sorted(out.split('\n')):
|
|
if not f:
|
|
continue
|
|
pkg = json.load(open(f))
|
|
pkg_name = pkg["name"]
|
|
|
|
pkg["bazel-sha1"] = bowerutil.hash_bower_component(
|
|
hashlib.sha1(), os.path.dirname(f)).hexdigest()
|
|
license = package_licenses.get(pkg_name, "DO_NOT_DISTRIBUTE")
|
|
|
|
pkg["bazel-license"] = license
|
|
|
|
# TODO(hanwen): bower packages can also have 'fully qualified'
|
|
# names, ("PolymerElements/iron-ajax") as well as short names
|
|
# ("iron-ajax"). It is possible for bower.json files to refer to
|
|
# long names as their dependencies. If any package does this, we
|
|
# will have to either 1) strip off the prefix (typically github
|
|
# user?), or 2) build a map of short name <=> fully qualified
|
|
# name. For now, we just ignore the problem.
|
|
pkg["normalized-name"] = pkg["name"]
|
|
data.append(pkg)
|
|
|
|
dump_workspace(data, seeds, ws_out)
|
|
dump_build(data, seeds, build_out)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main(sys.argv[1:])
|