From e69d4d31f629a651f6c3e85f181c0dbe1d1fe145 Mon Sep 17 00:00:00 2001 From: maleo Date: Mon, 11 Sep 2023 13:12:31 +0000 Subject: [PATCH 1/3] Re-use write_metadata_info() --- rules_gathering/gather_metadata.bzl | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/rules_gathering/gather_metadata.bzl b/rules_gathering/gather_metadata.bzl index 8c467d5..52e3488 100644 --- a/rules_gathering/gather_metadata.bzl +++ b/rules_gathering/gather_metadata.bzl @@ -85,14 +85,9 @@ def _write_metadata_info_impl(target, ctx): return [OutputGroupInfo(licenses = depset())] # Write the output file for the target - name = "%s_metadata_info.json" % ctx.label.name - content = "[\n%s\n]\n" % ",\n".join(metadata_info_to_json(info)) - out = ctx.actions.declare_file(name) - ctx.actions.write( - output = out, - content = content, - ) - outs.append(out) + json_out = ctx.actions.declare_file("%s_metadata_info.json" % ctx.label.name) + write_metadata_info(ctx, target, json_out) + outs.append(json_out) if ctx.attr._trace[TraceInfo].trace: trace = ctx.actions.declare_file("%s_trace_info.json" % ctx.label.name) @@ -140,8 +135,8 @@ def write_metadata_info(ctx, deps, json_out): def _foo_impl(ctx): ... - out = ctx.actions.declare_file("%s_licenses.json" % ctx.label.name) - write_metadata_info(ctx, ctx.attr.deps, metadata_file) + json_file = ctx.actions.declare_file("%s_licenses.json" % ctx.label.name) + write_metadata_info(ctx, ctx.attr.deps, json_file) Args: ctx: context of the caller @@ -150,10 +145,15 @@ def write_metadata_info(ctx, deps, json_out): aspect over them json_out: output handle to write the JSON info """ + + if type(deps) != type([]): + deps = [deps] + licenses = [] for dep in deps: if TransitiveMetadataInfo in dep: - licenses.extend(metadata_info_to_json(dep[TransitiveMetadataInfo])) + metadata_info = dep[TransitiveMetadataInfo] + licenses.extend(metadata_info_to_json(metadata_info)) ctx.actions.write( output = json_out, content = "[\n%s\n]\n" % ",\n".join(licenses), From 9f993e94d507ffab57c5ae87a8eaf1989232d0a4 Mon Sep 17 00:00:00 2001 From: maleo Date: Mon, 11 Sep 2023 13:32:25 +0000 Subject: [PATCH 2/3] Re-use write_licenses_info() --- rules/gather_licenses_info.bzl | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/rules/gather_licenses_info.bzl b/rules/gather_licenses_info.bzl index 518d5ff..173aa35 100644 --- a/rules/gather_licenses_info.bzl +++ b/rules/gather_licenses_info.bzl @@ -71,15 +71,9 @@ def _write_licenses_info_impl(target, ctx): return [OutputGroupInfo(licenses = depset())] # Write the output file for the target - name = "%s_licenses_info.json" % ctx.label.name - lic_info, _ = licenses_info_to_json(info) - content = "[\n%s\n]\n" % ",\n".join(lic_info) - out = ctx.actions.declare_file(name) - ctx.actions.write( - output = out, - content = content, - ) - outs.append(out) + json_out = ctx.actions.declare_file("%s_licenses_info.json" % ctx.label.name) + write_licenses_info(ctx, target, json_out) + outs.append(json_out) if ctx.attr._trace[TraceInfo].trace: trace = ctx.actions.declare_file("%s_trace_info.json" % ctx.label.name) @@ -146,6 +140,10 @@ def write_licenses_info(ctx, deps, json_out): Returns: A list of License File objects for each of the license paths referenced in the json. """ + + if type(deps) != type([]): + deps = [deps] + licenses_json = [] licenses_files = [] for dep in deps: From 8b560cdc88ec3511627ad995fcf75ba7c9e48c69 Mon Sep 17 00:00:00 2001 From: maleo Date: Thu, 14 Sep 2023 12:59:14 +0000 Subject: [PATCH 3/3] Embed licenses text in json --- rules/gather_licenses_info.bzl | 35 +++++++++++++++++++++++++++++++++- tools/BUILD | 7 +++++++ tools/embed_licenses_text.py | 30 +++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100755 tools/embed_licenses_text.py diff --git a/rules/gather_licenses_info.bzl b/rules/gather_licenses_info.bzl index 173aa35..233c907 100644 --- a/rules/gather_licenses_info.bzl +++ b/rules/gather_licenses_info.bzl @@ -72,8 +72,11 @@ def _write_licenses_info_impl(target, ctx): # Write the output file for the target json_out = ctx.actions.declare_file("%s_licenses_info.json" % ctx.label.name) - write_licenses_info(ctx, target, json_out) + licenses_files = write_licenses_info(ctx, target, json_out) outs.append(json_out) + json_out_full = ctx.actions.declare_file("%s_licenses_info_full.json" % ctx.label.name) + embed_licenses_text(ctx, json_out, licenses_files, json_out_full) + outs.append(json_out_full) if ctx.attr._trace[TraceInfo].trace: trace = ctx.actions.declare_file("%s_trace_info.json" % ctx.label.name) @@ -94,6 +97,12 @@ gather_licenses_info_and_write = aspect( attr_aspects = ["*"], attrs = { "_trace": attr.label(default = "@rules_license//rules:trace_target"), + "_embed_licenses_text_tool": attr.label( + default = Label("@rules_license//tools:embed_licenses_text"), + executable = True, + allow_files = True, + cfg = "exec", + ), }, provides = [OutputGroupInfo], requires = [gather_licenses_info], @@ -161,6 +170,30 @@ def write_licenses_info(ctx, deps, json_out): ) return licenses_files +def embed_licenses_text(ctx, json_in, licenses_files, json_out): + """Reads the license text from the referenced file and attaches it to the json + + Args: + ctx: context of the caller + json_in: input handle to read the JSON info + licenses_files: input handles for all LICENSE files + json_out: output handle to write the JSON info + """ + + inputs = [json_in]+licenses_files + outputs = [json_out] + args = ctx.actions.args() + args.add("--licenses_in", json_in.path) + args.add("--licenses_out", json_out.path) + ctx.actions.run( + mnemonic = "EmbedLICENSETexts", + progress_message = "Embedding license texts...", + inputs = inputs, + outputs = outputs, + executable = ctx.executable._embed_licenses_text_tool, + arguments = [args], + ) + def licenses_info_to_json(licenses_info): """Render a single LicenseInfo provider to JSON diff --git a/tools/BUILD b/tools/BUILD index 4422ca0..0ce4d77 100644 --- a/tools/BUILD +++ b/tools/BUILD @@ -44,3 +44,10 @@ py_binary( python_version = "PY3", visibility = ["//visibility:public"], ) + +py_binary( + name = "embed_licenses_text", + srcs = ["embed_licenses_text.py"], + python_version = "PY3", + visibility = ["//visibility:public"], +) diff --git a/tools/embed_licenses_text.py b/tools/embed_licenses_text.py new file mode 100755 index 0000000..271bf2a --- /dev/null +++ b/tools/embed_licenses_text.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +import argparse +import codecs +import json + + +def main(): + parser = argparse.ArgumentParser( + description='Demonstraton license compliance checker') + + parser.add_argument('--licenses_in', help='path to JSON file containing all license info') + parser.add_argument('--licenses_out', help='path to JSON file where augmented license info should be stored') + args = parser.parse_args() + + with codecs.open(args.licenses_in, encoding='utf-8') as inp: + license_data = json.loads(inp.read()) + + for target in license_data: + for license in target['licenses']: + license_path = license.get('license_text') + if license_path: + with codecs.open(license_path, encoding='utf-8') as license_file: + license['license_text'] = license_file.read() + + with codecs.open(args.licenses_out, mode='w', encoding='utf-8') as out: + json.dump(license_data, out, indent=4) + + +if __name__ == '__main__': + main()