Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
0f819e4
add test of expr->expr checks
hesa May 29, 2025
609fd75
make usable outside dir
hesa May 29, 2025
251fb75
fix formatters for licenses, usecases, resources
hesa May 29, 2025
7c956cf
create object, instead of manipulating input objects
hesa May 29, 2025
bdc32a4
add formatters for licenses
hesa May 29, 2025
f343d68
add schema for compatibility reply
hesa May 29, 2025
7ec84e9
add validator tests
hesa May 30, 2025
df80ad0
add schema
hesa May 31, 2025
81238ef
parse expressions rather than licenses
hesa May 31, 2025
d400add
add reuse info
hesa May 31, 2025
2d46b5c
add better default example
hesa May 31, 2025
9bad604
separate formating to file
hesa Jun 1, 2025
5af5a3a
code to check returned data against a schema
hesa Jun 1, 2025
6591026
add tests for the expression parser
hesa Jun 1, 2025
e8188f4
check expressions instead of licenses
hesa Jun 1, 2025
8ae6956
update with descriptions and controls
hesa Jun 1, 2025
f1d6eed
clean up
hesa Jun 1, 2025
ed66517
add expression parser and checker, remove format
hesa Jun 1, 2025
c20f2cd
move functions to utils
hesa Jun 1, 2025
36d01e8
adapt to new reply format
hesa Jun 1, 2025
d60e1bc
adapt to new reply format
hesa Jun 1, 2025
dbba360
adapt to new reply format
hesa Jun 1, 2025
c6b1f6d
fix typo
hesa Jun 1, 2025
8cad7a5
detailed report by default
hesa Jun 1, 2025
bca8c13
add vaildate method overriding the one from Licomp
hesa Jun 1, 2025
2a7352d
remove blank
hesa Jun 1, 2025
e47c72a
prevent out ot validation
hesa Jun 3, 2025
bcc9a43
update schema with licomp (copy for now)
hesa Jun 4, 2025
0318f84
simplify code
hesa Jun 12, 2025
7406d82
add log
hesa Jun 12, 2025
1634172
script for basic user tests
hesa Jun 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .reuse/dep5
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: licomp_osadl
Upstream-Name: licomp_toolkit
Upstream-Contact: Henrik Sandklef <hesa@sandklef.com>
Source: https://github.com/hesa/licomp_osadl
Source: https://github.com/hesa/licomp_toolkit

Files: licomp_toolkit/data/reply_schema.json
Copyright: Henrik Sandklef
License: GPL-3.0-or-later

Files: .github/**
Copyright: Henrik Sandklef
Expand Down
15 changes: 15 additions & 0 deletions devel/licomp-all.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

# SPDX-FileCopyrightText: 2025 Henrik Sandklef
#
# SPDX-License-Identifier: GPL-3.0-or-later



RESOURCES=$(./devel/licomp-toolkit supported-resources | jq -r .[] | cut -d : -f 1 | sed 's,_,-,g')

for RESOURCE in $RESOURCES
do
echo "# $RESOURCE"
$RESOURCE $*
done
8 changes: 5 additions & 3 deletions devel/licomp-toolkit
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later

SCRIPT_DIR=$(dirname ${BASH_SOURCE[0]})/../

if [ "$1" = "--local" ]
then
shift
EXTRA_PYTHONPATH=:../licomp:../licomp-osadl:../licomp-reclicense:../licomp-proprietary:../licomp-hermione:../licomp-dwheeler
EXTRA_PYTHONPATH=:${SCRIPT_DIR}/../licomp:${SCRIPT_DIR}/../licomp-osadl:${SCRIPT_DIR}/../licomp-reclicense:${SCRIPT_DIR}/../licomp-proprietary:${SCRIPT_DIR}/../licomp-hermione:${SCRIPT_DIR}/../licomp-dwheeler
fi
if [ "$1" = "" ]
then
ARGS="verify -il MIT -ol MIT"
ARGS="verify -il MIT -ol \"MIT OR X11\""
fi

PYTHONPATH=${EXTRA_PYTHONPATH}:${PYTHONPATH} ./licomp_toolkit/__main__.py $* $ARGS
PYTHONPATH=${EXTRA_PYTHONPATH}:${PYTHONPATH} ${SCRIPT_DIR}/licomp_toolkit/__main__.py $* $ARGS
32 changes: 22 additions & 10 deletions licomp_toolkit/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@
from licomp.interface import LicompException

from licomp_toolkit.toolkit import LicompToolkit
from licomp_toolkit.toolkit import LicompToolkitFormatter
from licomp_toolkit.toolkit import ExpressionExpressionChecker
from licomp_toolkit.format import LicompToolkitFormatter
from licomp_toolkit.config import cli_name
from licomp_toolkit.config import description
from licomp_toolkit.config import epilog
from licomp_toolkit.utils import licomp_results_to_return_code
from licomp_toolkit.schema_checker import LicompToolkitSchemaChecker

from licomp.main_base import LicompParser
from licomp.interface import UseCase
from licomp.interface import Provisioning
from licomp.return_codes import ReturnCodes
from licomp.return_codes import compatibility_status_to_returncode

from flame.license_db import FossLicenses
from flame.exception import FlameException
Expand All @@ -34,14 +36,21 @@ def __init__(self, name, description, epilog, default_usecase, default_provision
def __normalize_license(self, lic_name):
return self.flame.expression_license(lic_name, update_dual=False)['identified_license']

def validate(self, args):
LicompToolkitSchemaChecker().validate_file(args.file_name, deep=True)
return None, ReturnCodes.LICOMP_OK.value, None

def verify(self, args):
formatter = LicompToolkitFormatter.formatter(self.args.output_format)
try:
compatibilities = self.licomp_toolkit.outbound_inbound_compatibility(self.__normalize_license(args.out_license),
self.__normalize_license(args.in_license),
args.usecase,
args.provisioning)
ret_code = licomp_results_to_return_code(compatibilities['summary']['results'])
expr_checker = ExpressionExpressionChecker()
compatibilities = expr_checker.check_compatibility(self.__normalize_license(args.out_license),
self.__normalize_license(args.in_license),
args.usecase,
args.provisioning,
detailed_report=True)

ret_code = compatibility_status_to_returncode(compatibilities['compatibility'])
return formatter.format_compatibilities(compatibilities), ret_code, False
except LicompException as e:
return e, e.return_code.value, True
Expand All @@ -50,7 +59,8 @@ def verify(self, args):

def supported_licenses(self, args):
licenses = self.licomp_toolkit.supported_licenses()
return licenses, ReturnCodes.LICOMP_OK.value, None
formatter = LicompToolkitFormatter.formatter(args.output_format)
return formatter.format_licomp_resources(licenses), ReturnCodes.LICOMP_OK.value, None

def supported_usecases(self, args):
usecases = self.licomp_toolkit.supported_usecases()
Expand All @@ -65,7 +75,8 @@ def supported_provisionings(self, args):
return provisioning_names, ReturnCodes.LICOMP_OK.value, None

def supported_resources(self, args):
return [f'{x.name()}:{x.version()}' for x in self.licomp_toolkit.licomp_resources().values()], ReturnCodes.LICOMP_OK, False
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

def supports_license(self, args):
lic = args.license
Expand Down Expand Up @@ -131,7 +142,8 @@ def main():

res, code, err, func = lct_parser.run_noexit()
if _working_return_code(code):
print(res)
if res:
print(res)
else:
print(res, file=sys.stderr)

Expand Down
2 changes: 1 addition & 1 deletion licomp_toolkit/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
cli_name = 'licomp-toolkit'
module_name = 'licomp_toolkit'

disclaimer = 'This software and the data come with no gurantee. For more information read the disclaimers from the individual compatibility resources, and contact a lawyer to make sure your software is compliant.'
disclaimer = 'This software and the data come with no guarantee. For more information read the disclaimers from the individual compatibility resources, and contact a lawyer to make sure your software is compliant.'

description = """
Simple command line tool to check compatibility between two licenses, given context
Expand Down
255 changes: 255 additions & 0 deletions licomp_toolkit/data/reply_schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
{
"$schema" : "http://json-schema.org/draft-07/schema#",
"$id" : "",
"title" : "Licomp Toolkit Reply",
"type" : "object",
"properties" : {
"compatibility_report": {
"type" : "object",
"$ref": "#/$defs/compatibility_object"
},
"outbound" : {
"$ref": "#/$defs/license",
"description" : "The outbound license expression."
},
"inbound" : {
"$ref": "#/$defs/license",
"description" : "The inbound license expression."
},
"usecase" : {
"type" : "string",
"enum": ["library", "compiler", "snippet", "tool", "test"],
"description" : "Usecase for the compatibility check, e.g. library (as in using the inbound licensed component as a library)"
},
"provisioning" : {
"type" : "string",
"enum": ["source-code-distribution", "binary-distribution", "local-use", "provide-service", "provide-webui"],
"description" : "The way the component is provided to the user for the compatibility check, e.g. binary-distribution"
},
"modification" : {
"type" : "string",
"description" : "Has the component been modified. Currently not used/implemented.",
"enum": [ "unmodified", "modified"]
},
"compatibility" : {
"$ref": "#/$defs/compatibility",
"description" : "The inbound license expression."
}
},
"required" : [ "compatibility_report", "compatibility", "outbound", "inbound" , "usecase" ],
"additionalProperties" : false,
"$defs": {
"compatibility_object": {
"type" : "object",
"oneOf": [
{
"properties": {
"compatibility": {
"$ref": "#/$defs/compatibility",
"description" : "The inbound license expression."
},
"compatibility_type": {
"enum": [ "license" ],
"description": "Describing what is being checked. Can be either expression or license. In this case the value is \"license\"."
},
"compatibility_check": {
"$ref": "#/$defs/compatibility_check"
},
"inbound_license": {
"$ref": "#/$defs/license",
"description" : "The inbound license expression."
},
"outbound_license": {
"$ref": "#/$defs/license",
"description" : "The outbound license expression."
},
"compatibility_details": {
"oneOf": [
{
"type": "object",
"properties": {
"compatibilities": {
"type": "array",
"items": {
"$ref": "#/$defs/licomp_object"
}
}
}
},
{
"type": "null"
}
]
},
"compatibility_object": {
"type" : "object",
"anyOf": [
{
"$ref": "#/$defs/compatibility_object"
},
{
"properties": {}
}
]
}
},
"required": [ "compatibility", "compatibility_type", "compatibility_check", "inbound_license" , "outbound_license", "compatibility_object", "compatibility_details"],
"additionalProperties" : false
},
{
"properties": {
"compatibility" : {
"$ref": "#/$defs/compatibility",
"description" : "The inbound license expression."
},
"compatibility_type": {
"enum": [ "expression" ],
"description": "Describing what is being checked. Can be either expression or license. In this case the value is \"expression\"."
},
"compatibility_check": {
"$ref": "#/$defs/compatibility_check"
},
"inbound_license": {
"$ref": "#/$defs/license",
"description" : "The inbound license expression."
},
"outbound_license": {
"$ref": "#/$defs/license",
"description" : "The inbound license expression."
},
"compatibility_details": {
"type": "null"
},
"operator": {
"enum": [ "AND", "OR" ],
"description" : "The logical operator between two license expressions."
},
"operands": {
"type": "array",
"items": {
"compatibility_object": {
"type" : "object",
"$ref": "#/$defs/compatibility_object"
},
"compatibility": { "type": "string" }
},
"description": "The operands for the operator. The operands can be either a license or an operator."
}
},
"required": [ "compatibility", "compatibility_type", "compatibility_check", "inbound_license" , "outbound_license" , "operator", "operands" ],
"additionalProperties" : false
}
]
},
"compatibility" : {
"type" : "string",
"enum": [ "yes", "no", "depends", "unknown", "unsupported", "mixed", null],
"description" : "The compatbility between the Outbound and Inbound license expressions"
},
"license" : {
"type" : "string",
"minLength": 1
},
"compatibility_check": {
"type": "string",
"enum": [
"outbound-expression -> inbound-expression",
"outbound-expression -> inbound-license",
"outbound-license -> inbound-expression",
"outbound-license -> inbound-license"
],
"description" : "A text describing if outbound license or expression is checked for compatiblility against inbound license or expression."
},
"licomp_object": {
"type" : "object",
"properties" : {
"status" : {
"enum": [ "failure", "success" ],
"description" : "Overall status indicating if the compatibility check succeeded."
},
"status_details" : {
"type" : "object",
"properties" : {
"provisioning_status": {
"enum": [ "failure", "success" ],
"description" : "Status indicating if the provisioning is supported."
},
"usecase_status": {
"enum": [ "failure", "success" ],
"description" : "Status indicating if the usecase is supported."
},
"license_supported_status": {
"enum": [ "failure", "success" ],
"description" : "Status indicating if the licenses are supported."
}
}
},
"outbound" : {
"type" : "string",
"minLength": 1,
"description" : "The outbound license"
},
"inbound" : {
"type" : "string",
"minLength": 1,
"description" : "The inbound license"
},
"usecase" : {
"type" : "string",
"enum": ["library", "compiler", "snippet", "tool", "test"],
"description" : "Usecase for the compatibility check, e.g. library (as in using the inbound licensed component as a library)"
},
"provisioning" : {
"type" : "string",
"enum": ["source-code-distribution", "binary-distribution", "local-use", "provide-service", "provide-webui"],
"description" : "The way the component is provided to the user for the compatibility check, e.g. binary-distribution"
},
"modification" : {
"type" : "string",
"description" : "Has the component been modified. Currently not used/implemented.",
"enum": [ "unmodified", "modified"]
},
"compatibility_status" : {
"enum": [ "yes", "no", "depends", "unknown", "unsupported", null],
"description" : "The compatbility between the Outbound and Inbound license expressions"
},
"explanation" : {
"type" : [ "string", "null" ],
"description" : "A text describing the compatiblity, e.g. how the compatibility was determined"
},
"api_version" : {
"type" : "string",
"pattern": "^[0-9].[0-9](.[0-9]){0,1}$",
"description" : "The api version of the program providing the reply"
},
"resource_name1" : {
"type" : "string",
"minLength": 1,
"description" : "The name of the program providing the reply, e.g. licomp-osadl"
},
"resource_version" : {
"type" : "string",
"pattern": "^[0-9].[0-9](.[0-9]){0,1}$",
"description" : "The versions of the program providing the reply, e.g. licomp-osadl"
},
"resource_disclaimer" : {
"type" : "string",
"minLength": 10,
"description" : "A disclaimer of the program providing the reply."
},
"data_url" : {
"type" : "string",
"minLength": 10,
"description" : "A URL pointing to the data used to provide the resulting compatibility."
},
"resource_url" : {
"type" : "string",
"minLength": 10,
"description" : "A URL pointing to the project page (or similar) for the program providing the resulting compatibility."
}
},
"required" : [ "status", "status_details", "outbound", "inbound", "usecase", "provisioning", "modification", "compatibility_status", "explanation", "api_version", "resource_name1", "resource_version", "resource_disclaimer", "data_url", "resource_url"],
"additionalProperties" : false
}
}
}
Loading