blob: b428a2d903daa98d8d2f9136d6ccddc626b2cad7 [file] [log] [blame]
David Pursehouse1d536682019-01-10 21:44:13 +09001load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_binary", "closure_js_library")
David Ostrovskyae9c2012019-01-09 22:34:36 +01002load("//lib/js:npm.bzl", "NPM_SHA1S", "NPM_VERSIONS")
3
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +02004NPMJS = "NPMJS"
David Pursehouse2d085002016-12-11 19:00:10 +09005
David Ostrovsky269cce12016-11-14 17:38:30 -08006GERRIT = "GERRIT:"
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +02007
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +02008def _npm_tarball(name):
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +02009 return "%s@%s.npm_binary.tgz" % (name, NPM_VERSIONS[name])
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020010
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020011def _npm_binary_impl(ctx):
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020012 """rule to download a NPM archive."""
13 name = ctx.name
14 version = NPM_VERSIONS[name]
15 sha1 = NPM_SHA1S[name]
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020016
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020017 dir = "%s-%s" % (name, version)
18 filename = "%s.tgz" % dir
19 base = "%s@%s.npm_binary.tgz" % (name, version)
20 dest = ctx.path(base)
21 repository = ctx.attr.repository
22 if repository == GERRIT:
Paladox noneaecbac82019-04-07 22:22:03 +000023 url = "https://gerrit-maven.storage.googleapis.com/npm-packages/%s" % filename
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020024 elif repository == NPMJS:
Paladox noneaecbac82019-04-07 22:22:03 +000025 url = "https://registry.npmjs.org/%s/-/%s" % (name, filename)
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020026 else:
27 fail("repository %s not in {%s,%s}" % (repository, GERRIT, NPMJS))
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020028
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020029 python = ctx.which("python")
30 script = ctx.path(ctx.attr._download_script)
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020031
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020032 args = [python, script, "-o", dest, "-u", url, "-v", sha1]
33 out = ctx.execute(args)
34 if out.return_code:
35 fail("failed %s: %s" % (args, out.stderr))
36 ctx.file("BUILD", "package(default_visibility=['//visibility:public'])\nfilegroup(name='tarball', srcs=['%s'])" % base, False)
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020037
38npm_binary = repository_rule(
David Pursehouse2d085002016-12-11 19:00:10 +090039 attrs = {
David Pursehouse88d08852019-01-09 21:21:52 +090040 "repository": attr.string(default = NPMJS),
David Pursehouse2d085002016-12-11 19:00:10 +090041 # Label resolves within repo of the .bzl file.
42 "_download_script": attr.label(default = Label("//tools:download_file.py")),
David Pursehouse2d085002016-12-11 19:00:10 +090043 },
44 local = True,
45 implementation = _npm_binary_impl,
46)
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020047
David Ostrovsky2b720e72019-06-12 09:37:58 +020048ComponentInfo = provider()
49
Han-Wen Nienhuys36502622016-10-05 17:36:20 +020050# for use in repo rules.
51def _run_npm_binary_str(ctx, tarball, args):
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020052 python_bin = ctx.which("python")
53 return " ".join([
David Ostrovsky0c4d2882019-05-30 15:28:49 +020054 str(python_bin),
55 str(ctx.path(ctx.attr._run_npm)),
56 str(ctx.path(tarball)),
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020057 ] + args)
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020058
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020059def _bower_archive(ctx):
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020060 """Download a bower package."""
61 download_name = "%s__download_bower.zip" % ctx.name
62 renamed_name = "%s__renamed.zip" % ctx.name
63 version_name = "%s__version.json" % ctx.name
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020064
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020065 cmd = [
66 ctx.which("python"),
67 ctx.path(ctx.attr._download_bower),
68 "-b",
69 "%s" % _run_npm_binary_str(ctx, ctx.attr._bower_archive, []),
70 "-n",
71 ctx.name,
72 "-p",
73 ctx.attr.package,
74 "-v",
75 ctx.attr.version,
76 "-s",
77 ctx.attr.sha1,
78 "-o",
79 download_name,
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020080 ]
81
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020082 out = ctx.execute(cmd)
83 if out.return_code:
David Pursehouse42784412019-07-04 13:18:55 +090084 fail("failed %s: %s" % (cmd, out.stderr))
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020085
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020086 _bash(ctx, " && ".join([
87 "TMP=$(mktemp -d || mktemp -d -t bazel-tmp)",
88 "TZ=UTC",
89 "export UTC",
90 "cd $TMP",
91 "mkdir bower_components",
92 "cd bower_components",
93 "unzip %s" % ctx.path(download_name),
94 "cd ..",
95 "find . -exec touch -t 198001010000 '{}' ';'",
96 "zip -Xr %s bower_components" % renamed_name,
97 "cd ..",
98 "rm -rf ${TMP}",
99 ]))
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200100
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200101 dep_version = ctx.attr.semver if ctx.attr.semver else ctx.attr.version
102 ctx.file(
103 version_name,
104 '"%s":"%s#%s"' % (ctx.name, ctx.attr.package, dep_version),
105 )
106 ctx.file(
107 "BUILD",
108 "\n".join([
109 "package(default_visibility=['//visibility:public'])",
110 "filegroup(name = 'zipfile', srcs = ['%s'], )" % download_name,
111 "filegroup(name = 'version_json', srcs = ['%s'], visibility=['//visibility:public'])" % version_name,
112 ]),
113 False,
114 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200115
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200116def _bash(ctx, cmd):
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200117 cmd_list = ["bash", "-c", cmd]
118 out = ctx.execute(cmd_list)
119 if out.return_code:
David Pursehouse42784412019-07-04 13:18:55 +0900120 fail("failed %s: %s" % (cmd_list, out.stderr))
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200121
David Pursehouse2d085002016-12-11 19:00:10 +0900122bower_archive = repository_rule(
123 _bower_archive,
124 attrs = {
David Pursehouse2d085002016-12-11 19:00:10 +0900125 "package": attr.string(mandatory = True),
126 "semver": attr.string(),
David Pursehouse88d08852019-01-09 21:21:52 +0900127 "sha1": attr.string(mandatory = True),
128 "version": attr.string(mandatory = True),
129 "_bower_archive": attr.label(default = Label("@bower//:%s" % _npm_tarball("bower"))),
130 "_download_bower": attr.label(default = Label("//tools/js:download_bower.py")),
131 "_run_npm": attr.label(default = Label("//tools/js:run_npm_binary.py")),
David Pursehouse2d085002016-12-11 19:00:10 +0900132 },
133)
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200134
135def _bower_component_impl(ctx):
David Ostrovsky83fab682019-03-03 10:58:10 +0100136 transitive_zipfiles = depset(
137 direct = [ctx.file.zipfile],
David Ostrovsky2b720e72019-06-12 09:37:58 +0200138 transitive = [d[ComponentInfo].transitive_zipfiles for d in ctx.attr.deps],
David Ostrovsky83fab682019-03-03 10:58:10 +0100139 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200140
David Ostrovsky83fab682019-03-03 10:58:10 +0100141 transitive_licenses = depset(
142 direct = [ctx.file.license],
David Ostrovsky2b720e72019-06-12 09:37:58 +0200143 transitive = [d[ComponentInfo].transitive_licenses for d in ctx.attr.deps],
David Ostrovsky83fab682019-03-03 10:58:10 +0100144 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200145
David Ostrovsky83fab682019-03-03 10:58:10 +0100146 transitive_versions = depset(
147 direct = ctx.files.version_json,
David Ostrovsky2b720e72019-06-12 09:37:58 +0200148 transitive = [d[ComponentInfo].transitive_versions for d in ctx.attr.deps],
David Ostrovsky83fab682019-03-03 10:58:10 +0100149 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200150
David Ostrovsky2b720e72019-06-12 09:37:58 +0200151 return [
152 ComponentInfo(
153 transitive_licenses = transitive_licenses,
154 transitive_versions = transitive_versions,
155 transitive_zipfiles = transitive_zipfiles,
156 ),
157 ]
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200158
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200159_common_attrs = {
David Ostrovsky2b720e72019-06-12 09:37:58 +0200160 "deps": attr.label_list(providers = [ComponentInfo]),
David Pursehouse2d085002016-12-11 19:00:10 +0900161}
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200162
163def _js_component(ctx):
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200164 dir = ctx.outputs.zip.path + ".dir"
165 name = ctx.outputs.zip.basename
166 if name.endswith(".zip"):
167 name = name[:-4]
168 dest = "%s/%s" % (dir, name)
169 cmd = " && ".join([
170 "TZ=UTC",
171 "export TZ",
172 "mkdir -p %s" % dest,
173 "cp %s %s/" % (" ".join([s.path for s in ctx.files.srcs]), dest),
174 "cd %s" % dir,
175 "find . -exec touch -t 198001010000 '{}' ';'",
176 "zip -Xqr ../%s *" % ctx.outputs.zip.basename,
177 ])
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200178
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200179 ctx.actions.run_shell(
180 inputs = ctx.files.srcs,
181 outputs = [ctx.outputs.zip],
182 command = cmd,
183 mnemonic = "GenBowerZip",
184 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200185
David Ostrovsky83fab682019-03-03 10:58:10 +0100186 licenses = []
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200187 if ctx.file.license:
David Ostrovsky83fab682019-03-03 10:58:10 +0100188 licenses.append(ctx.file.license)
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200189
David Ostrovsky2b720e72019-06-12 09:37:58 +0200190 return [
191 ComponentInfo(
192 transitive_licenses = depset(licenses),
193 transitive_versions = depset(),
194 transitive_zipfiles = list([ctx.outputs.zip]),
195 ),
196 ]
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200197
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200198js_component = rule(
David Pursehouse2d085002016-12-11 19:00:10 +0900199 _js_component,
Vladimir Moskva4c8be85f2018-01-05 16:59:03 +0100200 attrs = dict(_common_attrs.items() + {
David Pursehouse2d085002016-12-11 19:00:10 +0900201 "srcs": attr.label_list(allow_files = [".js"]),
202 "license": attr.label(allow_single_file = True),
Vladimir Moskva4c8be85f2018-01-05 16:59:03 +0100203 }.items()),
David Pursehouse2d085002016-12-11 19:00:10 +0900204 outputs = {
205 "zip": "%{name}.zip",
206 },
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200207)
208
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200209_bower_component = rule(
David Pursehouse2d085002016-12-11 19:00:10 +0900210 _bower_component_impl,
Vladimir Moskva4c8be85f2018-01-05 16:59:03 +0100211 attrs = dict(_common_attrs.items() + {
David Pursehouse2d085002016-12-11 19:00:10 +0900212 "license": attr.label(allow_single_file = True),
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200213
David Pursehouse2d085002016-12-11 19:00:10 +0900214 # If set, define by hand, and don't regenerate this entry in bower2bazel.
215 "seed": attr.bool(default = False),
David Pursehouse88d08852019-01-09 21:21:52 +0900216 "version_json": attr.label(allow_files = [".json"]),
217 "zipfile": attr.label(allow_single_file = [".zip"]),
Vladimir Moskva4c8be85f2018-01-05 16:59:03 +0100218 }.items()),
David Pursehouse2d085002016-12-11 19:00:10 +0900219)
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200220
221# TODO(hanwen): make license mandatory.
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200222def bower_component(name, license = None, **kwargs):
223 prefix = "//lib:LICENSE-"
224 if license and not license.startswith(prefix):
225 license = prefix + license
226 _bower_component(
227 name = name,
228 license = license,
229 zipfile = "@%s//:zipfile" % name,
230 version_json = "@%s//:version_json" % name,
231 **kwargs
232 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200233
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200234def _bower_component_bundle_impl(ctx):
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200235 """A bunch of bower components zipped up."""
236 zips = depset()
237 for d in ctx.attr.deps:
David Ostrovsky2b720e72019-06-12 09:37:58 +0200238 files = d[ComponentInfo].transitive_zipfiles
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200239
David Ostrovsky83fab682019-03-03 10:58:10 +0100240 # TODO(davido): Make sure the field always contains a depset
241 if type(files) == "list":
242 files = depset(files)
243 zips = depset(transitive = [zips, files])
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200244
David Ostrovsky2b720e72019-06-12 09:37:58 +0200245 versions = depset(transitive = [d[ComponentInfo].transitive_versions for d in ctx.attr.deps])
David Ostrovsky83fab682019-03-03 10:58:10 +0100246
David Ostrovsky2b720e72019-06-12 09:37:58 +0200247 licenses = depset(transitive = [d[ComponentInfo].transitive_versions for d in ctx.attr.deps])
Han-Wen Nienhuys36502622016-10-05 17:36:20 +0200248
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200249 out_zip = ctx.outputs.zip
250 out_versions = ctx.outputs.version_json
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200251
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200252 ctx.actions.run_shell(
David Ostrovsky930f29e2019-01-08 23:11:59 +0100253 inputs = zips.to_list(),
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200254 outputs = [out_zip],
255 command = " && ".join([
256 "p=$PWD",
257 "TZ=UTC",
258 "export TZ",
259 "rm -rf %s.dir" % out_zip.path,
260 "mkdir -p %s.dir/bower_components" % out_zip.path,
261 "cd %s.dir/bower_components" % out_zip.path,
David Ostrovsky930f29e2019-01-08 23:11:59 +0100262 "for z in %s; do unzip -q $p/$z ; done" % " ".join(sorted([z.path for z in zips.to_list()])),
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200263 "cd ..",
264 "find . -exec touch -t 198001010000 '{}' ';'",
265 "zip -Xqr $p/%s bower_components/*" % out_zip.path,
266 ]),
267 mnemonic = "BowerCombine",
268 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200269
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200270 ctx.actions.run_shell(
David Ostrovsky930f29e2019-01-08 23:11:59 +0100271 inputs = versions.to_list(),
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200272 outputs = [out_versions],
273 mnemonic = "BowerVersions",
David Ostrovsky930f29e2019-01-08 23:11:59 +0100274 command = "(echo '{' ; for j in %s ; do cat $j; echo ',' ; done ; echo \\\"\\\":\\\"\\\"; echo '}') > %s" % (" ".join([v.path for v in versions.to_list()]), out_versions.path),
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200275 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200276
David Ostrovsky2b720e72019-06-12 09:37:58 +0200277 return [
278 ComponentInfo(
279 transitive_licenses = licenses,
280 transitive_versions = versions,
281 transitive_zipfiles = zips,
282 ),
283 ]
Han-Wen Nienhuys36502622016-10-05 17:36:20 +0200284
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200285bower_component_bundle = rule(
David Pursehouse2d085002016-12-11 19:00:10 +0900286 _bower_component_bundle_impl,
287 attrs = _common_attrs,
288 outputs = {
David Pursehouse2d085002016-12-11 19:00:10 +0900289 "version_json": "%{name}-versions.json",
David Pursehouse88d08852019-01-09 21:21:52 +0900290 "zip": "%{name}.zip",
David Pursehouse2d085002016-12-11 19:00:10 +0900291 },
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200292)
Dave Borowitz070df0f2017-11-03 09:14:02 -0400293
Viktar Donichee7b2a22018-07-17 14:12:22 -0700294def _bundle_impl(ctx):
295 """Groups a set of .html and .js together in a zip file.
Han-Wen Nienhuys3dede162017-02-01 13:33:19 +0100296
Viktar Donichee7b2a22018-07-17 14:12:22 -0700297 Outputs:
298 NAME-versions.json:
299 a JSON file containing a PKG-NAME => PKG-NAME#VERSION mapping for the
300 transitive dependencies.
301 NAME.zip:
302 a zip file containing the transitive dependencies for this bundle.
303 """
Han-Wen Nienhuys36502622016-10-05 17:36:20 +0200304
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200305 # intermediate artifact if split is wanted.
306 if ctx.attr.split:
David Ostrovsky86aa0b72019-03-02 12:50:48 +0100307 bundled = ctx.actions.declare_file(ctx.outputs.html.path + ".bundled.html")
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200308 else:
Viktar Donichee7b2a22018-07-17 14:12:22 -0700309 bundled = ctx.outputs.html
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200310 destdir = ctx.outputs.html.path + ".dir"
David Ostrovsky2b720e72019-06-12 09:37:58 +0200311 zips = [z for d in ctx.attr.deps for z in d[ComponentInfo].transitive_zipfiles.to_list()]
Han-Wen Nienhuys36502622016-10-05 17:36:20 +0200312
Ben Rohlfs0cd19052019-05-26 20:41:27 +0200313 # We are splitting off the package dir from the app.path such that
314 # we can set the package dir as the root for the bundler, which means
315 # that absolute imports are interpreted relative to that root.
316 pkg_dir = ctx.attr.pkg.lstrip("/")
317 app_path = ctx.file.app.path
318 app_path = app_path[app_path.index(pkg_dir) + len(pkg_dir):]
319
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200320 hermetic_npm_binary = " ".join([
321 "python",
322 "$p/" + ctx.file._run_npm.path,
Viktar Donichee7b2a22018-07-17 14:12:22 -0700323 "$p/" + ctx.file._bundler_archive.path,
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200324 "--inline-scripts",
325 "--inline-css",
David Ostrovskyb9dad712019-12-26 21:41:29 +0100326 "--sourcemaps",
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200327 "--strip-comments",
Viktar Donichee7b2a22018-07-17 14:12:22 -0700328 "--out-file",
329 "$p/" + bundled.path,
Ben Rohlfs0cd19052019-05-26 20:41:27 +0200330 "--root",
331 pkg_dir,
332 app_path,
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200333 ])
Han-Wen Nienhuys36502622016-10-05 17:36:20 +0200334
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200335 cmd = " && ".join([
336 # unpack dependencies.
337 "export PATH",
338 "p=$PWD",
339 "rm -rf %s" % destdir,
340 "mkdir -p %s/%s/bower_components" % (destdir, pkg_dir),
341 "for z in %s; do unzip -qd %s/%s/bower_components/ $z; done" % (
342 " ".join([z.path for z in zips]),
343 destdir,
344 pkg_dir,
345 ),
346 "tar -cf - %s | tar -C %s -xf -" % (" ".join([s.path for s in ctx.files.srcs]), destdir),
347 "cd %s" % destdir,
348 hermetic_npm_binary,
349 ])
Han-Wen Nienhuys3e9264f2016-11-12 15:57:37 -0800350
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200351 # Node/NPM is not (yet) hermeticized, so we have to get the binary
352 # from the environment, and it may be under $HOME, so we can't run
353 # in the sandbox.
354 node_tweaks = dict(
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200355 execution_requirements = {"local": "1"},
Viktar Donich9eab3362018-07-09 21:00:36 -0700356 use_default_shell_env = True,
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200357 )
Kasper Nilsson60264f12017-11-28 11:02:56 -0800358 ctx.actions.run_shell(
Viktar Donichee7b2a22018-07-17 14:12:22 -0700359 mnemonic = "Bundle",
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200360 inputs = [
361 ctx.file._run_npm,
362 ctx.file.app,
Viktar Donichee7b2a22018-07-17 14:12:22 -0700363 ctx.file._bundler_archive,
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200364 ] + list(zips) + ctx.files.srcs,
Viktar Donichee7b2a22018-07-17 14:12:22 -0700365 outputs = [bundled],
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200366 command = cmd,
367 **node_tweaks
368 )
369
370 if ctx.attr.split:
371 hermetic_npm_command = "export PATH && " + " ".join([
372 "python",
373 ctx.file._run_npm.path,
374 ctx.file._crisper_archive.path,
Tao Zhouaf6bf582019-12-13 18:40:07 +0100375 "--script-in-head=false",
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200376 "--always-write-script",
377 "--source",
Viktar Donichee7b2a22018-07-17 14:12:22 -0700378 bundled.path,
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200379 "--html",
380 ctx.outputs.html.path,
381 "--js",
382 ctx.outputs.js.path,
383 ])
384
385 ctx.actions.run_shell(
386 mnemonic = "Crisper",
387 inputs = [
388 ctx.file._run_npm,
389 ctx.file.app,
390 ctx.file._crisper_archive,
Viktar Donichee7b2a22018-07-17 14:12:22 -0700391 bundled,
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200392 ],
393 outputs = [ctx.outputs.js, ctx.outputs.html],
394 command = hermetic_npm_command,
395 **node_tweaks
396 )
Kasper Nilsson60264f12017-11-28 11:02:56 -0800397
Viktar Donichee7b2a22018-07-17 14:12:22 -0700398def _bundle_output_func(name, split):
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200399 _ignore = [name] # unused.
400 out = {"html": "%{name}.html"}
401 if split:
402 out["js"] = "%{name}.js"
403 return out
Han-Wen Nienhuys3e9264f2016-11-12 15:57:37 -0800404
Viktar Donichee7b2a22018-07-17 14:12:22 -0700405_bundle_rule = rule(
406 _bundle_impl,
David Pursehouse2d085002016-12-11 19:00:10 +0900407 attrs = {
David Pursehouse2d085002016-12-11 19:00:10 +0900408 "srcs": attr.label_list(allow_files = [
409 ".js",
410 ".html",
411 ".txt",
412 ".css",
413 ".ico",
414 ]),
David Pursehouse88d08852019-01-09 21:21:52 +0900415 "app": attr.label(
416 mandatory = True,
David Pursehouse2d085002016-12-11 19:00:10 +0900417 allow_single_file = True,
418 ),
David Pursehouse2d085002016-12-11 19:00:10 +0900419 "pkg": attr.string(mandatory = True),
David Pursehouse1d536682019-01-10 21:44:13 +0900420 "split": attr.bool(default = True),
David Ostrovsky2b720e72019-06-12 09:37:58 +0200421 "deps": attr.label_list(providers = [ComponentInfo]),
Viktar Donichee7b2a22018-07-17 14:12:22 -0700422 "_bundler_archive": attr.label(
423 default = Label("@polymer-bundler//:%s" % _npm_tarball("polymer-bundler")),
David Pursehouse2d085002016-12-11 19:00:10 +0900424 allow_single_file = True,
425 ),
426 "_crisper_archive": attr.label(
427 default = Label("@crisper//:%s" % _npm_tarball("crisper")),
428 allow_single_file = True,
429 ),
David Pursehouse2d085002016-12-11 19:00:10 +0900430 "_run_npm": attr.label(
431 default = Label("//tools/js:run_npm_binary.py"),
432 allow_single_file = True,
433 ),
David Pursehouse2d085002016-12-11 19:00:10 +0900434 },
Viktar Donichee7b2a22018-07-17 14:12:22 -0700435 outputs = _bundle_output_func,
Han-Wen Nienhuys36502622016-10-05 17:36:20 +0200436)
437
Viktar Donichee7b2a22018-07-17 14:12:22 -0700438def bundle_assets(*args, **kwargs):
439 """Combine html, js, css files and optionally split into js and html bundles."""
David Pursehouse1d536682019-01-10 21:44:13 +0900440 _bundle_rule(pkg = native.package_name(), *args, **kwargs)
Viktar Donich2e8b4b32017-12-05 16:05:26 -0800441
brohlfsedfb29a2019-03-26 12:51:26 +0100442def polygerrit_plugin(name, app, srcs = [], deps = [], externs = [], assets = None, plugin_name = None, **kwargs):
Viktar Donich9eab3362018-07-09 21:00:36 -0700443 """Bundles plugin dependencies for deployment.
444
445 This rule bundles all Polymer elements and JS dependencies into .html and .js files.
446 Run-time dependencies (e.g. JS libraries loaded after plugin starts) should be provided using "assets" property.
447 Output of this rule is a FileSet with "${name}_fs", with deploy artifacts in "plugins/${name}/static".
448
449 Args:
viktard063bdc62018-10-22 14:39:46 -0700450 name: String, rule name.
Viktar Donich9eab3362018-07-09 21:00:36 -0700451 app: String, the main or root source file.
brohlfsedfb29a2019-03-26 12:51:26 +0100452 externs: Fileset, external definitions that should not be bundled.
Viktar Donich9eab3362018-07-09 21:00:36 -0700453 assets: Fileset, additional files to be used by plugin in runtime, exported to "plugins/${name}/static".
viktard063bdc62018-10-22 14:39:46 -0700454 plugin_name: String, plugin name. ${name} is used if not provided.
Viktar Donich9eab3362018-07-09 21:00:36 -0700455 """
viktard063bdc62018-10-22 14:39:46 -0700456 if not plugin_name:
457 plugin_name = name
Viktar Donich9eab3362018-07-09 21:00:36 -0700458
viktard063bdc62018-10-22 14:39:46 -0700459 html_plugin = app.endswith(".html")
460 srcs = srcs if app in srcs else srcs + [app]
461
462 if html_plugin:
463 # Combines all .js and .html files into foo_combined.js and foo_combined.html
464 _bundle_rule(
465 name = name + "_combined",
466 app = app,
467 srcs = srcs,
brohlfs027551f2019-03-19 12:37:37 +0100468 deps = deps,
viktard063bdc62018-10-22 14:39:46 -0700469 pkg = native.package_name(),
470 **kwargs
471 )
472 js_srcs = [name + "_combined.js"]
473 else:
474 js_srcs = srcs
475
476 closure_js_library(
477 name = name + "_closure_lib",
brohlfsedfb29a2019-03-26 12:51:26 +0100478 srcs = js_srcs + externs,
viktard063bdc62018-10-22 14:39:46 -0700479 convention = "GOOGLE",
480 no_closure_library = True,
481 deps = [
482 "//lib/polymer_externs:polymer_closure",
483 "//polygerrit-ui/app/externs:plugin",
484 ],
Viktar Donichd3adb102018-07-12 10:00:22 -0700485 )
Viktar Donich9eab3362018-07-09 21:00:36 -0700486
487 closure_js_binary(
488 name = name + "_bin",
David Ostrovskyed891762019-04-07 18:58:47 -0700489 compilation_level = "WHITESPACE_ONLY",
Viktar Donich9eab3362018-07-09 21:00:36 -0700490 defs = [
Tao Zhou84f07972019-10-15 13:52:17 +0200491 "--polymer_version=2",
492 "--language_out=ECMASCRIPT_2017",
Viktar Donich9eab3362018-07-09 21:00:36 -0700493 "--rewrite_polyfills=false",
494 ],
495 deps = [
496 name + "_closure_lib",
497 ],
David Ostrovsky85eb9782019-12-24 14:47:17 +0100498 dependency_mode = "PRUNE_LEGACY",
Viktar Donich9eab3362018-07-09 21:00:36 -0700499 )
500
viktard063bdc62018-10-22 14:39:46 -0700501 if html_plugin:
502 native.genrule(
503 name = name + "_rename_html",
504 srcs = [name + "_combined.html"],
505 outs = [plugin_name + ".html"],
506 cmd = "sed 's/<script src=\"" + name + "_combined.js\"/<script src=\"" + plugin_name + ".js\"/g' $(SRCS) > $(OUTS)",
507 output_to_bindir = True,
508 )
Viktar Donich9eab3362018-07-09 21:00:36 -0700509
510 native.genrule(
511 name = name + "_rename_js",
512 srcs = [name + "_bin.js"],
viktard063bdc62018-10-22 14:39:46 -0700513 outs = [plugin_name + ".js"],
Viktar Donich9eab3362018-07-09 21:00:36 -0700514 cmd = "cp $< $@",
515 output_to_bindir = True,
516 )
517
viktard063bdc62018-10-22 14:39:46 -0700518 if html_plugin:
519 static_files = [plugin_name + ".js", plugin_name + ".html"]
520 else:
521 static_files = [plugin_name + ".js"]
Viktar Donich9eab3362018-07-09 21:00:36 -0700522
523 if assets:
524 nested, direct = [], []
525 for x in assets:
526 target = nested if "/" in x else direct
527 target.append(x)
528
529 static_files += direct
530
531 if nested:
532 native.genrule(
533 name = name + "_copy_assets",
534 srcs = assets,
535 outs = [f.split("/")[-1] for f in nested],
536 cmd = "cp $(SRCS) $(@D)",
537 output_to_bindir = True,
538 )
David Pursehouse462bc1b2020-03-05 14:48:51 +0900539 static_files.append(":" + name + "_copy_assets")
Viktar Donich9eab3362018-07-09 21:00:36 -0700540
541 native.filegroup(
542 name = name,
543 srcs = static_files,
544 )