| """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", |
| }, |
| ) |