| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 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 18 matching lines...) Expand all Loading... |
| 29 REPOSITORY_ROOT = os.path.abspath(os.path.join( | 29 REPOSITORY_ROOT = os.path.abspath(os.path.join( |
| 30 os.path.dirname(__file__), '..', '..')) | 30 os.path.dirname(__file__), '..', '..')) |
| 31 | 31 |
| 32 # Import third_party/PRESUBMIT.py via imp to avoid importing a random | 32 # Import third_party/PRESUBMIT.py via imp to avoid importing a random |
| 33 # PRESUBMIT.py from $PATH, also make sure we don't generate a .pyc file. | 33 # PRESUBMIT.py from $PATH, also make sure we don't generate a .pyc file. |
| 34 sys.dont_write_bytecode = True | 34 sys.dont_write_bytecode = True |
| 35 third_party = \ | 35 third_party = \ |
| 36 imp.load_source('PRESUBMIT', \ | 36 imp.load_source('PRESUBMIT', \ |
| 37 os.path.join(REPOSITORY_ROOT, 'third_party', 'PRESUBMIT.py')) | 37 os.path.join(REPOSITORY_ROOT, 'third_party', 'PRESUBMIT.py')) |
| 38 | 38 |
| 39 sys.path.append(os.path.join(REPOSITORY_ROOT, 'third_party')) |
| 40 import jinja2 |
| 39 sys.path.append(os.path.join(REPOSITORY_ROOT, 'tools')) | 41 sys.path.append(os.path.join(REPOSITORY_ROOT, 'tools')) |
| 40 import licenses | 42 import licenses |
| 41 | 43 |
| 42 import copyright_scanner | 44 import copyright_scanner |
| 43 import known_issues | 45 import known_issues |
| 44 | 46 |
| 45 class InputApi(object): | 47 class InputApi(object): |
| 46 def __init__(self): | 48 def __init__(self): |
| 47 self.os_path = os.path | 49 self.os_path = os.path |
| 48 self.os_walk = os.walk | 50 self.os_walk = os.walk |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 print 'Got LicenseError "%s" while scanning %s' % (e, path) | 247 print 'Got LicenseError "%s" while scanning %s' % (e, path) |
| 246 all_licenses_valid = False | 248 all_licenses_valid = False |
| 247 | 249 |
| 248 # Second, check for non-standard license text. | 250 # Second, check for non-standard license text. |
| 249 whitelisted_files = copyright_scanner.LoadWhitelistedFilesList(InputApi()) | 251 whitelisted_files = copyright_scanner.LoadWhitelistedFilesList(InputApi()) |
| 250 licenses_check = _CheckLicenseHeaders(third_party_dirs, whitelisted_files) | 252 licenses_check = _CheckLicenseHeaders(third_party_dirs, whitelisted_files) |
| 251 | 253 |
| 252 return licenses_check if all_licenses_valid else ScanResult.Errors | 254 return licenses_check if all_licenses_valid else ScanResult.Errors |
| 253 | 255 |
| 254 | 256 |
| 257 class TemplateEntryGenerator(object): |
| 258 def __init__(self): |
| 259 self.toc_index = 0 |
| 260 |
| 261 def _ReadFileGuessEncoding(self, name): |
| 262 contents = '' |
| 263 with open(name, 'rb') as input_file: |
| 264 contents = input_file.read() |
| 265 try: |
| 266 return contents.decode('utf8') |
| 267 except UnicodeDecodeError: |
| 268 pass |
| 269 # If it's not UTF-8, it must be CP-1252. Fail otherwise. |
| 270 return contents.decode('cp1252') |
| 271 |
| 272 def MetadataToTemplateEntry(self, metadata): |
| 273 self.toc_index += 1 |
| 274 return { |
| 275 'name': metadata['Name'], |
| 276 'url': metadata['URL'], |
| 277 'license': self._ReadFileGuessEncoding(metadata['License File']), |
| 278 'toc_href': 'entry' + str(self.toc_index), |
| 279 } |
| 280 |
| 281 |
| 255 def GenerateNoticeFile(): | 282 def GenerateNoticeFile(): |
| 256 """Generates the contents of an Android NOTICE file for the third-party code. | 283 """Generates the contents of an Android NOTICE file for the third-party code. |
| 257 This is used by the snapshot tool. | 284 This is used by the snapshot tool. |
| 258 Returns: | 285 Returns: |
| 259 The contents of the NOTICE file. | 286 The contents of the NOTICE file. |
| 260 """ | 287 """ |
| 261 | 288 |
| 289 generator = TemplateEntryGenerator() |
| 290 # Start from Chromium's LICENSE file |
| 291 entries = [generator.MetadataToTemplateEntry({ |
| 292 'Name': 'The Chromium Project', |
| 293 'URL': 'http://www.chromium.org', |
| 294 'License File': os.path.join(REPOSITORY_ROOT, 'LICENSE') }) |
| 295 ] |
| 296 |
| 262 third_party_dirs = _FindThirdPartyDirs() | 297 third_party_dirs = _FindThirdPartyDirs() |
| 263 | |
| 264 # Don't forget Chromium's LICENSE file | |
| 265 content = [_ReadLocalFile('LICENSE')] | |
| 266 | |
| 267 # We provide attribution for all third-party directories. | 298 # We provide attribution for all third-party directories. |
| 268 # TODO(steveblock): Limit this to only code used by the WebView binary. | 299 # TODO(mnaganov): Limit this to only code used by the WebView binary. |
| 269 for directory in sorted(third_party_dirs): | 300 for directory in sorted(third_party_dirs): |
| 270 metadata = licenses.ParseDir(directory, REPOSITORY_ROOT, | 301 metadata = licenses.ParseDir(directory, REPOSITORY_ROOT, |
| 271 require_license_file=False) | 302 require_license_file=False) |
| 272 license_file = metadata['License File'] | 303 license_file = metadata['License File'] |
| 273 if license_file and license_file != licenses.NOT_SHIPPED: | 304 if license_file and license_file != licenses.NOT_SHIPPED: |
| 274 content.append(_ReadLocalFile(license_file)) | 305 entries.append(generator.MetadataToTemplateEntry(metadata)) |
| 275 | 306 |
| 276 return '\n'.join(content) | 307 env = jinja2.Environment( |
| 308 loader=jinja2.FileSystemLoader(os.path.dirname(__file__)), |
| 309 extensions=['jinja2.ext.autoescape']) |
| 310 template = env.get_template('licenses_notice.tmpl') |
| 311 return template.render({ 'entries': entries }).encode('utf8') |
| 277 | 312 |
| 278 | 313 |
| 279 def _ProcessIncompatibleResult(incompatible_directories): | 314 def _ProcessIncompatibleResult(incompatible_directories): |
| 280 if incompatible_directories: | 315 if incompatible_directories: |
| 281 print ("Incompatibly licensed directories found:\n" + | 316 print ("Incompatibly licensed directories found:\n" + |
| 282 "\n".join(sorted(incompatible_directories))) | 317 "\n".join(sorted(incompatible_directories))) |
| 283 return ScanResult.Errors | 318 return ScanResult.Errors |
| 284 return ScanResult.Ok | 319 return ScanResult.Ok |
| 285 | 320 |
| 286 def main(): | 321 def main(): |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 files = sys.stdin.read().splitlines() | 359 files = sys.stdin.read().splitlines() |
| 325 for f, c in \ | 360 for f, c in \ |
| 326 zip(files, copyright_scanner.FindCopyrights(InputApi(), '.', files)): | 361 zip(files, copyright_scanner.FindCopyrights(InputApi(), '.', files)): |
| 327 print f, '\t', ' / '.join(sorted(c)) | 362 print f, '\t', ' / '.join(sorted(c)) |
| 328 return ScanResult.Ok | 363 return ScanResult.Ok |
| 329 parser.print_help() | 364 parser.print_help() |
| 330 return ScanResult.Errors | 365 return ScanResult.Errors |
| 331 | 366 |
| 332 if __name__ == '__main__': | 367 if __name__ == '__main__': |
| 333 sys.exit(main()) | 368 sys.exit(main()) |
| OLD | NEW |