-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathlicense_check.py
executable file
·133 lines (98 loc) · 3.93 KB
/
license_check.py
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
#!/bin/python3
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) Bao Project and Contributors. All rights reserved
"""
Check for SPDX license headers and copyright notice in source files
"""
import os
import sys
import re
import argparse
import license_expression
def eprint(*args, **kwargs):
"""Print to stderr."""
print(*args, file=sys.stderr, **kwargs)
SPDX_PARSER = None
def check_copyright(filename, copyright_notice):
"""Check if file `filename` contains a `copyright` notice string"""
try:
file = open(filename, encoding="utf-8")
except FileNotFoundError:
eprint(f'Can\'t open file \'{filename}\'')
return False
with file:
for line in file:
if copyright_notice in line:
return True
eprint(f'Copyright not found: \t\t{filename}')
return False
def check_license(filename, spdx_expr):
"""Check if 'filename' has a SPDX identifier complying with 'spdx_exr'"""
# TODO: improve regex to support multiple licenses (AND, OR) and exceptions (WITH)
spdx_regex = r'SPDX-License-Identifier: \(?(?P<license_expr>\S*)\)?'
try:
file = open(filename, encoding="utf-8")
except FileNotFoundError:
eprint(f'Can\'t open file \'{filename}\'')
return False
with file:
for line in file:
if line.strip() == '':
continue
# allow not in first line in case of scripts
if line.startswith('#!'):
continue
match = re.search(spdx_regex, line)
if match is not None:
license_expr_str = match.groupdict()['license_expr']
spdx_parser = license_expression.get_spdx_licensing()
license_expr_info = spdx_parser.validate(license_expr_str)
if license_expr_info.errors:
eprint(f'Invalid SPDX expression in \'{filename}\':')
for err in license_expr_info.errors:
eprint('\t' + err)
return False
license_expr = spdx_parser.parse(license_expr_str)
if not spdx_parser.contains(spdx_expr, license_expr):
eprint(f'\'{license_expr_str}\' in \'{filename}\' ' \
f'does not comply with supplied SPDX expression \'{spdx_expr}\'')
return False
return True
eprint(f'License not found: \t\t{filename}')
return False
def main():
"""
main function parses arguments, initializes the spdx expression and calls
check license on each source file
"""
parser = argparse.ArgumentParser(description='Check for SPDX ID in source files')
parser.add_argument('-l', '--license', metavar='license',
help='SPDX expression describing allowed licenses')
parser.add_argument('-c', '--copyright', metavar='copyright',
help='Copyright notice to be checked for')
parser.add_argument('file', metavar='file', nargs='+',
help='Source files to be checked for license')
args = parser.parse_args()
spdx_parser = license_expression.get_spdx_licensing()
spdx_expr = args.license
if not spdx_expr:
spdx_expr = 'Apache-2.0'
spdx_expr_info = spdx_parser.validate(spdx_expr)
if spdx_expr_info.errors:
eprint('Invalid supplied SPDX expression\':')
for err in spdx_expr_info.errors:
eprint('\t' + err)
return
spdx_expr = spdx_parser.parse(spdx_expr)
copyright_notice = args.copyright
if not copyright_notice:
copyright_notice = "Copyright (c) Bao Project and Contributors. All rights reserved"
success = True
for file in args.file:
rel_path = os.path.relpath(file, os.getcwd())
success = check_license(rel_path, spdx_expr) and success
success = check_copyright(rel_path, copyright_notice) and success
if not success:
sys.exit(-1)
if __name__ == "__main__":
main()