|
| 1 | +""" |
| 2 | + Exposes a custom Bazel rule for processing sources, which are extracted from Bazel |
| 3 | + targets, with the Angular linker plugin. |
| 4 | +""" |
| 5 | + |
| 6 | +load("@build_bazel_rules_nodejs//:providers.bzl", "JSModuleInfo", "JSNamedModuleInfo") |
| 7 | + |
| 8 | +""" |
| 9 | +Gets the Bazel manifest path for a given file. Manifest paths are used within Bazel runfile |
| 10 | +manifests and are formatted as followed: `<workspace_name>/<workspace_relative_file_path>` |
| 11 | +""" |
| 12 | + |
| 13 | +def _to_manifest_path(ctx, file): |
| 14 | + # If a file resides outside of the current workspace, we omit the leading `../` |
| 15 | + # segment as the rest will contain the workspace name. e.g. `../npm/node_modules/<..>`. |
| 16 | + if file.short_path.startswith("../"): |
| 17 | + return file.short_path[3:] |
| 18 | + else: |
| 19 | + return ctx.workspace_name + "/" + file.short_path |
| 20 | + |
| 21 | +"""Extracts all source files from the specified list of dependencies.""" |
| 22 | + |
| 23 | +def _extract_source_files(deps): |
| 24 | + depsets = [] |
| 25 | + for dep in deps: |
| 26 | + if JSNamedModuleInfo in dep: |
| 27 | + depsets.append(dep[JSNamedModuleInfo].sources) |
| 28 | + elif JSModuleInfo in dep: |
| 29 | + depsets.append(dep[JSModuleInfo].sources) |
| 30 | + elif hasattr(dep, "files"): |
| 31 | + depsets.append(dep.files) |
| 32 | + return depset(transitive = depsets) |
| 33 | + |
| 34 | +def _linker_process(ctx): |
| 35 | + args = ctx.actions.args() |
| 36 | + sources = _extract_source_files(ctx.attr.srcs) |
| 37 | + tmp_dir_name = ctx.label.name |
| 38 | + |
| 39 | + # The output directory manifest path. e.g `angular_material/src/cdk/a11y/linker_processed`. |
| 40 | + output_dir_manifest_path = "%s/%s/%s" % (ctx.workspace_name, ctx.label.package, tmp_dir_name) |
| 41 | + |
| 42 | + # The output directory exec path. e.g `bazel_out/<..>/src/cdk/a11y/linker_processed`. |
| 43 | + output_dir_exec_path = "%s/%s/%s" % (ctx.bin_dir.path, ctx.label.package, tmp_dir_name) |
| 44 | + |
| 45 | + # Given the sources being transformed and written to a new location, the AMD module names |
| 46 | + # need to be rewritten. This file maps AMD modules as per the new location to the AMD modules |
| 47 | + # as they appear in the sources. i.e. we generate AMD module aliases. |
| 48 | + amd_module_mapping_file = ctx.actions.declare_file("%s/_module_mappings.js" % tmp_dir_name) |
| 49 | + |
| 50 | + args.add(output_dir_exec_path) |
| 51 | + args.add(output_dir_manifest_path) |
| 52 | + args.add(amd_module_mapping_file.path) |
| 53 | + |
| 54 | + outputs = [amd_module_mapping_file] |
| 55 | + |
| 56 | + # Iterate through the determined sources and pass them to the tool as argument. |
| 57 | + for input_file in sources.to_list(): |
| 58 | + output_pkg_path = _to_manifest_path(ctx, input_file) |
| 59 | + args.add("%s:%s" % (input_file.path, output_pkg_path)) |
| 60 | + outputs.append(ctx.actions.declare_file("%s/%s" % (tmp_dir_name, output_pkg_path))) |
| 61 | + |
| 62 | + # Support passing arguments through a parameter file. This is necessary because on Windows |
| 63 | + # there is an argument limit and we need to handle a large amount of input files. Bazel |
| 64 | + # switches between parameter file and normal argument passing based on the operating system. |
| 65 | + # Read more here: https://docs.bazel.build/versions/master/skylark/lib/Args.html#use_param_file |
| 66 | + args.use_param_file(param_file_arg = "--param-file=%s", use_always = True) |
| 67 | + |
| 68 | + ctx.actions.run( |
| 69 | + inputs = sources, |
| 70 | + outputs = outputs, |
| 71 | + executable = ctx.executable._linker_process_tool, |
| 72 | + arguments = [args], |
| 73 | + progress_message = "NgLinkerProcess", |
| 74 | + ) |
| 75 | + |
| 76 | + outputs_depset = depset(outputs) |
| 77 | + |
| 78 | + return [ |
| 79 | + DefaultInfo(files = outputs_depset), |
| 80 | + ] |
| 81 | + |
| 82 | +""" |
| 83 | + Rule definition for the "linker_process" rule that can process a list of targets |
| 84 | + with the Angular linker. The processed files can be retrieved through the default |
| 85 | + files provider, or through the `JSNamedModuleInfo` provider. |
| 86 | +""" |
| 87 | +linker_process = rule( |
| 88 | + implementation = _linker_process, |
| 89 | + attrs = { |
| 90 | + "srcs": attr.label_list( |
| 91 | + allow_files = True, |
| 92 | + doc = """List of sources that should be processed with the Angular linker.""", |
| 93 | + ), |
| 94 | + "_linker_process_tool": attr.label( |
| 95 | + default = Label("//tools/linker-process"), |
| 96 | + executable = True, |
| 97 | + cfg = "host", |
| 98 | + ), |
| 99 | + }, |
| 100 | +) |
0 commit comments