From 5e0aa132445fb57dc20f6b781da5638840f68c19 Mon Sep 17 00:00:00 2001 From: Henrik Sandklef Date: Fri, 19 Dec 2025 21:32:28 +0100 Subject: [PATCH 01/12] remove unused list of resources --- licomp_toolkit/toolkit.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/licomp_toolkit/toolkit.py b/licomp_toolkit/toolkit.py index faf2f3d..91a9ba7 100644 --- a/licomp_toolkit/toolkit.py +++ b/licomp_toolkit/toolkit.py @@ -42,24 +42,6 @@ class LicompToolkit(Licomp): def __init__(self): Licomp.__init__(self) self.LICOMP_RESOURCES = {} - self.LICOMP_RESOURCE_NAMES = { - "osadl": { - "package": "licomp_osadl.osadl", - "class": "LicompOsadl", - }, - "reclicense": { - "package": "licomp_reclicense.reclicense", - "class": "LicompReclicense", - }, - "hermione": { - "package": "licomp_hermione.hermione", - "class": "LicompHermione", - }, - "dwheeler": { - "package": "licomp_dwheeler.dwheeler", - "class": "LicompDw", - }, - } def supported_api_version(self): return my_supported_api_version From 64dd961f8a1670203247489449abf6d2888ca219 Mon Sep 17 00:00:00 2001 From: Henrik Sandklef Date: Sat, 20 Dec 2025 23:18:30 +0100 Subject: [PATCH 02/12] pass the resources plainly --- licomp_toolkit/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/licomp_toolkit/__main__.py b/licomp_toolkit/__main__.py index 3449457..aa82bf5 100755 --- a/licomp_toolkit/__main__.py +++ b/licomp_toolkit/__main__.py @@ -106,7 +106,7 @@ def simplify(self, args): def supported_resources(self, args): formatter = LicompToolkitFormatter.formatter(args.output_format) - return formatter.format_licomp_resources([f'{x.name()}:{x.version()}' for x in self.licomp_toolkit.licomp_resources().values()]), ReturnCodes.LICOMP_OK.value, False + return formatter.format_licomp_resources(self.licomp_toolkit.licomp_resources_long()), ReturnCodes.LICOMP_OK.value, False def supports_license(self, args): lic = args.license From 98fbac6022b904e9a754963733d3c790672967a7 Mon Sep 17 00:00:00 2001 From: Henrik Sandklef Date: Sun, 21 Dec 2025 13:43:21 +0100 Subject: [PATCH 03/12] provide more info about resources --- licomp_toolkit/toolkit.py | 42 ++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/licomp_toolkit/toolkit.py b/licomp_toolkit/toolkit.py index 91a9ba7..ebd8887 100644 --- a/licomp_toolkit/toolkit.py +++ b/licomp_toolkit/toolkit.py @@ -41,7 +41,9 @@ class LicompToolkit(Licomp): def __init__(self): Licomp.__init__(self) - self.LICOMP_RESOURCES = {} + self._licomp_reource_classes = [LicompReclicense, LicompOsadl, LicompHermione, LicompProprietary, LicompDw, GnuQuickGuideLicense] + + self._licomp_resources = {} def supported_api_version(self): return my_supported_api_version @@ -58,24 +60,40 @@ def __add_meta(self, compatibilities): compatibilities["meta"]['disclaimer'] = disclaimer def licomp_resources(self): - if not self.LICOMP_RESOURCES: - for licomp in [LicompReclicense, LicompOsadl, LicompHermione, LicompProprietary, LicompDw, GnuQuickGuideLicense]: + if not self._licomp_resources: + for licomp in self._licomp_reource_classes: licomp_instance = licomp() - self.LICOMP_RESOURCES[licomp_instance.name()] = licomp_instance - return self.LICOMP_RESOURCES + self._licomp_resources[licomp_instance.name()] = licomp_instance + return self._licomp_resources + + def licomp_resources_long(self): + _resources = [] + for resource in self.licomp_resources().values(): + _resources.append({ + 'name': resource.name(), + 'version': resource.version(), + 'default': self._resource_is_default(resource) + }) + return _resources + + def _resource_is_optional(self, resource): + return resource.name() in ['licomp_proprietary'] + + def _resource_is_default(self, resource): + return not self._resource_is_optional(resource) def __summarize_compatibility(self, compatibilities, outbound, inbound, usecase, provisioning, resources): compatibilities["summary"] = {} statuses = {} compats = {} compatibilities['nr_licomp'] = len(resources) - # for resource_name in self.licomp_resources(): + # for resource_name in self._licomp_resources(): for compat in compatibilities["compatibilities"]: logging.debug(f': {compat}') logging.debug(f': {compat["resource_name"]}') self.__add_to_list(statuses, compat['status'], compat) self.__add_to_list(compats, compat['compatibility_status'], compat) - compatibilities["summary"]["resources"] = [f'{x.name()}:{x.version()}' for x in self.licomp_resources().values()] + compatibilities["summary"]["resources"] = [f'{x.name()}:{x.version()}' for x in self._licomp_resources().values()] compatibilities["summary"]["outbound"] = outbound compatibilities["summary"]["inbound"] = inbound compatibilities["summary"]["usecase"] = UseCase.usecase_to_string(usecase) @@ -111,10 +129,10 @@ def outbound_inbound_compatibility(self, outbound, inbound, usecase, provisionin compatibilities['compatibilities'] = [] if not resources: - resources = self.licomp_resources().keys() + resources = self._licomp_resources().keys() for resource_name in resources: - resource = self.licomp_resources()[resource_name] + resource = self._licomp_resources()[resource_name] logging.debug(f'-- resource: {resource.name()}') compat = resource.outbound_inbound_compatibility(outbound, inbound, usecase, provisioning=provisioning) @@ -130,7 +148,7 @@ def simplify(self, lic): def supported_licenses(self): licenses = set() - for resource in self.licomp_resources().values(): + for resource in self._licomp_resources().values(): licenses.update(set(resource.supported_licenses())) licenses = list(licenses) licenses.sort() @@ -138,13 +156,13 @@ def supported_licenses(self): def supported_provisionings(self): provisionings = set() - for resource in self.licomp_resources().values(): + for resource in self._licomp_resources().values(): provisionings.update(set(resource.supported_provisionings())) return list(provisionings) def supported_usecases(self): usecases = set() - for resource in self.licomp_resources().values(): + for resource in self._licomp_resources().values(): usecases.update(set(resource.supported_usecases())) return list(usecases) From 17714502d9e43bba97b8373073da845178b43ab1 Mon Sep 17 00:00:00 2001 From: Henrik Sandklef Date: Sun, 21 Dec 2025 23:39:28 +0100 Subject: [PATCH 04/12] add support for optional and standard resources --- licomp_toolkit/toolkit.py | 59 ++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/licomp_toolkit/toolkit.py b/licomp_toolkit/toolkit.py index ebd8887..9d4d073 100644 --- a/licomp_toolkit/toolkit.py +++ b/licomp_toolkit/toolkit.py @@ -41,9 +41,15 @@ class LicompToolkit(Licomp): def __init__(self): Licomp.__init__(self) - self._licomp_reource_classes = [LicompReclicense, LicompOsadl, LicompHermione, LicompProprietary, LicompDw, GnuQuickGuideLicense] - self._licomp_resources = {} + for licomp in [LicompReclicense, LicompOsadl]: + licomp_instance = licomp() + self._licomp_resources[licomp_instance.name()] = licomp_instance + + self._licomp_resources_optional = {} + for licomp in [LicompHermione, LicompProprietary, LicompDw, GnuQuickGuideLicense]: + licomp_instance = licomp() + self._licomp_resources_optional[licomp_instance.name()] = licomp_instance def supported_api_version(self): return my_supported_api_version @@ -60,26 +66,39 @@ def __add_meta(self, compatibilities): compatibilities["meta"]['disclaimer'] = disclaimer def licomp_resources(self): - if not self._licomp_resources: - for licomp in self._licomp_reource_classes: - licomp_instance = licomp() - self._licomp_resources[licomp_instance.name()] = licomp_instance + return self._licomp_resources | self._licomp_resources_optional + + def licomp_standard_resources(self): return self._licomp_resources + def licomp_optional_resources(self): + return self._licomp_resources_optional + + def licomp_resource_long(self, resource): + return { + 'name': resource.name(), + 'version': resource.version(), + 'usecases': [UseCase.usecase_to_string(x) for x in resource.supported_usecases()], + 'provisionings': [Provisioning.provisioning_to_string(x) for x in resource.supported_provisionings()], + 'licenses': resource.supported_licenses(), + 'type': self._resource_type(resource) + } + def licomp_resources_long(self): _resources = [] for resource in self.licomp_resources().values(): - _resources.append({ - 'name': resource.name(), - 'version': resource.version(), - 'default': self._resource_is_default(resource) - }) + _resources.append(self.licomp_resource_long(resource)) return _resources + def _resource_type(self, resource): + if self._resource_is_standard(resource): + return 'standard' + return 'optional' + def _resource_is_optional(self, resource): - return resource.name() in ['licomp_proprietary'] + return resource.name() in self._licomp_resources_optional - def _resource_is_default(self, resource): + def _resource_is_standard(self, resource): return not self._resource_is_optional(resource) def __summarize_compatibility(self, compatibilities, outbound, inbound, usecase, provisioning, resources): @@ -93,7 +112,7 @@ def __summarize_compatibility(self, compatibilities, outbound, inbound, usecase, logging.debug(f': {compat["resource_name"]}') self.__add_to_list(statuses, compat['status'], compat) self.__add_to_list(compats, compat['compatibility_status'], compat) - compatibilities["summary"]["resources"] = [f'{x.name()}:{x.version()}' for x in self._licomp_resources().values()] + compatibilities["summary"]["resources"] = self.licomp_resources_long() compatibilities["summary"]["outbound"] = outbound compatibilities["summary"]["inbound"] = inbound compatibilities["summary"]["usecase"] = UseCase.usecase_to_string(usecase) @@ -129,10 +148,10 @@ def outbound_inbound_compatibility(self, outbound, inbound, usecase, provisionin compatibilities['compatibilities'] = [] if not resources: - resources = self._licomp_resources().keys() + resources = self.licomp_resources().keys() for resource_name in resources: - resource = self._licomp_resources()[resource_name] + resource = self.licomp_resources()[resource_name] logging.debug(f'-- resource: {resource.name()}') compat = resource.outbound_inbound_compatibility(outbound, inbound, usecase, provisioning=provisioning) @@ -148,7 +167,7 @@ def simplify(self, lic): def supported_licenses(self): licenses = set() - for resource in self._licomp_resources().values(): + for resource in self.licomp_resources().values(): licenses.update(set(resource.supported_licenses())) licenses = list(licenses) licenses.sort() @@ -156,13 +175,13 @@ def supported_licenses(self): def supported_provisionings(self): provisionings = set() - for resource in self._licomp_resources().values(): + for resource in self.licomp_resources().values(): provisionings.update(set(resource.supported_provisionings())) return list(provisionings) def supported_usecases(self): usecases = set() - for resource in self._licomp_resources().values(): + for resource in self.licomp_resources().values(): usecases.update(set(resource.supported_usecases())) return list(usecases) @@ -337,7 +356,7 @@ def check_compatibility(self, outbound, inbound, usecase, provisioning, resource except KeyError: raise LicompException(f'Provisioning {provisioning} not supported.', ReturnCodes.LICOMP_UNSUPPORTED_PROVISIONING) - licomp_resources = list(self.licomp_toolkit.licomp_resources().keys()) + licomp_resources = list(self.licomp_toolkit.licomp_standard_resources().keys()) if not resources: resources = licomp_resources else: From a72e77b2dccae66f3c6bffd58ffc2fb04b956640 Mon Sep 17 00:00:00 2001 From: Henrik Sandklef Date: Sun, 21 Dec 2025 23:39:35 +0100 Subject: [PATCH 05/12] add support for optional and standard resources --- licomp_toolkit/__main__.py | 76 +++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/licomp_toolkit/__main__.py b/licomp_toolkit/__main__.py index aa82bf5..5599a7e 100755 --- a/licomp_toolkit/__main__.py +++ b/licomp_toolkit/__main__.py @@ -42,6 +42,26 @@ def validate(self, args): LicompToolkitSchemaChecker().validate_file(args.file_name, deep=True) return None, ReturnCodes.LICOMP_OK.value, None + def _resources_to_use(self, args): + lt = LicompToolkit() + resources = args.resources + new_resources = [] + unsupported = [] + if args.resources == ['all']: + new_resources = list(lt.licomp_resources().keys()) + return new_resources, [] + for resource in resources: + if 'licomp' not in resource: + resource = f'licomp_{resource}' + else: + resource = resource.replace('-', '_') + + if not self.resource_avilable(resource): + unsupported.append(resource) + else: + new_resources.append(resource) + return new_resources, unsupported + def verify(self, args): formatter = LicompToolkitFormatter.formatter(self.args.output_format) try: @@ -50,22 +70,9 @@ def verify(self, args): else: detailed_report = True - resources = args.resources - new_resources = [] - unsupported = [] - for resource in resources: - if 'licomp' not in resource: - resource = f'licomp_{resource}' - else: - resource = resource.replace('-', '_') - - if not self.resource_avilable(resource): - unsupported.append(resource) - else: - new_resources.append(resource) + resources, unsupported = self._resources_to_use(args) if unsupported: return f'Resource(s) {", ".join(unsupported)} is/are not supported', ReturnCodes.LICOMP_UNSUPPORTED_RESOURCE.value, True - resources = new_resources expr_checker = ExpressionExpressionChecker() compatibilities = expr_checker.check_compatibility(self.__normalize_license(args.out_license), self.__normalize_license(args.in_license), @@ -108,20 +115,28 @@ def supported_resources(self, args): formatter = LicompToolkitFormatter.formatter(args.output_format) return formatter.format_licomp_resources(self.licomp_toolkit.licomp_resources_long()), ReturnCodes.LICOMP_OK.value, False + def _supports_helper(self, key, value, output_format): + licomp_resources = [x for x in self.licomp_toolkit.licomp_resources_long() if value in x[key]] + formatter = LicompToolkitFormatter.formatter(output_format) + return formatter.format_licomp_resources(licomp_resources) + def supports_license(self, args): - lic = args.license - licomp_resources = [f'{x.name()}:{x.version()}' for x in self.licomp_toolkit.licomp_resources().values() if lic in x.supported_licenses()] - formatter = LicompToolkitFormatter.formatter(args.output_format) - return formatter.format_licomp_resources(licomp_resources), ReturnCodes.LICOMP_OK.value, None + try: + return self._supports_helper('licenses', args.license, args.output_format), ReturnCodes.LICOMP_OK.value, None + except KeyError: + return None, ReturnCodes.LICOMP_UNSUPPORTED_LICENSE.value, f'License "{args.license}" not supported.' def supports_usecase(self, args): try: - usecase = UseCase.string_to_usecase(args.usecase) - licomp_resources = [f'{x.name()}:{x.version()}' for x in self.licomp_toolkit.licomp_resources().values() if usecase in x.supported_usecases()] - formatter = LicompToolkitFormatter.formatter(args.output_format) - return formatter.format_licomp_resources(licomp_resources), ReturnCodes.LICOMP_OK.value, None + return self._supports_helper('usecases', args.usecase, args.output_format), ReturnCodes.LICOMP_OK.value, None except KeyError: - return None, f'Use case "{args.usecase}" not supported. Supported use cases: {self.supported_usecases(args)[0]}' + return None, ReturnCodes.LICOMP_UNSUPPORTED_USECASE.value, f'Use case "{args.usecase}" not supported. Supported use cases: {self.supported_usecases(args)[0]}' + + def supports_provisioning(self, args): + try: + return self._supports_helper('provisionings', args.provisioning, args.output_format), ReturnCodes.LICOMP_OK.value, None + except KeyError: + return None, ReturnCodes.LICOMP_UNSUPPORTED_PROVISIONING.value, f'Provisioning "{args.provisioning}" not supported. Supported provisionings: {self.supported_provisionings(args)[0]}' def outbound_candidate(self, args): suggester = OutboundSuggester() @@ -152,15 +167,6 @@ def display_compatibility(self, args): {'discard_unsupported': args.discard_unsupported_licenses}) return formatted, ReturnCodes.LICOMP_OK.value, None - def supports_provisioning(self, args): - try: - provisioning = Provisioning.string_to_provisioning(args.provisioning) - licomp_resources = [f'{x.name()}:{x.version()}' for x in self.licomp_toolkit.licomp_resources().values() if provisioning in x.supported_provisionings()] - formatter = LicompToolkitFormatter.formatter(args.output_format) - return formatter.format_licomp_resources(licomp_resources), ReturnCodes.LICOMP_OK.value, None - except KeyError: - return None, f'Provisioning "{args.provisioning}" not supported. Supported provisionings: {self.supported_provisionings(args)[0]}' - def versions(self, args): formatter = LicompToolkitFormatter.formatter(args.output_format) return formatter.format_licomp_versions(self.licomp_toolkit.versions()), ReturnCodes.LICOMP_OK.value, False @@ -169,7 +175,7 @@ def resource_avilable(self, resource): return resource in self.licomp_toolkit.licomp_resources().keys() def _working_return_code(return_code): - return return_code < ReturnCodes.LICOMP_LAST_SUCCESSFUL_CODE.value + return return_code >= 0 and return_code < ReturnCodes.LICOMP_LAST_SUCCESSFUL_CODE.value def main(): logging.debug("Licomp Toolkit") @@ -186,7 +192,7 @@ def main(): parser.add_argument('-r', '--resources', type=str, action='append', - help='use only specified licomp resource', + help='use specified licomp resource. For a list use the commands \'supported-resources\'. Use \'all\' to use all', default=[]) parser.add_argument('-nv', '--no-verbose', @@ -245,6 +251,8 @@ def main(): if _working_return_code(code): if res: print(res) + else: + print(err, file=sys.stderr) else: print(res, file=sys.stderr) From 1e21a2ddb138934489d62a2593ff74bbd9a864f8 Mon Sep 17 00:00:00 2001 From: Henrik Sandklef Date: Sun, 21 Dec 2025 23:40:06 +0100 Subject: [PATCH 06/12] adapt to new optional and standard resources --- licomp_toolkit/format.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/licomp_toolkit/format.py b/licomp_toolkit/format.py index fb2d1cb..c25e1f1 100644 --- a/licomp_toolkit/format.py +++ b/licomp_toolkit/format.py @@ -93,25 +93,33 @@ def format_display_compatibilities(self, compats, settings={}): class TextLicompToolkitFormatter(LicompToolkitFormatter): + def _format_licomp_resource(self, licomp_resource): + name = licomp_resource['name'] + version = licomp_resource['version'] + usecases = ','.join(licomp_resource['usecases']) + provisionings = ','.join(licomp_resource['provisionings']) + resource_type = licomp_resource['type'] + return f'{name}:{version}:{usecases}:{provisionings}:{resource_type}' + def format_licomp_resources(self, licomp_resources): - return "\n".join(licomp_resources) + return '\n'.join([self._format_licomp_resource(x) for x in licomp_resources]) def format_licomp_licenses(self, licomp_licenses): - return "\n".join(licomp_licenses) + return '\n'.join(licomp_licenses) - def __get_responses(self, results, indent=""): + def __get_responses(self, results, indent=''): output = [] for res in ['yes', 'no', 'schneben']: result = results.get(res) if not result: count = 0 else: - count = result["count"] + count = result['count'] output.append(f'{indent}{res}: {count}') return output - def __compatibility_statuses(self, statuses, indent=""): + def __compatibility_statuses(self, statuses, indent=''): output = [] for status, values in statuses.items(): resources = [] @@ -121,7 +129,7 @@ def __compatibility_statuses(self, statuses, indent=""): return output - def __statuses(self, statuses, indent=""): + def __statuses(self, statuses, indent=''): output = [] for status, values in statuses.items(): resources = [] From e7163ca78585eb1dee7b981f66626087dc7184a7 Mon Sep 17 00:00:00 2001 From: Henrik Sandklef Date: Sun, 21 Dec 2025 23:40:18 +0100 Subject: [PATCH 07/12] prepare to remove --- licomp_toolkit/lic_expr.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/licomp_toolkit/lic_expr.py b/licomp_toolkit/lic_expr.py index f396a2c..7310a8e 100644 --- a/licomp_toolkit/lic_expr.py +++ b/licomp_toolkit/lic_expr.py @@ -241,7 +241,7 @@ def summarise_compatibilities(self, operator, operands): OR: self.__summarise_compatibilities_or, }[operator](operands) -class ExpressionExpressionChecker(): +class _OBSOLETE_ExpressionExpressionChecker(): def __init__(self): self.le_checker = LicenseExpressionChecker() @@ -251,7 +251,6 @@ def __parsed_expression_to_name(self, parsed_expression): return parsed_expression[parsed_expression[COMPATIBILITY_TYPE]] def check_compatibility(self, outbound, inbound, usecase, provisioning, detailed_report=False): - inbound_parsed = self.le_parser.parse_license_expression(inbound) outbound_parsed = self.le_parser.parse_license_expression(outbound) From 83b31cb50236a8a0bdce16a5a9b5f823ed6b471e Mon Sep 17 00:00:00 2001 From: Henrik Sandklef Date: Mon, 22 Dec 2025 00:05:25 +0100 Subject: [PATCH 08/12] add tests for standard/optional resources --- tests/python/test_resources.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/python/test_resources.py b/tests/python/test_resources.py index 8284958..d21c2fc 100644 --- a/tests/python/test_resources.py +++ b/tests/python/test_resources.py @@ -14,11 +14,13 @@ lt = LicompToolkit() resource_names = [x for x in lt.licomp_resources()] +standard_resource_names = [x for x in lt.licomp_standard_resources()] +optional_resource_names = [x for x in lt.licomp_optional_resources()] def test_supported_resources(): assert len(lt.licomp_resources()) == 6 -def test_supported_resources_reclicense(): +def test_supported_resources(): assert "licomp_reclicense" in resource_names assert "licomp_osadl" in resource_names assert "licomp_proprietary" in resource_names @@ -26,3 +28,18 @@ def test_supported_resources_reclicense(): assert "licomp_dwheeler" in resource_names assert "licomp_gnuguide" in resource_names +def test_supported_resources_standard(): + assert "licomp_reclicense" in standard_resource_names + assert "licomp_osadl" in standard_resource_names + assert "licomp_proprietary" not in standard_resource_names + assert "licomp_hermione" not in standard_resource_names + assert "licomp_dwheeler" not in standard_resource_names + assert "licomp_gnuguide" not in standard_resource_names + +def test_supported_resources_standard(): + assert "licomp_reclicense" not in optional_resource_names + assert "licomp_osadl" not in optional_resource_names + assert "licomp_proprietary" in optional_resource_names + assert "licomp_hermione" in optional_resource_names + assert "licomp_dwheeler" in optional_resource_names + assert "licomp_gnuguide" in optional_resource_names From 3d50fc550320604bf1365a1ed3687c941ec06408 Mon Sep 17 00:00:00 2001 From: Henrik Sandklef Date: Mon, 22 Dec 2025 10:23:24 +0100 Subject: [PATCH 09/12] update tests to reflect optional resources --- tests/shell/test-cli.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/shell/test-cli.sh b/tests/shell/test-cli.sh index cc5f975..e3b6ace 100755 --- a/tests/shell/test-cli.sh +++ b/tests/shell/test-cli.sh @@ -72,7 +72,7 @@ test_version() test_supp_unsupp() { echo "# test supported/unsupported licenses" - test_licomp_tk "verify -il MIT -ol MIT" "${EXTRACT_COMPAT}.summary.results.yes.count" 5 + test_licomp_tk "verify -il MIT -ol MIT" "${EXTRACT_COMPAT}.summary.results.yes.count" 1 test_licomp_tk "verify -il MIT -ol MIT2" "${EXTRACT_COMPAT}.summary.results.nr_valid" 0 test_licomp_tk "verify -il MIT2 -ol MIT" "${EXTRACT_COMPAT}.summary.results.nr_valid" 0 test_licomp_tk "verify -il MIT2 -ol MIT2" "${EXTRACT_COMPAT}.summary.results.nr_valid" 0 @@ -94,16 +94,16 @@ test_snippet_bindist() echo "# snippet vs bin dist" test_licomp_tk "-u snippet verify -il BSD-3-Clause -ol LGPL-2.1-or-later" "${EXTRACT_COMPAT}.summary.results.nr_valid" 1 test_licomp_tk "-u snippet verify -il BSD-3-Clause -ol LGPL-2.1-or-later" "${EXTRACT_COMPAT}.summary.results.yes.count" 1 - test_licomp_tk "verify -il BSD-3-Clause -ol LGPL-2.1-or-later" "${EXTRACT_COMPAT}.summary.results.nr_valid" 4 - test_licomp_tk "verify -il BSD-3-Clause -ol LGPL-2.1-or-later" "${EXTRACT_COMPAT}.summary.results.yes.count" 4 + test_licomp_tk "verify -il BSD-3-Clause -ol LGPL-2.1-or-later" "${EXTRACT_COMPAT}.summary.results.nr_valid" 1 + test_licomp_tk "verify -il BSD-3-Clause -ol LGPL-2.1-or-later" "${EXTRACT_COMPAT}.summary.results.yes.count" 1 } test_supports_license() { echo "# supports license" test_licomp_tk_text " -of text supports-license MIT" " | wc -l" 6 - test_licomp_tk_text " -of json supports-license MIT" " | jq .[] | wc -l" 6 - test_licomp_tk_text " supports-license MIT" " | jq .[] | wc -l" 6 + test_licomp_tk_text " -of json supports-license MIT" " | jq .[].name | wc -l" 6 + test_licomp_tk_text " supports-license MIT" " | jq .[].name | wc -l" 6 } test_supports_provisioning() From 933efd73d463ee1c04f2bf075a4bb385bdeb0f57 Mon Sep 17 00:00:00 2001 From: Henrik Sandklef Date: Mon, 22 Dec 2025 10:35:31 +0100 Subject: [PATCH 10/12] fix flake errors --- licomp_toolkit/__main__.py | 2 +- licomp_toolkit/toolkit.py | 14 +++++++------- tests/shell/test_returns.sh | 2 +- tests/shell/test_validate.sh | 10 +++++----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/licomp_toolkit/__main__.py b/licomp_toolkit/__main__.py index 5599a7e..06975c5 100755 --- a/licomp_toolkit/__main__.py +++ b/licomp_toolkit/__main__.py @@ -119,7 +119,7 @@ def _supports_helper(self, key, value, output_format): licomp_resources = [x for x in self.licomp_toolkit.licomp_resources_long() if value in x[key]] formatter = LicompToolkitFormatter.formatter(output_format) return formatter.format_licomp_resources(licomp_resources) - + def supports_license(self, args): try: return self._supports_helper('licenses', args.license, args.output_format), ReturnCodes.LICOMP_OK.value, None diff --git a/licomp_toolkit/toolkit.py b/licomp_toolkit/toolkit.py index 9d4d073..c86df09 100644 --- a/licomp_toolkit/toolkit.py +++ b/licomp_toolkit/toolkit.py @@ -76,13 +76,13 @@ def licomp_optional_resources(self): def licomp_resource_long(self, resource): return { - 'name': resource.name(), - 'version': resource.version(), - 'usecases': [UseCase.usecase_to_string(x) for x in resource.supported_usecases()], - 'provisionings': [Provisioning.provisioning_to_string(x) for x in resource.supported_provisionings()], - 'licenses': resource.supported_licenses(), - 'type': self._resource_type(resource) - } + 'name': resource.name(), + 'version': resource.version(), + 'usecases': [UseCase.usecase_to_string(x) for x in resource.supported_usecases()], + 'provisionings': [Provisioning.provisioning_to_string(x) for x in resource.supported_provisionings()], + 'licenses': resource.supported_licenses(), + 'type': self._resource_type(resource), + } def licomp_resources_long(self): _resources = [] diff --git a/tests/shell/test_returns.sh b/tests/shell/test_returns.sh index 460ea2f..dcffdf6 100755 --- a/tests/shell/test_returns.sh +++ b/tests/shell/test_returns.sh @@ -47,7 +47,7 @@ test_verify() run_comp_test 0 "verify -il BSD-3-Clause -ol GPL-2.0-only" # Success and mixed compatibility - run_comp_test 9 "verify -ol 0BSD -il MS-PL" + run_comp_test 2 "verify -ol 0BSD -il MS-PL" # Success and incompatible run_comp_test 2 "verify -il GPL-2.0-only -ol BSD-3-Clause" diff --git a/tests/shell/test_validate.sh b/tests/shell/test_validate.sh index e4a2851..b92df2a 100755 --- a/tests/shell/test_validate.sh +++ b/tests/shell/test_validate.sh @@ -38,7 +38,8 @@ validate_reply() OUTBOUND="$2" VERIFY_EXPECTED=$3 VALIDATE_EXPECTED=$4 - PYTHONPATH=$IMPLEMENTAIONS:${PYTHONPATH}:. python3 licomp_toolkit/__main__.py verify -il "$INBOUND" -ol "$OUTBOUND" > $REPLY_FILE + RESOURCE_ARGS="$5" + PYTHONPATH=$IMPLEMENTAIONS:${PYTHONPATH}:. python3 licomp_toolkit/__main__.py $RESOURCE_ARGS verify -il "$INBOUND" -ol "$OUTBOUND" > $REPLY_FILE RET=$? # echo " ---------------------------||||| RET: $RET == $VERIFY_EXPECTED" printf "%-80s" "verify -il \"$INBOUND\" -ol \"$OUTBOUND\"" @@ -63,9 +64,7 @@ compatibles() validate_reply "BSD-3-Clause OR GPL-2.0-only" "BSD-2-Clause AND ISC" 0 0 validate_reply "BSD-3-Clause OR GPL-2.0-only" "BSD-2-Clause AND Apache-2.0" 0 0 validate_reply "BSD-2-Clause OR Apache-2.0" "GPL-2.0-only" 0 0 - # 9 is mixed - validate_reply "Apache-2.0" "GPL-3.0-only" 9 0 - # 9 is no + validate_reply "Apache-2.0" "GPL-3.0-only" 0 0 validate_reply "GPL-3.0-only" "Apache-2.0" 2 0 } @@ -77,7 +76,8 @@ incompatibles() validate_reply "BSD-3-Clause AND GPL-2.0-only" "BSD-2-Clause AND Apache-2.0" 2 0 validate_reply "GPL-2.0-only" "BSD-2-Clause AND Apache-2.0" 2 0 validate_reply "BSD-2-Clause AND Apache-2.0" "GPL-2.0-only" 2 0 - validate_reply "Apache-2.0" "GPL-2.0-only" 2 0 + validate_reply "Apache-2.0" "GPL-2.0-only" 2 0 + validate_reply "Apache-2.0" "GPL-3.0-only" 9 0 " -r all" } echo "Compatibles" From 4c785a2d34179c100dfb09a3852f21f1488e9041 Mon Sep 17 00:00:00 2001 From: Henrik Sandklef Date: Mon, 22 Dec 2025 10:55:34 +0100 Subject: [PATCH 11/12] improve feedback if license/provisioning/usecases not supported --- licomp_toolkit/__main__.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/licomp_toolkit/__main__.py b/licomp_toolkit/__main__.py index 06975c5..3e8de23 100755 --- a/licomp_toolkit/__main__.py +++ b/licomp_toolkit/__main__.py @@ -121,22 +121,22 @@ def _supports_helper(self, key, value, output_format): return formatter.format_licomp_resources(licomp_resources) def supports_license(self, args): - try: - return self._supports_helper('licenses', args.license, args.output_format), ReturnCodes.LICOMP_OK.value, None - except KeyError: + lic = args.license + if lic not in self.licomp_toolkit.supported_licenses(): return None, ReturnCodes.LICOMP_UNSUPPORTED_LICENSE.value, f'License "{args.license}" not supported.' + return self._supports_helper('licenses', lic, args.output_format), ReturnCodes.LICOMP_OK.value, None def supports_usecase(self, args): - try: - return self._supports_helper('usecases', args.usecase, args.output_format), ReturnCodes.LICOMP_OK.value, None - except KeyError: + usecase = args.usecase + if usecase not in [UseCase.usecase_to_string(x) for x in self.licomp_toolkit.supported_usecases()]: return None, ReturnCodes.LICOMP_UNSUPPORTED_USECASE.value, f'Use case "{args.usecase}" not supported. Supported use cases: {self.supported_usecases(args)[0]}' + return self._supports_helper('usecases', usecase, args.output_format), ReturnCodes.LICOMP_OK.value, None def supports_provisioning(self, args): - try: - return self._supports_helper('provisionings', args.provisioning, args.output_format), ReturnCodes.LICOMP_OK.value, None - except KeyError: + provisioning = args.provisioning + if provisioning not in [Provisioning.provisioning_to_string(x) for x in self.licomp_toolkit.supported_provisionings()]: return None, ReturnCodes.LICOMP_UNSUPPORTED_PROVISIONING.value, f'Provisioning "{args.provisioning}" not supported. Supported provisionings: {self.supported_provisionings(args)[0]}' + return self._supports_helper('provisionings', provisioning, args.output_format), ReturnCodes.LICOMP_OK.value, None def outbound_candidate(self, args): suggester = OutboundSuggester() @@ -252,7 +252,10 @@ def main(): if res: print(res) else: - print(err, file=sys.stderr) + if err: + print(err, file=sys.stderr) + else: + pass else: print(res, file=sys.stderr) From 493d2636afac0764ab241ad099fcd4424b03261e Mon Sep 17 00:00:00 2001 From: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 22 Dec 2025 09:59:25 +0000 Subject: [PATCH 12/12] Autofix (Push test pipeline / generate) https://github.com/hesa/licomp-toolkit/actions/runs/20428451348 --- licomp_toolkit_test.tmp | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 licomp_toolkit_test.tmp diff --git a/licomp_toolkit_test.tmp b/licomp_toolkit_test.tmp new file mode 100644 index 0000000..e101afb --- /dev/null +++ b/licomp_toolkit_test.tmp @@ -0,0 +1,6 @@ +digraph depends { + graph [label="License Compatibility Graph (library)" labelloc=t] + node [shape=plaintext] + "MIT" -> "BSD-3-Clause" [color="darkblue" style="dotted"] + "BSD-3-Clause" -> "MIT" [color="darkgreen" ] +}