Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand template rule #191

Closed
laurentlb opened this issue Sep 9, 2019 · 9 comments · Fixed by #330
Closed

Expand template rule #191

laurentlb opened this issue Sep 9, 2019 · 9 comments · Fixed by #330
Labels
good first issue P3 We're not considering to work on this, but happy to review a PR. (No assignee) type: feature request

Comments

@laurentlb
Copy link
Contributor

It's often useful to generate a file using a template. For example, to create a launcher script (usable from bazel run). Having to create a new rule for this can be annoying.

In the past, I've been using the following implementation and I think it could be useful to have it in Skylib. I'm pasting the code, hoping that someone will make a PR out of it. :)

"""Rule for simple expansion of template files. This performs a simple
search over the template file for the keys in substitutions,
and replaces them with the corresponding values.

Typical usage:
  load("//tools/build_rules:expand_template.bzl", "expand_template")
  expand_template(
      name = "ExpandMyTemplate",
      template = "my.template",
      out = "my.txt",
      substitutions = {
        "$VAR1": "foo",
        "$VAR2": "bar",
      }
  )

Args:
  name: The name of the rule.
  template: The template file to expand
  out: The destination of the expanded file
  substitutions: A dictionary mapping strings to their substitutions
  is_executable: A boolean indicating whether the output file should be executable
"""

def expand_template_impl(ctx):
    ctx.actions.expand_template(
        template = ctx.file.template,
        output = ctx.outputs.out,
        substitutions = {
            k: ctx.expand_location(v, ctx.attr.data)
            for k, v in ctx.attr.substitutions.items()
        },
        is_executable = ctx.attr.is_executable,
    )

expand_template = rule(
    implementation = expand_template_impl,
    attrs = {
        "template": attr.label(mandatory = True, allow_single_file = True),
        "substitutions": attr.string_dict(mandatory = True),
        "out": attr.output(mandatory = True),
        "is_executable": attr.bool(default = False, mandatory = False),
        "data": attr.label_list(allow_files = True),
    },
)
@ashi009
Copy link

ashi009 commented Nov 1, 2019

We also have something similar internally and would like to have it in a shared lib.

The code is easy, but naming is hard. Having both expand_template and write_file in skylib for writing files could be confusing. How about generate_file or gen_file?

@cpsauer
Copy link
Contributor

cpsauer commented Mar 31, 2021

Ran across this looking for the same thing. The code's handy--certainly looks like there's popular demand to me.

@laurentlb, would you be down to get your code in?

P.S. I just watched your immersion demo. It's super neat!

@Vertexwahn
Copy link
Contributor

Vertexwahn commented Nov 1, 2021

Would also be helpful for tensorflow, kythe, and OpenEXR

@alexeagle
Copy link
Contributor

FWIW we now have this in https://github.com/aspect-build/bazel-lib/blob/main/lib/expand_make_vars.bzl
Since bazel-skylib wants to reduce scope, we're adding these helpers over there.

@laurentlb
Copy link
Contributor Author

fyi, I'll let the code owners (@brandjon @tetromino) decide what to do here. Feel free to reuse my code sample in any way you want.

@ghost
Copy link

ghost commented Jan 25, 2022

We've used laurentlb's sketchup internally for a while now, so I look forward to vertexwahn's PR landing.

I'm currently tweaking our internal version, however, to additionally accept substitution information via a SubstitutionInfo provider. Would this be useful to Skylib?

Use cases:

  • Values of a string_dict aren't configurable. Suppose I have a template where I'm expanding 6 variable expressions, and assume 5 of those 6 are static, while the 6th varies by build configuration. If I have N configuration cases, I have to define N unique dictionaries with the common key-value items repeated. (I can reduce repetition w/ dicts.add, but it's still clumsy.)
  • I have a template file with two variables to expand. I can define one expansion via an expand_template rule in a BUILD file. However, the other expansion is performed by a rule class which examines a Java library's runtime classpath and generates its own ctx.expand_template action. To apply both substitutions today, I have to define a chain of expansions, where the output of one expansion rule is the input to another.

Sketchup of a BUILD file using a provider-aware expand_template:

expand_template_info(
    name = "foo_subinfo",
    substitutions = {"%FOO%": "foo"},
)

expand_template_info(
    name = "bar_subinfo",
    substitutions = select({
        "//condition_1": {"%BAR%": "bar1"},
        "//conditions:default": {"%BAR%": "bar"},
    }),
)

# Returns a `SubstitutionInfo` containing a dict of `"%RUNTIME_CLASSPATH%": ":".join([...])`.
java_runtime_classpath(
    name = "libfoo_classpath",
    runtime_deps = [":foo"],
    marker = "%RUNTIME_CLASSPATH%",
)

expand_template(
    name = "dummy_json",
    template = "dummy.tpl.json",
    deps = [
        ":foo_subinfo",
        ":bar_subinfo",  # Or I could `select` here between a static `bar1..N_subinfo`.
        ":libfoo_classpath",
    ],
)

@pauldraper
Copy link

I was very sad to learn that https://github.com/bazel-contrib/rules-template was not this.

@alexeagle
Copy link
Contributor

@pauldraper sorry about that 😛

@Vertexwahn
Copy link
Contributor

meanwhile, I updated my PR (#330). Would be nice if anyone could review it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue P3 We're not considering to work on this, but happy to review a PR. (No assignee) type: feature request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants