Austin Schuh | 3a2f4a4 | 2020-09-16 14:10:39 -0700 | [diff] [blame] | 1 | def _jinja2_template_impl(ctx): |
Milind Upadhyay | 302296f | 2023-03-23 16:36:51 -0700 | [diff] [blame] | 2 | out = ctx.outputs.out |
| 3 | parameters = dict(ctx.attr.parameters) |
| 4 | parameters.update(ctx.attr.list_parameters) |
Austin Schuh | 3a2f4a4 | 2020-09-16 14:10:39 -0700 | [diff] [blame] | 5 | |
Philipp Schrader | 75f1c26 | 2024-04-03 11:32:58 -0700 | [diff] [blame] | 6 | # For now we don't really want the user to worry about which configuration |
| 7 | # to pull the file from. We don't yet have a use case for pulling the same |
| 8 | # file from multiple configurations. We point Jinja at all the configuration |
| 9 | # roots. |
| 10 | include_dirs = depset([ |
| 11 | file.root.path or "." |
| 12 | for file in ctx.files.includes |
| 13 | ]).to_list() |
| 14 | |
| 15 | args = ctx.actions.args() |
| 16 | args.add(ctx.file.src) |
| 17 | args.add(json.encode(parameters)) |
| 18 | args.add(out) |
| 19 | args.add_all(include_dirs, before_each = "--include_dir") |
Philipp Schrader | 4187e17 | 2024-04-03 11:45:19 -0700 | [diff] [blame] | 20 | if ctx.file.parameters_file: |
| 21 | args.add("--replacements_file", ctx.file.parameters_file) |
Philipp Schrader | af21324 | 2024-04-03 11:51:25 -0700 | [diff] [blame] | 22 | args.add_all(ctx.files.filter_srcs, before_each = "--filter_file") |
Philipp Schrader | 75f1c26 | 2024-04-03 11:32:58 -0700 | [diff] [blame] | 23 | |
| 24 | ctx.actions.run( |
Philipp Schrader | af21324 | 2024-04-03 11:51:25 -0700 | [diff] [blame] | 25 | inputs = ctx.files.src + ctx.files.includes + ctx.files.parameters_file + ctx.files.filter_srcs, |
Austin Schuh | 3a2f4a4 | 2020-09-16 14:10:39 -0700 | [diff] [blame] | 26 | tools = [ctx.executable._jinja2], |
| 27 | progress_message = "Generating " + out.short_path, |
| 28 | outputs = [out], |
Philipp Schrader | 75f1c26 | 2024-04-03 11:32:58 -0700 | [diff] [blame] | 29 | executable = ctx.executable._jinja2, |
| 30 | arguments = [args], |
Austin Schuh | 3a2f4a4 | 2020-09-16 14:10:39 -0700 | [diff] [blame] | 31 | ) |
| 32 | |
| 33 | return [DefaultInfo(files = depset([out])), OutputGroupInfo(out = depset([out]))] |
| 34 | |
Milind Upadhyay | 302296f | 2023-03-23 16:36:51 -0700 | [diff] [blame] | 35 | jinja2_template_rule = rule( |
Austin Schuh | 3a2f4a4 | 2020-09-16 14:10:39 -0700 | [diff] [blame] | 36 | attrs = { |
Milind Upadhyay | 302296f | 2023-03-23 16:36:51 -0700 | [diff] [blame] | 37 | "out": attr.output( |
| 38 | mandatory = True, |
| 39 | doc = """The file to generate using the template. If using the jinja2_template macro below, this will automatically be populated with the contents of the `name` parameter.""", |
| 40 | ), |
Austin Schuh | 3a2f4a4 | 2020-09-16 14:10:39 -0700 | [diff] [blame] | 41 | "src": attr.label( |
| 42 | mandatory = True, |
| 43 | allow_single_file = True, |
| 44 | doc = """The jinja2 template file to expand.""", |
| 45 | ), |
| 46 | "parameters": attr.string_dict( |
Milind Upadhyay | 302296f | 2023-03-23 16:36:51 -0700 | [diff] [blame] | 47 | mandatory = False, |
| 48 | default = {}, |
| 49 | doc = """The string parameters to supply to Jinja2.""", |
| 50 | ), |
| 51 | "list_parameters": attr.string_list_dict( |
| 52 | mandatory = False, |
| 53 | default = {}, |
| 54 | doc = """The string list parameters to supply to Jinja2.""", |
Austin Schuh | 3a2f4a4 | 2020-09-16 14:10:39 -0700 | [diff] [blame] | 55 | ), |
Philipp Schrader | 4187e17 | 2024-04-03 11:45:19 -0700 | [diff] [blame] | 56 | "parameters_file": attr.label( |
| 57 | allow_single_file = True, |
| 58 | doc = """A JSON file whose contents are supplied as parameters to Jinja2.""", |
| 59 | ), |
James Kuszmaul | fe65020 | 2023-02-05 17:31:19 -0800 | [diff] [blame] | 60 | "includes": attr.label_list( |
| 61 | allow_files = True, |
| 62 | doc = """Files which are included by the template.""", |
| 63 | ), |
Philipp Schrader | af21324 | 2024-04-03 11:51:25 -0700 | [diff] [blame] | 64 | "filter_srcs": attr.label_list( |
| 65 | allow_files = [".py"], |
| 66 | doc = """Files that are sourced for filters. |
| 67 | Needs to have a register_filters function defined.""", |
| 68 | ), |
Austin Schuh | 3a2f4a4 | 2020-09-16 14:10:39 -0700 | [diff] [blame] | 69 | "_jinja2": attr.label( |
| 70 | default = "//tools/build_rules:jinja2_generator", |
Adam Snaider | 13d48d9 | 2023-08-03 12:20:15 -0700 | [diff] [blame] | 71 | cfg = "exec", |
Austin Schuh | 3a2f4a4 | 2020-09-16 14:10:39 -0700 | [diff] [blame] | 72 | executable = True, |
| 73 | ), |
| 74 | }, |
| 75 | implementation = _jinja2_template_impl, |
| 76 | doc = """Expands a jinja2 template given parameters.""", |
| 77 | ) |
Milind Upadhyay | 302296f | 2023-03-23 16:36:51 -0700 | [diff] [blame] | 78 | |
| 79 | def jinja2_template(name, src, parameters = {}, list_parameters = {}, **kwargs): |
Milind Upadhyay | 302296f | 2023-03-23 16:36:51 -0700 | [diff] [blame] | 80 | # Since the `out` field will be set to `name`, and the name for the rule must |
Milind Upadhyay | 0ff31aa | 2023-03-28 14:18:41 -0700 | [diff] [blame] | 81 | # differ from `out`, name the rule as the `name` plus a suffix |
| 82 | rule_name = name + "_rule" |
Milind Upadhyay | 302296f | 2023-03-23 16:36:51 -0700 | [diff] [blame] | 83 | |
Philipp Schrader | 75f1c26 | 2024-04-03 11:32:58 -0700 | [diff] [blame] | 84 | jinja2_template_rule( |
| 85 | name = rule_name, |
| 86 | out = name, |
| 87 | src = src, |
| 88 | parameters = parameters, |
| 89 | list_parameters = list_parameters, |
| 90 | **kwargs |
| 91 | ) |