| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2010 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 """ | 6 """ |
| 7 Utilities for checking and processing licensing information in third_party | 7 Utilities for checking and processing licensing information in third_party |
| 8 directories. | 8 directories. |
| 9 """ | 9 """ |
| 10 | 10 |
| 11 import os | 11 import os |
| 12 | 12 |
| 13 # Paths from the root of the tree to directories to skip. |
| 14 PRUNE_PATHS = set([ |
| 15 # This is just a tiny vsprops file, presumably written by the googleurl |
| 16 # authors. Not third-party code. |
| 17 "googleurl/third_party/icu", |
| 18 |
| 19 # We don't bundle o3d samples into our resulting binaries. |
| 20 "o3d/samples", |
| 21 |
| 22 # Written as part of Chromium. |
| 23 "tools/fuzzymatch", |
| 24 |
| 25 # Two directories that are the same as those in base/third_party. |
| 26 "v8/src/third_party/dtoa", |
| 27 "v8/src/third_party/valgrind", |
| 28 ]) |
| 29 |
| 13 | 30 |
| 14 class LicenseError(Exception): | 31 class LicenseError(Exception): |
| 15 """We raise this exception when a directory's licensing info isn't | 32 """We raise this exception when a directory's licensing info isn't |
| 16 fully filled out.""" | 33 fully filled out.""" |
| 17 pass | 34 pass |
| 18 | 35 |
| 19 | 36 |
| 20 def ParseDir(path): | 37 def ParseDir(path): |
| 21 """Examine a third_party/foo component and extract its metadata.""" | 38 """Examine a third_party/foo component and extract its metadata.""" |
| 22 | 39 |
| 23 # Try to find README.chromium. | 40 # Try to find README.chromium. |
| 24 readme_path = os.path.join(path, 'README.chromium') | 41 readme_path = os.path.join(path, 'README.chromium') |
| 25 if not os.path.exists(readme_path): | 42 if not os.path.exists(readme_path): |
| 26 raise LicenseError("missing README.chromium") | 43 raise LicenseError("missing README.chromium") |
| 27 | 44 |
| 28 # Parse metadata fields out of README.chromium. | 45 # Parse metadata fields out of README.chromium. |
| 29 # We provide a default value of "LICENSE" for the license file. | 46 # We examine "LICENSE" for the license file by default. |
| 30 metadata = { | 47 metadata = { |
| 31 "License File": "LICENSE", # Relative path to license text. | 48 "License File": "LICENSE", # Relative path to license text. |
| 32 "Name": None, # Short name (for header on about:credits). | 49 "Name": None, # Short name (for header on about:credits). |
| 33 "URL": None, # Project home page. | 50 "URL": None, # Project home page. |
| 34 } | 51 } |
| 35 for line in open(readme_path): | 52 for line in open(readme_path): |
| 36 line = line.strip() | 53 line = line.strip() |
| 37 for key in metadata.keys(): | 54 for key in metadata.keys(): |
| 38 field = key + ": " | 55 field = key + ": " |
| 39 if line.startswith(field): | 56 if line.startswith(field): |
| 40 metadata[key] = line[len(field):] | 57 metadata[key] = line[len(field):] |
| 41 | 58 |
| 42 # Check that all expected metadata is present. | 59 # Check that all expected metadata is present. |
| 43 for key, value in metadata.iteritems(): | 60 for key, value in metadata.iteritems(): |
| 44 if not value: | 61 if not value: |
| 45 raise LicenseError("couldn't find '" + key + "' line " | 62 raise LicenseError("couldn't find '" + key + "' line " |
| 46 "in README.chromium") | 63 "in README.chromium") |
| 47 | 64 |
| 48 # Check that the license file exists. | 65 # Check that the license file exists. |
| 49 license_file = metadata["License File"] | 66 for filename in (metadata["License File"], "COPYING"): |
| 50 license_path = os.path.join(path, license_file) | 67 license_path = os.path.join(path, filename) |
| 51 if not os.path.exists(license_path): | 68 if os.path.exists(license_path): |
| 52 raise LicenseError("License file '" + license_file + "' doesn't exist. " | 69 metadata["License File"] = filename |
| 53 "Either add a 'License File:' section to " | 70 break |
| 54 "README.chromium or add the missing file.") | 71 license_path = None |
| 72 |
| 73 if not license_path: |
| 74 raise LicenseError("License file not found. " |
| 75 "Either add a file named LICENSE, " |
| 76 "import upstream's COPYING if available, " |
| 77 "or add a 'License File:' line to README.chromium " |
| 78 "with the appropriate path.") |
| 55 | 79 |
| 56 return metadata | 80 return metadata |
| 57 | 81 |
| 58 | 82 |
| 59 def ScanThirdPartyDirs(third_party_dirs): | 83 def ScanThirdPartyDirs(third_party_dirs): |
| 60 """Scan a list of directories and report on any problems we find.""" | 84 """Scan a list of directories and report on any problems we find.""" |
| 61 errors = [] | 85 errors = [] |
| 62 for path in sorted(third_party_dirs): | 86 for path in sorted(third_party_dirs): |
| 63 try: | 87 try: |
| 64 metadata = ParseDir(path) | 88 metadata = ParseDir(path) |
| 65 except LicenseError, e: | 89 except LicenseError, e: |
| 66 errors.append((path, e.args[0])) | 90 errors.append((path, e.args[0])) |
| 67 continue | 91 continue |
| 68 print path, "OK:", metadata["License File"] | 92 print path, "OK:", metadata["License File"] |
| 69 | 93 |
| 70 for path, error in sorted(errors): | 94 for path, error in sorted(errors): |
| 71 print path + ": " + error | 95 print path + ": " + error |
| 72 | 96 |
| 73 | 97 |
| 74 def FindThirdPartyDirs(): | 98 def FindThirdPartyDirs(): |
| 75 """Find all third_party directories underneath the current directory.""" | 99 """Find all third_party directories underneath the current directory.""" |
| 76 skip_dirs = ('.svn', '.git', # VCS metadata | 100 skip_dirs = ('.svn', '.git', # VCS metadata |
| 77 'out', 'Debug', 'Release', # build files | 101 'out', 'Debug', 'Release', # build files |
| 78 'layout_tests') # lots of subdirs | 102 'layout_tests') # lots of subdirs |
| 79 | 103 |
| 80 third_party_dirs = [] | 104 third_party_dirs = [] |
| 81 for path, dirs, files in os.walk('.'): | 105 for path, dirs, files in os.walk('.'): |
| 82 path = path[len('./'):] # Pretty up the path. | 106 path = path[len('./'):] # Pretty up the path. |
| 83 | 107 |
| 108 if path in PRUNE_PATHS: |
| 109 dirs[:] = [] |
| 110 continue |
| 111 |
| 84 # Prune out directories we want to skip. | 112 # Prune out directories we want to skip. |
| 85 for skip in skip_dirs: | 113 for skip in skip_dirs: |
| 86 if skip in dirs: | 114 if skip in dirs: |
| 87 dirs.remove(skip) | 115 dirs.remove(skip) |
| 88 | 116 |
| 89 if os.path.basename(path) == 'third_party': | 117 if os.path.basename(path) == 'third_party': |
| 90 third_party_dirs.extend([os.path.join(path, dir) for dir in dirs]) | 118 # Add all subdirectories that are not marked for skipping. |
| 119 for dir in dirs: |
| 120 dirpath = os.path.join(path, dir) |
| 121 if dirpath not in PRUNE_PATHS: |
| 122 third_party_dirs.append(dirpath) |
| 123 |
| 91 # Don't recurse into any subdirs from here. | 124 # Don't recurse into any subdirs from here. |
| 92 dirs[:] = [] | 125 dirs[:] = [] |
| 93 continue | 126 continue |
| 94 | 127 |
| 95 return third_party_dirs | 128 return third_party_dirs |
| 96 | 129 |
| 97 | 130 |
| 98 if __name__ == '__main__': | 131 if __name__ == '__main__': |
| 99 third_party_dirs = FindThirdPartyDirs() | 132 third_party_dirs = FindThirdPartyDirs() |
| 100 ScanThirdPartyDirs(third_party_dirs) | 133 ScanThirdPartyDirs(third_party_dirs) |
| OLD | NEW |