diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/BUILD | 10 | ||||
-rw-r--r-- | tools/checker_demo.py | 132 | ||||
-rwxr-xr-x | tools/diff_test.sh | 36 | ||||
-rw-r--r-- | tools/test_helpers.bzl | 40 |
4 files changed, 218 insertions, 0 deletions
diff --git a/tools/BUILD b/tools/BUILD new file mode 100644 index 0000000..d3a5658 --- /dev/null +++ b/tools/BUILD @@ -0,0 +1,10 @@ +# License declaration and compliance checking rules. + +py_binary( + name = "checker_demo", + srcs = ["checker_demo.py"], + python_version = "PY3", + visibility = ["//visibility:public"], +) + +exports_files(["diff_test.sh"]) diff --git a/tools/checker_demo.py b/tools/checker_demo.py new file mode 100644 index 0000000..0b57cee --- /dev/null +++ b/tools/checker_demo.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Proof of concept license checker. + +This is only a demonstration. It will be replaced with other tools. +""" + +import argparse +import codecs +import json + +# Conditions allowed for all applications +_ALWAYS_ALLOWED_CONDITIONS = frozenset(['notice', 'permissive', 'unencumberd']) + + +def _get_licenses(licenses_info): + with codecs.open(licenses_info, encoding='utf-8') as licenses_file: + # TODO(aiuto): Bazel is not parsing the BUILD file as utf-8, so it is + # double encoding characters. We should use the line below, but we have + # to hack up a double utf-8 decode. + # return json.loads(licenses_file.read()) + b = bytearray([ord(c) for c in licenses_file.read()]) + return json.loads(b.decode('utf-8')) + + +def _do_report(out, licenses): + """Produce a report showing the set of licenses being used. + + Args: + out: file object to write to + licenses: list of LicenseInfo objects + + Returns: + 0 for no restricted licenses. + """ + for lic in licenses: # using strange name lic because license is built-in + rule = lic['rule'] + for kind in lic['license_kinds']: + out.write('= %s\n kind: %s\n' % (rule, kind['target'])) + out.write(' conditions: %s\n' % kind['conditions']) + + +def _check_conditions(out, licenses, allowed_conditions): + """Check that the application does not use any disallowed licenses. + + Args: + out: file object to write to + licenses: list of LicenseInfo objects + allowed_conditions: list of allowed condition names + + Returns: + 0 for no licenses from outside allowed_conditions. + """ + err = 0 + for lic in licenses: # using strange name lic because license is built-in + rule = lic['rule'] + for kind in lic['license_kinds']: + disallowed = [] + for condition in kind['conditions']: + if condition not in allowed_conditions: + disallowed.append(condition) + if disallowed: + out.write('ERROR: %s\n' % rule) + out.write(' kind: %s\n' % kind['target']) + out.write(' conditions: %s\n' % kind['conditions']) + out.write(' disallowed condition: %s\n' % ','.join(disallowed)) + err += 1 + return err + + +def _do_copyright_notices(out, licenses): + for l in licenses: + # IGNORE_COPYRIGHT: Not a copyright notice. It is a variable holding one. + out.write('package(%s), copyright(%s)\n' % (l.get('package_name') or '<unknown>', + l['copyright_notice'])) + + +def _do_licenses(out, licenses): + for lic in licenses: + path = lic['license_text'] + with codecs.open(path, encoding='utf-8') as license_file: + out.write('= %s\n' % path) + out.write(license_file.read()) + + +def main(): + parser = argparse.ArgumentParser( + description='Demonstraton license compliance checker') + + parser.add_argument('--licenses_info', + help='path to JSON file containing all license data') + parser.add_argument('--report', default='report', help='Summary report') + parser.add_argument('--copyright_notices', + help='output file of all copyright notices') + parser.add_argument('--license_texts', help='output file of all license files') + parser.add_argument('--check_conditions', action='store_true', + help='check that the dep only includes allowed license conditions') + args = parser.parse_args() + + licenses = _get_licenses(args.licenses_info) + err = 0 + with codecs.open(args.report, mode='w', encoding='utf-8') as rpt: + _do_report(rpt, licenses) + if args.check_conditions: + # TODO(aiuto): Read conditions from a file of allowed conditions for + # a specified application deployment environment. + err = _check_conditions(rpt, licenses, _ALWAYS_ALLOWED_CONDITIONS) + if args.copyright_notices: + with codecs.open( + args.copyright_notices, mode='w', encoding='utf-8') as out: + _do_copyright_notices(out, licenses) + if args.license_texts: + with codecs.open(args.license_texts, mode='w', encoding='utf-8') as out: + _do_licenses(out, licenses) + return err + + +if __name__ == '__main__': + main() diff --git a/tools/diff_test.sh b/tools/diff_test.sh new file mode 100755 index 0000000..ee06790 --- /dev/null +++ b/tools/diff_test.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Diff two files and PASS if they are equal, FAIL otherwise. +# Usage: +# diff_test.sh path_to_expected path_to_got + +# Find input files +declare -r EXPECTED="$1" +declare -r GOT="$2" + +diff_out=$(mktemp /tmp/diff_test.XXXXXXXXX) +diff -cB "$EXPECTED" "$GOT" >"$diff_out" +err=0 +if [[ -s "$diff_out" ]] ; then + cat "$diff_out" + err=1 + echo 'To update:' + echo ' cp bazel-bin/'"$GOT" "$EXPECTED" + echo FAIL +else + echo PASS +fi +exit $err diff --git a/tools/test_helpers.bzl b/tools/test_helpers.bzl new file mode 100644 index 0000000..30f1980 --- /dev/null +++ b/tools/test_helpers.bzl @@ -0,0 +1,40 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Compare rule output to a golden version.""" + +def golden_test( + name, + golden, + subject): + """Check that output from a rule matches the expected output. + + Args: + name: test name + golden: expected content of subect + subject: build target + """ + native.sh_test( + name = name, + size = "medium", + srcs = ["@rules_license//tools:diff_test.sh"], + args = [ + "$(location %s)" % golden, + "$(location %s)" % subject, + ], + data = [ + subject, + golden, + ], + ) |