xref: /OK3568_Linux_fs/yocto/poky/scripts/contrib/convert-spdx-licenses.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#!/usr/bin/env python3
2*4882a593Smuzhiyun#
3*4882a593Smuzhiyun# Conversion script to change LICENSE entries to SPDX identifiers
4*4882a593Smuzhiyun#
5*4882a593Smuzhiyun# Copyright (C) 2021-2022 Richard Purdie
6*4882a593Smuzhiyun#
7*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only
8*4882a593Smuzhiyun#
9*4882a593Smuzhiyun
10*4882a593Smuzhiyunimport re
11*4882a593Smuzhiyunimport os
12*4882a593Smuzhiyunimport sys
13*4882a593Smuzhiyunimport tempfile
14*4882a593Smuzhiyunimport shutil
15*4882a593Smuzhiyunimport mimetypes
16*4882a593Smuzhiyun
17*4882a593Smuzhiyunif len(sys.argv) < 2:
18*4882a593Smuzhiyun    print("Please specify a directory to run the conversion script against.")
19*4882a593Smuzhiyun    sys.exit(1)
20*4882a593Smuzhiyun
21*4882a593Smuzhiyunlicense_map = {
22*4882a593Smuzhiyun"AGPL-3" : "AGPL-3.0-only",
23*4882a593Smuzhiyun"AGPL-3+" : "AGPL-3.0-or-later",
24*4882a593Smuzhiyun"AGPLv3" : "AGPL-3.0-only",
25*4882a593Smuzhiyun"AGPLv3+" : "AGPL-3.0-or-later",
26*4882a593Smuzhiyun"AGPLv3.0" : "AGPL-3.0-only",
27*4882a593Smuzhiyun"AGPLv3.0+" : "AGPL-3.0-or-later",
28*4882a593Smuzhiyun"AGPL-3.0" : "AGPL-3.0-only",
29*4882a593Smuzhiyun"AGPL-3.0+" : "AGPL-3.0-or-later",
30*4882a593Smuzhiyun"BSD-0-Clause" : "0BSD",
31*4882a593Smuzhiyun"GPL-1" : "GPL-1.0-only",
32*4882a593Smuzhiyun"GPL-1+" : "GPL-1.0-or-later",
33*4882a593Smuzhiyun"GPLv1" : "GPL-1.0-only",
34*4882a593Smuzhiyun"GPLv1+" : "GPL-1.0-or-later",
35*4882a593Smuzhiyun"GPLv1.0" : "GPL-1.0-only",
36*4882a593Smuzhiyun"GPLv1.0+" : "GPL-1.0-or-later",
37*4882a593Smuzhiyun"GPL-1.0" : "GPL-1.0-only",
38*4882a593Smuzhiyun"GPL-1.0+" : "GPL-1.0-or-later",
39*4882a593Smuzhiyun"GPL-2" : "GPL-2.0-only",
40*4882a593Smuzhiyun"GPL-2+" : "GPL-2.0-or-later",
41*4882a593Smuzhiyun"GPLv2" : "GPL-2.0-only",
42*4882a593Smuzhiyun"GPLv2+" : "GPL-2.0-or-later",
43*4882a593Smuzhiyun"GPLv2.0" : "GPL-2.0-only",
44*4882a593Smuzhiyun"GPLv2.0+" : "GPL-2.0-or-later",
45*4882a593Smuzhiyun"GPL-2.0" : "GPL-2.0-only",
46*4882a593Smuzhiyun"GPL-2.0+" : "GPL-2.0-or-later",
47*4882a593Smuzhiyun"GPL-3" : "GPL-3.0-only",
48*4882a593Smuzhiyun"GPL-3+" : "GPL-3.0-or-later",
49*4882a593Smuzhiyun"GPLv3" : "GPL-3.0-only",
50*4882a593Smuzhiyun"GPLv3+" : "GPL-3.0-or-later",
51*4882a593Smuzhiyun"GPLv3.0" : "GPL-3.0-only",
52*4882a593Smuzhiyun"GPLv3.0+" : "GPL-3.0-or-later",
53*4882a593Smuzhiyun"GPL-3.0" : "GPL-3.0-only",
54*4882a593Smuzhiyun"GPL-3.0+" : "GPL-3.0-or-later",
55*4882a593Smuzhiyun"LGPLv2" : "LGPL-2.0-only",
56*4882a593Smuzhiyun"LGPLv2+" : "LGPL-2.0-or-later",
57*4882a593Smuzhiyun"LGPLv2.0" : "LGPL-2.0-only",
58*4882a593Smuzhiyun"LGPLv2.0+" : "LGPL-2.0-or-later",
59*4882a593Smuzhiyun"LGPL-2.0" : "LGPL-2.0-only",
60*4882a593Smuzhiyun"LGPL-2.0+" : "LGPL-2.0-or-later",
61*4882a593Smuzhiyun"LGPL2.1" : "LGPL-2.1-only",
62*4882a593Smuzhiyun"LGPL2.1+" : "LGPL-2.1-or-later",
63*4882a593Smuzhiyun"LGPLv2.1" : "LGPL-2.1-only",
64*4882a593Smuzhiyun"LGPLv2.1+" : "LGPL-2.1-or-later",
65*4882a593Smuzhiyun"LGPL-2.1" : "LGPL-2.1-only",
66*4882a593Smuzhiyun"LGPL-2.1+" : "LGPL-2.1-or-later",
67*4882a593Smuzhiyun"LGPLv3" : "LGPL-3.0-only",
68*4882a593Smuzhiyun"LGPLv3+" : "LGPL-3.0-or-later",
69*4882a593Smuzhiyun"LGPL-3.0" : "LGPL-3.0-only",
70*4882a593Smuzhiyun"LGPL-3.0+" : "LGPL-3.0-or-later",
71*4882a593Smuzhiyun"MPL-1" : "MPL-1.0",
72*4882a593Smuzhiyun"MPLv1" : "MPL-1.0",
73*4882a593Smuzhiyun"MPLv1.1" : "MPL-1.1",
74*4882a593Smuzhiyun"MPLv2" : "MPL-2.0",
75*4882a593Smuzhiyun"MIT-X" : "MIT",
76*4882a593Smuzhiyun"MIT-style" : "MIT",
77*4882a593Smuzhiyun"openssl" : "OpenSSL",
78*4882a593Smuzhiyun"PSF" : "PSF-2.0",
79*4882a593Smuzhiyun"PSFv2" : "PSF-2.0",
80*4882a593Smuzhiyun"Python-2" : "Python-2.0",
81*4882a593Smuzhiyun"Apachev2" : "Apache-2.0",
82*4882a593Smuzhiyun"Apache-2" : "Apache-2.0",
83*4882a593Smuzhiyun"Artisticv1" : "Artistic-1.0",
84*4882a593Smuzhiyun"Artistic-1" : "Artistic-1.0",
85*4882a593Smuzhiyun"AFL-2" : "AFL-2.0",
86*4882a593Smuzhiyun"AFL-1" : "AFL-1.2",
87*4882a593Smuzhiyun"AFLv2" : "AFL-2.0",
88*4882a593Smuzhiyun"AFLv1" : "AFL-1.2",
89*4882a593Smuzhiyun"CDDLv1" : "CDDL-1.0",
90*4882a593Smuzhiyun"CDDL-1" : "CDDL-1.0",
91*4882a593Smuzhiyun"EPLv1.0" : "EPL-1.0",
92*4882a593Smuzhiyun"FreeType" : "FTL",
93*4882a593Smuzhiyun"Nauman" : "Naumen",
94*4882a593Smuzhiyun"tcl" : "TCL",
95*4882a593Smuzhiyun"vim" : "Vim",
96*4882a593Smuzhiyun"SGIv1" : "SGI-1",
97*4882a593Smuzhiyun}
98*4882a593Smuzhiyun
99*4882a593Smuzhiyundef processfile(fn):
100*4882a593Smuzhiyun    print("processing file '%s'" % fn)
101*4882a593Smuzhiyun    try:
102*4882a593Smuzhiyun        fh, abs_path = tempfile.mkstemp()
103*4882a593Smuzhiyun        modified = False
104*4882a593Smuzhiyun        with os.fdopen(fh, 'w') as new_file:
105*4882a593Smuzhiyun            with open(fn, "r") as old_file:
106*4882a593Smuzhiyun                for line in old_file:
107*4882a593Smuzhiyun                    if not line.startswith("LICENSE"):
108*4882a593Smuzhiyun                        new_file.write(line)
109*4882a593Smuzhiyun                        continue
110*4882a593Smuzhiyun                    orig = line
111*4882a593Smuzhiyun                    for license in sorted(license_map, key=len, reverse=True):
112*4882a593Smuzhiyun                        for ending in ['"', "'", " ", ")"]:
113*4882a593Smuzhiyun                            line = line.replace(license + ending, license_map[license] + ending)
114*4882a593Smuzhiyun                    if orig != line:
115*4882a593Smuzhiyun                        modified = True
116*4882a593Smuzhiyun                    new_file.write(line)
117*4882a593Smuzhiyun        new_file.close()
118*4882a593Smuzhiyun        if modified:
119*4882a593Smuzhiyun            shutil.copymode(fn, abs_path)
120*4882a593Smuzhiyun            os.remove(fn)
121*4882a593Smuzhiyun            shutil.move(abs_path, fn)
122*4882a593Smuzhiyun    except UnicodeDecodeError:
123*4882a593Smuzhiyun        pass
124*4882a593Smuzhiyun
125*4882a593Smuzhiyunourname = os.path.basename(sys.argv[0])
126*4882a593Smuzhiyunourversion = "0.01"
127*4882a593Smuzhiyun
128*4882a593Smuzhiyunif os.path.isfile(sys.argv[1]):
129*4882a593Smuzhiyun    processfile(sys.argv[1])
130*4882a593Smuzhiyun    sys.exit(0)
131*4882a593Smuzhiyun
132*4882a593Smuzhiyunfor targetdir in sys.argv[1:]:
133*4882a593Smuzhiyun    print("processing directory '%s'" % targetdir)
134*4882a593Smuzhiyun    for root, dirs, files in os.walk(targetdir):
135*4882a593Smuzhiyun        for name in files:
136*4882a593Smuzhiyun            if name == ourname:
137*4882a593Smuzhiyun                continue
138*4882a593Smuzhiyun            fn = os.path.join(root, name)
139*4882a593Smuzhiyun            if os.path.islink(fn):
140*4882a593Smuzhiyun                continue
141*4882a593Smuzhiyun            if "/.git/" in fn or fn.endswith(".html") or fn.endswith(".patch") or fn.endswith(".m4") or fn.endswith(".diff") or fn.endswith(".orig"):
142*4882a593Smuzhiyun                continue
143*4882a593Smuzhiyun            processfile(fn)
144*4882a593Smuzhiyun
145*4882a593Smuzhiyunprint("All files processed with version %s" % ourversion)
146