Blob Blame History Raw
#!/usr/bin/python3
import argparse
import os.path
import sys
from lark import Lark, Transformer, v_args
from lark.exceptions import LarkError
import json

allowed_values = [
    "allowed",
    "allowed-content",
    "allowed-documentation",
    "allowed-fonts",
    "allowed-firmware",
]
set_allowed_values = set(allowed_values)

class T(Transformer):
    def license_item(self, s):
        return str(s[0])
    def license(self, s):
        return " ".join(s)
    def start(self, s):
        return s[0]
    def left_parenthesis(self, s):
        return '('
    def right_parenthesis(self, s):
        return ')'
    def operator(self, s):
        return str(s[0]) 
    def __default_token__(self, token):
        if token.value in LICENSES:
            token.value = LICENSES[token]
            if COUNT[token] > 1:
                token.value = "{{{{pick {} choice}}}}".format(token)
                print("Warning: more options on how to interpret {}. Possible options: {}".format(
                        token, VARIATIONS[token]))
        elif token in ["(", ")"]:
            pass
        elif token in ["and", "or"]:
            token.value = token.upper()
        else:
            print("Warning: we do not have SPDX identifier for {}".format(token))
        return token.value


parser = argparse.ArgumentParser(description='Converts old Fedora license string to SPDX identifier.')
parser.add_argument('license', help='license string')
parser.add_argument('--file', help='read the grammar from this file (default /usr/share/license-validate/grammar-shortnames.lark)')
parser.add_argument('--verbose', '-v', action='count', default=0)
opts = parser.parse_args()

data = json.load(open('/usr/share/fedora-license-data/licenses/fedora-licenses.json'))
LICENSES={}
COUNT={}
VARIATIONS={}

if opts.file:
    filename = opts.file
else:
    filename = "/usr/share/license-validate/grammar-shortnames.lark"
    if not os.path.exists(filename):
        filename = 'full-grammar-shortnames.lark'

if not os.path.exists(filename):
    print("The file {0} does not exists.".format(filename))
    sys.exit(128)

with open(filename) as f:
    grammar = f.read()

# read data from fedora-license-data and populate LICENSES, COUNT and VARIATIONS
for l in data.keys():
    license_item = data[l].get("license")
    fedora_item = data[l].get("fedora")
    if license_item:
        if not set_allowed_values.intersection(set(license_item["status"])):
            continue
        if not fedora_item or not fedora_item["legacy-abbreviation"]:
            continue
        for legacy_abbrev in fedora_item["legacy-abbreviation"]:
            spdx = license_item["expression"]
            LICENSES[legacy_abbrev] = spdx
            COUNT[legacy_abbrev] = COUNT.get(legacy_abbrev, 0) + 1
            if not spdx:
                spdx = "no-spdx-yet ({})".format(l)
            if VARIATIONS.get(legacy_abbrev):
                if spdx not in VARIATIONS[legacy_abbrev]:
                    VARIATIONS[legacy_abbrev].append(spdx)
            else:
                VARIATIONS[legacy_abbrev] = [spdx]

parser = Lark(grammar, parser="lalr", keep_all_tokens=True)

def check_if_already_spdx(message):
    # check if it is already SPDX formula
    filename = "/usr/share/fedora-license-data/grammar.lark"
    with open(filename) as f:
        grammar = f.read()
    new_parser = Lark(grammar)
    try:
        new_parser.parse(text)
        print(message)
    except LarkError as e:
        pass

try:
    text = opts.license
    tree = parser.parse(text)
    print(T(visit_tokens=True).transform(tree))
    # approved license
    if opts.verbose > 0:
        print("Approved license")
    check_if_already_spdx("""
Note: the input is already valid SPDX formula, But that may be a coincidence,
because the legacy identifier represented the whole family of licenses.
Please check if the license would match one of the licenses above.
""")
except LarkError as e:
    # not approved license
    print("Not a valid license string in legacy syntax. Pass '--verbose' to get full parser error.")
    if opts.verbose > 0:
        print(e)
    check_if_already_spdx("Note: the input is already valid SPDX formula")
    sys.exit(1)