blob: ba538158cb6d21a07662f8fb6121ca8bb0715b6f [file] [log] [blame]
"""This file contains rules to preprocess files before bundling"""
def _update_links_impl(ctx):
"""Wrapper for the links-update command-line tool"""
dir_name = ctx.label.name
output_files = []
input_js_files = []
output_js_files = []
js_files_args = ctx.actions.args()
js_files_args.set_param_file_format("multiline")
js_files_args.use_param_file("%s", use_always = True)
for f in ctx.files.srcs:
output_file = ctx.actions.declare_file(dir_name + "/" + f.path)
output_files.append(output_file)
if f.extension == "html":
input_js_files.append(f)
output_js_files.append(output_file)
js_files_args.add(f)
js_files_args.add(output_file)
else:
ctx.actions.expand_template(
output = output_file,
template = f,
substitutions = {},
)
ctx.actions.run(
executable = ctx.executable._updater,
outputs = output_js_files,
inputs = input_js_files + [ctx.file.redirects],
arguments = [js_files_args, ctx.file.redirects.path],
)
return [DefaultInfo(files = depset(output_files))]
update_links = rule(
implementation = _update_links_impl,
attrs = {
"srcs": attr.label_list(allow_files = True),
"redirects": attr.label(allow_single_file = True, mandatory = True),
"_updater": attr.label(
default = ":links-updater-bin",
executable = True,
cfg = "host",
),
},
)
def _get_node_modules_root(node_modules):
if node_modules == None or len(node_modules) == 0:
return None
node_module_root = node_modules[0].label.workspace_root
for target in node_modules:
if target.label.workspace_root != node_module_root:
fail("Only one node_modules workspace can be used")
return node_module_root + "/"
def _get_relative_path(file, root):
root_len = len(root)
if file.path.startswith(root):
return file.path[root_len - 1:]
else:
fail("The file '%s' is not under the root '%s'." % (file.path, root))
def _copy_file(ctx, src, target_name):
output_file = ctx.actions.declare_file(target_name)
ctx.actions.expand_template(
output = output_file,
template = src,
substitutions = {},
)
return output_file
def _get_generated_files(ctx, files, files_root_path, target_dir):
gen_files_for_html = dict()
gen_files_for_js = dict()
copied_files = []
for f in files:
target_name = target_dir + _get_relative_path(f, files_root_path)
if f.extension == "html":
html_output_file = ctx.actions.declare_file(target_name)
js_output_file = ctx.actions.declare_file(target_name + "_gen.js")
gen_files_for_html.update([[f, {"html": html_output_file, "js": js_output_file}]])
elif f.extension == "js":
js_output_file = ctx.actions.declare_file(target_name)
gen_files_for_js.update([[f, {"js": js_output_file}]])
else:
copied_files.append(_copy_file(ctx, f, target_name))
return (gen_files_for_html, gen_files_for_js, copied_files)
def _prepare_for_bundling_impl(ctx):
dir_name = ctx.label.name
all_output_files = []
node_modules_root = _get_node_modules_root(ctx.attr.node_modules)
html_files_dict = dict()
js_files_dict = dict()
root_path = ctx.bin_dir.path + "/" + ctx.attr.root_path
if not root_path.endswith("/"):
root_path = root_path + "/"
gen_files_for_html, gen_files_for_js, copied_files = _get_generated_files(ctx, ctx.files.srcs, root_path, dir_name)
html_files_dict.update(gen_files_for_html)
js_files_dict.update(gen_files_for_js)
all_output_files.extend(copied_files)
gen_files_for_html, gen_files_for_js, copied_files = _get_generated_files(ctx, ctx.files.additional_node_modules_to_preprocess, node_modules_root, dir_name)
html_files_dict.update(gen_files_for_html)
js_files_dict.update(gen_files_for_js)
all_output_files.extend(copied_files)
for f in ctx.files.node_modules:
target_name = dir_name + _get_relative_path(f, node_modules_root)
if html_files_dict.get(f) == None and js_files_dict.get(f) == None:
all_output_files.append(_copy_file(ctx, f, target_name))
preprocessed_output_files = []
html_files_args = ctx.actions.args()
html_files_args.set_param_file_format("multiline")
html_files_args.use_param_file("%s", use_always = True)
for src_path, output_files in html_files_dict.items():
html_files_args.add(src_path)
html_files_args.add(output_files["html"])
html_files_args.add(output_files["js"])
preprocessed_output_files.append(output_files["html"])
preprocessed_output_files.append(output_files["js"])
js_files_args = ctx.actions.args()
js_files_args.set_param_file_format("multiline")
js_files_args.use_param_file("%s", use_always = True)
for src_path, output_files in js_files_dict.items():
js_files_args.add(src_path)
js_files_args.add(output_files["js"])
preprocessed_output_files.append(output_files["js"])
all_output_files.extend(preprocessed_output_files)
ctx.actions.run(
executable = ctx.executable._preprocessor,
outputs = preprocessed_output_files,
inputs = ctx.files.srcs + ctx.files.additional_node_modules_to_preprocess,
arguments = [root_path, html_files_args, js_files_args],
)
entry_point_html = ctx.attr.entry_point
entry_point_js = ctx.attr.entry_point + "_gen.js"
ctx.actions.write(ctx.outputs.html, "<link rel=\"import\" href=\"./%s\" >" % entry_point_html)
ctx.actions.write(ctx.outputs.js, "import \"./%s\";" % entry_point_js)
return [
DefaultInfo(files = depset([ctx.outputs.html, ctx.outputs.js], transitive = [depset(all_output_files)])),
OutputGroupInfo(
js = depset([ctx.outputs.js] + [f for f in all_output_files if f.extension == "js"]),
html = depset([ctx.outputs.html] + [f for f in all_output_files if f.extension == "html"]),
),
]
prepare_for_bundling = rule(
implementation = _prepare_for_bundling_impl,
attrs = {
"srcs": attr.label_list(allow_files = True),
"node_modules": attr.label_list(allow_files = True),
"_preprocessor": attr.label(
default = ":preprocessor-bin",
executable = True,
cfg = "host",
),
"additional_node_modules_to_preprocess": attr.label_list(allow_files = True),
"root_path": attr.string(),
"entry_point": attr.string(
mandatory = True,
doc = "Path relative to root_path",
),
},
outputs = {
"html": "%{name}/entry.html",
"js": "%{name}/entry.js",
},
)