license: split license parsing into oe.license

In addition to moving this functionality to oe.license, makes the string
preparation more picky before passing it off to the ast compilation. This
ensures that LICENSE entries like 'GPL/BSD' are seen as invalid (due to the
presence of the unsupported '/').

(From OE-Core rev: 20d4068045c76e9dc2aff0c152dd02d6a109c9dd)

Signed-off-by: Christopher Larson <kergoth@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Christopher Larson 2011-12-04 20:03:37 -05:00 committed by Richard Purdie
parent 91378835c6
commit a57de1ac9d
3 changed files with 89 additions and 38 deletions

View File

@ -57,12 +57,9 @@ python do_populate_lic() {
import os import os
import bb import bb
import shutil import shutil
import ast import oe.license
class LicenseVisitor(ast.NodeVisitor):
def generic_visit(self, node):
ast.NodeVisitor.generic_visit(self, node)
class FindVisitor(oe.license.LicenseVisitor):
def visit_Str(self, node): def visit_Str(self, node):
# #
# Until I figure out what to do with # Until I figure out what to do with
@ -71,16 +68,7 @@ python do_populate_lic() {
# we'll just strip out the modifier and put # we'll just strip out the modifier and put
# the base license. # the base license.
find_license(node.s.replace("+", "").replace("*", "")) find_license(node.s.replace("+", "").replace("*", ""))
ast.NodeVisitor.generic_visit(self, node) self.generic_visit(node)
def visit_BinOp(self, node):
op = node.op
if isinstance(op, ast.BitOr):
x = LicenseVisitor()
x.visit(node.left)
x.visit(node.right)
else:
ast.NodeVisitor.generic_visit(self, node)
def copy_license(source, destination, file_name): def copy_license(source, destination, file_name):
try: try:
@ -156,18 +144,11 @@ python do_populate_lic() {
gen_lic_dest = os.path.join(d.getVar('LICENSE_DIRECTORY', True), "common-licenses") gen_lic_dest = os.path.join(d.getVar('LICENSE_DIRECTORY', True), "common-licenses")
clean_licenses = "" v = FindVisitor()
try:
for x in license_types.replace("(", " ( ").replace(")", " ) ").split(): v.visit_string(license_types)
if ((x != "(") and (x != ")") and (x != "&") and (x != "|")): except oe.license.InvalidLicense as exc:
clean_licenses += "'" + x + "'" bb.fatal("%s: %s" % (d.getVar('PF', True), exc))
else:
clean_licenses += " " + x + " "
# lstrip any possible indents, since ast needs python syntax.
node = ast.parse(clean_licenses.lstrip())
v = LicenseVisitor()
v.visit(node)
} }
SSTATETASKS += "do_populate_lic" SSTATETASKS += "do_populate_lic"

32
meta/lib/oe/license.py Normal file
View File

@ -0,0 +1,32 @@
# vi:sts=4:sw=4:et
"""Code for parsing OpenEmbedded license strings"""
import ast
import re
class InvalidLicense(StandardError):
def __init__(self, license):
self.license = license
StandardError.__init__(self)
def __str__(self):
return "invalid license '%s'" % self.license
license_operator = re.compile('([&|() ])')
license_pattern = re.compile('[a-zA-Z0-9.+_\-]+$')
class LicenseVisitor(ast.NodeVisitor):
"""Syntax tree visitor which can accept OpenEmbedded license strings"""
def visit_string(self, licensestr):
new_elements = []
elements = filter(lambda x: x.strip(), license_operator.split(licensestr))
for pos, element in enumerate(elements):
if license_pattern.match(element):
if pos > 0 and license_pattern.match(elements[pos-1]):
new_elements.append('&')
element = '"' + element + '"'
elif not license_operator.match(element):
raise InvalidLicense(element)
new_elements.append(element)
self.visit(ast.parse(' '.join(new_elements)))

View File

@ -0,0 +1,38 @@
import unittest
import oe.license
class SeenVisitor(oe.license.LicenseVisitor):
def __init__(self):
self.seen = []
oe.license.LicenseVisitor.__init__(self)
def visit_Str(self, node):
self.seen.append(node.s)
class TestSingleLicense(unittest.TestCase):
licenses = [
"GPLv2",
"LGPL-2.0",
"Artistic",
"MIT",
"GPLv3+",
"FOO_BAR",
]
invalid_licenses = ["GPL/BSD"]
@staticmethod
def parse(licensestr):
visitor = SeenVisitor()
visitor.visit_string(licensestr)
return visitor.seen
def test_single_licenses(self):
for license in self.licenses:
licenses = self.parse(license)
self.assertListEqual(licenses, [license])
def test_invalid_licenses(self):
for license in self.invalid_licenses:
with self.assertRaises(oe.license.InvalidLicense) as cm:
self.parse(license)
self.assertEqual(cm.exception.license, license)