d0259c42abff5 (Bert Vermeulen 2021-01-21 09:54:12 +0100 1) #!/usr/bin/env python3
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 2) # SPDX-License-Identifier: GPL-2.0
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 3) # Copyright Thomas Gleixner <tglx@linutronix.de>
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 4)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 5) from argparse import ArgumentParser
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 6) from ply import lex, yacc
bed95c43c15eb (Jeremy Cline 2018-08-17 15:44:01 -0700 7) import locale
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 8) import traceback
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 9) import sys
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 10) import git
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 11) import re
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 12) import os
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 13)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 14) class ParserException(Exception):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 15) def __init__(self, tok, txt):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 16) self.tok = tok
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 17) self.txt = txt
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 18)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 19) class SPDXException(Exception):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 20) def __init__(self, el, txt):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 21) self.el = el
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 22) self.txt = txt
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 23)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 24) class SPDXdata(object):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 25) def __init__(self):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 26) self.license_files = 0
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 27) self.exception_files = 0
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 28) self.licenses = [ ]
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 29) self.exceptions = { }
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 30)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 31) # Read the spdx data from the LICENSES directory
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 32) def read_spdxdata(repo):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 33)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 34) # The subdirectories of LICENSES in the kernel source
8d7a7abfc6b42 (Vincenzo Frascino 2019-05-31 22:30:45 -0700 35) # Note: exceptions needs to be parsed as last directory.
8d7a7abfc6b42 (Vincenzo Frascino 2019-05-31 22:30:45 -0700 36) license_dirs = [ "preferred", "dual", "deprecated", "exceptions" ]
fde5e903fb589 (Joe Perches 2018-08-17 15:43:57 -0700 37) lictree = repo.head.commit.tree['LICENSES']
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 38)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 39) spdx = SPDXdata()
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 40)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 41) for d in license_dirs:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 42) for el in lictree[d].traverse():
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 43) if not os.path.isfile(el.path):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 44) continue
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 45)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 46) exception = None
40751c6c9bea6 (Nishanth Menon 2021-07-07 15:48:40 -0500 47) for l in open(el.path, encoding="utf-8").readlines():
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 48) if l.startswith('Valid-License-Identifier:'):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 49) lid = l.split(':')[1].strip().upper()
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 50) if lid in spdx.licenses:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 51) raise SPDXException(el, 'Duplicate License Identifier: %s' %lid)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 52) else:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 53) spdx.licenses.append(lid)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 54)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 55) elif l.startswith('SPDX-Exception-Identifier:'):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 56) exception = l.split(':')[1].strip().upper()
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 57) spdx.exceptions[exception] = []
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 58)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 59) elif l.startswith('SPDX-Licenses:'):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 60) for lic in l.split(':')[1].upper().strip().replace(' ', '').replace('\t', '').split(','):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 61) if not lic in spdx.licenses:
8d7a7abfc6b42 (Vincenzo Frascino 2019-05-31 22:30:45 -0700 62) raise SPDXException(None, 'Exception %s missing license %s' %(exception, lic))
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 63) spdx.exceptions[exception].append(lic)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 64)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 65) elif l.startswith("License-Text:"):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 66) if exception:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 67) if not len(spdx.exceptions[exception]):
8d7a7abfc6b42 (Vincenzo Frascino 2019-05-31 22:30:45 -0700 68) raise SPDXException(el, 'Exception %s is missing SPDX-Licenses' %exception)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 69) spdx.exception_files += 1
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 70) else:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 71) spdx.license_files += 1
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 72) break
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 73) return spdx
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 74)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 75) class id_parser(object):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 76)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 77) reserved = [ 'AND', 'OR', 'WITH' ]
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 78) tokens = [ 'LPAR', 'RPAR', 'ID', 'EXC' ] + reserved
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 79)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 80) precedence = ( ('nonassoc', 'AND', 'OR'), )
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 81)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 82) t_ignore = ' \t'
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 83)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 84) def __init__(self, spdx):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 85) self.spdx = spdx
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 86) self.lasttok = None
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 87) self.lastid = None
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 88) self.lexer = lex.lex(module = self, reflags = re.UNICODE)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 89) # Initialize the parser. No debug file and no parser rules stored on disk
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 90) # The rules are small enough to be generated on the fly
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 91) self.parser = yacc.yacc(module = self, write_tables = False, debug = False)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 92) self.lines_checked = 0
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 93) self.checked = 0
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 94) self.spdx_valid = 0
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 95) self.spdx_errors = 0
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 96) self.curline = 0
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 97) self.deepest = 0
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 98)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 99) # Validate License and Exception IDs
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 100) def validate(self, tok):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 101) id = tok.value.upper()
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 102) if tok.type == 'ID':
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 103) if not id in self.spdx.licenses:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 104) raise ParserException(tok, 'Invalid License ID')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 105) self.lastid = id
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 106) elif tok.type == 'EXC':
bed95c43c15eb (Jeremy Cline 2018-08-17 15:44:01 -0700 107) if id not in self.spdx.exceptions:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 108) raise ParserException(tok, 'Invalid Exception ID')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 109) if self.lastid not in self.spdx.exceptions[id]:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 110) raise ParserException(tok, 'Exception not valid for license %s' %self.lastid)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 111) self.lastid = None
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 112) elif tok.type != 'WITH':
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 113) self.lastid = None
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 114)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 115) # Lexer functions
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 116) def t_RPAR(self, tok):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 117) r'\)'
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 118) self.lasttok = tok.type
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 119) return tok
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 120)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 121) def t_LPAR(self, tok):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 122) r'\('
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 123) self.lasttok = tok.type
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 124) return tok
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 125)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 126) def t_ID(self, tok):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 127) r'[A-Za-z.0-9\-+]+'
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 128)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 129) if self.lasttok == 'EXC':
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 130) print(tok)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 131) raise ParserException(tok, 'Missing parentheses')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 132)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 133) tok.value = tok.value.strip()
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 134) val = tok.value.upper()
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 135)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 136) if val in self.reserved:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 137) tok.type = val
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 138) elif self.lasttok == 'WITH':
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 139) tok.type = 'EXC'
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 140)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 141) self.lasttok = tok.type
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 142) self.validate(tok)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 143) return tok
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 144)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 145) def t_error(self, tok):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 146) raise ParserException(tok, 'Invalid token')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 147)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 148) def p_expr(self, p):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 149) '''expr : ID
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 150) | ID WITH EXC
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 151) | expr AND expr
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 152) | expr OR expr
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 153) | LPAR expr RPAR'''
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 154) pass
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 155)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 156) def p_error(self, p):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 157) if not p:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 158) raise ParserException(None, 'Unfinished license expression')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 159) else:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 160) raise ParserException(p, 'Syntax error')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 161)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 162) def parse(self, expr):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 163) self.lasttok = None
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 164) self.lastid = None
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 165) self.parser.parse(expr, lexer = self.lexer)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 166)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 167) def parse_lines(self, fd, maxlines, fname):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 168) self.checked += 1
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 169) self.curline = 0
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 170) try:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 171) for line in fd:
3a6ab5c7dc114 (Thierry Reding 2018-12-14 14:17:24 -0800 172) line = line.decode(locale.getpreferredencoding(False), errors='ignore')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 173) self.curline += 1
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 174) if self.curline > maxlines:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 175) break
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 176) self.lines_checked += 1
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 177) if line.find("SPDX-License-Identifier:") < 0:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 178) continue
959b49687838c (Thomas Gleixner 2019-01-16 11:26:53 +0100 179) expr = line.split(':')[1].strip()
959b49687838c (Thomas Gleixner 2019-01-16 11:26:53 +0100 180) # Remove trailing comment closure
a5f4cb4288e54 (Aurélien Cedeyn 2019-02-20 22:18:34 +0100 181) if line.strip().endswith('*/'):
959b49687838c (Thomas Gleixner 2019-01-16 11:26:53 +0100 182) expr = expr.rstrip('*/').strip()
c5c553850899e (Lukas Bulwahn 2020-09-26 21:03:54 +0200 183) # Remove trailing xml comment closure
c5c553850899e (Lukas Bulwahn 2020-09-26 21:03:54 +0200 184) if line.strip().endswith('-->'):
c5c553850899e (Lukas Bulwahn 2020-09-26 21:03:54 +0200 185) expr = expr.rstrip('-->').strip()
959b49687838c (Thomas Gleixner 2019-01-16 11:26:53 +0100 186) # Special case for SH magic boot code files
959b49687838c (Thomas Gleixner 2019-01-16 11:26:53 +0100 187) if line.startswith('LIST \"'):
959b49687838c (Thomas Gleixner 2019-01-16 11:26:53 +0100 188) expr = expr.rstrip('\"').strip()
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 189) self.parse(expr)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 190) self.spdx_valid += 1
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 191) #
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 192) # Should we check for more SPDX ids in the same file and
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 193) # complain if there are any?
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 194) #
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 195) break
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 196)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 197) except ParserException as pe:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 198) if pe.tok:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 199) col = line.find(expr) + pe.tok.lexpos
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 200) tok = pe.tok.value
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 201) sys.stdout.write('%s: %d:%d %s: %s\n' %(fname, self.curline, col, pe.txt, tok))
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 202) else:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 203) sys.stdout.write('%s: %d:0 %s\n' %(fname, self.curline, col, pe.txt))
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 204) self.spdx_errors += 1
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 205)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 206) def scan_git_tree(tree):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 207) for el in tree.traverse():
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 208) # Exclude stuff which would make pointless noise
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 209) # FIXME: Put this somewhere more sensible
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 210) if el.path.startswith("LICENSES"):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 211) continue
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 212) if el.path.find("license-rules.rst") >= 0:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 213) continue
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 214) if not os.path.isfile(el.path):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 215) continue
bed95c43c15eb (Jeremy Cline 2018-08-17 15:44:01 -0700 216) with open(el.path, 'rb') as fd:
bed95c43c15eb (Jeremy Cline 2018-08-17 15:44:01 -0700 217) parser.parse_lines(fd, args.maxlines, el.path)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 218)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 219) def scan_git_subtree(tree, path):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 220) for p in path.strip('/').split('/'):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 221) tree = tree[p]
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 222) scan_git_tree(tree)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 223)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 224) if __name__ == '__main__':
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 225)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 226) ap = ArgumentParser(description='SPDX expression checker')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 227) ap.add_argument('path', nargs='*', help='Check path or file. If not given full git tree scan. For stdin use "-"')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 228) ap.add_argument('-m', '--maxlines', type=int, default=15,
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 229) help='Maximum number of lines to scan in a file. Default 15')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 230) ap.add_argument('-v', '--verbose', action='store_true', help='Verbose statistics output')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 231) args = ap.parse_args()
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 232)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 233) # Sanity check path arguments
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 234) if '-' in args.path and len(args.path) > 1:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 235) sys.stderr.write('stdin input "-" must be the only path argument\n')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 236) sys.exit(1)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 237)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 238) try:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 239) # Use git to get the valid license expressions
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 240) repo = git.Repo(os.getcwd())
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 241) assert not repo.bare
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 242)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 243) # Initialize SPDX data
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 244) spdx = read_spdxdata(repo)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 245)
40635128fee8c (Bhaskar Chowdhury 2021-03-26 14:44:43 +0530 246) # Initialize the parser
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 247) parser = id_parser(spdx)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 248)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 249) except SPDXException as se:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 250) if se.el:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 251) sys.stderr.write('%s: %s\n' %(se.el.path, se.txt))
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 252) else:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 253) sys.stderr.write('%s\n' %se.txt)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 254) sys.exit(1)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 255)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 256) except Exception as ex:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 257) sys.stderr.write('FAIL: %s\n' %ex)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 258) sys.stderr.write('%s\n' %traceback.format_exc())
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 259) sys.exit(1)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 260)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 261) try:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 262) if len(args.path) and args.path[0] == '-':
3a6ab5c7dc114 (Thierry Reding 2018-12-14 14:17:24 -0800 263) stdin = os.fdopen(sys.stdin.fileno(), 'rb')
3a6ab5c7dc114 (Thierry Reding 2018-12-14 14:17:24 -0800 264) parser.parse_lines(stdin, args.maxlines, '-')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 265) else:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 266) if args.path:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 267) for p in args.path:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 268) if os.path.isfile(p):
3a6ab5c7dc114 (Thierry Reding 2018-12-14 14:17:24 -0800 269) parser.parse_lines(open(p, 'rb'), args.maxlines, p)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 270) elif os.path.isdir(p):
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 271) scan_git_subtree(repo.head.reference.commit.tree, p)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 272) else:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 273) sys.stderr.write('path %s does not exist\n' %p)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 274) sys.exit(1)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 275) else:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 276) # Full git tree scan
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 277) scan_git_tree(repo.head.commit.tree)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 278)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 279) if args.verbose:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 280) sys.stderr.write('\n')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 281) sys.stderr.write('License files: %12d\n' %spdx.license_files)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 282) sys.stderr.write('Exception files: %12d\n' %spdx.exception_files)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 283) sys.stderr.write('License IDs %12d\n' %len(spdx.licenses))
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 284) sys.stderr.write('Exception IDs %12d\n' %len(spdx.exceptions))
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 285) sys.stderr.write('\n')
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 286) sys.stderr.write('Files checked: %12d\n' %parser.checked)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 287) sys.stderr.write('Lines checked: %12d\n' %parser.lines_checked)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 288) sys.stderr.write('Files with SPDX: %12d\n' %parser.spdx_valid)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 289) sys.stderr.write('Files with errors: %12d\n' %parser.spdx_errors)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 290)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 291) sys.exit(0)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 292)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 293) except Exception as ex:
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 294) sys.stderr.write('FAIL: %s\n' %ex)
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 295) sys.stderr.write('%s\n' %traceback.format_exc())
5385a295ec00e (Thomas Gleixner 2018-04-26 15:54:27 +0200 296) sys.exit(1)