Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Checks third-party licenses for the purposes of the Android WebView build. | 6 """Checks third-party licenses for the purposes of the Android WebView build. |
| 7 | 7 |
| 8 The Android tree includes a snapshot of Chromium in order to power the system | 8 The Android tree includes a snapshot of Chromium in order to power the system |
| 9 WebView. This tool checks that all code uses open-source licenses compatible | 9 WebView. This tool checks that all code uses open-source licenses compatible |
| 10 with Android, and that we meet the requirements of those licenses. It can also | 10 with Android, and that we meet the requirements of those licenses. It can also |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 67 if metadata.get('License Android Compatible', 'no') == 'yes': | 67 if metadata.get('License Android Compatible', 'no') == 'yes': |
| 68 continue | 68 continue |
| 69 license = re.split(' [Ll]icenses?$', metadata['License'])[0] | 69 license = re.split(' [Ll]icenses?$', metadata['License'])[0] |
| 70 tokens = [x.strip() for x in re.split(' and |,', license) if len(x) > 0] | 70 tokens = [x.strip() for x in re.split(' and |,', license) if len(x) > 0] |
| 71 for token in tokens: | 71 for token in tokens: |
| 72 if not re.match(regex, token, re.IGNORECASE): | 72 if not re.match(regex, token, re.IGNORECASE): |
| 73 result.append(directory) | 73 result.append(directory) |
| 74 break | 74 break |
| 75 return result | 75 return result |
| 76 | 76 |
| 77 SCAN_OK = 0 | |
| 78 SCAN_WARNINGS = 1 << 0 | |
| 79 SCAN_ERRORS = 1 << 1 | |
|
mkosiba (inactive)
2013/02/06 15:40:49
It seems these are exclusive, not flags, so how ab
mnaganov (inactive)
2013/02/06 16:42:17
Fixed, thanks!
| |
| 77 | 80 |
| 78 def _CheckLicenseHeaders(excluded_dirs_list, whitelisted_files): | 81 def _CheckLicenseHeaders(excluded_dirs_list, whitelisted_files): |
| 79 """Checks that all files which are not in a listed third-party directory, | 82 """Checks that all files which are not in a listed third-party directory, |
| 80 and which do not use the standard Chromium license, are whitelisted. | 83 and which do not use the standard Chromium license, are whitelisted. |
| 81 Args: | 84 Args: |
| 82 excluded_dirs_list: The list of directories to exclude from scanning. | 85 excluded_dirs_list: The list of directories to exclude from scanning. |
| 83 whitelisted_files: The whitelist of files. | 86 whitelisted_files: The whitelist of files. |
| 84 Returns: | 87 Returns: |
| 85 True if all files with non-standard license headers are whitelisted and the | 88 SCAN_OK if all files with non-standard license headers are whitelisted and |
|
mkosiba (inactive)
2013/02/06 15:40:49
if you go with the suggestion above you could say
mnaganov (inactive)
2013/02/06 16:42:17
The interpretation of results are method-dependent
mkosiba (inactive)
2013/02/06 16:54:51
ah, ok then.
| |
| 86 whitelist contains no stale entries, otherwise false. | 89 the whitelist contains no stale entries; |
| 90 SCAN_WARNINGS if there are stale entries; | |
| 91 SCAN_ERRORS if new non-whitelisted entries found. | |
| 87 """ | 92 """ |
| 88 | 93 |
| 89 excluded_dirs_list = [d for d in excluded_dirs_list if not 'third_party' in d] | 94 excluded_dirs_list = [d for d in excluded_dirs_list if not 'third_party' in d] |
| 90 # Using a commond pattern for third-partyies makes the ignore regexp shorter | 95 # Using a commond pattern for third-partyies makes the ignore regexp shorter |
| 91 excluded_dirs_list.append('third_party') | 96 excluded_dirs_list.append('third_party') |
| 92 # VCS dirs | 97 # VCS dirs |
| 93 excluded_dirs_list.append('.git') | 98 excluded_dirs_list.append('.git') |
| 94 excluded_dirs_list.append('.svn') | 99 excluded_dirs_list.append('.svn') |
| 95 # Build output | 100 # Build output |
| 96 excluded_dirs_list.append('out/Debug') | 101 excluded_dirs_list.append('out/Debug') |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 122 for l in lines: | 127 for l in lines: |
| 123 entries = l.split('\t') | 128 entries = l.split('\t') |
| 124 if entries[1] == "GENERATED FILE": | 129 if entries[1] == "GENERATED FILE": |
| 125 continue | 130 continue |
| 126 copyrights = entries[1].split(' / ') | 131 copyrights = entries[1].split(' / ') |
| 127 for c in copyrights: | 132 for c in copyrights: |
| 128 if c and not allowed_copyrights_re.match(c): | 133 if c and not allowed_copyrights_re.match(c): |
| 129 offending_files.append(os.path.normpath(entries[0])) | 134 offending_files.append(os.path.normpath(entries[0])) |
| 130 break | 135 break |
| 131 | 136 |
| 132 all_files_valid = True | |
| 133 unknown = set(offending_files) - set(whitelisted_files) | 137 unknown = set(offending_files) - set(whitelisted_files) |
| 134 if unknown: | 138 if unknown: |
| 135 print 'The following files contain a third-party license but are not in ' \ | 139 print 'The following files contain a third-party license but are not in ' \ |
| 136 'a listed third-party directory and are not whitelisted. You must ' \ | 140 'a listed third-party directory and are not whitelisted. You must ' \ |
| 137 'add the following files to the whitelist.\n%s' % \ | 141 'add the following files to the whitelist.\n%s' % \ |
| 138 '\n'.join(sorted(unknown)) | 142 '\n'.join(sorted(unknown)) |
| 139 all_files_valid = False | |
| 140 | 143 |
| 141 stale = set(whitelisted_files) - set(offending_files) | 144 stale = set(whitelisted_files) - set(offending_files) |
| 142 if stale: | 145 if stale: |
| 143 print 'The following files are whitelisted unnecessarily. You must ' \ | 146 print 'The following files are whitelisted unnecessarily. You must ' \ |
| 144 ' remove the following files from the whitelist.\n%s' % \ | 147 ' remove the following files from the whitelist.\n%s' % \ |
| 145 '\n'.join(sorted(stale)) | 148 '\n'.join(sorted(stale)) |
| 146 all_files_valid = False | |
| 147 | 149 |
| 148 return all_files_valid | 150 return SCAN_ERRORS if unknown else (SCAN_WARNINGS if stale else SCAN_OK) |
|
mkosiba (inactive)
2013/02/06 15:40:49
I think it would be slightly clearer to make this
mnaganov (inactive)
2013/02/06 16:42:17
Done.
| |
| 149 | 151 |
| 150 | 152 |
| 151 def _ReadFile(path): | 153 def _ReadFile(path): |
| 152 """Reads a file from disk. | 154 """Reads a file from disk. |
| 153 Args: | 155 Args: |
| 154 path: The path of the file to read, relative to the root of the repository. | 156 path: The path of the file to read, relative to the root of the repository. |
| 155 Returns: | 157 Returns: |
| 156 The contents of the file as a string. | 158 The contents of the file as a string. |
| 157 """ | 159 """ |
| 158 | 160 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 179 # The llvm-build doesn't exist for non-clang builder | 181 # The llvm-build doesn't exist for non-clang builder |
| 180 os.path.join('third_party', 'llvm-build'), | 182 os.path.join('third_party', 'llvm-build'), |
| 181 # Binaries doesn't apply to android | 183 # Binaries doesn't apply to android |
| 182 os.path.join('third_party', 'widevine'), | 184 os.path.join('third_party', 'widevine'), |
| 183 ] | 185 ] |
| 184 third_party_dirs = licenses.FindThirdPartyDirs(prune_paths, REPOSITORY_ROOT) | 186 third_party_dirs = licenses.FindThirdPartyDirs(prune_paths, REPOSITORY_ROOT) |
| 185 return licenses.FilterDirsWithFiles(third_party_dirs, REPOSITORY_ROOT) | 187 return licenses.FilterDirsWithFiles(third_party_dirs, REPOSITORY_ROOT) |
| 186 | 188 |
| 187 | 189 |
| 188 def _Scan(): | 190 def _Scan(): |
| 189 """Checks that license meta-data is present for all third-party code. | 191 """Checks that license meta-data is present for all third-party code and |
| 192 that all non third-party code doesn't contain external copyrighted code. | |
| 190 Returns: | 193 Returns: |
| 191 Whether the check succeeded. | 194 SCAN_OK if everything is in order; |
| 195 SCAN_WARNINGS if there are non-fatal problems (e.g. stale whitelist entries) | |
| 196 SCAN_ERRORS otherwise. | |
| 192 """ | 197 """ |
| 193 | 198 |
| 194 third_party_dirs = _FindThirdPartyDirs() | 199 third_party_dirs = _FindThirdPartyDirs() |
| 195 | 200 |
| 196 # First, check designated third-party directories using src/tools/licenses.py. | 201 # First, check designated third-party directories using src/tools/licenses.py. |
| 197 all_licenses_valid = True | 202 all_licenses_valid = True |
| 198 for path in sorted(third_party_dirs): | 203 for path in sorted(third_party_dirs): |
| 199 try: | 204 try: |
| 200 licenses.ParseDir(path, REPOSITORY_ROOT) | 205 licenses.ParseDir(path, REPOSITORY_ROOT) |
| 201 except licenses.LicenseError, e: | 206 except licenses.LicenseError, e: |
| 202 if not (path in known_issues.KNOWN_ISSUES): | 207 if not (path in known_issues.KNOWN_ISSUES): |
| 203 print 'Got LicenseError "%s" while scanning %s' % (e, path) | 208 print 'Got LicenseError "%s" while scanning %s' % (e, path) |
| 204 all_licenses_valid = False | 209 all_licenses_valid = False |
| 205 | 210 |
| 206 # Second, check for non-standard license text. | 211 # Second, check for non-standard license text. |
| 207 files_data = _ReadFile(os.path.join('android_webview', 'tools', | 212 files_data = _ReadFile(os.path.join('android_webview', 'tools', |
| 208 'third_party_files_whitelist.txt')) | 213 'third_party_files_whitelist.txt')) |
| 209 whitelisted_files = [] | 214 whitelisted_files = [] |
| 210 for line in files_data.splitlines(): | 215 for line in files_data.splitlines(): |
| 211 match = re.match(r'([^#\s]+)', line) | 216 match = re.match(r'([^#\s]+)', line) |
| 212 if match: | 217 if match: |
| 213 whitelisted_files.append(match.group(1)) | 218 whitelisted_files.append(match.group(1)) |
| 214 return _CheckLicenseHeaders(third_party_dirs, whitelisted_files) \ | 219 licenses_check = _CheckLicenseHeaders(third_party_dirs, whitelisted_files) |
| 215 and all_licenses_valid | 220 |
| 221 return licenses_check if all_licenses_valid else SCAN_ERRORS | |
| 216 | 222 |
| 217 | 223 |
| 218 def GenerateNoticeFile(): | 224 def GenerateNoticeFile(): |
| 219 """Generates the contents of an Android NOTICE file for the third-party code. | 225 """Generates the contents of an Android NOTICE file for the third-party code. |
| 220 This is used by the snapshot tool. | 226 This is used by the snapshot tool. |
| 221 Returns: | 227 Returns: |
| 222 The contents of the NOTICE file. | 228 The contents of the NOTICE file. |
| 223 """ | 229 """ |
| 224 | 230 |
| 225 third_party_dirs = _FindThirdPartyDirs() | 231 third_party_dirs = _FindThirdPartyDirs() |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 248 | 254 |
| 249 parser = optparse.OptionParser(formatter=FormatterWithNewLines(), | 255 parser = optparse.OptionParser(formatter=FormatterWithNewLines(), |
| 250 usage='%prog [options]') | 256 usage='%prog [options]') |
| 251 parser.description = (__doc__ + | 257 parser.description = (__doc__ + |
| 252 '\nCommands:\n' \ | 258 '\nCommands:\n' \ |
| 253 ' scan Check licenses.\n' \ | 259 ' scan Check licenses.\n' \ |
| 254 ' notice Generate Android NOTICE file on stdout') | 260 ' notice Generate Android NOTICE file on stdout') |
| 255 (options, args) = parser.parse_args() | 261 (options, args) = parser.parse_args() |
| 256 if len(args) != 1: | 262 if len(args) != 1: |
| 257 parser.print_help() | 263 parser.print_help() |
| 258 return 1 | 264 return SCAN_ERRORS |
| 259 | 265 |
| 260 if args[0] == 'scan': | 266 if args[0] == 'scan': |
| 261 if _Scan(): | 267 scan_result = _Scan() |
| 268 if scan_result == SCAN_OK: | |
| 262 print 'OK!' | 269 print 'OK!' |
| 263 return 0 | 270 return scan_result |
| 264 else: | |
| 265 return 1 | |
| 266 elif args[0] == 'notice': | 271 elif args[0] == 'notice': |
| 267 print GenerateNoticeFile() | 272 print GenerateNoticeFile() |
| 268 return 0 | 273 return SCAN_OK |
| 269 | 274 |
| 270 parser.print_help() | 275 parser.print_help() |
| 271 return 1 | 276 return SCAN_ERRORS |
| 272 | 277 |
| 273 if __name__ == '__main__': | 278 if __name__ == '__main__': |
| 274 sys.exit(main()) | 279 sys.exit(main()) |
| OLD | NEW |