diff options
author | Billy Donahue <billy.donahue@mongodb.com> | 2021-02-11 04:11:47 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-02-12 20:58:51 +0000 |
commit | c8a02bacb3c3fa1a530669af7373603896f336d0 (patch) | |
tree | e6eef830846ac7b3637935e467dbdcd32ed813bf /buildscripts/linter | |
parent | 28ff000bbd83e9856e4b470554a98c36eabf4ce9 (diff) | |
download | mongo-c8a02bacb3c3fa1a530669af7373603896f336d0.tar.gz |
SERVER-54475 Add SSPL to shim files. Refactor sspl check.
simplecpplint.py
Improve license check
Clearer exception handling
Fix process exit code (success:0, lintFail:1, internalError:2)
Add '-present' year range suffix to copyright notice in a few c++ files.
Diffstat (limited to 'buildscripts/linter')
-rw-r--r-- | buildscripts/linter/simplecpplint.py | 151 |
1 files changed, 76 insertions, 75 deletions
diff --git a/buildscripts/linter/simplecpplint.py b/buildscripts/linter/simplecpplint.py index e0b3e4a04e2..3acf5a9d19f 100644 --- a/buildscripts/linter/simplecpplint.py +++ b/buildscripts/linter/simplecpplint.py @@ -78,6 +78,36 @@ _RE_GENERIC_FCV_REF = re.compile(r'(' + '|'.join(GENERIC_FCV) + r')\b') class Linter: """Simple C++ Linter.""" + _license_header = '''\ +/** + * Copyright (C) {year}-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */'''.splitlines() + def __init__(self, file_name, raw_lines): """Create new linter.""" self.file_name = file_name @@ -90,28 +120,13 @@ class Linter: self.found_config_header = False def lint(self): - """Run linter.""" + """Run linter, returning error count.""" # 3 steps: - # 1. Check for header - # 2. Check for NOLINT and Strip multi line comments - # 3. Run per line checks + # 1. Check for header + # 2. Check for NOLINT and Strip multi line comments + # 3. Run per-line checks - # The license header is 28 lines and we are 0 indexed unless the file does not have the - # correct header. - start_line = 0 - - # We expect the SSPL license in all files but it is not expected in the Enterprise code - expect_sspl_license = "enterprise" not in self.file_name - has_sspl_license = self._check_for_server_side_public_license(3) - - if has_sspl_license: - start_line = 27 - - if not expect_sspl_license: - self._error( - 0, 'legal/enterprise_license', 'Incorrect license header found. ' - 'Expected Enterprise license. ' - 'See https://github.com/mongodb/mongo/wiki/Server-Code-Style') + start_line = self._check_for_server_side_public_license() self._check_and_strip_comments() @@ -223,57 +238,36 @@ class Linter: self._error(linenum, 'mongodb/ctype', 'Use of prohibited <ctype.h> or <cctype> header, use "mongo/util/ctype.h"') - def _check_for_server_side_public_license(self, copyright_offset): - license_header = '''\ - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */'''.splitlines() - - # We expect the first line of the license header to follow shortly after the - # "Copyright" message. - if r'This program is free software' in self.raw_lines[copyright_offset]: - license_header_start_line = copyright_offset - for i in range(len(license_header)): # pylint: disable=consider-using-enumerate - line = i + license_header_start_line - # We don't trim the lines so we check length and then do strncmp - if line >= len(self.raw_lines) or \ - len(self.raw_lines[line]) != len(license_header[i]) + 1 or \ - self.raw_lines[line][:len(license_header[i])] != license_header[i]: - self._error( - 0, 'legal/license', 'Incorrect license header found. ' - 'Expected "' + license_header[i] + '". ' - 'See https://github.com/mongodb/mongo/wiki/Server-Code-Style') - # We break here to stop reporting legal/license errors for this file. - return False - else: - self._error( - 0, 'legal/license', 'No license header found. ' - 'See https://github.com/mongodb/mongo/wiki/Server-Code-Style') - return False - - return True + def _license_error(self, linenum, msg, category='legal/license'): + style_url = 'https://github.com/mongodb/mongo/wiki/Server-Code-Style' + self._error(linenum, category, '{} See {}'.format(msg, style_url)) + return (False, linenum) + + def _check_for_server_side_public_license(self): + """Return the number of the line at which the check ended.""" + src_iter = (x.rstrip() for x in self.raw_lines) + linenum = 0 + for linenum, lic_line in enumerate(self._license_header): + src_line = next(src_iter, None) + if src_line is None: + self._license_error(linenum, 'Missing or incomplete license header.') + return linenum + lic_re = re.escape(lic_line).replace(r'\{year\}', r'\d{4}') + if not re.fullmatch(lic_re, src_line): + self._license_error( + linenum, 'Incorrect license header.\n' + ' Expected: "{}"\n' + ' Received: "{}"\n'.format(lic_line, src_line)) + return linenum + + # Warn if SSPL appears in Enterprise code, which has a different license. + expect_sspl_license = "enterprise" not in self.file_name + if not expect_sspl_license: + self._license_error(linenum, + 'Incorrect license header found. Expected Enterprise license.', + category='legal/enterprise_license') + return linenum + return linenum def _check_for_mongo_config_header(self, linenum): """Check for a config file.""" @@ -342,7 +336,7 @@ def lint_file(file_name): def main(): - # type: () -> None + # type: () -> int """Execute Main Entry point.""" parser = argparse.ArgumentParser(description='MongoDB Simple C++ Linter.') @@ -355,9 +349,16 @@ def main(): if args.verbose: logging.basicConfig(level=logging.DEBUG) - if not lint_file(args.file): - sys.exit(1) + try: + error_count = lint_file(args.file) + if error_count != 0: + print('File "{}" failed with {} errors.'.format(args.file, error_count)) + return 1 + return 0 + except Exception as ex: # pylint: disable=broad-except + print('Exception while checking file "{}": {}'.format(args.file, ex)) + return 2 if __name__ == '__main__': - main() + sys.exit(main()) |