summaryrefslogtreecommitdiffstats
path: root/meta/classes/license.bbclass
blob: 4d036b171ed73c6d3e753f34e0cd36ad349d0399 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# Populates LICENSE_DIRECTORY as set in distro config with the license files as set by
# LIC_FILES_CHKSUM. 
# TODO:
# - We should also enable the ability to put the generated license directory onto the
#  rootfs
# - Gather up more generic licenses
# - There is a real issue revolving around license naming standards. See license names 
#  licenses.conf and compare them to the license names in the recipes. You'll see some
#  differences and that should be corrected.

LICENSE_DIRECTORY ??= "${DEPLOY_DIR}/licenses"
LICSSTATEDIR = "${WORKDIR}/license-destdir/"

addtask populate_lic after do_patch before do_package 
do_populate_lic[dirs] = "${LICSSTATEDIR}/${PN}"
do_populate_lic[cleandirs] = "${LICSSTATEDIR}"

# Standards are great! Everyone has their own. In an effort to standardize licensing
# names, common-licenses will use the SPDX standard license names. In order to not
# break the non-standardized license names that we find in LICENSE, we'll set
# up a bunch of VarFlags to accomodate non-SPDX license names.
#
# We should really discuss standardizing this field, but that's a longer term goal. 
# For now, we can do this and it should grab the most common LICENSE naming variations.

#GPL variations
SPDXLICENSEMAP[GPL] = "GPL-1"
SPDXLICENSEMAP[GPLv2] = "GPL-2"
SPDXLICENSEMAP[GPLv3] = "GPL-3"

#LGPL variations
SPDXLICENSEMAP[LGPL] = "LGPL-2"
SPDXLICENSEMAP[LGPLv2] = "LGPL-2"
SPDXLICENSEMAP[LGPL2.1] = "LGPL-2.1"
SPDXLICENSEMAP[LGPLv2.1] = "LGPL-2.1"
SPDXLICENSEMAP[LGPLv3] = "LGPL-3"

#MPL variations
SPDXLICENSEMAP[MPL] = "MPL-1"
SPDXLICENSEMAP[MPLv1] = "MPL-1"
SPDXLICENSEMAP[MPLv1.1] = "MPL-1"

#MIT variations
SPDXLICENSEMAP[MIT-X] = "MIT"

#Openssl variations
SPDXLICENSEMAP[openssl] = "OpenSSL"

#Other variations
SPDXLICENSEMAP[AFL2.1] = "AFL-2"
SPDXLICENSEMAP[EPLv1.0] = "EPL-1"

python do_populate_lic() {
    """
    Populate LICENSE_DIRECTORY with licenses.
    """
    import os
    import bb
    import shutil
    import ast

    class LicenseVisitor(ast.NodeVisitor):
        def generic_visit(self, node):
            ast.NodeVisitor.generic_visit(self, node)

        def visit_Str(self, node):
            #
            # Until I figure out what to do with
            # the two modifiers I support (or greater = +
            # and "with exceptions" being *
            # we'll just strip out the modifier and put 
            # the base license.
            find_license(node.s.replace("+", "").replace("*", ""))
            ast.NodeVisitor.generic_visit(self, 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):
        try:
            bb.copyfile(os.path.join(source, file_name), os.path.join(destination, file_name))
        except:
            bb.warn("%s: No generic license file exists for: %s at %s" % (pn, file_name, source))
            pass 

    def link_license(source, destination, file_name):
        try:
            os.symlink(os.path.join(source, file_name), os.path.join(destination, "generic_" + file_name))
        except:
            bb.warn("%s: Could not symlink: %s at %s to %s at %s" % (pn, file_name, source, file_name, destination))
            pass

    def find_license(license_type):
        try:
            bb.mkdirhier(gen_lic_dest)
        except:
            pass

        # If the generic does not exist we need to check to see if there is an SPDX mapping to it
        if not os.path.isfile(os.path.join(generic_directory, license_type)):
            if d.getVarFlag('SPDXLICENSEMAP', license_type) != None:
                # Great, there is an SPDXLICENSEMAP. We can copy!
                bb.note("We need to use a SPDXLICENSEMAP for %s" % (license_type))
                spdx_generic = d.getVarFlag('SPDXLICENSEMAP', license_type)
                copy_license(generic_directory, gen_lic_dest, spdx_generic)            
                link_license(gen_lic_dest, destdir, spdx_generic)            
            else:
                # And here is where we warn people that their licenses are lousy
                bb.warn("%s: No generic license file exists for: %s at %s" % (pn, license_type, generic_directory))
                bb.warn("%s: There is also no SPDXLICENSEMAP for this license type: %s at %s" % (pn, license_type, generic_directory))
                pass
        elif os.path.isfile(os.path.join(generic_directory, license_type)):
            copy_license(generic_directory, gen_lic_dest, license_type)
            link_license(gen_lic_dest, destdir, license_type)            

    # All the license types for the package
    license_types = d.getVar('LICENSE', True)
    # All the license files for the package
    lic_files = d.getVar('LIC_FILES_CHKSUM', True)
    pn = d.getVar('PN', True)
    # The base directory we wrangle licenses to
    destdir = os.path.join(d.getVar('LICSSTATEDIR', True), pn)
    # The license files are located in S/LIC_FILE_CHECKSUM.
    srcdir = d.getVar('S', True)
    # Directory we store the generic licenses as set in the distro configuration
    generic_directory = d.getVar('COMMON_LICENSE_DIR', True)
    
    try:
        bb.mkdirhier(destdir)
    except:
        pass

    if not generic_directory:
        raise bb.build.FuncFailed("COMMON_LICENSE_DIR is unset. Please set this in your distro config")

    if not lic_files:
        # No recipe should have an invalid license file. This is checked else
        # where, but let's be pedantic
        bb.note(pn + ": Recipe file does not have license file information.")
        return True

    for url in lic_files.split():
        (type, host, path, user, pswd, parm) = bb.decodeurl(url)
        # We want the license file to be copied into the destination
        srclicfile = os.path.join(srcdir, path)
        ret = bb.copyfile(srclicfile, os.path.join(destdir, os.path.basename(path)))
        # If the copy didn't occur, something horrible went wrong and we fail out
        if ret is False or ret == 0:
            bb.warn("%s could not be copied for some reason. It may not exist. WARN for now." % srclicfile)
 
    gen_lic_dest = os.path.join(d.getVar('LICENSE_DIRECTORY', True), "common-licenses")
    
    clean_licenses = ""

    for x in license_types.replace("(", " ( ").replace(")", " ) ").split():
        if ((x != "(") and (x != ")") and (x != "&") and (x != "|")):
            clean_licenses += "'" + x + "'"
        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"
do_populate_lic[sstate-name] = "populate-lic"
do_populate_lic[sstate-inputdirs] = "${LICSSTATEDIR}"
do_populate_lic[sstate-outputdirs] = "${LICENSE_DIRECTORY}/"

python do_populate_lic_setscene () {
	sstate_setscene(d)
}
addtask do_populate_lic_setscene