From 39a05a399d39a25e0ff4139a4ad0c1e17c6d59ff Mon Sep 17 00:00:00 2001 From: Ayan Sinha Mahapatra Date: Thu, 15 Oct 2026 10:35:35 -0700 Subject: [PATCH 1/2] Rename JsonCompactOutput to JsonOutput As a preperation step to adding a compact JSON output. Signed-off-by: Ayan Sinha Mahapatra --- docs/source/reference/scancode-cli/cli-help-text-options.rst | 2 +- pyproject-scancode-toolkit-mini.toml | 2 +- pyproject-scancode-toolkit.toml | 2 +- pyproject.toml | 2 +- src/formattedcode/output_json.py | 4 ++-- tests/formattedcode/test_reuse_output_plugins.py | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/source/reference/scancode-cli/cli-help-text-options.rst b/docs/source/reference/scancode-cli/cli-help-text-options.rst index caa0a03636b..9b5b1ec08f4 100644 --- a/docs/source/reference/scancode-cli/cli-help-text-options.rst +++ b/docs/source/reference/scancode-cli/cli-help-text-options.rst @@ -402,7 +402,7 @@ for ScanCode Version 32.0.0. -------------------------------------------- - Plugin: scancode_output:json class: formattedcode.output_json:JsonCompactOutput + Plugin: scancode_output:json class: formattedcode.output_json:JsonOutput codebase_attributes: resource_attributes: sort_order: 100 diff --git a/pyproject-scancode-toolkit-mini.toml b/pyproject-scancode-toolkit-mini.toml index b40f4d07fe5..50947642da8 100644 --- a/pyproject-scancode-toolkit-mini.toml +++ b/pyproject-scancode-toolkit-mini.toml @@ -306,7 +306,7 @@ ignore-copyrights = "cluecode.plugin_ignore_copyrights:IgnoreCopyrights" [project.entry-points.scancode_output] html = "formattedcode.output_html:HtmlOutput" html-app = "formattedcode.output_html:HtmlAppOutput" -json = "formattedcode.output_json:JsonCompactOutput" +json = "formattedcode.output_json:JsonOutput" json-pp = "formattedcode.output_json:JsonPrettyOutput" spdx-tv = "formattedcode.output_spdx:SpdxTvOutput" spdx-rdf = "formattedcode.output_spdx:SpdxRdfOutput" diff --git a/pyproject-scancode-toolkit.toml b/pyproject-scancode-toolkit.toml index 29f8157b8dc..4a3fc35fcd5 100644 --- a/pyproject-scancode-toolkit.toml +++ b/pyproject-scancode-toolkit.toml @@ -307,7 +307,7 @@ ignore-copyrights = "cluecode.plugin_ignore_copyrights:IgnoreCopyrights" [project.entry-points.scancode_output] html = "formattedcode.output_html:HtmlOutput" html-app = "formattedcode.output_html:HtmlAppOutput" -json = "formattedcode.output_json:JsonCompactOutput" +json = "formattedcode.output_json:JsonOutput" json-pp = "formattedcode.output_json:JsonPrettyOutput" spdx-tv = "formattedcode.output_spdx:SpdxTvOutput" spdx-rdf = "formattedcode.output_spdx:SpdxRdfOutput" diff --git a/pyproject.toml b/pyproject.toml index 9893c3c5853..b752aa8df22 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -311,7 +311,7 @@ ignore-copyrights = "cluecode.plugin_ignore_copyrights:IgnoreCopyrights" [project.entry-points.scancode_output] html = "formattedcode.output_html:HtmlOutput" html-app = "formattedcode.output_html:HtmlAppOutput" -json = "formattedcode.output_json:JsonCompactOutput" +json = "formattedcode.output_json:JsonOutput" json-pp = "formattedcode.output_json:JsonPrettyOutput" spdx-tv = "formattedcode.output_spdx:SpdxTvOutput" spdx-rdf = "formattedcode.output_spdx:SpdxRdfOutput" diff --git a/src/formattedcode/output_json.py b/src/formattedcode/output_json.py index d3ce570b83d..041f362734f 100644 --- a/src/formattedcode/output_json.py +++ b/src/formattedcode/output_json.py @@ -40,14 +40,14 @@ def logger_debug(*args): @output_impl -class JsonCompactOutput(OutputPlugin): +class JsonOutput(OutputPlugin): options = [ PluggableCommandLineOption(('--json', 'output_json',), type=FileOptionType(mode='w', encoding='utf-8', lazy=True), metavar='FILE', default=None, - help='Write scan output as compact JSON to FILE.', + help='Write scan output as JSON to FILE.', help_group=OUTPUT_GROUP, sort_order=10), ] diff --git a/tests/formattedcode/test_reuse_output_plugins.py b/tests/formattedcode/test_reuse_output_plugins.py index 90236ae0450..eca0a52f0e2 100644 --- a/tests/formattedcode/test_reuse_output_plugins.py +++ b/tests/formattedcode/test_reuse_output_plugins.py @@ -47,7 +47,7 @@ def check_plugin(plugin_class, test_file='reuse/vb.json', force_text=False): def test_can_call_json_output_from_regular_code_with_virtualcodebase(): - from formattedcode.output_json import JsonCompactOutput as plug + from formattedcode.output_json import JsonOutput as plug check_plugin(plug, 'reuse/vb.json') From 6a18e3910db9869c7e14488eccd7458ea8e19f53 Mon Sep 17 00:00:00 2001 From: Ayan Sinha Mahapatra Date: Thu, 15 Oct 2026 23:03:14 -0700 Subject: [PATCH 2/2] Add compact JSON output for scancode Reference: https://github.com/aboutcode-org/scancode-toolkit/issues/4555 Signed-off-by: Ayan Sinha Mahapatra --- pyproject-scancode-toolkit-mini.toml | 1 + pyproject-scancode-toolkit.toml | 1 + pyproject.toml | 1 + src/formattedcode/output_compact.py | 233 +++++ src/formattedcode/output_json.py | 41 +- .../common/manifests-expected.compact.json | 856 ++++++++++++++++++ tests/formattedcode/test_output_json.py | 10 +- .../test_reuse_output_plugins.py | 5 + tests/scancode/data/help/help.txt | 3 +- tests/scancode/data/help/help_linux.txt | 3 +- 10 files changed, 1148 insertions(+), 6 deletions(-) create mode 100644 src/formattedcode/output_compact.py create mode 100644 tests/formattedcode/data/common/manifests-expected.compact.json diff --git a/pyproject-scancode-toolkit-mini.toml b/pyproject-scancode-toolkit-mini.toml index 50947642da8..041c0bc10cf 100644 --- a/pyproject-scancode-toolkit-mini.toml +++ b/pyproject-scancode-toolkit-mini.toml @@ -307,6 +307,7 @@ ignore-copyrights = "cluecode.plugin_ignore_copyrights:IgnoreCopyrights" html = "formattedcode.output_html:HtmlOutput" html-app = "formattedcode.output_html:HtmlAppOutput" json = "formattedcode.output_json:JsonOutput" +compact-json = "formattedcode.output_json:JsonCompactOutput" json-pp = "formattedcode.output_json:JsonPrettyOutput" spdx-tv = "formattedcode.output_spdx:SpdxTvOutput" spdx-rdf = "formattedcode.output_spdx:SpdxRdfOutput" diff --git a/pyproject-scancode-toolkit.toml b/pyproject-scancode-toolkit.toml index 4a3fc35fcd5..899340a3c7e 100644 --- a/pyproject-scancode-toolkit.toml +++ b/pyproject-scancode-toolkit.toml @@ -308,6 +308,7 @@ ignore-copyrights = "cluecode.plugin_ignore_copyrights:IgnoreCopyrights" html = "formattedcode.output_html:HtmlOutput" html-app = "formattedcode.output_html:HtmlAppOutput" json = "formattedcode.output_json:JsonOutput" +compact-json = "formattedcode.output_json:JsonCompactOutput" json-pp = "formattedcode.output_json:JsonPrettyOutput" spdx-tv = "formattedcode.output_spdx:SpdxTvOutput" spdx-rdf = "formattedcode.output_spdx:SpdxRdfOutput" diff --git a/pyproject.toml b/pyproject.toml index b752aa8df22..4df07aa6ace 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -312,6 +312,7 @@ ignore-copyrights = "cluecode.plugin_ignore_copyrights:IgnoreCopyrights" html = "formattedcode.output_html:HtmlOutput" html-app = "formattedcode.output_html:HtmlAppOutput" json = "formattedcode.output_json:JsonOutput" +compact-json = "formattedcode.output_json:JsonCompactOutput" json-pp = "formattedcode.output_json:JsonPrettyOutput" spdx-tv = "formattedcode.output_spdx:SpdxTvOutput" spdx-rdf = "formattedcode.output_spdx:SpdxRdfOutput" diff --git a/src/formattedcode/output_compact.py b/src/formattedcode/output_compact.py new file mode 100644 index 00000000000..dd8c347e3f3 --- /dev/null +++ b/src/formattedcode/output_compact.py @@ -0,0 +1,233 @@ +# +# Copyright (c) nexB Inc. and others. All rights reserved. +# ScanCode is a trademark of nexB Inc. +# SPDX-License-Identifier: Apache-2.0 +# See http://www.apache.org/licenses/LICENSE-2.0 for the license text. +# See https://github.com/nexB/scancode-toolkit for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# + +""" +Helper functions to write scan results in a compact manner as JSON, preserving +only non-duplicated key detection information, and skipping attributes with +large values or more details. +""" + +# Tracing flags +TRACE = False + + +def logger_debug(*args): + pass + + +if TRACE: + import sys + import logging + + logger = logging.getLogger(__name__) + logging.basicConfig(stream=sys.stdout) + logger.setLevel(logging.DEBUG) + + def logger_debug(*args): + return logger.debug(' '.join(isinstance(a, str) + and a or repr(a) for a in args)) + + +COMPACT_CONFLICTING_OPTIONS = [ + 'summary', 'classify', 'consolidate', 'todo', 'mark_source', 'tallies', + 'tallies_by_facet', 'tallies_with_details', 'tallies_key_files', + 'license_references', 'license_text', 'license_diagnostics', 'license_text_diagnostics', + 'go_symbol', 'rust_symbol' +] + +PACKAGE_DETECTION_FIELDS = [ + # Detection fields have a lot of inlined duplicated data which needs to be skipped, + # just identifiers are enough, and this will be kept in the data mapping seperately + "license_detections", + "other_license_detections" +] + +COMPACT_PACKAGES_SKIP_ATTRIBUTES = [ + # These are PackageURL fields and are coontained in `package_uid` which is a purl + identifier + "type", + "namespace", + "name", + "version", + "qualifiers", + "subpath", + "purl", + # This usually has text which is too large and not useful for a compact output + "description", + # Just `declared_license_expression_spdx` is enough + "declared_license_expression", + # Just `other_license_expression_spdx` is enough + "other_license_expression_spdx", + # Already captured by license detection fields if present + "extracted_license_statement", + # This usually has text which is too large and not useful for a compact output + "notice_text", + "extra_data", + # This can be deduced from datafile_paths + "datasource_ids" +] + PACKAGE_DETECTION_FIELDS + + +COMPACT_DEPENDENCIES_SKIP_ATTRIBUTES = [ + "resolved_package", + # Not essential information + "extra_data", + # This can be deduced from `datafile_path` + "datasource_id" +] + +COMPACT_LICENSES_SKIP_ATTRIBUTES = [ + # Just keeping `license_expression_spdx` is enough + "license_expression", + # This needs to be compact further, so we can't have as-is + "reference_matches" +] + +COMPACT_LICENSE_MATCHES_SKIP_ATTRIBUTES = [ + # Just keeping `license_expression_spdx` is enough + "license_expression", + # We have the `rule_identifier` and this is derivative + "rule_url", + # We have the `rule_identifier` and this info can be fetched + "rule_relevance" +] + +COMPACT_RESOURCES_SKIP_ATTRIBUTES = [ + # Just keeping `detected_license_expression_spdx` is enough + "detected_license_expression", + # Detection fields have a lot of inlined duplicated data which needs to be skipped, + # just identifiers are enough, and this will be kept in the data mapping seperately + "license_detections", + "package_data", + # license clues are matches not aggregated in the top-level license detections, but + # these mappings need to be processed to make them more compact + "license_clues", + # `name`, `base_name` and `extension` info is also present in the full-path + "name", + "base_name", + "extension" +] + +def get_compact_packages(package_mapping): + compact_package_mapping = get_compact_mapping( + mapping=package_mapping, + keys_to_skip=COMPACT_PACKAGES_SKIP_ATTRIBUTES, + ) + + # Only keep the license detection identifiers from the detection mappings + for detection_attribute in PACKAGE_DETECTION_FIELDS: + detection_mapping = [ + {"identifier": detection.get("identifier")} + for detection in package_mapping.get(detection_attribute, []) + if detection + ] + if detection_mapping: + compact_package_mapping[detection_attribute] = detection_mapping + + return compact_package_mapping + + +def get_compact_dependencies(dependency_mapping): + return get_compact_mapping( + mapping=dependency_mapping, + keys_to_skip=COMPACT_DEPENDENCIES_SKIP_ATTRIBUTES, + ) + + +def get_compact_license_detections(license_mapping): + compact_license_mapping = get_compact_mapping( + mapping=license_mapping, + keys_to_skip=COMPACT_LICENSES_SKIP_ATTRIBUTES, + ) + compact_license_mapping["reference_matches"] = [ + get_compact_mapping( + mapping=match, + keys_to_skip=COMPACT_LICENSE_MATCHES_SKIP_ATTRIBUTES, + ) + for match in license_mapping.get("reference_matches", []) + ] + return compact_license_mapping + + +def get_compact_mapping(mapping, keys_to_skip=[]): + """ + Get a more compact version of `mapping` which doesn't have + empty key/value pairs or attributes which are explicitly skipped + with the `keys_to_skip` list. + + Also removes empty key/value pairs recursively. + """ + if type(mapping) is not dict: + return mapping + + return { + key: get_compact_mapping(value) + for key, value in mapping.items() + if value and key not in keys_to_skip + } + + +get_compact_func_by_key = { + "packages": get_compact_packages, + "dependencies": get_compact_dependencies, + "license_detections": get_compact_license_detections, +} + +def write_compact_codebase_attributes(stream, key, value): + if not key in get_compact_func_by_key: + return + + func = get_compact_func_by_key.get(key) + if func: + compact_output = [ + func(instance) + for instance in value + ] + if compact_output: + return stream.write(key, compact_output) + + +def get_compact_resource(resource_mapping): + compact_resource_mapping = get_compact_mapping( + mapping=resource_mapping, + keys_to_skip=COMPACT_RESOURCES_SKIP_ATTRIBUTES, + ) + + # Only keep detection identifiers for resource level package/license + # detections as these are assembled into top-level summaries and so + # these inlined data is duplicate information + package_data = [ + {"purl": detection.get("purl")} + for detection in resource_mapping.get("package_data", []) + if detection and detection.get("purl") + ] + if package_data: + compact_resource_mapping["package_data"] = package_data + + license_detections = [ + {"identifier": detection.get("identifier")} + for detection in resource_mapping.get("license_detections", []) + if detection + ] + if license_detections: + compact_resource_mapping["license_detections"] = license_detections + + # license clues are matches not aggregated in the top-level license detections, but + # these mappings need to be processed to make them more compact + license_clues = [ + get_compact_mapping( + mapping=clue_mapping, + keys_to_skip=COMPACT_LICENSE_MATCHES_SKIP_ATTRIBUTES, + ) + for clue_mapping in resource_mapping.get("license_clues", []) + if clue_mapping + ] + if license_clues: + compact_resource_mapping["license_clues"] = license_clues + + return compact_resource_mapping diff --git a/src/formattedcode/output_json.py b/src/formattedcode/output_json.py index 041f362734f..84e12ebe802 100644 --- a/src/formattedcode/output_json.py +++ b/src/formattedcode/output_json.py @@ -9,6 +9,9 @@ import jsonstreams from formattedcode import FileOptionType +from formattedcode.output_compact import COMPACT_CONFLICTING_OPTIONS +from formattedcode.output_compact import write_compact_codebase_attributes +from formattedcode.output_compact import get_compact_resource from commoncode.cliutils import PluggableCommandLineOption from commoncode.cliutils import OUTPUT_GROUP from plugincode.output import output_impl @@ -59,6 +62,27 @@ def process_codebase(self, codebase, output_json, **kwargs): write_results(codebase, output_file=output_json, pretty=False, **kwargs) +@output_impl +class JsonCompactOutput(OutputPlugin): + + options = [ + PluggableCommandLineOption(('--compact-json', 'output_compact_json',), + type=FileOptionType(mode='w', encoding='utf-8', lazy=True), + metavar='FILE', + default=None, + conflicting_options=COMPACT_CONFLICTING_OPTIONS, + help='Write scan output as compact JSON to FILE.', + help_group=OUTPUT_GROUP, + sort_order=10), + ] + + def is_enabled(self, output_compact_json, **kwargs): + return output_compact_json + + def process_codebase(self, codebase, output_compact_json, **kwargs): + write_results(codebase, output_file=output_compact_json, pretty=False, compact=True, **kwargs) + + @output_impl class JsonPrettyOutput(OutputPlugin): @@ -79,11 +103,12 @@ def process_codebase(self, codebase, output_json_pp, **kwargs): write_results(codebase, output_file=output_json_pp, pretty=True, **kwargs) -def write_results(codebase, output_file, pretty=False, **kwargs): +def write_results(codebase, output_file, pretty=False, compact=False, **kwargs): """ Write headers, files, and other attributes from `codebase` to `output_file` Enable JSON indentation if `pretty` is True + Only return useful, non-duplicated """ # Set indentation for JSON output if `pretty` is True # We use a separate dict for jsonstream kwargs since we are passing @@ -114,12 +139,22 @@ def write_results(codebase, output_file, pretty=False, **kwargs): # Write attributes if codebase.attributes: for attribute_key, attribute_value in codebase.attributes.to_dict().items(): - s.write(attribute_key, attribute_value) + if compact: + write_compact_codebase_attributes(stream=s, key=attribute_key, value=attribute_value) + else: + s.write(attribute_key, attribute_value) # Write files codebase_files = OutputPlugin.get_files(codebase, **kwargs) # OutputPlugin.get_files() returns a generator, not JSON-serializable - codebase_files = list(codebase_files) + if compact: + codebase_files = list( + get_compact_resource(codebase_file) + for codebase_file in codebase_files + ) + else: + codebase_files = list(codebase_files) + s.write('files', codebase_files) diff --git a/tests/formattedcode/data/common/manifests-expected.compact.json b/tests/formattedcode/data/common/manifests-expected.compact.json new file mode 100644 index 00000000000..7d8bfbde3ee --- /dev/null +++ b/tests/formattedcode/data/common/manifests-expected.compact.json @@ -0,0 +1,856 @@ +{ + "packages": [ + { + "primary_language": "Java", + "homepage_url": "http://www.jcp.org/en/jsr/detail?id=220", + "declared_license_expression_spdx": "CDDL-1.0", + "source_packages": [ + "pkg:maven/javax.persistence/persistence-api@1.0?classifier=sources" + ], + "repository_homepage_url": "https://repo1.maven.org/maven2/javax/persistence/persistence-api/1.0/", + "repository_download_url": "https://repo1.maven.org/maven2/javax/persistence/persistence-api/1.0/persistence-api-1.0.jar", + "api_data_url": "https://repo1.maven.org/maven2/javax/persistence/persistence-api/1.0/persistence-api-1.0.pom", + "package_uid": "pkg:maven/javax.persistence/persistence-api@1.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_paths": [ + "manifests/maven/persistence-api-1.0.pom" + ], + "license_detections": [ + { + "identifier": "cddl_1_0-b17acf03-1e4f-20e6-cbb8-1b6945ee4c4c" + } + ] + }, + { + "primary_language": "JavaScript", + "parties": [ + { + "type": "person", + "role": "author", + "name": "Spencer Alger", + "email": "spencer.alger@elasticsearch.com", + "url": null + } + ], + "keywords": [ + "gruntplugin" + ], + "homepage_url": "https://github.com/spenceralger/grunt-esvm", + "download_url": "https://registry.npmjs.org/grunt-esvm/-/grunt-esvm-3.2.8.tgz", + "bug_tracking_url": "https://github.com/spenceralger/grunt-esvm/issues", + "vcs_url": "git://github.com/spenceralger/grunt-esvm.git", + "declared_license_expression_spdx": "Apache-2.0", + "repository_homepage_url": "https://www.npmjs.com/package/grunt-esvm", + "repository_download_url": "https://registry.npmjs.org/grunt-esvm/-/grunt-esvm-3.2.8.tgz", + "api_data_url": "https://registry.npmjs.org/grunt-esvm/3.2.8", + "package_uid": "pkg:npm/grunt-esvm@3.2.8?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_paths": [ + "manifests/npm-license-mapping/package.json" + ], + "license_detections": [ + { + "identifier": "apache_2_0-d66ab77d-a5cc-7104-e702-dc7df61fe9e8" + }, + { + "identifier": "apache_2_0-d66ab77d-a5cc-7104-e702-dc7df61fe9e8" + } + ] + }, + { + "primary_language": "JavaScript", + "parties": [ + { + "type": "person", + "role": "maintainer", + "name": "georgdangl", + "email": "npm@dan.gl", + "url": null + } + ], + "homepage_url": "https://github.com/GeorgDangl/angular-compare-validator#readme", + "download_url": "https://registry.npmjs.org/angular-compare-validator/-/angular-compare-validator-0.1.1.tgz", + "sha1": "d35a0754c8587b0502874e3636cf0f19565d09b7", + "sha512": "8f70ed5e3513185ad58fb2a3114769ac93ddd68836ce89146e586fc03e03ac93dcfb1f11354ac26f408b75c0ebf51663d5e4e8e27c38752a3c06bdde749a7c03", + "bug_tracking_url": "https://github.com/GeorgDangl/angular-compare-validator/issues", + "vcs_url": "git+https://github.com/GeorgDangl/angular-compare-validator.git", + "declared_license_expression_spdx": "MIT", + "repository_homepage_url": "https://www.npmjs.com/package/angular-compare-validator", + "repository_download_url": "https://registry.npmjs.org/angular-compare-validator/-/angular-compare-validator-0.1.1.tgz", + "api_data_url": "https://registry.npmjs.org/angular-compare-validator/0.1.1", + "package_uid": "pkg:npm/angular-compare-validator@0.1.1?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_paths": [ + "manifests/npm-license-string/package.json" + ], + "license_detections": [ + { + "identifier": "mit-a822f434-d61f-f2b1-c792-8b8cb9e7b9bf" + } + ] + }, + { + "primary_language": "Python", + "parties": [ + { + "type": "person", + "role": "author", + "name": "BlueBrain Project, EPFL", + "email": "werner.vangeit@epfl.ch", + "url": null + } + ], + "keywords": [ + "optimisation", + "neuroscience", + "BlueBrainProject", + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Programming Language :: Python :: 3 :: Only", + "Operating System :: POSIX", + "Topic :: Scientific/Engineering", + "Topic :: Utilities" + ], + "homepage_url": "https://github.com/BlueBrain/BluePyOpt", + "declared_license_expression_spdx": "LGPL-3.0-only", + "repository_homepage_url": "https://pypi.org/project/bluepyopt", + "api_data_url": "https://pypi.org/pypi/bluepyopt/json", + "package_uid": "pkg:pypi/bluepyopt?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_paths": [ + "manifests/pypi/bluepyopt_setup.py" + ], + "license_detections": [ + { + "identifier": "lgpl_3_0-38174920-e8ed-7bda-41ec-94df7380b7d5" + }, + { + "identifier": "lgpl_3_0-272571eb-5e68-95b6-ddb0-71de2d8df321" + } + ] + } + ], + "dependencies": [ + { + "purl": "pkg:npm/bluebird", + "extracted_requirement": "^2.9.30", + "scope": "dependencies", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:npm/bluebird?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/grunt-esvm@3.2.8?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-mapping/package.json" + }, + { + "purl": "pkg:npm/cli-color", + "extracted_requirement": "~0.3.2", + "scope": "dependencies", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:npm/cli-color?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/grunt-esvm@3.2.8?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-mapping/package.json" + }, + { + "purl": "pkg:npm/cli-table", + "extracted_requirement": "~0.3.0", + "scope": "dependencies", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:npm/cli-table?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/grunt-esvm@3.2.8?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-mapping/package.json" + }, + { + "purl": "pkg:npm/libesvm", + "extracted_requirement": "^3.8.2", + "scope": "dependencies", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:npm/libesvm?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/grunt-esvm@3.2.8?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-mapping/package.json" + }, + { + "purl": "pkg:npm/lodash", + "extracted_requirement": "^3.9.3", + "scope": "dependencies", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:npm/lodash?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/grunt-esvm@3.2.8?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-mapping/package.json" + }, + { + "purl": "pkg:npm/moment", + "extracted_requirement": "^2.10.3", + "scope": "dependencies", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:npm/moment?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/grunt-esvm@3.2.8?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-mapping/package.json" + }, + { + "purl": "pkg:npm/wreck", + "extracted_requirement": "^5.6.0", + "scope": "dependencies", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:npm/wreck?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/grunt-esvm@3.2.8?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-mapping/package.json" + }, + { + "purl": "pkg:npm/grunt", + "extracted_requirement": ">=0.4.0", + "scope": "devDependencies", + "is_optional": true, + "is_direct": true, + "dependency_uid": "pkg:npm/grunt?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/grunt-esvm@3.2.8?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-mapping/package.json" + }, + { + "purl": "pkg:npm/load-grunt-config", + "extracted_requirement": "~0.19.0", + "scope": "devDependencies", + "is_optional": true, + "is_direct": true, + "dependency_uid": "pkg:npm/load-grunt-config?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/grunt-esvm@3.2.8?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-mapping/package.json" + }, + { + "purl": "pkg:npm/grunt", + "extracted_requirement": ">=0.4.0", + "scope": "peerDependencies", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:npm/grunt?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/grunt-esvm@3.2.8?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-mapping/package.json" + }, + { + "purl": "pkg:npm/%40angular/core", + "extracted_requirement": ">=2.0.0", + "scope": "dependencies", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:npm/%40angular/core?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/angular-compare-validator@0.1.1?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-string/package.json" + }, + { + "purl": "pkg:npm/%40angular/forms", + "extracted_requirement": ">=2.0.0", + "scope": "dependencies", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:npm/%40angular/forms?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/angular-compare-validator@0.1.1?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-string/package.json" + }, + { + "purl": "pkg:npm/%40angular/common", + "extracted_requirement": ">=2.0.0", + "scope": "dependencies", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:npm/%40angular/common?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/angular-compare-validator@0.1.1?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-string/package.json" + }, + { + "purl": "pkg:npm/rxjs", + "extracted_requirement": ">=5.0.0-beta.12", + "scope": "dependencies", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:npm/rxjs?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/angular-compare-validator@0.1.1?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-string/package.json" + }, + { + "purl": "pkg:npm/zone.js", + "extracted_requirement": ">=0.6.21", + "scope": "dependencies", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:npm/zone.js?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/angular-compare-validator@0.1.1?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/npm-license-string/package.json" + }, + { + "purl": "pkg:pypi/numpy", + "extracted_requirement": ">=1.6", + "scope": "install", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:pypi/numpy?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/bluepyopt?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/pypi/bluepyopt_setup.py" + }, + { + "purl": "pkg:pypi/pandas", + "extracted_requirement": ">=0.18", + "scope": "install", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:pypi/pandas?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/bluepyopt?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/pypi/bluepyopt_setup.py" + }, + { + "purl": "pkg:pypi/deap", + "scope": "install", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:pypi/deap?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/bluepyopt?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/pypi/bluepyopt_setup.py" + }, + { + "purl": "pkg:pypi/efel", + "extracted_requirement": ">=2.13", + "scope": "install", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:pypi/efel?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/bluepyopt?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/pypi/bluepyopt_setup.py" + }, + { + "purl": "pkg:pypi/ipyparallel", + "scope": "install", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:pypi/ipyparallel?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/bluepyopt?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/pypi/bluepyopt_setup.py" + }, + { + "purl": "pkg:pypi/pickleshare", + "extracted_requirement": ">=0.7.3", + "scope": "install", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:pypi/pickleshare?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/bluepyopt?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/pypi/bluepyopt_setup.py" + }, + { + "purl": "pkg:pypi/jinja2", + "extracted_requirement": ">=2.8", + "scope": "install", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:pypi/jinja2?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/bluepyopt?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/pypi/bluepyopt_setup.py" + }, + { + "purl": "pkg:pypi/future", + "scope": "install", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:pypi/future?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/bluepyopt?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/pypi/bluepyopt_setup.py" + }, + { + "purl": "pkg:pypi/pebble", + "extracted_requirement": ">=4.3.10", + "scope": "install", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:pypi/pebble?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/bluepyopt?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/pypi/bluepyopt_setup.py" + }, + { + "purl": "pkg:pypi/scoop", + "extracted_requirement": ">=0.7", + "scope": "all", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:pypi/scoop?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/bluepyopt?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/pypi/bluepyopt_setup.py" + }, + { + "purl": "pkg:pypi/scoop", + "extracted_requirement": ">=0.7", + "scope": "scoop", + "is_runtime": true, + "is_direct": true, + "dependency_uid": "pkg:pypi/scoop?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:pypi/bluepyopt?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "manifests/pypi/bluepyopt_setup.py" + } + ], + "license_detections": [ + { + "identifier": "apache_2_0-d66ab77d-a5cc-7104-e702-dc7df61fe9e8", + "license_expression_spdx": "Apache-2.0", + "detection_count": 2, + "reference_matches": [ + { + "license_expression_spdx": "Apache-2.0", + "from_file": "manifests/npm-license-mapping/package.json", + "start_line": 1, + "end_line": 1, + "matcher": "1-hash", + "score": 100.0, + "matched_length": 3, + "match_coverage": 100.0, + "rule_identifier": "spdx_license_id_apache-2.0_for_apache-2.0.RULE" + } + ] + }, + { + "identifier": "apache_2_0-0d7a2023-aae9-2989-7f00-27b713b809bb", + "license_expression_spdx": "Apache-2.0", + "detection_count": 1, + "reference_matches": [ + { + "license_expression_spdx": "Apache-2.0", + "from_file": "manifests/npm-license-mapping/package.json", + "start_line": 18, + "end_line": 20, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 5, + "match_coverage": 100.0, + "rule_identifier": "apache-2.0_required_phrase_7.RULE" + } + ] + }, + { + "identifier": "apache_2_0-ec759ae0-ea5a-f138-793e-388520e080c0", + "license_expression_spdx": "Apache-2.0", + "detection_count": 1, + "reference_matches": [ + { + "license_expression_spdx": "Apache-2.0", + "from_file": "manifests/npm-license-mapping/package.json", + "start_line": 6, + "end_line": 6, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 4, + "match_coverage": 100.0, + "rule_identifier": "apache-2.0_65.RULE" + } + ] + }, + { + "identifier": "cddl_1_0-0507fc0c-7fd5-3ecd-8c7b-5ea542059d4f", + "license_expression_spdx": "CDDL-1.0", + "detection_count": 1, + "reference_matches": [ + { + "license_expression_spdx": "CDDL-1.0", + "from_file": "manifests/maven/persistence-api-1.0.pom", + "start_line": 17, + "end_line": 20, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 21, + "match_coverage": 100.0, + "rule_identifier": "cddl-1.0_95.RULE" + } + ] + }, + { + "identifier": "cddl_1_0-b17acf03-1e4f-20e6-cbb8-1b6945ee4c4c", + "license_expression_spdx": "CDDL-1.0", + "detection_count": 1, + "reference_matches": [ + { + "license_expression_spdx": "CDDL-1.0", + "from_file": "manifests/maven/persistence-api-1.0.pom", + "start_line": 1, + "end_line": 2, + "matcher": "1-hash", + "score": 100.0, + "matched_length": 17, + "match_coverage": 100.0, + "rule_identifier": "cddl-1.0_98.RULE" + } + ] + }, + { + "identifier": "lgpl_3_0-272571eb-5e68-95b6-ddb0-71de2d8df321", + "license_expression_spdx": "LGPL-3.0-only", + "detection_count": 2, + "reference_matches": [ + { + "license_expression_spdx": "LGPL-3.0-only", + "from_file": "manifests/pypi/bluepyopt_setup.py", + "start_line": 74, + "end_line": 75, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 10, + "match_coverage": 100.0, + "rule_identifier": "pypi_gnu_lesser_general_public_license_v3.RULE" + } + ] + }, + { + "identifier": "lgpl_3_0-121be3c2-9c80-df84-d3da-8f674e4125c0", + "license_expression_spdx": "LGPL-3.0-only", + "detection_count": 1, + "reference_matches": [ + { + "license_expression_spdx": "LGPL-3.0-only", + "from_file": "manifests/pypi/bluepyopt_setup.py", + "start_line": 9, + "end_line": 20, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 106, + "match_coverage": 100.0, + "rule_identifier": "lgpl-3.0_276.RULE" + } + ] + }, + { + "identifier": "lgpl_3_0-2db87bcf-56b4-9d7d-7075-2effae31c631", + "license_expression_spdx": "LGPL-3.0-only", + "detection_count": 1, + "reference_matches": [ + { + "license_expression_spdx": "LGPL-3.0-only", + "from_file": "manifests/pypi/bluepyopt_setup.py", + "start_line": 65, + "end_line": 65, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 2, + "match_coverage": 100.0, + "rule_identifier": "lgpl-3.0_152.RULE" + } + ] + }, + { + "identifier": "lgpl_3_0-38174920-e8ed-7bda-41ec-94df7380b7d5", + "license_expression_spdx": "LGPL-3.0-only", + "detection_count": 1, + "reference_matches": [ + { + "license_expression_spdx": "LGPL-3.0-only", + "from_file": "manifests/pypi/bluepyopt_setup.py", + "start_line": 1, + "end_line": 1, + "matcher": "1-hash", + "score": 100.0, + "matched_length": 1, + "match_coverage": 100.0, + "rule_identifier": "lgpl-3.0_29.RULE" + } + ] + }, + { + "identifier": "mit-3fce6ea2-8abd-6c6b-3ede-a37af7c6efee", + "license_expression_spdx": "MIT", + "detection_count": 1, + "reference_matches": [ + { + "license_expression_spdx": "MIT", + "from_file": "manifests/npm-license-string/package.json", + "start_line": 4, + "end_line": 4, + "matcher": "2-aho", + "score": 100.0, + "matched_length": 2, + "match_coverage": 100.0, + "rule_identifier": "mit_30.RULE" + } + ] + }, + { + "identifier": "mit-a822f434-d61f-f2b1-c792-8b8cb9e7b9bf", + "license_expression_spdx": "MIT", + "detection_count": 1, + "reference_matches": [ + { + "license_expression_spdx": "MIT", + "from_file": "manifests/npm-license-string/package.json", + "start_line": 1, + "end_line": 1, + "matcher": "1-spdx-id", + "score": 100.0, + "matched_length": 1, + "match_coverage": 100.0, + "rule_identifier": "spdx-license-identifier-mit-5da48780aba670b0860c46d899ed42a0f243ff06" + } + ] + } + ], + "files": [ + { + "path": "manifests", + "type": "directory", + "files_count": 4, + "dirs_count": 4, + "size_count": 6962 + }, + { + "path": "manifests/maven", + "type": "directory", + "for_packages": [ + "pkg:maven/javax.persistence/persistence-api@1.0?uuid=fixed-uid-done-for-testing-5642512d1758" + ], + "files_count": 1, + "size_count": 1307 + }, + { + "path": "manifests/maven/persistence-api-1.0.pom", + "type": "file", + "size": 1307, + "sha1": "82107f6781df8da9aa7cb60abc649208256af5cb", + "md5": "e79938fe4e630b02e3526c0195292cc6", + "sha256": "f94648bd92ddf2464e62c56c3833b36927fa8b9803e8ebf3e4cfa7f2d797f3ad", + "sha1_git": "614191600be349e61331a3a0eb2b883493f0db0f", + "mime_type": "text/xml", + "file_type": "XML 1.0 document, ASCII text", + "is_text": true, + "for_packages": [ + "pkg:maven/javax.persistence/persistence-api@1.0?uuid=fixed-uid-done-for-testing-5642512d1758" + ], + "detected_license_expression_spdx": "CDDL-1.0", + "percentage_of_license_text": 12.14, + "urls": [ + { + "url": "http://www.jcp.org/en/jsr/detail?id=220", + "start_line": 15, + "end_line": 15 + }, + { + "url": "http://www.sun.com/cddl/cddl.html", + "start_line": 20, + "end_line": 20 + } + ], + "package_data": [ + { + "purl": "pkg:maven/javax.persistence/persistence-api@1.0" + } + ], + "license_detections": [ + { + "identifier": "cddl_1_0-0507fc0c-7fd5-3ecd-8c7b-5ea542059d4f" + } + ] + }, + { + "path": "manifests/npm-license-mapping", + "type": "directory", + "files_count": 1, + "size_count": 1184 + }, + { + "path": "manifests/npm-license-mapping/package.json", + "type": "file", + "size": 1184, + "sha1": "0ed61bf6912407a143ce96c95bea56ad13463f5b", + "md5": "427e6d3b579b128fed50328ac65b698e", + "sha256": "d292aa647dc82e007ba319c878ec182d6f235f0a923cfe012ffc0ae8b7fa23be", + "sha1_git": "fee016dc24204e079cb9e0217d4439d73e1398ac", + "mime_type": "application/json", + "file_type": "JSON data", + "is_text": true, + "for_packages": [ + "pkg:npm/grunt-esvm@3.2.8?uuid=fixed-uid-done-for-testing-5642512d1758" + ], + "detected_license_expression_spdx": "Apache-2.0", + "percentage_of_license_text": 7.09, + "authors": [ + { + "author": "Spencer Alger", + "start_line": 7, + "end_line": 8 + } + ], + "emails": [ + { + "email": "spencer.alger@elasticsearch.com", + "start_line": 9, + "end_line": 9 + } + ], + "urls": [ + { + "url": "https://github.com/spenceralger/grunt-esvm", + "start_line": 5, + "end_line": 5 + }, + { + "url": "git://github.com/spenceralger/grunt-esvm.git", + "start_line": 13, + "end_line": 13 + }, + { + "url": "https://github.com/spenceralger/grunt-esvm/issues", + "start_line": 16, + "end_line": 16 + }, + { + "url": "https://github.com/spenceralger/grunt-esvm/blob/master/LICENSE.md", + "start_line": 21, + "end_line": 21 + } + ], + "package_data": [ + { + "purl": "pkg:npm/grunt-esvm@3.2.8" + } + ], + "license_detections": [ + { + "identifier": "apache_2_0-ec759ae0-ea5a-f138-793e-388520e080c0" + }, + { + "identifier": "apache_2_0-0d7a2023-aae9-2989-7f00-27b713b809bb" + } + ] + }, + { + "path": "manifests/npm-license-string", + "type": "directory", + "files_count": 1, + "size_count": 1544 + }, + { + "path": "manifests/npm-license-string/package.json", + "type": "file", + "size": 1544, + "sha1": "e6acddf907b7089d197d9d46879cd18ffb8f5198", + "md5": "5ba816691af915c02567f459ae26ebd6", + "sha256": "11129bc3bbf44b2567307ad13a31bc231f08416919e36bbdeabb9195b3e6ad58", + "sha1_git": "99128a9e08f5a23c650d83af5dcf40c3b976753d", + "mime_type": "application/json", + "file_type": "JSON data", + "is_text": true, + "for_packages": [ + "pkg:npm/angular-compare-validator@0.1.1?uuid=fixed-uid-done-for-testing-5642512d1758" + ], + "detected_license_expression_spdx": "MIT", + "percentage_of_license_text": 1.32, + "emails": [ + { + "email": "npm@dan.gl", + "start_line": 28, + "end_line": 28 + } + ], + "urls": [ + { + "url": "https://github.com/GeorgDangl/angular-compare-validator.git", + "start_line": 7, + "end_line": 7 + }, + { + "url": "https://github.com/GeorgDangl/angular-compare-validator/issues", + "start_line": 20, + "end_line": 20 + }, + { + "url": "https://github.com/GeorgDangl/angular-compare-validator#readme", + "start_line": 22, + "end_line": 22 + }, + { + "url": "https://registry.npmjs.org/angular-compare-validator/-/angular-compare-validator-0.1.1.tgz", + "start_line": 33, + "end_line": 33 + } + ], + "package_data": [ + { + "purl": "pkg:npm/angular-compare-validator@0.1.1" + } + ], + "license_detections": [ + { + "identifier": "mit-3fce6ea2-8abd-6c6b-3ede-a37af7c6efee" + } + ] + }, + { + "path": "manifests/pypi", + "type": "directory", + "files_count": 1, + "size_count": 2927 + }, + { + "path": "manifests/pypi/bluepyopt_setup.py", + "type": "file", + "size": 2927, + "sha1": "5507192502255517e006c531d07dd84dc2325be8", + "md5": "6795bed0c9c6b6cb915bfa959a2d1d4a", + "sha256": "4378d297df9fcb4f65fdcd1299e17eef7db86883baf149bc41b0335f943cf006", + "sha1_git": "887bd3bfe3bdba0c8f737a69df38454b3d489ac1", + "mime_type": "text/x-script.python", + "file_type": "Python script, ASCII text executable", + "programming_language": "Python", + "is_text": true, + "is_source": true, + "is_script": true, + "for_packages": [ + "pkg:pypi/bluepyopt?uuid=fixed-uid-done-for-testing-5642512d1758" + ], + "detected_license_expression_spdx": "LGPL-3.0-only", + "percentage_of_license_text": 34.71, + "copyrights": [ + { + "copyright": "Copyright (c) 2016-2020, EPFL/Blue Brain Project", + "start_line": 5, + "end_line": 5 + } + ], + "holders": [ + { + "holder": "EPFL/Blue Brain Project", + "start_line": 5, + "end_line": 5 + } + ], + "authors": [ + { + "author": "BlueBrain Project", + "start_line": 54, + "end_line": 54 + } + ], + "emails": [ + { + "email": "werner.vangeit@epfl.ch", + "start_line": 55, + "end_line": 55 + } + ], + "urls": [ + { + "url": "https://github.com/BlueBrain/BluePyOpt", + "start_line": 7, + "end_line": 7 + } + ], + "package_data": [ + { + "purl": "pkg:pypi/bluepyopt" + } + ], + "license_detections": [ + { + "identifier": "lgpl_3_0-121be3c2-9c80-df84-d3da-8f674e4125c0" + }, + { + "identifier": "lgpl_3_0-2db87bcf-56b4-9d7d-7075-2effae31c631" + }, + { + "identifier": "lgpl_3_0-272571eb-5e68-95b6-ddb0-71de2d8df321" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/formattedcode/test_output_json.py b/tests/formattedcode/test_output_json.py index b9d77046ffa..6c34d026065 100644 --- a/tests/formattedcode/test_output_json.py +++ b/tests/formattedcode/test_output_json.py @@ -33,7 +33,7 @@ def test_json_pretty_print(): check_json_scan(expected, result_file, remove_file_date=True, regen=REGEN_TEST_FIXTURES) -def test_json_compact(): +def test_json_output(): test_dir = test_env.get_test_loc('json/simple') result_file = test_env.get_temp_file('json') run_scan_click(['-clip', test_dir, '--json', result_file]) @@ -81,3 +81,11 @@ def test_scan_output_for_timestamp(): header = result_json['headers'][0] assert 'start_timestamp' in header assert 'end_timestamp' in header + + +def test_compact_json_with_all_scan_options(): + test_dir = test_env.get_test_loc('common/manifests') + result_file = test_env.get_temp_file('json') + run_scan_click(['-clipeu', test_dir, '--compact-json', result_file]) + expected = test_env.get_test_loc('common/manifests-expected.compact.json') + check_json_scan(expected, result_file, remove_file_date=True, regen=REGEN_TEST_FIXTURES) diff --git a/tests/formattedcode/test_reuse_output_plugins.py b/tests/formattedcode/test_reuse_output_plugins.py index eca0a52f0e2..a551105f86b 100644 --- a/tests/formattedcode/test_reuse_output_plugins.py +++ b/tests/formattedcode/test_reuse_output_plugins.py @@ -51,6 +51,11 @@ def test_can_call_json_output_from_regular_code_with_virtualcodebase(): check_plugin(plug, 'reuse/vb.json') +def test_can_call_json_output_from_regular_code_with_virtualcodebase(): + from formattedcode.output_json import JsonCompactOutput as plug + check_plugin(plug, 'reuse/vb.json') + + def test_can_call_jsonpp_output_from_regular_code_with_virtualcodebase(): from formattedcode.output_json import JsonPrettyOutput as plug check_plugin(plug, 'reuse/vb.json') diff --git a/tests/scancode/data/help/help.txt b/tests/scancode/data/help/help.txt index 39c233615e3..0539823cdc9 100644 --- a/tests/scancode/data/help/help.txt +++ b/tests/scancode/data/help/help.txt @@ -48,7 +48,8 @@ Options: --unknown-licenses [EXPERIMENTAL] Detect unknown licenses. output formats: - --json FILE Write scan output as compact JSON to FILE. + --compact-json FILE Write scan output as compact JSON to FILE. + --json FILE Write scan output as JSON to FILE. --json-pp FILE Write scan output as pretty-printed JSON to FILE. --json-lines FILE Write scan output as JSON Lines to FILE. --yaml FILE Write scan output as YAML to FILE. diff --git a/tests/scancode/data/help/help_linux.txt b/tests/scancode/data/help/help_linux.txt index f976d90fc52..b0e462bad98 100644 --- a/tests/scancode/data/help/help_linux.txt +++ b/tests/scancode/data/help/help_linux.txt @@ -50,7 +50,8 @@ Options: --unknown-licenses [EXPERIMENTAL] Detect unknown licenses. output formats: - --json FILE Write scan output as compact JSON to FILE. + --compact-json FILE Write scan output as compact JSON to FILE. + --json FILE Write scan output as JSON to FILE. --json-pp FILE Write scan output as pretty-printed JSON to FILE. --json-lines FILE Write scan output as JSON Lines to FILE. --yaml FILE Write scan output as YAML to FILE.