OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env 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 """Utility for checking and processing licensing information in third_party | 6 """Utility for checking and processing licensing information in third_party |
7 directories. | 7 directories. |
8 | 8 |
9 Usage: licenses.py <command> | 9 Usage: licenses.py <command> |
10 | 10 |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
247 if filename.startswith('/'): | 247 if filename.startswith('/'): |
248 # Absolute-looking paths are relative to the source root | 248 # Absolute-looking paths are relative to the source root |
249 # (which is the directory we're run from). | 249 # (which is the directory we're run from). |
250 absolute_path = os.path.join(root, filename[1:]) | 250 absolute_path = os.path.join(root, filename[1:]) |
251 else: | 251 else: |
252 absolute_path = os.path.join(root, path, filename) | 252 absolute_path = os.path.join(root, path, filename) |
253 if os.path.exists(absolute_path): | 253 if os.path.exists(absolute_path): |
254 return absolute_path | 254 return absolute_path |
255 return None | 255 return None |
256 | 256 |
257 def ParseDir(path, root, require_license_file=True): | 257 def ParseDir(path, root, require_license_file=True, optional_keys=None): |
258 """Examine a third_party/foo component and extract its metadata.""" | 258 """Examine a third_party/foo component and extract its metadata.""" |
259 | 259 |
260 # Parse metadata fields out of README.chromium. | 260 # Parse metadata fields out of README.chromium. |
261 # We examine "LICENSE" for the license file by default. | 261 # We examine "LICENSE" for the license file by default. |
262 metadata = { | 262 metadata = { |
263 "License File": "LICENSE", # Relative path to license text. | 263 "License File": "LICENSE", # Relative path to license text. |
264 "Name": None, # Short name (for header on about:credits). | 264 "Name": None, # Short name (for header on about:credits). |
265 "URL": None, # Project home page. | 265 "URL": None, # Project home page. |
266 "License": None, # Software license. | 266 "License": None, # Software license. |
267 } | 267 } |
268 | 268 |
269 # Relative path to a file containing some html we're required to place in | 269 if optional_keys is None: |
270 # about:credits. | 270 optional_keys = [] |
271 optional_keys = ["Required Text", "License Android Compatible"] | |
272 | 271 |
273 if path in SPECIAL_CASES: | 272 if path in SPECIAL_CASES: |
274 metadata.update(SPECIAL_CASES[path]) | 273 metadata.update(SPECIAL_CASES[path]) |
275 else: | 274 else: |
276 # Try to find README.chromium. | 275 # Try to find README.chromium. |
277 readme_path = os.path.join(root, path, 'README.chromium') | 276 readme_path = os.path.join(root, path, 'README.chromium') |
278 if not os.path.exists(readme_path): | 277 if not os.path.exists(readme_path): |
279 raise LicenseError("missing README.chromium or licenses.py " | 278 raise LicenseError("missing README.chromium or licenses.py " |
280 "SPECIAL_CASES entry") | 279 "SPECIAL_CASES entry") |
281 | 280 |
(...skipping 23 matching lines...) Expand all Loading... |
305 break | 304 break |
306 | 305 |
307 if require_license_file and not license_path: | 306 if require_license_file and not license_path: |
308 raise LicenseError("License file not found. " | 307 raise LicenseError("License file not found. " |
309 "Either add a file named LICENSE, " | 308 "Either add a file named LICENSE, " |
310 "import upstream's COPYING if available, " | 309 "import upstream's COPYING if available, " |
311 "or add a 'License File:' line to " | 310 "or add a 'License File:' line to " |
312 "README.chromium with the appropriate path.") | 311 "README.chromium with the appropriate path.") |
313 metadata["License File"] = license_path | 312 metadata["License File"] = license_path |
314 | 313 |
315 if "Required Text" in metadata: | |
316 required_path = AbsolutePath(path, metadata["Required Text"], root) | |
317 if required_path is not None: | |
318 metadata["Required Text"] = required_path | |
319 else: | |
320 raise LicenseError("Required text file listed but not found.") | |
321 | |
322 return metadata | 314 return metadata |
323 | 315 |
324 | 316 |
325 def ContainsFiles(path, root): | 317 def ContainsFiles(path, root): |
326 """Determines whether any files exist in a directory or in any of its | 318 """Determines whether any files exist in a directory or in any of its |
327 subdirectories.""" | 319 subdirectories.""" |
328 for _, dirs, files in os.walk(os.path.join(root, path)): | 320 for _, dirs, files in os.walk(os.path.join(root, path)): |
329 if files: | 321 if files: |
330 return True | 322 return True |
331 for vcs_metadata in VCS_METADATA_DIRS: | 323 for vcs_metadata in VCS_METADATA_DIRS: |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
405 """Generate about:credits.""" | 397 """Generate about:credits.""" |
406 | 398 |
407 if len(sys.argv) not in (2, 3): | 399 if len(sys.argv) not in (2, 3): |
408 print 'usage: licenses.py credits [output_file]' | 400 print 'usage: licenses.py credits [output_file]' |
409 return False | 401 return False |
410 | 402 |
411 def EvaluateTemplate(template, env, escape=True): | 403 def EvaluateTemplate(template, env, escape=True): |
412 """Expand a template with variables like {{foo}} using a | 404 """Expand a template with variables like {{foo}} using a |
413 dictionary of expansions.""" | 405 dictionary of expansions.""" |
414 for key, val in env.items(): | 406 for key, val in env.items(): |
415 if escape and not key.endswith("_unescaped"): | 407 if escape: |
416 val = cgi.escape(val) | 408 val = cgi.escape(val) |
417 template = template.replace('{{%s}}' % key, val) | 409 template = template.replace('{{%s}}' % key, val) |
418 return template | 410 return template |
419 | 411 |
420 root = os.path.join(os.path.dirname(__file__), '..') | 412 root = os.path.join(os.path.dirname(__file__), '..') |
421 third_party_dirs = FindThirdPartyDirs(PRUNE_PATHS, root) | 413 third_party_dirs = FindThirdPartyDirs(PRUNE_PATHS, root) |
422 | 414 |
423 entry_template = open(os.path.join(root, 'chrome', 'browser', 'resources', | 415 entry_template = open(os.path.join(root, 'chrome', 'browser', 'resources', |
424 'about_credits_entry.tmpl'), 'rb').read() | 416 'about_credits_entry.tmpl'), 'rb').read() |
425 entries = [] | 417 entries = [] |
426 for path in sorted(third_party_dirs): | 418 for path in sorted(third_party_dirs): |
427 try: | 419 try: |
428 metadata = ParseDir(path, root) | 420 metadata = ParseDir(path, root) |
429 except LicenseError: | 421 except LicenseError: |
430 # TODO(phajdan.jr): Convert to fatal error (http://crbug.com/39240). | 422 # TODO(phajdan.jr): Convert to fatal error (http://crbug.com/39240). |
431 continue | 423 continue |
432 if metadata['License File'] == NOT_SHIPPED: | 424 if metadata['License File'] == NOT_SHIPPED: |
433 continue | 425 continue |
434 env = { | 426 env = { |
435 'name': metadata['Name'], | 427 'name': metadata['Name'], |
436 'url': metadata['URL'], | 428 'url': metadata['URL'], |
437 'license': open(metadata['License File'], 'rb').read(), | 429 'license': open(metadata['License File'], 'rb').read(), |
438 'license_unescaped': '', | |
439 } | 430 } |
440 if 'Required Text' in metadata: | |
441 required_text = open(metadata['Required Text'], 'rb').read() | |
442 env["license_unescaped"] = required_text | |
443 entries.append(EvaluateTemplate(entry_template, env)) | 431 entries.append(EvaluateTemplate(entry_template, env)) |
444 | 432 |
445 file_template = open(os.path.join(root, 'chrome', 'browser', 'resources', | 433 file_template = open(os.path.join(root, 'chrome', 'browser', 'resources', |
446 'about_credits.tmpl'), 'rb').read() | 434 'about_credits.tmpl'), 'rb').read() |
447 template_contents = "<!-- Generated by licenses.py; do not edit. -->" | 435 template_contents = "<!-- Generated by licenses.py; do not edit. -->" |
448 template_contents += EvaluateTemplate(file_template, | 436 template_contents += EvaluateTemplate(file_template, |
449 {'entries': '\n'.join(entries)}, | 437 {'entries': '\n'.join(entries)}, |
450 escape=False) | 438 escape=False) |
451 | 439 |
452 if len(sys.argv) == 3: | 440 if len(sys.argv) == 3: |
(...skipping 16 matching lines...) Expand all Loading... |
469 elif command == 'credits': | 457 elif command == 'credits': |
470 if not GenerateCredits(): | 458 if not GenerateCredits(): |
471 return 1 | 459 return 1 |
472 else: | 460 else: |
473 print __doc__ | 461 print __doc__ |
474 return 1 | 462 return 1 |
475 | 463 |
476 | 464 |
477 if __name__ == '__main__': | 465 if __name__ == '__main__': |
478 sys.exit(main()) | 466 sys.exit(main()) |
OLD | NEW |