From e6fdd1403b961b585f9ff8000b50939cda9c1ec9 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Thu, 9 Dec 2021 22:10:43 -0800 Subject: [PATCH] license metadata text notice files Introduce the below command-line tool: textnotice outputs a NOTICE text file constructed from the license texts of the transitive closure of dependencies. Bug: 68860345 Bug: 151177513 Bug: 151953481 Bug: 213388645 Bug: 210912771 Test: m all Test: m systemlicense Test: m textnotice; out/soong/host/linux-x85/textnotice ... where ... is the path to the .meta_lic file for the system image. In my case if $ export PRODUCT=$(realpath $ANDROID_PRODUCT_OUT --relative-to=$PWD) ... can be expressed as: ${PRODUCT}/gen/META/lic_intermediates/${PRODUCT}/system.img.meta_lic Change-Id: Ia691869fd8e58ef008024f48c23b1a4b4435677a --- tools/compliance/Android.bp | 8 + .../testdata/firstparty/FIRST_PARTY_LICENSE | 1 + .../testdata/firstparty/application.meta_lic | 2 +- .../cmd/testdata/firstparty/bin/bin1.meta_lic | 2 +- .../cmd/testdata/firstparty/bin/bin2.meta_lic | 6 +- .../cmd/testdata/firstparty/bin/bin3.meta_lic | 2 +- .../firstparty/container.zip.meta_lic | 6 +- .../testdata/firstparty/highest.apex.meta_lic | 10 +- .../testdata/firstparty/lib/liba.so.meta_lic | 2 +- .../testdata/firstparty/lib/libb.so.meta_lic | 2 +- .../testdata/firstparty/lib/libc.a.meta_lic | 2 +- .../testdata/firstparty/lib/libd.so.meta_lic | 2 +- .../cmd/testdata/notice/NOTICE_LICENSE | 1 + .../cmd/testdata/notice/application.meta_lic | 2 +- .../cmd/testdata/notice/bin/bin1.meta_lic | 2 +- .../cmd/testdata/notice/bin/bin2.meta_lic | 6 +- .../cmd/testdata/notice/bin/bin3.meta_lic | 1 + .../testdata/notice/container.zip.meta_lic | 6 +- .../cmd/testdata/notice/highest.apex.meta_lic | 10 +- .../cmd/testdata/notice/lib/liba.so.meta_lic | 1 + .../cmd/testdata/notice/lib/libb.so.meta_lic | 2 +- .../cmd/testdata/notice/lib/libc.a.meta_lic | 1 + .../cmd/testdata/notice/lib/libd.so.meta_lic | 1 + .../testdata/proprietary/PROPRIETARY_LICENSE | 1 + .../testdata/proprietary/application.meta_lic | 2 +- .../testdata/proprietary/bin/bin1.meta_lic | 2 +- .../testdata/proprietary/bin/bin2.meta_lic | 5 +- .../testdata/proprietary/bin/bin3.meta_lic | 1 + .../proprietary/container.zip.meta_lic | 6 +- .../proprietary/highest.apex.meta_lic | 10 +- .../testdata/proprietary/lib/liba.so.meta_lic | 1 + .../testdata/proprietary/lib/libb.so.meta_lic | 1 + .../testdata/proprietary/lib/libc.a.meta_lic | 1 + .../testdata/proprietary/lib/libd.so.meta_lic | 1 + .../testdata/reciprocal/RECIPROCAL_LICENSE | 1 + .../testdata/reciprocal/application.meta_lic | 2 +- .../cmd/testdata/reciprocal/bin/bin1.meta_lic | 2 +- .../cmd/testdata/reciprocal/bin/bin2.meta_lic | 6 +- .../cmd/testdata/reciprocal/bin/bin3.meta_lic | 1 + .../reciprocal/container.zip.meta_lic | 6 +- .../testdata/reciprocal/highest.apex.meta_lic | 10 +- .../testdata/reciprocal/lib/liba.so.meta_lic | 1 + .../testdata/reciprocal/lib/libb.so.meta_lic | 2 +- .../testdata/reciprocal/lib/libc.a.meta_lic | 1 + .../testdata/reciprocal/lib/libd.so.meta_lic | 1 + .../regressgpl1/container.zip.meta_lic | 4 +- .../regressgpl2/container.zip.meta_lic | 4 +- .../testdata/restricted/RESTRICTED_LICENSE | 1 + .../testdata/restricted/application.meta_lic | 2 +- .../cmd/testdata/restricted/bin/bin1.meta_lic | 2 +- .../cmd/testdata/restricted/bin/bin2.meta_lic | 6 +- .../cmd/testdata/restricted/bin/bin3.meta_lic | 1 + .../restricted/container.zip.meta_lic | 6 +- .../testdata/restricted/highest.apex.meta_lic | 10 +- .../testdata/restricted/lib/liba.so.meta_lic | 1 + .../testdata/restricted/lib/libb.so.meta_lic | 1 + .../testdata/restricted/lib/libc.a.meta_lic | 1 + .../testdata/restricted/lib/libd.so.meta_lic | 1 + tools/compliance/cmd/textnotice.go | 153 +++++ tools/compliance/cmd/textnotice_test.go | 613 ++++++++++++++++++ tools/compliance/graph.go | 15 + tools/compliance/noticeindex.go | 527 +++++++++++++++ tools/compliance/policy/policy.go | 34 + 63 files changed, 1449 insertions(+), 75 deletions(-) create mode 100644 tools/compliance/cmd/testdata/firstparty/FIRST_PARTY_LICENSE create mode 100644 tools/compliance/cmd/testdata/notice/NOTICE_LICENSE create mode 100644 tools/compliance/cmd/testdata/proprietary/PROPRIETARY_LICENSE create mode 100644 tools/compliance/cmd/testdata/reciprocal/RECIPROCAL_LICENSE create mode 100644 tools/compliance/cmd/testdata/restricted/RESTRICTED_LICENSE create mode 100644 tools/compliance/cmd/textnotice.go create mode 100644 tools/compliance/cmd/textnotice_test.go create mode 100644 tools/compliance/noticeindex.go diff --git a/tools/compliance/Android.bp b/tools/compliance/Android.bp index bbeb76fcee..5684f2f63d 100644 --- a/tools/compliance/Android.bp +++ b/tools/compliance/Android.bp @@ -45,6 +45,13 @@ blueprint_go_binary { testSrcs: ["cmd/dumpresolutions_test.go"], } +blueprint_go_binary { + name: "textnotice", + srcs: ["cmd/textnotice.go"], + deps: ["compliance-module"], + testSrcs: ["cmd/textnotice_test.go"], +} + bootstrap_go_package { name: "compliance-module", srcs: [ @@ -52,6 +59,7 @@ bootstrap_go_package { "conditionset.go", "doc.go", "graph.go", + "noticeindex.go", "policy/policy.go", "policy/resolve.go", "policy/resolvenotices.go", diff --git a/tools/compliance/cmd/testdata/firstparty/FIRST_PARTY_LICENSE b/tools/compliance/cmd/testdata/firstparty/FIRST_PARTY_LICENSE new file mode 100644 index 0000000000..a7e7e64ce9 --- /dev/null +++ b/tools/compliance/cmd/testdata/firstparty/FIRST_PARTY_LICENSE @@ -0,0 +1 @@ +&&&First Party License&&& diff --git a/tools/compliance/cmd/testdata/firstparty/application.meta_lic b/tools/compliance/cmd/testdata/firstparty/application.meta_lic index 58a15662f1..ac3338f393 100644 --- a/tools/compliance/cmd/testdata/firstparty/application.meta_lic +++ b/tools/compliance/cmd/testdata/firstparty/application.meta_lic @@ -3,7 +3,7 @@ module_classes: "EXECUTABLES" projects: "distributable/application" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/application_intermediates/application" installed: "out/target/product/fictional/bin/application" diff --git a/tools/compliance/cmd/testdata/firstparty/bin/bin1.meta_lic b/tools/compliance/cmd/testdata/firstparty/bin/bin1.meta_lic index 34d81d9750..30071293eb 100644 --- a/tools/compliance/cmd/testdata/firstparty/bin/bin1.meta_lic +++ b/tools/compliance/cmd/testdata/firstparty/bin/bin1.meta_lic @@ -3,7 +3,7 @@ module_classes: "EXECUTABLES" projects: "static/binary" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin1" installed: "out/target/product/fictional/system/bin/bin1" diff --git a/tools/compliance/cmd/testdata/firstparty/bin/bin2.meta_lic b/tools/compliance/cmd/testdata/firstparty/bin/bin2.meta_lic index 6154421782..89bc6a4abe 100644 --- a/tools/compliance/cmd/testdata/firstparty/bin/bin2.meta_lic +++ b/tools/compliance/cmd/testdata/firstparty/bin/bin2.meta_lic @@ -3,10 +3,10 @@ module_classes: "EXECUTABLES" projects: "dynamic/binary" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false -built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin1" -installed: "out/target/product/fictional/system/bin/bin1" +built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin2" +installed: "out/target/product/fictional/system/bin/bin2" sources: "out/target/product/fictional/system/lib/libb.so" sources: "out/target/product/fictional/system/lib/libd.so" deps: { diff --git a/tools/compliance/cmd/testdata/firstparty/bin/bin3.meta_lic b/tools/compliance/cmd/testdata/firstparty/bin/bin3.meta_lic index 9b7908e2b8..a81c76462d 100644 --- a/tools/compliance/cmd/testdata/firstparty/bin/bin3.meta_lic +++ b/tools/compliance/cmd/testdata/firstparty/bin/bin3.meta_lic @@ -3,7 +3,7 @@ module_classes: "EXECUTABLES" projects: "standalone/binary" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin3" installed: "out/target/product/fictional/system/bin/bin3" diff --git a/tools/compliance/cmd/testdata/firstparty/container.zip.meta_lic b/tools/compliance/cmd/testdata/firstparty/container.zip.meta_lic index 350b123089..9f6a679c39 100644 --- a/tools/compliance/cmd/testdata/firstparty/container.zip.meta_lic +++ b/tools/compliance/cmd/testdata/firstparty/container.zip.meta_lic @@ -2,17 +2,17 @@ package_name: "Android" projects: "container/zip" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: true built: "out/target/product/fictional/obj/ETC/container_intermediates/container.zip" installed: "out/target/product/fictional/data/container.zip" install_map { from_path: "out/target/product/fictional/system/lib/" - container_path: "" + container_path: "/" } install_map { from_path: "out/target/product/fictional/system/bin/" - container_path: "" + container_path: "/" } sources: "out/target/product/fictional/system/lib/liba.so" sources: "out/target/product/fictional/system/lib/libb.so" diff --git a/tools/compliance/cmd/testdata/firstparty/highest.apex.meta_lic b/tools/compliance/cmd/testdata/firstparty/highest.apex.meta_lic index 53f81a25ce..abad5f168c 100644 --- a/tools/compliance/cmd/testdata/firstparty/highest.apex.meta_lic +++ b/tools/compliance/cmd/testdata/firstparty/highest.apex.meta_lic @@ -2,25 +2,25 @@ package_name: "Android" projects: "highest/apex" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: true built: "out/target/product/fictional/obj/ETC/highest_intermediates/highest.apex" installed: "out/target/product/fictional/system/apex/highest.apex" install_map { from_path: "out/target/product/fictional/system/lib/liba.so" - container_path: "lib/liba.so" + container_path: "/lib/liba.so" } install_map { from_path: "out/target/product/fictional/system/lib/libb.so" - container_path: "lib/libb.so" + container_path: "/lib/libb.so" } install_map { from_path: "out/target/product/fictional/system/bin/bin1" - container_path: "bin/bin1" + container_path: "/bin/bin1" } install_map { from_path: "out/target/product/fictional/system/bin/bin2" - container_path: "bin/bin2" + container_path: "/bin/bin2" } sources: "out/target/product/fictional/system/lib/liba.so" sources: "out/target/product/fictional/system/lib/libb.so" diff --git a/tools/compliance/cmd/testdata/firstparty/lib/liba.so.meta_lic b/tools/compliance/cmd/testdata/firstparty/lib/liba.so.meta_lic index 7913af0461..2985719e54 100644 --- a/tools/compliance/cmd/testdata/firstparty/lib/liba.so.meta_lic +++ b/tools/compliance/cmd/testdata/firstparty/lib/liba.so.meta_lic @@ -2,7 +2,7 @@ package_name: "Android" projects: "device/library" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/liba.so" built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/liba.a" diff --git a/tools/compliance/cmd/testdata/firstparty/lib/libb.so.meta_lic b/tools/compliance/cmd/testdata/firstparty/lib/libb.so.meta_lic index a4935d4fd1..e60ef73481 100644 --- a/tools/compliance/cmd/testdata/firstparty/lib/libb.so.meta_lic +++ b/tools/compliance/cmd/testdata/firstparty/lib/libb.so.meta_lic @@ -2,7 +2,7 @@ package_name: "Android" projects: "base/library" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libb.so" built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libb.a" diff --git a/tools/compliance/cmd/testdata/firstparty/lib/libc.a.meta_lic b/tools/compliance/cmd/testdata/firstparty/lib/libc.a.meta_lic index fa7459ae49..24d3f0da22 100644 --- a/tools/compliance/cmd/testdata/firstparty/lib/libc.a.meta_lic +++ b/tools/compliance/cmd/testdata/firstparty/lib/libc.a.meta_lic @@ -2,6 +2,6 @@ package_name: "Android" projects: "static/library" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libc.a" diff --git a/tools/compliance/cmd/testdata/firstparty/lib/libd.so.meta_lic b/tools/compliance/cmd/testdata/firstparty/lib/libd.so.meta_lic index a2db94a26c..f7e537cf05 100644 --- a/tools/compliance/cmd/testdata/firstparty/lib/libd.so.meta_lic +++ b/tools/compliance/cmd/testdata/firstparty/lib/libd.so.meta_lic @@ -2,7 +2,7 @@ package_name: "Android" projects: "dynamic/library" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libd.so" installed: "out/target/product/fictional/system/lib/libd.so" diff --git a/tools/compliance/cmd/testdata/notice/NOTICE_LICENSE b/tools/compliance/cmd/testdata/notice/NOTICE_LICENSE new file mode 100644 index 0000000000..752b249381 --- /dev/null +++ b/tools/compliance/cmd/testdata/notice/NOTICE_LICENSE @@ -0,0 +1 @@ +%%%Notice License%%% diff --git a/tools/compliance/cmd/testdata/notice/application.meta_lic b/tools/compliance/cmd/testdata/notice/application.meta_lic index 56c60efce1..8ce0a986e0 100644 --- a/tools/compliance/cmd/testdata/notice/application.meta_lic +++ b/tools/compliance/cmd/testdata/notice/application.meta_lic @@ -3,7 +3,7 @@ module_classes: "EXECUTABLES" projects: "distributable/application" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/application_intermediates/application" installed: "out/target/product/fictional/bin/application" diff --git a/tools/compliance/cmd/testdata/notice/bin/bin1.meta_lic b/tools/compliance/cmd/testdata/notice/bin/bin1.meta_lic index 9bede1ba86..6d173a4221 100644 --- a/tools/compliance/cmd/testdata/notice/bin/bin1.meta_lic +++ b/tools/compliance/cmd/testdata/notice/bin/bin1.meta_lic @@ -3,7 +3,7 @@ module_classes: "EXECUTABLES" projects: "static/binary" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin1" installed: "out/target/product/fictional/system/bin/bin1" diff --git a/tools/compliance/cmd/testdata/notice/bin/bin2.meta_lic b/tools/compliance/cmd/testdata/notice/bin/bin2.meta_lic index 86e06c655e..a9e9c71a09 100644 --- a/tools/compliance/cmd/testdata/notice/bin/bin2.meta_lic +++ b/tools/compliance/cmd/testdata/notice/bin/bin2.meta_lic @@ -3,10 +3,10 @@ module_classes: "EXECUTABLES" projects: "dynamic/binary" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false -built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin1" -installed: "out/target/product/fictional/system/bin/bin1" +built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin2" +installed: "out/target/product/fictional/system/bin/bin2" sources: "out/target/product/fictional/system/lib/libb.so" sources: "out/target/product/fictional/system/lib/libd.so" deps: { diff --git a/tools/compliance/cmd/testdata/notice/bin/bin3.meta_lic b/tools/compliance/cmd/testdata/notice/bin/bin3.meta_lic index 285d89959d..bb9a3d55f1 100644 --- a/tools/compliance/cmd/testdata/notice/bin/bin3.meta_lic +++ b/tools/compliance/cmd/testdata/notice/bin/bin3.meta_lic @@ -3,6 +3,7 @@ module_classes: "EXECUTABLES" projects: "standalone/binary" license_kinds: "SPDX-license-identifier-NCSA" license_conditions: "notice" +license_texts: "testdata/notice/NOTICE_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin3" installed: "out/target/product/fictional/system/bin/bin3" diff --git a/tools/compliance/cmd/testdata/notice/container.zip.meta_lic b/tools/compliance/cmd/testdata/notice/container.zip.meta_lic index e8af61ce53..e9c051133c 100644 --- a/tools/compliance/cmd/testdata/notice/container.zip.meta_lic +++ b/tools/compliance/cmd/testdata/notice/container.zip.meta_lic @@ -2,17 +2,17 @@ package_name: "Android" projects: "container/zip" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: true built: "out/target/product/fictional/obj/ETC/container_intermediates/container.zip" installed: "out/target/product/fictional/data/container.zip" install_map { from_path: "out/target/product/fictional/system/lib/" - container_path: "" + container_path: "/" } install_map { from_path: "out/target/product/fictional/system/bin/" - container_path: "" + container_path: "/" } sources: "out/target/product/fictional/system/lib/liba.so" sources: "out/target/product/fictional/system/lib/libb.so" diff --git a/tools/compliance/cmd/testdata/notice/highest.apex.meta_lic b/tools/compliance/cmd/testdata/notice/highest.apex.meta_lic index 9b90aa5833..2abb76e91d 100644 --- a/tools/compliance/cmd/testdata/notice/highest.apex.meta_lic +++ b/tools/compliance/cmd/testdata/notice/highest.apex.meta_lic @@ -2,25 +2,25 @@ package_name: "Android" projects: "highest/apex" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: true built: "out/target/product/fictional/obj/ETC/highest_intermediates/highest.apex" installed: "out/target/product/fictional/system/apex/highest.apex" install_map { from_path: "out/target/product/fictional/system/lib/liba.so" - container_path: "lib/liba.so" + container_path: "/lib/liba.so" } install_map { from_path: "out/target/product/fictional/system/lib/libb.so" - container_path: "lib/libb.so" + container_path: "/lib/libb.so" } install_map { from_path: "out/target/product/fictional/system/bin/bin1" - container_path: "bin/bin1" + container_path: "/bin/bin1" } install_map { from_path: "out/target/product/fictional/system/bin/bin2" - container_path: "bin/bin2" + container_path: "/bin/bin2" } sources: "out/target/product/fictional/system/lib/liba.so" sources: "out/target/product/fictional/system/lib/libb.so" diff --git a/tools/compliance/cmd/testdata/notice/lib/liba.so.meta_lic b/tools/compliance/cmd/testdata/notice/lib/liba.so.meta_lic index a69839fb93..7fed5d7be7 100644 --- a/tools/compliance/cmd/testdata/notice/lib/liba.so.meta_lic +++ b/tools/compliance/cmd/testdata/notice/lib/liba.so.meta_lic @@ -2,6 +2,7 @@ package_name: "Device" projects: "device/library" license_kinds: "SPDX-license-identifier-BSD" license_conditions: "notice" +license_texts: "testdata/notice/NOTICE_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/liba.so" built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/liba.a" diff --git a/tools/compliance/cmd/testdata/notice/lib/libb.so.meta_lic b/tools/compliance/cmd/testdata/notice/lib/libb.so.meta_lic index a4935d4fd1..e60ef73481 100644 --- a/tools/compliance/cmd/testdata/notice/lib/libb.so.meta_lic +++ b/tools/compliance/cmd/testdata/notice/lib/libb.so.meta_lic @@ -2,7 +2,7 @@ package_name: "Android" projects: "base/library" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libb.so" built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libb.a" diff --git a/tools/compliance/cmd/testdata/notice/lib/libc.a.meta_lic b/tools/compliance/cmd/testdata/notice/lib/libc.a.meta_lic index eb0f81f248..8dbc41bf26 100644 --- a/tools/compliance/cmd/testdata/notice/lib/libc.a.meta_lic +++ b/tools/compliance/cmd/testdata/notice/lib/libc.a.meta_lic @@ -2,5 +2,6 @@ package_name: "External" projects: "static/library" license_kinds: "SPDX-license-identifier-MIT" license_conditions: "notice" +license_texts: "testdata/notice/NOTICE_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libc.a" diff --git a/tools/compliance/cmd/testdata/notice/lib/libd.so.meta_lic b/tools/compliance/cmd/testdata/notice/lib/libd.so.meta_lic index 942d298075..e6a060c1ed 100644 --- a/tools/compliance/cmd/testdata/notice/lib/libd.so.meta_lic +++ b/tools/compliance/cmd/testdata/notice/lib/libd.so.meta_lic @@ -2,6 +2,7 @@ package_name: "External" projects: "dynamic/library" license_kinds: "SPDX-license-identifier-MIT" license_conditions: "notice" +license_texts: "testdata/notice/NOTICE_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libd.so" installed: "out/target/product/fictional/system/lib/libd.so" diff --git a/tools/compliance/cmd/testdata/proprietary/PROPRIETARY_LICENSE b/tools/compliance/cmd/testdata/proprietary/PROPRIETARY_LICENSE new file mode 100644 index 0000000000..5d0eb0930d --- /dev/null +++ b/tools/compliance/cmd/testdata/proprietary/PROPRIETARY_LICENSE @@ -0,0 +1 @@ +@@@Proprietary License@@@ diff --git a/tools/compliance/cmd/testdata/proprietary/application.meta_lic b/tools/compliance/cmd/testdata/proprietary/application.meta_lic index 51b97c541f..f307c5c9a4 100644 --- a/tools/compliance/cmd/testdata/proprietary/application.meta_lic +++ b/tools/compliance/cmd/testdata/proprietary/application.meta_lic @@ -3,7 +3,7 @@ module_classes: "EXECUTABLES" projects: "distributable/application" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/application_intermediates/application" installed: "out/target/product/fictional/bin/application" diff --git a/tools/compliance/cmd/testdata/proprietary/bin/bin1.meta_lic b/tools/compliance/cmd/testdata/proprietary/bin/bin1.meta_lic index c815858c79..e0394da7e9 100644 --- a/tools/compliance/cmd/testdata/proprietary/bin/bin1.meta_lic +++ b/tools/compliance/cmd/testdata/proprietary/bin/bin1.meta_lic @@ -3,7 +3,7 @@ module_classes: "EXECUTABLES" projects: "static/binary" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin1" installed: "out/target/product/fictional/system/bin/bin1" diff --git a/tools/compliance/cmd/testdata/proprietary/bin/bin2.meta_lic b/tools/compliance/cmd/testdata/proprietary/bin/bin2.meta_lic index 6b89ba457b..da64aa6dc3 100644 --- a/tools/compliance/cmd/testdata/proprietary/bin/bin2.meta_lic +++ b/tools/compliance/cmd/testdata/proprietary/bin/bin2.meta_lic @@ -4,9 +4,10 @@ projects: "dynamic/binary" license_kinds: "legacy_proprietary" license_conditions: "proprietary" license_conditions: "by_exception_only" +license_texts: "testdata/proprietary/PROPRIETARY_LICENSE" is_container: false -built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin1" -installed: "out/target/product/fictional/system/bin/bin1" +built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin2" +installed: "out/target/product/fictional/system/bin/bin2" sources: "out/target/product/fictional/system/lib/libb.so" sources: "out/target/product/fictional/system/lib/libd.so" deps: { diff --git a/tools/compliance/cmd/testdata/proprietary/bin/bin3.meta_lic b/tools/compliance/cmd/testdata/proprietary/bin/bin3.meta_lic index f93553db67..7ef14e9450 100644 --- a/tools/compliance/cmd/testdata/proprietary/bin/bin3.meta_lic +++ b/tools/compliance/cmd/testdata/proprietary/bin/bin3.meta_lic @@ -3,6 +3,7 @@ module_classes: "EXECUTABLES" projects: "standalone/binary" license_kinds: "SPDX-license-identifier-LGPL-2.0" license_conditions: "restricted" +license_texts: "testdata/restricted/RESTRICTED_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin3" installed: "out/target/product/fictional/system/bin/bin3" diff --git a/tools/compliance/cmd/testdata/proprietary/container.zip.meta_lic b/tools/compliance/cmd/testdata/proprietary/container.zip.meta_lic index 889e17ef00..d6605f48dd 100644 --- a/tools/compliance/cmd/testdata/proprietary/container.zip.meta_lic +++ b/tools/compliance/cmd/testdata/proprietary/container.zip.meta_lic @@ -2,17 +2,17 @@ package_name: "Android" projects: "container/zip" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: true built: "out/target/product/fictional/obj/ETC/container_intermediates/container.zip" installed: "out/target/product/fictional/data/container.zip" install_map { from_path: "out/target/product/fictional/system/lib/" - container_path: "" + container_path: "/" } install_map { from_path: "out/target/product/fictional/system/bin/" - container_path: "" + container_path: "/" } sources: "out/target/product/fictional/system/lib/liba.so" sources: "out/target/product/fictional/system/lib/libb.so" diff --git a/tools/compliance/cmd/testdata/proprietary/highest.apex.meta_lic b/tools/compliance/cmd/testdata/proprietary/highest.apex.meta_lic index d615404f53..27ced10959 100644 --- a/tools/compliance/cmd/testdata/proprietary/highest.apex.meta_lic +++ b/tools/compliance/cmd/testdata/proprietary/highest.apex.meta_lic @@ -2,25 +2,25 @@ package_name: "Android" projects: "highest/apex" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: true built: "out/target/product/fictional/obj/ETC/highest_intermediates/highest.apex" installed: "out/target/product/fictional/system/apex/highest.apex" install_map { from_path: "out/target/product/fictional/system/lib/liba.so" - container_path: "lib/liba.so" + container_path: "/lib/liba.so" } install_map { from_path: "out/target/product/fictional/system/lib/libb.so" - container_path: "lib/libb.so" + container_path: "/lib/libb.so" } install_map { from_path: "out/target/product/fictional/system/bin/bin1" - container_path: "bin/bin1" + container_path: "/bin/bin1" } install_map { from_path: "out/target/product/fictional/system/bin/bin2" - container_path: "bin/bin2" + container_path: "/bin/bin2" } sources: "out/target/product/fictional/system/lib/liba.so" sources: "out/target/product/fictional/system/lib/libb.so" diff --git a/tools/compliance/cmd/testdata/proprietary/lib/liba.so.meta_lic b/tools/compliance/cmd/testdata/proprietary/lib/liba.so.meta_lic index 51141c8922..ceb0f9f554 100644 --- a/tools/compliance/cmd/testdata/proprietary/lib/liba.so.meta_lic +++ b/tools/compliance/cmd/testdata/proprietary/lib/liba.so.meta_lic @@ -3,6 +3,7 @@ projects: "device/library" license_kinds: "legacy_proprietary" license_conditions: "proprietary" license_conditions: "by_exception_only" +license_texts: "testdata/proprietary/PROPRIETARY_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/liba.so" built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/liba.a" diff --git a/tools/compliance/cmd/testdata/proprietary/lib/libb.so.meta_lic b/tools/compliance/cmd/testdata/proprietary/lib/libb.so.meta_lic index c1b86d7a70..739d3571da 100644 --- a/tools/compliance/cmd/testdata/proprietary/lib/libb.so.meta_lic +++ b/tools/compliance/cmd/testdata/proprietary/lib/libb.so.meta_lic @@ -2,6 +2,7 @@ package_name: "Android" projects: "base/library" license_kinds: "SPDX-license-identifier-GPL-2.0" license_conditions: "restricted" +license_texts: "testdata/restricted/RESTRICTED_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libb.so" built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libb.a" diff --git a/tools/compliance/cmd/testdata/proprietary/lib/libc.a.meta_lic b/tools/compliance/cmd/testdata/proprietary/lib/libc.a.meta_lic index 1ade7da602..5440ea7cf2 100644 --- a/tools/compliance/cmd/testdata/proprietary/lib/libc.a.meta_lic +++ b/tools/compliance/cmd/testdata/proprietary/lib/libc.a.meta_lic @@ -3,5 +3,6 @@ projects: "static/library" license_kinds: "legacy_proprietary" license_conditions: "proprietary" license_conditions: "by_exception_only" +license_texts: "testdata/proprietary/PROPRIETARY_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libc.a" diff --git a/tools/compliance/cmd/testdata/proprietary/lib/libd.so.meta_lic b/tools/compliance/cmd/testdata/proprietary/lib/libd.so.meta_lic index 942d298075..e6a060c1ed 100644 --- a/tools/compliance/cmd/testdata/proprietary/lib/libd.so.meta_lic +++ b/tools/compliance/cmd/testdata/proprietary/lib/libd.so.meta_lic @@ -2,6 +2,7 @@ package_name: "External" projects: "dynamic/library" license_kinds: "SPDX-license-identifier-MIT" license_conditions: "notice" +license_texts: "testdata/notice/NOTICE_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libd.so" installed: "out/target/product/fictional/system/lib/libd.so" diff --git a/tools/compliance/cmd/testdata/reciprocal/RECIPROCAL_LICENSE b/tools/compliance/cmd/testdata/reciprocal/RECIPROCAL_LICENSE new file mode 100644 index 0000000000..82c2019697 --- /dev/null +++ b/tools/compliance/cmd/testdata/reciprocal/RECIPROCAL_LICENSE @@ -0,0 +1 @@ +$$$Reciprocal License$$$ diff --git a/tools/compliance/cmd/testdata/reciprocal/application.meta_lic b/tools/compliance/cmd/testdata/reciprocal/application.meta_lic index 015c2d92b5..60233cb6e2 100644 --- a/tools/compliance/cmd/testdata/reciprocal/application.meta_lic +++ b/tools/compliance/cmd/testdata/reciprocal/application.meta_lic @@ -3,7 +3,7 @@ module_classes: "EXECUTABLES" projects: "distributable/application" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/application_intermediates/application" installed: "out/target/product/fictional/bin/application" diff --git a/tools/compliance/cmd/testdata/reciprocal/bin/bin1.meta_lic b/tools/compliance/cmd/testdata/reciprocal/bin/bin1.meta_lic index 4ebf653ca8..54d552ff4d 100644 --- a/tools/compliance/cmd/testdata/reciprocal/bin/bin1.meta_lic +++ b/tools/compliance/cmd/testdata/reciprocal/bin/bin1.meta_lic @@ -3,7 +3,7 @@ module_classes: "EXECUTABLES" projects: "static/binary" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin1" installed: "out/target/product/fictional/system/bin/bin1" diff --git a/tools/compliance/cmd/testdata/reciprocal/bin/bin2.meta_lic b/tools/compliance/cmd/testdata/reciprocal/bin/bin2.meta_lic index 4d28608077..a28cb91761 100644 --- a/tools/compliance/cmd/testdata/reciprocal/bin/bin2.meta_lic +++ b/tools/compliance/cmd/testdata/reciprocal/bin/bin2.meta_lic @@ -3,10 +3,10 @@ module_classes: "EXECUTABLES" projects: "dynamic/binary" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false -built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin1" -installed: "out/target/product/fictional/system/bin/bin1" +built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin2" +installed: "out/target/product/fictional/system/bin/bin2" sources: "out/target/product/fictional/system/lib/libb.so" sources: "out/target/product/fictional/system/lib/libd.so" deps: { diff --git a/tools/compliance/cmd/testdata/reciprocal/bin/bin3.meta_lic b/tools/compliance/cmd/testdata/reciprocal/bin/bin3.meta_lic index 285d89959d..bb9a3d55f1 100644 --- a/tools/compliance/cmd/testdata/reciprocal/bin/bin3.meta_lic +++ b/tools/compliance/cmd/testdata/reciprocal/bin/bin3.meta_lic @@ -3,6 +3,7 @@ module_classes: "EXECUTABLES" projects: "standalone/binary" license_kinds: "SPDX-license-identifier-NCSA" license_conditions: "notice" +license_texts: "testdata/notice/NOTICE_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin3" installed: "out/target/product/fictional/system/bin/bin3" diff --git a/tools/compliance/cmd/testdata/reciprocal/container.zip.meta_lic b/tools/compliance/cmd/testdata/reciprocal/container.zip.meta_lic index ea3598f4df..feb08fe958 100644 --- a/tools/compliance/cmd/testdata/reciprocal/container.zip.meta_lic +++ b/tools/compliance/cmd/testdata/reciprocal/container.zip.meta_lic @@ -2,17 +2,17 @@ package_name: "Android" projects: "container/zip" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: true built: "out/target/product/fictional/obj/ETC/container_intermediates/container.zip" installed: "out/target/product/fictional/data/container.zip" install_map { from_path: "out/target/product/fictional/system/lib/" - container_path: "" + container_path: "/" } install_map { from_path: "out/target/product/fictional/system/bin/" - container_path: "" + container_path: "/" } sources: "out/target/product/fictional/system/lib/liba.so" sources: "out/target/product/fictional/system/lib/libb.so" diff --git a/tools/compliance/cmd/testdata/reciprocal/highest.apex.meta_lic b/tools/compliance/cmd/testdata/reciprocal/highest.apex.meta_lic index 1fec741f37..185d04acf9 100644 --- a/tools/compliance/cmd/testdata/reciprocal/highest.apex.meta_lic +++ b/tools/compliance/cmd/testdata/reciprocal/highest.apex.meta_lic @@ -2,25 +2,25 @@ package_name: "Android" projects: "highest/apex" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: true built: "out/target/product/fictional/obj/ETC/highest_intermediates/highest.apex" installed: "out/target/product/fictional/system/apex/highest.apex" install_map { from_path: "out/target/product/fictional/system/lib/liba.so" - container_path: "lib/liba.so" + container_path: "/lib/liba.so" } install_map { from_path: "out/target/product/fictional/system/lib/libb.so" - container_path: "lib/libb.so" + container_path: "/lib/libb.so" } install_map { from_path: "out/target/product/fictional/system/bin/bin1" - container_path: "bin/bin1" + container_path: "/bin/bin1" } install_map { from_path: "out/target/product/fictional/system/bin/bin2" - container_path: "bin/bin2" + container_path: "/bin/bin2" } sources: "out/target/product/fictional/system/lib/liba.so" sources: "out/target/product/fictional/system/lib/libb.so" diff --git a/tools/compliance/cmd/testdata/reciprocal/lib/liba.so.meta_lic b/tools/compliance/cmd/testdata/reciprocal/lib/liba.so.meta_lic index 79d7a9e205..dd0515526d 100644 --- a/tools/compliance/cmd/testdata/reciprocal/lib/liba.so.meta_lic +++ b/tools/compliance/cmd/testdata/reciprocal/lib/liba.so.meta_lic @@ -2,6 +2,7 @@ package_name: "Device" projects: "device/library" license_kinds: "SPDX-license-identifier-MPL" license_conditions: "reciprocal" +license_texts: "testdata/reciprocal/RECIPROCAL_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/liba.so" built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/liba.a" diff --git a/tools/compliance/cmd/testdata/reciprocal/lib/libb.so.meta_lic b/tools/compliance/cmd/testdata/reciprocal/lib/libb.so.meta_lic index a4935d4fd1..e60ef73481 100644 --- a/tools/compliance/cmd/testdata/reciprocal/lib/libb.so.meta_lic +++ b/tools/compliance/cmd/testdata/reciprocal/lib/libb.so.meta_lic @@ -2,7 +2,7 @@ package_name: "Android" projects: "base/library" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libb.so" built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libb.a" diff --git a/tools/compliance/cmd/testdata/reciprocal/lib/libc.a.meta_lic b/tools/compliance/cmd/testdata/reciprocal/lib/libc.a.meta_lic index 8f6d356c9c..f7943051d2 100644 --- a/tools/compliance/cmd/testdata/reciprocal/lib/libc.a.meta_lic +++ b/tools/compliance/cmd/testdata/reciprocal/lib/libc.a.meta_lic @@ -2,5 +2,6 @@ package_name: "External" projects: "static/library" license_kinds: "SPDX-license-identifier-MPL" license_conditions: "reciprocal" +license_texts: "testdata/reciprocal/RECIPROCAL_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libc.a" diff --git a/tools/compliance/cmd/testdata/reciprocal/lib/libd.so.meta_lic b/tools/compliance/cmd/testdata/reciprocal/lib/libd.so.meta_lic index 942d298075..e6a060c1ed 100644 --- a/tools/compliance/cmd/testdata/reciprocal/lib/libd.so.meta_lic +++ b/tools/compliance/cmd/testdata/reciprocal/lib/libd.so.meta_lic @@ -2,6 +2,7 @@ package_name: "External" projects: "dynamic/library" license_kinds: "SPDX-license-identifier-MIT" license_conditions: "notice" +license_texts: "testdata/notice/NOTICE_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libd.so" installed: "out/target/product/fictional/system/lib/libd.so" diff --git a/tools/compliance/cmd/testdata/regressgpl1/container.zip.meta_lic b/tools/compliance/cmd/testdata/regressgpl1/container.zip.meta_lic index 295bcdbac2..21b6d5a536 100644 --- a/tools/compliance/cmd/testdata/regressgpl1/container.zip.meta_lic +++ b/tools/compliance/cmd/testdata/regressgpl1/container.zip.meta_lic @@ -8,11 +8,11 @@ built: "out/target/product/fictional/obj/ETC/container_intermediates/container. installed: "out/target/product/fictional/data/container.zip" install_map { from_path: "out/target/product/fictional/system/lib/" - container_path: "" + container_path: "/" } install_map { from_path: "out/target/product/fictional/system/bin/" - container_path: "" + container_path: "/" } sources: "out/target/product/fictional/system/bin/bin1" sources: "out/target/product/fictional/system/bin/bin2" diff --git a/tools/compliance/cmd/testdata/regressgpl2/container.zip.meta_lic b/tools/compliance/cmd/testdata/regressgpl2/container.zip.meta_lic index 71b68cdec2..d32bf94f7c 100644 --- a/tools/compliance/cmd/testdata/regressgpl2/container.zip.meta_lic +++ b/tools/compliance/cmd/testdata/regressgpl2/container.zip.meta_lic @@ -8,11 +8,11 @@ built: "out/target/product/fictional/obj/ETC/container_intermediates/container. installed: "out/target/product/fictional/data/container.zip" install_map { from_path: "out/target/product/fictional/system/lib/" - container_path: "" + container_path: "/" } install_map { from_path: "out/target/product/fictional/system/bin/" - container_path: "" + container_path: "/" } sources: "out/target/product/fictional/system/bin/bin1" sources: "out/target/product/fictional/system/bin/bin2" diff --git a/tools/compliance/cmd/testdata/restricted/RESTRICTED_LICENSE b/tools/compliance/cmd/testdata/restricted/RESTRICTED_LICENSE new file mode 100644 index 0000000000..16a281915e --- /dev/null +++ b/tools/compliance/cmd/testdata/restricted/RESTRICTED_LICENSE @@ -0,0 +1 @@ +###Restricted License### diff --git a/tools/compliance/cmd/testdata/restricted/application.meta_lic b/tools/compliance/cmd/testdata/restricted/application.meta_lic index a06a2c88f2..7ef536dff7 100644 --- a/tools/compliance/cmd/testdata/restricted/application.meta_lic +++ b/tools/compliance/cmd/testdata/restricted/application.meta_lic @@ -3,7 +3,7 @@ module_classes: "EXECUTABLES" projects: "distributable/application" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/application_intermediates/application" installed: "out/target/product/fictional/bin/application" diff --git a/tools/compliance/cmd/testdata/restricted/bin/bin1.meta_lic b/tools/compliance/cmd/testdata/restricted/bin/bin1.meta_lic index dd8a2e0e51..ef0d0c0523 100644 --- a/tools/compliance/cmd/testdata/restricted/bin/bin1.meta_lic +++ b/tools/compliance/cmd/testdata/restricted/bin/bin1.meta_lic @@ -3,7 +3,7 @@ module_classes: "EXECUTABLES" projects: "static/binary" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin1" installed: "out/target/product/fictional/system/bin/bin1" diff --git a/tools/compliance/cmd/testdata/restricted/bin/bin2.meta_lic b/tools/compliance/cmd/testdata/restricted/bin/bin2.meta_lic index 714b53753c..331d5ac620 100644 --- a/tools/compliance/cmd/testdata/restricted/bin/bin2.meta_lic +++ b/tools/compliance/cmd/testdata/restricted/bin/bin2.meta_lic @@ -3,10 +3,10 @@ module_classes: "EXECUTABLES" projects: "dynamic/binary" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: false -built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin1" -installed: "out/target/product/fictional/system/bin/bin1" +built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin2" +installed: "out/target/product/fictional/system/bin/bin2" sources: "out/target/product/fictional/system/lib/libb.so" sources: "out/target/product/fictional/system/lib/libd.so" deps: { diff --git a/tools/compliance/cmd/testdata/restricted/bin/bin3.meta_lic b/tools/compliance/cmd/testdata/restricted/bin/bin3.meta_lic index f93553db67..7ef14e9450 100644 --- a/tools/compliance/cmd/testdata/restricted/bin/bin3.meta_lic +++ b/tools/compliance/cmd/testdata/restricted/bin/bin3.meta_lic @@ -3,6 +3,7 @@ module_classes: "EXECUTABLES" projects: "standalone/binary" license_kinds: "SPDX-license-identifier-LGPL-2.0" license_conditions: "restricted" +license_texts: "testdata/restricted/RESTRICTED_LICENSE" is_container: false built: "out/target/product/fictional/obj/EXECUTABLES/bin_intermediates/bin3" installed: "out/target/product/fictional/system/bin/bin3" diff --git a/tools/compliance/cmd/testdata/restricted/container.zip.meta_lic b/tools/compliance/cmd/testdata/restricted/container.zip.meta_lic index a63263b59a..47e0e24704 100644 --- a/tools/compliance/cmd/testdata/restricted/container.zip.meta_lic +++ b/tools/compliance/cmd/testdata/restricted/container.zip.meta_lic @@ -2,17 +2,17 @@ package_name: "Android" projects: "container/zip" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: true built: "out/target/product/fictional/obj/ETC/container_intermediates/container.zip" installed: "out/target/product/fictional/data/container.zip" install_map { from_path: "out/target/product/fictional/system/lib/" - container_path: "" + container_path: "/" } install_map { from_path: "out/target/product/fictional/system/bin/" - container_path: "" + container_path: "/" } sources: "out/target/product/fictional/system/lib/liba.so" sources: "out/target/product/fictional/system/lib/libb.so" diff --git a/tools/compliance/cmd/testdata/restricted/highest.apex.meta_lic b/tools/compliance/cmd/testdata/restricted/highest.apex.meta_lic index dba419a239..3042309a87 100644 --- a/tools/compliance/cmd/testdata/restricted/highest.apex.meta_lic +++ b/tools/compliance/cmd/testdata/restricted/highest.apex.meta_lic @@ -2,25 +2,25 @@ package_name: "Android" projects: "highest/apex" license_kinds: "SPDX-license-identifier-Apache-2.0" license_conditions: "notice" -license_texts: "build/soong/licenses/LICENSE" +license_texts: "testdata/firstparty/FIRST_PARTY_LICENSE" is_container: true built: "out/target/product/fictional/obj/ETC/highest_intermediates/highest.apex" installed: "out/target/product/fictional/system/apex/highest.apex" install_map { from_path: "out/target/product/fictional/system/lib/liba.so" - container_path: "lib/liba.so" + container_path: "/lib/liba.so" } install_map { from_path: "out/target/product/fictional/system/lib/libb.so" - container_path: "lib/libb.so" + container_path: "/lib/libb.so" } install_map { from_path: "out/target/product/fictional/system/bin/bin1" - container_path: "bin/bin1" + container_path: "/bin/bin1" } install_map { from_path: "out/target/product/fictional/system/bin/bin2" - container_path: "bin/bin2" + container_path: "/bin/bin2" } sources: "out/target/product/fictional/system/lib/liba.so" sources: "out/target/product/fictional/system/lib/libb.so" diff --git a/tools/compliance/cmd/testdata/restricted/lib/liba.so.meta_lic b/tools/compliance/cmd/testdata/restricted/lib/liba.so.meta_lic index b1d456043d..a505d4a6e0 100644 --- a/tools/compliance/cmd/testdata/restricted/lib/liba.so.meta_lic +++ b/tools/compliance/cmd/testdata/restricted/lib/liba.so.meta_lic @@ -2,6 +2,7 @@ package_name: "Device" projects: "device/library" license_kinds: "SPDX-license-identifier-LGPL-2.0" license_conditions: "restricted" +license_texts: "testdata/restricted/RESTRICTED_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/liba.so" built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/liba.a" diff --git a/tools/compliance/cmd/testdata/restricted/lib/libb.so.meta_lic b/tools/compliance/cmd/testdata/restricted/lib/libb.so.meta_lic index c1b86d7a70..739d3571da 100644 --- a/tools/compliance/cmd/testdata/restricted/lib/libb.so.meta_lic +++ b/tools/compliance/cmd/testdata/restricted/lib/libb.so.meta_lic @@ -2,6 +2,7 @@ package_name: "Android" projects: "base/library" license_kinds: "SPDX-license-identifier-GPL-2.0" license_conditions: "restricted" +license_texts: "testdata/restricted/RESTRICTED_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libb.so" built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libb.a" diff --git a/tools/compliance/cmd/testdata/restricted/lib/libc.a.meta_lic b/tools/compliance/cmd/testdata/restricted/lib/libc.a.meta_lic index 8f6d356c9c..f7943051d2 100644 --- a/tools/compliance/cmd/testdata/restricted/lib/libc.a.meta_lic +++ b/tools/compliance/cmd/testdata/restricted/lib/libc.a.meta_lic @@ -2,5 +2,6 @@ package_name: "External" projects: "static/library" license_kinds: "SPDX-license-identifier-MPL" license_conditions: "reciprocal" +license_texts: "testdata/reciprocal/RECIPROCAL_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libc.a" diff --git a/tools/compliance/cmd/testdata/restricted/lib/libd.so.meta_lic b/tools/compliance/cmd/testdata/restricted/lib/libd.so.meta_lic index 942d298075..e6a060c1ed 100644 --- a/tools/compliance/cmd/testdata/restricted/lib/libd.so.meta_lic +++ b/tools/compliance/cmd/testdata/restricted/lib/libd.so.meta_lic @@ -2,6 +2,7 @@ package_name: "External" projects: "dynamic/library" license_kinds: "SPDX-license-identifier-MIT" license_conditions: "notice" +license_texts: "testdata/notice/NOTICE_LICENSE" is_container: false built: "out/target/product/fictional/obj/SHARED_LIBRARIES/lib_intermediates/libd.so" installed: "out/target/product/fictional/system/lib/libd.so" diff --git a/tools/compliance/cmd/textnotice.go b/tools/compliance/cmd/textnotice.go new file mode 100644 index 0000000000..91c57b03e9 --- /dev/null +++ b/tools/compliance/cmd/textnotice.go @@ -0,0 +1,153 @@ +// Copyright 2021 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 +// +// http://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. + +package main + +import ( + "bytes" + "compliance" + "flag" + "fmt" + "io" + "io/fs" + "os" + "path/filepath" + "strings" +) + +var ( + outputFile = flag.String("o", "-", "Where to write the NOTICE text file. (default stdout)") + stripPrefix = flag.String("strip_prefix", "", "Prefix to remove from paths. i.e. path to root") + + failNoneRequested = fmt.Errorf("\nNo license metadata files requested") + failNoLicenses = fmt.Errorf("No licenses found") +) + +type context struct { + stdout io.Writer + stderr io.Writer + rootFS fs.FS + stripPrefix string +} + +func init() { + flag.Usage = func() { + fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...} + +Outputs a text NOTICE file. + +Options: +`, filepath.Base(os.Args[0])) + flag.PrintDefaults() + } +} + +func main() { + flag.Parse() + + // Must specify at least one root target. + if flag.NArg() == 0 { + flag.Usage() + os.Exit(2) + } + + if len(*outputFile) == 0 { + flag.Usage() + fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n") + os.Exit(2) + } else { + dir, err := filepath.Abs(filepath.Dir(*outputFile)) + if err != nil { + fmt.Fprintf(os.Stderr, "cannot determine path to %q: %w\n", *outputFile, err) + os.Exit(1) + } + fi, err := os.Stat(dir) + if err != nil { + fmt.Fprintf(os.Stderr, "cannot read directory %q of %q: %w\n", dir, *outputFile, err) + os.Exit(1) + } + if !fi.IsDir() { + fmt.Fprintf(os.Stderr, "parent %q of %q is not a directory\n", dir, *outputFile) + os.Exit(1) + } + } + + var ofile io.Writer + ofile = os.Stdout + if *outputFile != "-" { + ofile = &bytes.Buffer{} + } + + ctx := &context{ofile, os.Stderr, os.DirFS("."), *stripPrefix} + + err := textNotice(ctx, flag.Args()...) + if err != nil { + if err == failNoneRequested { + flag.Usage() + } + fmt.Fprintf(os.Stderr, "%s\n", err.Error()) + os.Exit(1) + } + if *outputFile != "-" { + err := os.WriteFile(*outputFile, ofile.(*bytes.Buffer).Bytes(), 0666) + if err != nil { + fmt.Fprintf(os.Stderr, "could not write output to %q: %w\n", *outputFile, err) + os.Exit(1) + } + } + os.Exit(0) +} + +// textNotice implements the textNotice utility. +func textNotice(ctx *context, files ...string) error { + // Must be at least one root file. + if len(files) < 1 { + return failNoneRequested + } + + // Read the license graph from the license metadata files (*.meta_lic). + licenseGraph, err := compliance.ReadLicenseGraph(ctx.rootFS, ctx.stderr, files) + if err != nil { + return fmt.Errorf("Unable to read license metadata file(s) %q: %v\n", files, err) + } + if licenseGraph == nil { + return failNoLicenses + } + + // rs contains all notice resolutions. + rs := compliance.ResolveNotices(licenseGraph) + + ni, err := compliance.IndexLicenseTexts(ctx.rootFS, licenseGraph, rs) + if err != nil { + return fmt.Errorf("Unable to read license text file(s) for %q: %v\n", files, err) + } + + for h := range ni.Hashes() { + fmt.Fprintln(ctx.stdout, "==============================================================================") + for _, libName := range ni.HashLibs(h) { + fmt.Fprintf(ctx.stdout, "%s used by:\n", libName) + for _, installPath := range ni.HashLibInstalls(h, libName) { + if 0 < len(ctx.stripPrefix) && strings.HasPrefix(installPath, ctx.stripPrefix) { + fmt.Fprintf(ctx.stdout, " %s\n", installPath[len(ctx.stripPrefix):]) + } else { + fmt.Fprintf(ctx.stdout, " %s\n", installPath) + } + } + fmt.Fprintln(ctx.stdout) + } + ctx.stdout.Write(ni.HashText(h)) + fmt.Fprintln(ctx.stdout) + } + return nil +} diff --git a/tools/compliance/cmd/textnotice_test.go b/tools/compliance/cmd/textnotice_test.go new file mode 100644 index 0000000000..156fb90486 --- /dev/null +++ b/tools/compliance/cmd/textnotice_test.go @@ -0,0 +1,613 @@ +// Copyright 2021 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 +// +// http://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. + +package main + +import ( + "bufio" + "bytes" + "fmt" + "os" + "regexp" + "strings" + "testing" +) + +var ( + horizontalRule = regexp.MustCompile("^===[=]*===$") +) + +func Test(t *testing.T) { + tests := []struct { + condition string + name string + roots []string + stripPrefix string + expectedOut []matcher + }{ + { + condition: "firstparty", + name: "apex", + roots: []string{"highest.apex.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"highest.apex"}, + usedBy{"highest.apex/bin/bin1"}, + usedBy{"highest.apex/bin/bin2"}, + usedBy{"highest.apex/lib/liba.so"}, + usedBy{"highest.apex/lib/libb.so"}, + firstParty{}, + }, + }, + { + condition: "firstparty", + name: "container", + roots: []string{"container.zip.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"container.zip"}, + usedBy{"container.zip/bin1"}, + usedBy{"container.zip/bin2"}, + usedBy{"container.zip/liba.so"}, + usedBy{"container.zip/libb.so"}, + firstParty{}, + }, + }, + { + condition: "firstparty", + name: "application", + roots: []string{"application.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"application"}, + firstParty{}, + }, + }, + { + condition: "firstparty", + name: "binary", + roots: []string{"bin/bin1.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"bin/bin1"}, + firstParty{}, + }, + }, + { + condition: "firstparty", + name: "library", + roots: []string{"lib/libd.so.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"lib/libd.so"}, + firstParty{}, + }, + }, + { + condition: "notice", + name: "apex", + roots: []string{"highest.apex.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"highest.apex"}, + usedBy{"highest.apex/bin/bin1"}, + usedBy{"highest.apex/bin/bin2"}, + usedBy{"highest.apex/lib/libb.so"}, + firstParty{}, + hr{}, + library{"Device"}, + usedBy{"highest.apex/bin/bin1"}, + usedBy{"highest.apex/lib/liba.so"}, + library{"External"}, + usedBy{"highest.apex/bin/bin1"}, + notice{}, + }, + }, + { + condition: "notice", + name: "container", + roots: []string{"container.zip.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"container.zip"}, + usedBy{"container.zip/bin1"}, + usedBy{"container.zip/bin2"}, + usedBy{"container.zip/libb.so"}, + firstParty{}, + hr{}, + library{"Device"}, + usedBy{"container.zip/bin1"}, + usedBy{"container.zip/liba.so"}, + library{"External"}, + usedBy{"container.zip/bin1"}, + notice{}, + }, + }, + { + condition: "notice", + name: "application", + roots: []string{"application.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"application"}, + firstParty{}, + hr{}, + library{"Device"}, + usedBy{"application"}, + notice{}, + }, + }, + { + condition: "notice", + name: "binary", + roots: []string{"bin/bin1.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"bin/bin1"}, + firstParty{}, + hr{}, + library{"Device"}, + usedBy{"bin/bin1"}, + library{"External"}, + usedBy{"bin/bin1"}, + notice{}, + }, + }, + { + condition: "notice", + name: "library", + roots: []string{"lib/libd.so.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"External"}, + usedBy{"lib/libd.so"}, + notice{}, + }, + }, + { + condition: "reciprocal", + name: "apex", + roots: []string{"highest.apex.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"highest.apex"}, + usedBy{"highest.apex/bin/bin1"}, + usedBy{"highest.apex/bin/bin2"}, + usedBy{"highest.apex/lib/libb.so"}, + firstParty{}, + hr{}, + library{"Device"}, + usedBy{"highest.apex/bin/bin1"}, + usedBy{"highest.apex/lib/liba.so"}, + library{"External"}, + usedBy{"highest.apex/bin/bin1"}, + reciprocal{}, + }, + }, + { + condition: "reciprocal", + name: "container", + roots: []string{"container.zip.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"container.zip"}, + usedBy{"container.zip/bin1"}, + usedBy{"container.zip/bin2"}, + usedBy{"container.zip/libb.so"}, + firstParty{}, + hr{}, + library{"Device"}, + usedBy{"container.zip/bin1"}, + usedBy{"container.zip/liba.so"}, + library{"External"}, + usedBy{"container.zip/bin1"}, + reciprocal{}, + }, + }, + { + condition: "reciprocal", + name: "application", + roots: []string{"application.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"application"}, + firstParty{}, + hr{}, + library{"Device"}, + usedBy{"application"}, + reciprocal{}, + }, + }, + { + condition: "reciprocal", + name: "binary", + roots: []string{"bin/bin1.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"bin/bin1"}, + firstParty{}, + hr{}, + library{"Device"}, + usedBy{"bin/bin1"}, + library{"External"}, + usedBy{"bin/bin1"}, + reciprocal{}, + }, + }, + { + condition: "reciprocal", + name: "library", + roots: []string{"lib/libd.so.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"External"}, + usedBy{"lib/libd.so"}, + notice{}, + }, + }, + { + condition: "restricted", + name: "apex", + roots: []string{"highest.apex.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"highest.apex"}, + usedBy{"highest.apex/bin/bin1"}, + usedBy{"highest.apex/bin/bin2"}, + firstParty{}, + hr{}, + library{"Android"}, + usedBy{"highest.apex/bin/bin2"}, + usedBy{"highest.apex/lib/libb.so"}, + library{"Device"}, + usedBy{"highest.apex/bin/bin1"}, + usedBy{"highest.apex/lib/liba.so"}, + restricted{}, + hr{}, + library{"External"}, + usedBy{"highest.apex/bin/bin1"}, + reciprocal{}, + }, + }, + { + condition: "restricted", + name: "container", + roots: []string{"container.zip.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"container.zip"}, + usedBy{"container.zip/bin1"}, + usedBy{"container.zip/bin2"}, + firstParty{}, + hr{}, + library{"Android"}, + usedBy{"container.zip/bin2"}, + usedBy{"container.zip/libb.so"}, + library{"Device"}, + usedBy{"container.zip/bin1"}, + usedBy{"container.zip/liba.so"}, + restricted{}, + hr{}, + library{"External"}, + usedBy{"container.zip/bin1"}, + reciprocal{}, + }, + }, + { + condition: "restricted", + name: "application", + roots: []string{"application.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"application"}, + firstParty{}, + hr{}, + library{"Device"}, + usedBy{"application"}, + restricted{}, + }, + }, + { + condition: "restricted", + name: "binary", + roots: []string{"bin/bin1.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"bin/bin1"}, + firstParty{}, + hr{}, + library{"Device"}, + usedBy{"bin/bin1"}, + restricted{}, + hr{}, + library{"External"}, + usedBy{"bin/bin1"}, + reciprocal{}, + }, + }, + { + condition: "restricted", + name: "library", + roots: []string{"lib/libd.so.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"External"}, + usedBy{"lib/libd.so"}, + notice{}, + }, + }, + { + condition: "proprietary", + name: "apex", + roots: []string{"highest.apex.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"highest.apex/bin/bin2"}, + usedBy{"highest.apex/lib/libb.so"}, + restricted{}, + hr{}, + library{"Android"}, + usedBy{"highest.apex"}, + usedBy{"highest.apex/bin/bin1"}, + firstParty{}, + hr{}, + library{"Android"}, + usedBy{"highest.apex/bin/bin2"}, + library{"Device"}, + usedBy{"highest.apex/bin/bin1"}, + usedBy{"highest.apex/lib/liba.so"}, + library{"External"}, + usedBy{"highest.apex/bin/bin1"}, + proprietary{}, + }, + }, + { + condition: "proprietary", + name: "container", + roots: []string{"container.zip.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"container.zip/bin2"}, + usedBy{"container.zip/libb.so"}, + restricted{}, + hr{}, + library{"Android"}, + usedBy{"container.zip"}, + usedBy{"container.zip/bin1"}, + firstParty{}, + hr{}, + library{"Android"}, + usedBy{"container.zip/bin2"}, + library{"Device"}, + usedBy{"container.zip/bin1"}, + usedBy{"container.zip/liba.so"}, + library{"External"}, + usedBy{"container.zip/bin1"}, + proprietary{}, + }, + }, + { + condition: "proprietary", + name: "application", + roots: []string{"application.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"application"}, + firstParty{}, + hr{}, + library{"Device"}, + usedBy{"application"}, + proprietary{}, + }, + }, + { + condition: "proprietary", + name: "binary", + roots: []string{"bin/bin1.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"Android"}, + usedBy{"bin/bin1"}, + firstParty{}, + hr{}, + library{"Device"}, + usedBy{"bin/bin1"}, + library{"External"}, + usedBy{"bin/bin1"}, + proprietary{}, + }, + }, + { + condition: "proprietary", + name: "library", + roots: []string{"lib/libd.so.meta_lic"}, + expectedOut: []matcher{ + hr{}, + library{"External"}, + usedBy{"lib/libd.so"}, + notice{}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.condition+" "+tt.name, func(t *testing.T) { + stdout := &bytes.Buffer{} + stderr := &bytes.Buffer{} + + rootFiles := make([]string, 0, len(tt.roots)) + for _, r := range tt.roots { + rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r) + } + + ctx := context{stdout, stderr, os.DirFS("."), tt.stripPrefix} + + err := textNotice(&ctx, rootFiles...) + if err != nil { + t.Fatalf("textnotice: error = %w, stderr = %v", err, stderr) + return + } + if stderr.Len() > 0 { + t.Errorf("textnotice: gotStderr = %v, want none", stderr) + } + + t.Logf("got stdout: %s", stdout.String()) + + t.Logf("want stdout: %s", matcherList(tt.expectedOut).String()) + + out := bufio.NewScanner(stdout) + lineno := 0 + for out.Scan() { + line := out.Text() + if strings.TrimLeft(line, " ") == "" { + continue + } + if len(tt.expectedOut) <= lineno { + t.Errorf("unexpected output at line %d: got %q, want nothing (wanted %d lines)", lineno+1, line, len(tt.expectedOut)) + } else if !tt.expectedOut[lineno].isMatch(line) { + t.Errorf("unexpected output at line %d: got %q, want %q", lineno+1, line, tt.expectedOut[lineno].String()) + } + lineno++ + } + for ; lineno < len(tt.expectedOut); lineno++ { + t.Errorf("textnotice: missing output line %d: ended early, want %q", lineno+1, tt.expectedOut[lineno].String()) + } + }) + } +} + +type matcher interface { + isMatch(line string) bool + String() string +} + +type hr struct{} + +func (m hr) isMatch(line string) bool { + return horizontalRule.MatchString(line) +} + +func (m hr) String() string { + return " ================================================== " +} + +type library struct { + name string +} + +func (m library) isMatch(line string) bool { + return strings.HasPrefix(line, m.name+" ") +} + +func (m library) String() string { + return m.name + " used by:" +} + +type usedBy struct { + name string +} + +func (m usedBy) isMatch(line string) bool { + return len(line) > 0 && line[0] == ' ' && strings.HasPrefix(strings.TrimLeft(line, " "), "out/") && strings.HasSuffix(line, "/"+m.name) +} + +func (m usedBy) String() string { + return " out/.../" + m.name +} + +type firstParty struct{} + +func (m firstParty) isMatch(line string) bool { + return strings.HasPrefix(strings.TrimLeft(line, " "), "&&&First Party License&&&") +} + +func (m firstParty) String() string { + return "&&&First Party License&&&" +} + +type notice struct{} + +func (m notice) isMatch(line string) bool { + return strings.HasPrefix(strings.TrimLeft(line, " "), "%%%Notice License%%%") +} + +func (m notice) String() string { + return "%%%Notice License%%%" +} + +type reciprocal struct{} + +func (m reciprocal) isMatch(line string) bool { + return strings.HasPrefix(strings.TrimLeft(line, " "), "$$$Reciprocal License$$$") +} + +func (m reciprocal) String() string { + return "$$$Reciprocal License$$$" +} + +type restricted struct{} + +func (m restricted) isMatch(line string) bool { + return strings.HasPrefix(strings.TrimLeft(line, " "), "###Restricted License###") +} + +func (m restricted) String() string { + return "###Restricted License###" +} + +type proprietary struct{} + +func (m proprietary) isMatch(line string) bool { + return strings.HasPrefix(strings.TrimLeft(line, " "), "@@@Proprietary License@@@") +} + +func (m proprietary) String() string { + return "@@@Proprietary License@@@" +} + +type matcherList []matcher + +func (l matcherList) String() string { + var sb strings.Builder + for _, m := range l { + s := m.String() + if s[:3] == s[len(s)-3:] { + fmt.Fprintln(&sb) + } + fmt.Fprintf(&sb, "%s\n", s) + if s[:3] == s[len(s)-3:] { + fmt.Fprintln(&sb) + } + } + return sb.String() +} diff --git a/tools/compliance/graph.go b/tools/compliance/graph.go index 97fa657fd7..efcc6e4f7d 100644 --- a/tools/compliance/graph.go +++ b/tools/compliance/graph.go @@ -245,6 +245,15 @@ func (p *TargetEdgePath) Clear() { *p = (*p)[:0] } +// Copy makes a new path with the same value. +func (p *TargetEdgePath) Copy() *TargetEdgePath { + result := make(TargetEdgePath, 0, len(*p)) + for _, e := range *p { + result = append(result, e) + } + return &result +} + // String returns a string representation of the path: [n1 -> n2 -> ... -> nn]. func (p *TargetEdgePath) String() string { if p == nil { @@ -357,6 +366,12 @@ func (tn *TargetNode) Installed() []string { return append([]string{}, tn.proto.Installed...) } +// TargetFiles returns the list of files built or installed by the module or +// target. (unordered) +func (tn *TargetNode) TargetFiles() []string { + return append(tn.proto.Built, tn.proto.Installed...) +} + // InstallMap returns the list of path name transformations to make to move // files from their original location in the file system to their destination // inside a container. (unordered) diff --git a/tools/compliance/noticeindex.go b/tools/compliance/noticeindex.go new file mode 100644 index 0000000000..06c2627d15 --- /dev/null +++ b/tools/compliance/noticeindex.go @@ -0,0 +1,527 @@ +// Copyright 2021 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 +// +// http://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. + +package compliance + +import ( + "bufio" + "crypto/md5" + "fmt" + "io" + "io/fs" + "path/filepath" + "regexp" + "sort" + "strings" +) + +const ( + noProjectName = "\u2205" +) + +var ( + nameRegexp = regexp.MustCompile(`^\s*name\s*:\s*"(.*)"\s*$`) + descRegexp = regexp.MustCompile(`^\s*description\s*:\s*"(.*)"\s*$`) + versionRegexp = regexp.MustCompile(`^\s*version\s*:\s*"(.*)"\s*$`) + licensesPathRegexp = regexp.MustCompile(`licen[cs]es?/`) +) + +// NoticeIndex transforms license metadata into license text hashes, library +// names, and install paths indexing them for fast lookup/iteration. +type NoticeIndex struct { + // lg identifies the license graph to which the index applies. + lg *LicenseGraph + // rs identifies the set of resolutions upon which the index is based. + rs ResolutionSet + // shipped identifies the set of target nodes shipped directly or as derivative works. + shipped *TargetNodeSet + // rootFS locates the root of the file system from which to read the files. + rootFS fs.FS + // hash maps license text filenames to content hashes + hash map[string]hash + // text maps content hashes to content + text map[hash][]byte + // hashLibInstall maps hashes to libraries to install paths. + hashLibInstall map[hash]map[string]map[string]struct{} + // installLibHash maps install paths to libraries to hashes. + installLibHash map[string]map[string]map[hash]struct{} + // libHash maps libraries to hashes. + libHash map[string]map[hash]struct{} + // targetHash maps target nodes to hashes. + targetHashes map[*TargetNode]map[hash]struct{} + // projectName maps project directory names to project name text. + projectName map[string]string +} + +// IndexLicenseTexts creates a hashed index of license texts for `lg` and `rs` +// using the files rooted at `rootFS`. +func IndexLicenseTexts(rootFS fs.FS, lg *LicenseGraph, rs ResolutionSet) (*NoticeIndex, error) { + if rs == nil { + rs = ResolveNotices(lg) + } + ni := &NoticeIndex{ + lg, rs, ShippedNodes(lg), rootFS, + make(map[string]hash), + make(map[hash][]byte), + make(map[hash]map[string]map[string]struct{}), + make(map[string]map[string]map[hash]struct{}), + make(map[string]map[hash]struct{}), + make(map[*TargetNode]map[hash]struct{}), + make(map[string]string), + } + + // index adds all license texts for `tn` to the index. + index := func(tn *TargetNode) (map[hash]struct{}, error) { + if hashes, ok := ni.targetHashes[tn]; ok { + return hashes, nil + } + hashes := make(map[hash]struct{}) + for _, text := range tn.LicenseTexts() { + if _, ok := ni.hash[text]; !ok { + err := ni.addText(text) + if err != nil { + return nil, err + } + } + hash := ni.hash[text] + if _, ok := hashes[hash]; !ok { + hashes[hash] = struct{}{} + } + } + ni.targetHashes[tn] = hashes + return hashes, nil + } + + link := func(libName string, hashes map[hash]struct{}, installPaths []string) { + if _, ok := ni.libHash[libName]; !ok { + ni.libHash[libName] = make(map[hash]struct{}) + } + for h := range hashes { + if _, ok := ni.hashLibInstall[h]; !ok { + ni.hashLibInstall[h] = make(map[string]map[string]struct{}) + } + if _, ok := ni.libHash[libName][h]; !ok { + ni.libHash[libName][h] = struct{}{} + } + for _, installPath := range installPaths { + if _, ok := ni.installLibHash[installPath]; !ok { + ni.installLibHash[installPath] = make(map[string]map[hash]struct{}) + ni.installLibHash[installPath][libName] = make(map[hash]struct{}) + ni.installLibHash[installPath][libName][h] = struct{}{} + } else if _, ok = ni.installLibHash[installPath][libName]; !ok { + ni.installLibHash[installPath][libName] = make(map[hash]struct{}) + ni.installLibHash[installPath][libName][h] = struct{}{} + } else if _, ok = ni.installLibHash[installPath][libName][h]; !ok { + ni.installLibHash[installPath][libName][h] = struct{}{} + } + if _, ok := ni.hashLibInstall[h]; !ok { + ni.hashLibInstall[h] = make(map[string]map[string]struct{}) + ni.hashLibInstall[h][libName] = make(map[string]struct{}) + ni.hashLibInstall[h][libName][installPath] = struct{}{} + } else if _, ok = ni.hashLibInstall[h][libName]; !ok { + ni.hashLibInstall[h][libName] = make(map[string]struct{}) + ni.hashLibInstall[h][libName][installPath] = struct{}{} + } else if _, ok = ni.hashLibInstall[h][libName][installPath]; !ok { + ni.hashLibInstall[h][libName][installPath] = struct{}{} + } + } + } + } + + // returns error from walk below. + var err error + + WalkTopDown(NoEdgeContext{}, lg, func(lg *LicenseGraph, tn *TargetNode, path TargetEdgePath) bool { + if err != nil { + return false + } + if !ni.shipped.Contains(tn) { + return false + } + installPaths := getInstallPaths(tn, path) + var hashes map[hash]struct{} + hashes, err = index(tn) + if err != nil { + return false + } + link(ni.getLibName(tn), hashes, installPaths) + if tn.IsContainer() { + return true + } + + for _, r := range rs.Resolutions(tn) { + hashes, err = index(r.actsOn) + if err != nil { + return false + } + link(ni.getLibName(r.actsOn), hashes, installPaths) + } + return false + }) + + if err != nil { + return nil, err + } + + return ni, nil +} + +// Hashes returns an ordered channel of the hashed license texts. +func (ni *NoticeIndex) Hashes() chan hash { + c := make(chan hash) + go func() { + libs := make([]string, 0, len(ni.libHash)) + for libName := range ni.libHash { + libs = append(libs, libName) + } + sort.Strings(libs) + hashes := make(map[hash]struct{}) + for _, libName := range libs { + hl := make([]hash, 0, len(ni.libHash[libName])) + for h := range ni.libHash[libName] { + if _, ok := hashes[h]; ok { + continue + } + hashes[h] = struct{}{} + hl = append(hl, h) + } + if len(hl) > 0 { + sort.Sort(hashList{ni, libName, &hl}) + for _, h := range hl { + c <- h + } + } + } + close(c) + }() + return c +} + +// HashLibs returns the ordered array of library names using the license text +// hashed as `h`. +func (ni *NoticeIndex) HashLibs(h hash) []string { + libs := make([]string, 0, len(ni.hashLibInstall[h])) + for libName := range ni.hashLibInstall[h] { + libs = append(libs, libName) + } + sort.Strings(libs) + return libs +} + +// HashLibInstalls returns the ordered array of install paths referencing +// library `libName` using the license text hashed as `h`. +func (ni *NoticeIndex) HashLibInstalls(h hash, libName string) []string { + installs := make([]string, 0, len(ni.hashLibInstall[h][libName])) + for installPath := range ni.hashLibInstall[h][libName] { + installs = append(installs, installPath) + } + sort.Strings(installs) + return installs +} + +// HashText returns the file content of the license text hashed as `h`. +func (ni *NoticeIndex) HashText(h hash) []byte { + return ni.text[h] +} + +// getLibName returns the name of the library associated with `noticeFor`. +func (ni *NoticeIndex) getLibName(noticeFor *TargetNode) string { + // use name from METADATA if available + ln := ni.checkMetadata(noticeFor) + if len(ln) > 0 { + return ln + } + // use package_name: from license{} module if available + pn := noticeFor.PackageName() + if len(pn) > 0 { + return pn + } + for _, p := range noticeFor.Projects() { + if strings.HasPrefix(p, "prebuilts/") { + for _, licenseText := range noticeFor.LicenseTexts() { + if !strings.HasPrefix(licenseText, "prebuilts/") { + continue + } + for r, prefix := range SafePrebuiltPrefixes { + match := r.FindString(licenseText) + if len(match) == 0 { + continue + } + strip := SafePathPrefixes[prefix] + if strip { + // strip entire prefix + match = licenseText[len(match):] + } else { + // strip from prebuilts/ until safe prefix + match = licenseText[len(match)-len(prefix):] + } + // remove LICENSE or NOTICE or other filename + li := strings.LastIndex(match, "/") + if 0 < li { + match = match[:li] + } + // remove *licenses/ path segment and subdirectory if in path + if offsets := licensesPathRegexp.FindAllStringIndex(match, -1); offsets != nil && 0 < offsets[len(offsets)-1][0] { + match = match[:offsets[len(offsets)-1][0]] + li = strings.LastIndex(match, "/") + if 0 < li { + match = match[:li] + } + } + return match + } + break + } + } + for prefix, strip := range SafePathPrefixes { + if strings.HasPrefix(p, prefix) { + if strip { + return p[len(prefix):] + } else { + return p + } + } + } + } + // strip off [./]meta_lic from license metadata path and extract base name + n := noticeFor.name[:len(noticeFor.name)-9] + li := strings.LastIndex(n, "/") + if 0 < li { + n = n[li+1:] + } + return n +} + +// checkMetadata tries to look up a library name from a METADATA file associated with `noticeFor`. +func (ni *NoticeIndex) checkMetadata(noticeFor *TargetNode) string { + for _, p := range noticeFor.Projects() { + if name, ok := ni.projectName[p]; ok { + if name == noProjectName { + continue + } + return name + } + f, err := ni.rootFS.Open(filepath.Join(p, "METADATA")) + if err != nil { + ni.projectName[p] = noProjectName + continue + } + name := "" + description := "" + version := "" + s := bufio.NewScanner(f) + for s.Scan() { + line := s.Text() + m := nameRegexp.FindStringSubmatch(line) + if m != nil { + if 1 < len(m) && m[1] != "" { + name = m[1] + } + if version != "" { + break + } + continue + } + m = versionRegexp.FindStringSubmatch(line) + if m != nil { + if 1 < len(m) && m[1] != "" { + version = m[1] + } + if name != "" { + break + } + continue + } + m = descRegexp.FindStringSubmatch(line) + if m != nil { + if 1 < len(m) && m[1] != "" { + description = m[1] + } + } + } + _ = s.Err() + _ = f.Close() + if name != "" { + if version != "" { + if version[0] == 'v' || version[0] == 'V' { + ni.projectName[p] = name + "_" + version + } else { + ni.projectName[p] = name + "_v_" + version + } + } else { + ni.projectName[p] = name + } + return ni.projectName[p] + } + if description != "" { + ni.projectName[p] = description + return ni.projectName[p] + } + ni.projectName[p] = noProjectName + } + return "" +} + +// addText reads and indexes the content of a license text file. +func (ni *NoticeIndex) addText(file string) error { + f, err := ni.rootFS.Open(filepath.Clean(file)) + if err != nil { + return fmt.Errorf("error opening license text file %q: %w", file, err) + } + + // read the file + text, err := io.ReadAll(f) + if err != nil { + return fmt.Errorf("error reading license text file %q: %w", file, err) + } + + hash := hash{fmt.Sprintf("%x", md5.Sum(text))} + ni.hash[file] = hash + if _, alreadyPresent := ni.text[hash]; !alreadyPresent { + ni.text[hash] = text + } + + return nil +} + +// getInstallPaths returns the names of the used dependencies mapped to their +// installed locations. +func getInstallPaths(attachesTo *TargetNode, path TargetEdgePath) []string { + if len(path) == 0 { + installs := attachesTo.Installed() + if 0 == len(installs) { + installs = attachesTo.Built() + } + return installs + } + + var getInstalls func(path TargetEdgePath) []string + + getInstalls = func(path TargetEdgePath) []string { + // deps contains the output targets from the dependencies in the path + var deps []string + if len(path) > 1 { + // recursively get the targets from the sub-path skipping 1 path segment + deps = getInstalls(path[1:]) + } else { + // stop recursion at 1 path segment + deps = path[0].Dependency().TargetFiles() + } + size := 0 + prefixes := path[0].Target().TargetFiles() + installMap := path[0].Target().InstallMap() + sources := path[0].Target().Sources() + for _, dep := range deps { + found := false + for _, source := range sources { + if strings.HasPrefix(dep, source) { + found = true + break + } + } + if !found { + continue + } + for _, im := range installMap { + if strings.HasPrefix(dep, im.FromPath) { + size += len(prefixes) + break + } + } + } + + installs := make([]string, 0, size) + for _, dep := range deps { + found := false + for _, source := range sources { + if strings.HasPrefix(dep, source) { + found = true + break + } + } + if !found { + continue + } + for _, im := range installMap { + if strings.HasPrefix(dep, im.FromPath) { + for _, prefix := range prefixes { + installs = append(installs, prefix+im.ContainerPath+dep[len(im.FromPath):]) + } + break + } + } + } + return installs + } + allInstalls := getInstalls(path) + installs := path[0].Target().Installed() + if len(installs) == 0 { + return allInstalls + } + result := make([]string, 0, len(allInstalls)) + for _, install := range allInstalls { + for _, prefix := range installs { + if strings.HasPrefix(install, prefix) { + result = append(result, install) + } + } + } + return result +} + +// hash is an opaque string derived from md5sum. +type hash struct { + key string +} + +// String returns the hexadecimal representation of the hash. +func (h hash) String() string { + return h.key +} + +// hashList orders an array of hashes +type hashList struct { + ni *NoticeIndex + libName string + hashes *[]hash +} + +// Len returns the count of elements in the slice. +func (l hashList) Len() int { return len(*l.hashes) } + +// Swap rearranges 2 elements of the slice so that each occupies the other's +// former position. +func (l hashList) Swap(i, j int) { (*l.hashes)[i], (*l.hashes)[j] = (*l.hashes)[j], (*l.hashes)[i] } + +// Less returns true when the `i`th element is lexicographically less than +// the `j`th element. +func (l hashList) Less(i, j int) bool { + var insti, instj int + if 0 < len(l.libName) { + insti = len(l.ni.hashLibInstall[(*l.hashes)[i]][l.libName]) + instj = len(l.ni.hashLibInstall[(*l.hashes)[j]][l.libName]) + } + if insti == instj { + leni := len(l.ni.text[(*l.hashes)[i]]) + lenj := len(l.ni.text[(*l.hashes)[j]]) + if leni == lenj { + // all else equal, just order by hash value + return (*l.hashes)[i].key < (*l.hashes)[j].key + } + // put shortest texts first within same # of installs + return leni < lenj + } + // reverse order of # installs so that most popular appears first + return instj < insti +} diff --git a/tools/compliance/policy/policy.go b/tools/compliance/policy/policy.go index 581912a7ee..4261ed011a 100644 --- a/tools/compliance/policy/policy.go +++ b/tools/compliance/policy/policy.go @@ -29,6 +29,31 @@ var ( "toolchain": "toolchain", } + // SafePathPrefixes maps the path prefixes presumed not to contain any + // proprietary or confidential pathnames to whether to strip the prefix + // from the path when used as the library name for notices. + SafePathPrefixes = map[string]bool{ + "external/": true, + "art/": false, + "build/": false, + "cts/": false, + "dalvik/": false, + "developers/": false, + "development/": false, + "frameworks/": false, + "packages/": true, + "prebuilts/": false, + "sdk/": false, + "system/": false, + "test/": false, + "toolchain/": false, + "tools/": false, + } + + // SafePrebuiltPrefixes maps the regular expression to match a prebuilt + // containing the path of a safe prefix to the safe prefix. + SafePrebuiltPrefixes = make(map[*regexp.Regexp]string) + // ImpliesUnencumbered lists the condition names representing an author attempt to disclaim copyright. ImpliesUnencumbered = LicenseConditionSet(UnencumberedCondition) @@ -66,6 +91,15 @@ var ( ccBySa = regexp.MustCompile(`^SPDX-license-identifier-CC-BY.*-SA.*`) ) +func init() { + for prefix := range SafePathPrefixes { + if prefix == "prebuilts/" { + continue + } + r := regexp.MustCompile("^prebuilts/[^ ]*/" + prefix) + SafePrebuiltPrefixes[r] = prefix + } +} // LicenseConditionSetFromNames returns a set containing the recognized `names` and // silently ignoring or discarding the unrecognized `names`.