blob: a4080e59428f347a826c55b2439b6abc9b8add0f [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
Han-Wen Nienhuys36502622016-10-05 17:36:20 +020048# for use in repo rules.
49def _run_npm_binary_str(ctx, tarball, args):
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020050 python_bin = ctx.which("python")
51 return " ".join([
52 python_bin,
53 ctx.path(ctx.attr._run_npm),
54 ctx.path(tarball),
55 ] + args)
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020056
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020057def _bower_archive(ctx):
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020058 """Download a bower package."""
59 download_name = "%s__download_bower.zip" % ctx.name
60 renamed_name = "%s__renamed.zip" % ctx.name
61 version_name = "%s__version.json" % ctx.name
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020062
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020063 cmd = [
64 ctx.which("python"),
65 ctx.path(ctx.attr._download_bower),
66 "-b",
67 "%s" % _run_npm_binary_str(ctx, ctx.attr._bower_archive, []),
68 "-n",
69 ctx.name,
70 "-p",
71 ctx.attr.package,
72 "-v",
73 ctx.attr.version,
74 "-s",
75 ctx.attr.sha1,
76 "-o",
77 download_name,
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020078 ]
79
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020080 out = ctx.execute(cmd)
81 if out.return_code:
82 fail("failed %s: %s" % (" ".join(cmd), out.stderr))
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020083
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020084 _bash(ctx, " && ".join([
85 "TMP=$(mktemp -d || mktemp -d -t bazel-tmp)",
86 "TZ=UTC",
87 "export UTC",
88 "cd $TMP",
89 "mkdir bower_components",
90 "cd bower_components",
91 "unzip %s" % ctx.path(download_name),
92 "cd ..",
93 "find . -exec touch -t 198001010000 '{}' ';'",
94 "zip -Xr %s bower_components" % renamed_name,
95 "cd ..",
96 "rm -rf ${TMP}",
97 ]))
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020098
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +020099 dep_version = ctx.attr.semver if ctx.attr.semver else ctx.attr.version
100 ctx.file(
101 version_name,
102 '"%s":"%s#%s"' % (ctx.name, ctx.attr.package, dep_version),
103 )
104 ctx.file(
105 "BUILD",
106 "\n".join([
107 "package(default_visibility=['//visibility:public'])",
108 "filegroup(name = 'zipfile', srcs = ['%s'], )" % download_name,
109 "filegroup(name = 'version_json', srcs = ['%s'], visibility=['//visibility:public'])" % version_name,
110 ]),
111 False,
112 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200113
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200114def _bash(ctx, cmd):
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200115 cmd_list = ["bash", "-c", cmd]
116 out = ctx.execute(cmd_list)
117 if out.return_code:
118 fail("failed %s: %s" % (" ".join(cmd_list), out.stderr))
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200119
David Pursehouse2d085002016-12-11 19:00:10 +0900120bower_archive = repository_rule(
121 _bower_archive,
122 attrs = {
David Pursehouse2d085002016-12-11 19:00:10 +0900123 "package": attr.string(mandatory = True),
124 "semver": attr.string(),
David Pursehouse88d08852019-01-09 21:21:52 +0900125 "sha1": attr.string(mandatory = True),
126 "version": attr.string(mandatory = True),
127 "_bower_archive": attr.label(default = Label("@bower//:%s" % _npm_tarball("bower"))),
128 "_download_bower": attr.label(default = Label("//tools/js:download_bower.py")),
129 "_run_npm": attr.label(default = Label("//tools/js:run_npm_binary.py")),
David Pursehouse2d085002016-12-11 19:00:10 +0900130 },
131)
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200132
133def _bower_component_impl(ctx):
David Ostrovsky83fab682019-03-03 10:58:10 +0100134 transitive_zipfiles = depset(
135 direct = [ctx.file.zipfile],
136 transitive = [d.transitive_zipfiles for d in ctx.attr.deps],
137 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200138
David Ostrovsky83fab682019-03-03 10:58:10 +0100139 transitive_licenses = depset(
140 direct = [ctx.file.license],
141 transitive = [d.transitive_licenses for d in ctx.attr.deps],
142 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200143
David Ostrovsky83fab682019-03-03 10:58:10 +0100144 transitive_versions = depset(
145 direct = ctx.files.version_json,
146 transitive = [d.transitive_versions for d in ctx.attr.deps],
147 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200148
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200149 return struct(
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200150 transitive_licenses = transitive_licenses,
Viktar Donich9eab3362018-07-09 21:00:36 -0700151 transitive_versions = transitive_versions,
152 transitive_zipfiles = transitive_zipfiles,
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200153 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200154
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200155_common_attrs = {
David Pursehouse2d085002016-12-11 19:00:10 +0900156 "deps": attr.label_list(providers = [
157 "transitive_zipfiles",
158 "transitive_versions",
159 "transitive_licenses",
160 ]),
161}
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
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200190 return struct(
David Ostrovsky83fab682019-03-03 10:58:10 +0100191 transitive_licenses = depset(licenses),
Viktar Donich9eab3362018-07-09 21:00:36 -0700192 transitive_versions = depset(),
193 transitive_zipfiles = list([ctx.outputs.zip]),
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200194 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200195
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200196js_component = rule(
David Pursehouse2d085002016-12-11 19:00:10 +0900197 _js_component,
Vladimir Moskva4c8be85f2018-01-05 16:59:03 +0100198 attrs = dict(_common_attrs.items() + {
David Pursehouse2d085002016-12-11 19:00:10 +0900199 "srcs": attr.label_list(allow_files = [".js"]),
200 "license": attr.label(allow_single_file = True),
Vladimir Moskva4c8be85f2018-01-05 16:59:03 +0100201 }.items()),
David Pursehouse2d085002016-12-11 19:00:10 +0900202 outputs = {
203 "zip": "%{name}.zip",
204 },
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200205)
206
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200207_bower_component = rule(
David Pursehouse2d085002016-12-11 19:00:10 +0900208 _bower_component_impl,
Vladimir Moskva4c8be85f2018-01-05 16:59:03 +0100209 attrs = dict(_common_attrs.items() + {
David Pursehouse2d085002016-12-11 19:00:10 +0900210 "license": attr.label(allow_single_file = True),
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200211
David Pursehouse2d085002016-12-11 19:00:10 +0900212 # If set, define by hand, and don't regenerate this entry in bower2bazel.
213 "seed": attr.bool(default = False),
David Pursehouse88d08852019-01-09 21:21:52 +0900214 "version_json": attr.label(allow_files = [".json"]),
215 "zipfile": attr.label(allow_single_file = [".zip"]),
Vladimir Moskva4c8be85f2018-01-05 16:59:03 +0100216 }.items()),
David Pursehouse2d085002016-12-11 19:00:10 +0900217)
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200218
219# TODO(hanwen): make license mandatory.
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200220def bower_component(name, license = None, **kwargs):
221 prefix = "//lib:LICENSE-"
222 if license and not license.startswith(prefix):
223 license = prefix + license
224 _bower_component(
225 name = name,
226 license = license,
227 zipfile = "@%s//:zipfile" % name,
228 version_json = "@%s//:version_json" % name,
229 **kwargs
230 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200231
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200232def _bower_component_bundle_impl(ctx):
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200233 """A bunch of bower components zipped up."""
234 zips = depset()
235 for d in ctx.attr.deps:
David Ostrovsky83fab682019-03-03 10:58:10 +0100236 files = d.transitive_zipfiles
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200237
David Ostrovsky83fab682019-03-03 10:58:10 +0100238 # TODO(davido): Make sure the field always contains a depset
239 if type(files) == "list":
240 files = depset(files)
241 zips = depset(transitive = [zips, files])
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200242
David Ostrovsky83fab682019-03-03 10:58:10 +0100243 versions = depset(transitive = [d.transitive_versions for d in ctx.attr.deps])
244
245 licenses = depset(transitive = [d.transitive_versions for d in ctx.attr.deps])
Han-Wen Nienhuys36502622016-10-05 17:36:20 +0200246
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200247 out_zip = ctx.outputs.zip
248 out_versions = ctx.outputs.version_json
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200249
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200250 ctx.actions.run_shell(
David Ostrovsky930f29e2019-01-08 23:11:59 +0100251 inputs = zips.to_list(),
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200252 outputs = [out_zip],
253 command = " && ".join([
254 "p=$PWD",
255 "TZ=UTC",
256 "export TZ",
257 "rm -rf %s.dir" % out_zip.path,
258 "mkdir -p %s.dir/bower_components" % out_zip.path,
259 "cd %s.dir/bower_components" % out_zip.path,
David Ostrovsky930f29e2019-01-08 23:11:59 +0100260 "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 +0200261 "cd ..",
262 "find . -exec touch -t 198001010000 '{}' ';'",
263 "zip -Xqr $p/%s bower_components/*" % out_zip.path,
264 ]),
265 mnemonic = "BowerCombine",
266 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200267
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200268 ctx.actions.run_shell(
David Ostrovsky930f29e2019-01-08 23:11:59 +0100269 inputs = versions.to_list(),
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200270 outputs = [out_versions],
271 mnemonic = "BowerVersions",
David Ostrovsky930f29e2019-01-08 23:11:59 +0100272 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 +0200273 )
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200274
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200275 return struct(
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200276 transitive_licenses = licenses,
Viktar Donich9eab3362018-07-09 21:00:36 -0700277 transitive_versions = versions,
278 transitive_zipfiles = zips,
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200279 )
Han-Wen Nienhuys36502622016-10-05 17:36:20 +0200280
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200281bower_component_bundle = rule(
David Pursehouse2d085002016-12-11 19:00:10 +0900282 _bower_component_bundle_impl,
283 attrs = _common_attrs,
284 outputs = {
David Pursehouse2d085002016-12-11 19:00:10 +0900285 "version_json": "%{name}-versions.json",
David Pursehouse88d08852019-01-09 21:21:52 +0900286 "zip": "%{name}.zip",
David Pursehouse2d085002016-12-11 19:00:10 +0900287 },
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +0200288)
Dave Borowitz070df0f2017-11-03 09:14:02 -0400289
Viktar Donichee7b2a22018-07-17 14:12:22 -0700290def _bundle_impl(ctx):
291 """Groups a set of .html and .js together in a zip file.
Han-Wen Nienhuys3dede162017-02-01 13:33:19 +0100292
Viktar Donichee7b2a22018-07-17 14:12:22 -0700293 Outputs:
294 NAME-versions.json:
295 a JSON file containing a PKG-NAME => PKG-NAME#VERSION mapping for the
296 transitive dependencies.
297 NAME.zip:
298 a zip file containing the transitive dependencies for this bundle.
299 """
Han-Wen Nienhuys36502622016-10-05 17:36:20 +0200300
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200301 # intermediate artifact if split is wanted.
302 if ctx.attr.split:
David Ostrovsky86aa0b72019-03-02 12:50:48 +0100303 bundled = ctx.actions.declare_file(ctx.outputs.html.path + ".bundled.html")
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200304 else:
Viktar Donichee7b2a22018-07-17 14:12:22 -0700305 bundled = ctx.outputs.html
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200306 destdir = ctx.outputs.html.path + ".dir"
David Ostrovsky6e9d4842019-05-21 22:13:25 +0200307 zips = [z for d in ctx.attr.deps for z in d.transitive_zipfiles.to_list()]
Han-Wen Nienhuys36502622016-10-05 17:36:20 +0200308
Ben Rohlfs0cd19052019-05-26 20:41:27 +0200309 # We are splitting off the package dir from the app.path such that
310 # we can set the package dir as the root for the bundler, which means
311 # that absolute imports are interpreted relative to that root.
312 pkg_dir = ctx.attr.pkg.lstrip("/")
313 app_path = ctx.file.app.path
314 app_path = app_path[app_path.index(pkg_dir) + len(pkg_dir):]
315
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200316 hermetic_npm_binary = " ".join([
317 "python",
318 "$p/" + ctx.file._run_npm.path,
Viktar Donichee7b2a22018-07-17 14:12:22 -0700319 "$p/" + ctx.file._bundler_archive.path,
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200320 "--inline-scripts",
321 "--inline-css",
322 "--strip-comments",
Viktar Donichee7b2a22018-07-17 14:12:22 -0700323 "--out-file",
324 "$p/" + bundled.path,
Ben Rohlfs0cd19052019-05-26 20:41:27 +0200325 "--root",
326 pkg_dir,
327 app_path,
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200328 ])
Han-Wen Nienhuys36502622016-10-05 17:36:20 +0200329
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200330 cmd = " && ".join([
331 # unpack dependencies.
332 "export PATH",
333 "p=$PWD",
334 "rm -rf %s" % destdir,
335 "mkdir -p %s/%s/bower_components" % (destdir, pkg_dir),
336 "for z in %s; do unzip -qd %s/%s/bower_components/ $z; done" % (
337 " ".join([z.path for z in zips]),
338 destdir,
339 pkg_dir,
340 ),
341 "tar -cf - %s | tar -C %s -xf -" % (" ".join([s.path for s in ctx.files.srcs]), destdir),
342 "cd %s" % destdir,
343 hermetic_npm_binary,
344 ])
Han-Wen Nienhuys3e9264f2016-11-12 15:57:37 -0800345
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200346 # Node/NPM is not (yet) hermeticized, so we have to get the binary
347 # from the environment, and it may be under $HOME, so we can't run
348 # in the sandbox.
349 node_tweaks = dict(
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200350 execution_requirements = {"local": "1"},
Viktar Donich9eab3362018-07-09 21:00:36 -0700351 use_default_shell_env = True,
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200352 )
Kasper Nilsson60264f12017-11-28 11:02:56 -0800353 ctx.actions.run_shell(
Viktar Donichee7b2a22018-07-17 14:12:22 -0700354 mnemonic = "Bundle",
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200355 inputs = [
356 ctx.file._run_npm,
357 ctx.file.app,
Viktar Donichee7b2a22018-07-17 14:12:22 -0700358 ctx.file._bundler_archive,
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200359 ] + list(zips) + ctx.files.srcs,
Viktar Donichee7b2a22018-07-17 14:12:22 -0700360 outputs = [bundled],
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200361 command = cmd,
362 **node_tweaks
363 )
364
365 if ctx.attr.split:
366 hermetic_npm_command = "export PATH && " + " ".join([
367 "python",
368 ctx.file._run_npm.path,
369 ctx.file._crisper_archive.path,
370 "--always-write-script",
371 "--source",
Viktar Donichee7b2a22018-07-17 14:12:22 -0700372 bundled.path,
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200373 "--html",
374 ctx.outputs.html.path,
375 "--js",
376 ctx.outputs.js.path,
377 ])
378
379 ctx.actions.run_shell(
380 mnemonic = "Crisper",
381 inputs = [
382 ctx.file._run_npm,
383 ctx.file.app,
384 ctx.file._crisper_archive,
Viktar Donichee7b2a22018-07-17 14:12:22 -0700385 bundled,
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200386 ],
387 outputs = [ctx.outputs.js, ctx.outputs.html],
388 command = hermetic_npm_command,
389 **node_tweaks
390 )
Kasper Nilsson60264f12017-11-28 11:02:56 -0800391
Viktar Donichee7b2a22018-07-17 14:12:22 -0700392def _bundle_output_func(name, split):
Han-Wen Nienhuysa667b4c2018-07-10 11:51:36 +0200393 _ignore = [name] # unused.
394 out = {"html": "%{name}.html"}
395 if split:
396 out["js"] = "%{name}.js"
397 return out
Han-Wen Nienhuys3e9264f2016-11-12 15:57:37 -0800398
Viktar Donichee7b2a22018-07-17 14:12:22 -0700399_bundle_rule = rule(
400 _bundle_impl,
David Pursehouse2d085002016-12-11 19:00:10 +0900401 attrs = {
David Pursehouse2d085002016-12-11 19:00:10 +0900402 "srcs": attr.label_list(allow_files = [
403 ".js",
404 ".html",
405 ".txt",
406 ".css",
407 ".ico",
408 ]),
David Pursehouse88d08852019-01-09 21:21:52 +0900409 "app": attr.label(
410 mandatory = True,
David Pursehouse2d085002016-12-11 19:00:10 +0900411 allow_single_file = True,
412 ),
David Pursehouse2d085002016-12-11 19:00:10 +0900413 "pkg": attr.string(mandatory = True),
David Pursehouse1d536682019-01-10 21:44:13 +0900414 "split": attr.bool(default = True),
David Pursehouse88d08852019-01-09 21:21:52 +0900415 "deps": attr.label_list(providers = ["transitive_zipfiles"]),
Viktar Donichee7b2a22018-07-17 14:12:22 -0700416 "_bundler_archive": attr.label(
417 default = Label("@polymer-bundler//:%s" % _npm_tarball("polymer-bundler")),
David Pursehouse2d085002016-12-11 19:00:10 +0900418 allow_single_file = True,
419 ),
420 "_crisper_archive": attr.label(
421 default = Label("@crisper//:%s" % _npm_tarball("crisper")),
422 allow_single_file = True,
423 ),
David Pursehouse2d085002016-12-11 19:00:10 +0900424 "_run_npm": attr.label(
425 default = Label("//tools/js:run_npm_binary.py"),
426 allow_single_file = True,
427 ),
David Pursehouse2d085002016-12-11 19:00:10 +0900428 },
Viktar Donichee7b2a22018-07-17 14:12:22 -0700429 outputs = _bundle_output_func,
Han-Wen Nienhuys36502622016-10-05 17:36:20 +0200430)
431
Viktar Donichee7b2a22018-07-17 14:12:22 -0700432def bundle_assets(*args, **kwargs):
433 """Combine html, js, css files and optionally split into js and html bundles."""
David Pursehouse1d536682019-01-10 21:44:13 +0900434 _bundle_rule(pkg = native.package_name(), *args, **kwargs)
Viktar Donich2e8b4b32017-12-05 16:05:26 -0800435
brohlfsedfb29a2019-03-26 12:51:26 +0100436def polygerrit_plugin(name, app, srcs = [], deps = [], externs = [], assets = None, plugin_name = None, **kwargs):
Viktar Donich9eab3362018-07-09 21:00:36 -0700437 """Bundles plugin dependencies for deployment.
438
439 This rule bundles all Polymer elements and JS dependencies into .html and .js files.
440 Run-time dependencies (e.g. JS libraries loaded after plugin starts) should be provided using "assets" property.
441 Output of this rule is a FileSet with "${name}_fs", with deploy artifacts in "plugins/${name}/static".
442
443 Args:
viktard063bdc62018-10-22 14:39:46 -0700444 name: String, rule name.
Viktar Donich9eab3362018-07-09 21:00:36 -0700445 app: String, the main or root source file.
brohlfsedfb29a2019-03-26 12:51:26 +0100446 externs: Fileset, external definitions that should not be bundled.
Viktar Donich9eab3362018-07-09 21:00:36 -0700447 assets: Fileset, additional files to be used by plugin in runtime, exported to "plugins/${name}/static".
viktard063bdc62018-10-22 14:39:46 -0700448 plugin_name: String, plugin name. ${name} is used if not provided.
Viktar Donich9eab3362018-07-09 21:00:36 -0700449 """
viktard063bdc62018-10-22 14:39:46 -0700450 if not plugin_name:
451 plugin_name = name
Viktar Donich9eab3362018-07-09 21:00:36 -0700452
viktard063bdc62018-10-22 14:39:46 -0700453 html_plugin = app.endswith(".html")
454 srcs = srcs if app in srcs else srcs + [app]
455
456 if html_plugin:
457 # Combines all .js and .html files into foo_combined.js and foo_combined.html
458 _bundle_rule(
459 name = name + "_combined",
460 app = app,
461 srcs = srcs,
brohlfs027551f2019-03-19 12:37:37 +0100462 deps = deps,
viktard063bdc62018-10-22 14:39:46 -0700463 pkg = native.package_name(),
464 **kwargs
465 )
466 js_srcs = [name + "_combined.js"]
467 else:
468 js_srcs = srcs
469
470 closure_js_library(
471 name = name + "_closure_lib",
brohlfsedfb29a2019-03-26 12:51:26 +0100472 srcs = js_srcs + externs,
viktard063bdc62018-10-22 14:39:46 -0700473 convention = "GOOGLE",
474 no_closure_library = True,
475 deps = [
476 "//lib/polymer_externs:polymer_closure",
477 "//polygerrit-ui/app/externs:plugin",
478 ],
Viktar Donichd3adb102018-07-12 10:00:22 -0700479 )
Viktar Donich9eab3362018-07-09 21:00:36 -0700480
481 closure_js_binary(
482 name = name + "_bin",
David Ostrovskyed891762019-04-07 18:58:47 -0700483 compilation_level = "WHITESPACE_ONLY",
Viktar Donich9eab3362018-07-09 21:00:36 -0700484 defs = [
485 "--polymer_version=1",
486 "--language_out=ECMASCRIPT6",
487 "--rewrite_polyfills=false",
488 ],
489 deps = [
490 name + "_closure_lib",
491 ],
492 )
493
viktard063bdc62018-10-22 14:39:46 -0700494 if html_plugin:
495 native.genrule(
496 name = name + "_rename_html",
497 srcs = [name + "_combined.html"],
498 outs = [plugin_name + ".html"],
499 cmd = "sed 's/<script src=\"" + name + "_combined.js\"/<script src=\"" + plugin_name + ".js\"/g' $(SRCS) > $(OUTS)",
500 output_to_bindir = True,
501 )
Viktar Donich9eab3362018-07-09 21:00:36 -0700502
503 native.genrule(
504 name = name + "_rename_js",
505 srcs = [name + "_bin.js"],
viktard063bdc62018-10-22 14:39:46 -0700506 outs = [plugin_name + ".js"],
Viktar Donich9eab3362018-07-09 21:00:36 -0700507 cmd = "cp $< $@",
508 output_to_bindir = True,
509 )
510
viktard063bdc62018-10-22 14:39:46 -0700511 if html_plugin:
512 static_files = [plugin_name + ".js", plugin_name + ".html"]
513 else:
514 static_files = [plugin_name + ".js"]
Viktar Donich9eab3362018-07-09 21:00:36 -0700515
516 if assets:
517 nested, direct = [], []
518 for x in assets:
519 target = nested if "/" in x else direct
520 target.append(x)
521
522 static_files += direct
523
524 if nested:
525 native.genrule(
526 name = name + "_copy_assets",
527 srcs = assets,
528 outs = [f.split("/")[-1] for f in nested],
529 cmd = "cp $(SRCS) $(@D)",
530 output_to_bindir = True,
531 )
532 static_files += [":" + name + "_copy_assets"]
533
534 native.filegroup(
535 name = name,
536 srcs = static_files,
537 )