bazelbuild / bazel

a fast, scalable, multi-language and extensible build system
https://bazel.build
Apache License 2.0
23.21k stars 4.06k forks source link

args.add_joined(format_joined) needs an option to not quote the final string. #13800

Open aiuto opened 3 years ago

aiuto commented 3 years ago

Description of the problem / feature request:

I am trying to use ctx.actions.args.add_joined to efficiently write out a large JSON structure. The output should look something like

[
{obj1},
{obj2},
...
]

The natural syntax for representing that would be

def _encode_entry(value):
   return <value to JSON in some way>

args = ctx.actions.args()
args.add_joined(
    [some list of values],
    map_each = _encode_entry,
    join_with = ",\n",
    format_joined = "[\n%s\n]\n",
)
ctx.actions.write(manifest_file, args)

This almost works, but format_joined also wraps the entire value in single quotes. So you get something like

'[
{obj1},
{obj2}
]'

What's the output of bazel info release?

Bazel 4.x and above.

brandjon commented 3 years ago

Have you seen Args.set_param_file_format()? Sounds like you want the "multiline" option.

Note that Args.add_joined() is for adding a single argument to the command line, so it makes sense that it'd be quoted as one unit.

If your list of values is actually a list and not a depset, you can also just format it in Starlark and write it out explicitly, rather than relying on Args.

Finally, there's a json module that may do what you want if it doesn't involve depsets. If it does involve depsets then it may still be useful for encoding individual items.

aiuto commented 3 years ago

That won't work for my use case. I am writing a structured entry (a JSON blob actually). The actual arg list (which includes the path to this json blob) is already multiline.

I am currently using the JSON module, but I am trying to avoid the work of instantiating a large string.

aiuto commented 3 years ago

Not, another way to solve this is give a lambda to ctx.actions.write() so we can encode at the last second. I think we discuss that in another issue.

comius commented 1 year ago

Quotes are WAI as add_joined adds a single argument.

if you want to add multiple args use add_all. (I’m a bit worried this might actually work)

aiuto commented 1 year ago

I don't think add_all would work either. What I need is for the result of each arg added to be unquoted. My use case is that I am using args to defer building a very large string from analysis time to exec time. Roughly 5K provider instances, that I want to format into a huge JSON list.

fmeum commented 1 year ago

@aiuto Can you use https://bazel.build/rules/lib/builtins/actions#template_dict?

aiuto commented 1 year ago

I'm not sure. If it ends up quoting the results of each map_each call that would not do what I need. I am not returning a string. I am returning the string representation of a dict. It looks like the end of the template fills things in using Starlark.format() rather than plain old format, so it's going to add the quotes again.

github-actions[bot] commented 2 weeks ago

Thank you for contributing to the Bazel repository! This issue has been marked as stale since it has not had any activity in the last 1+ years. It will be closed in the next 90 days unless any other activity occurs. If you think this issue is still relevant and should stay open, please post any comment here and the issue will no longer be marked as stale.