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 |