| 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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 # Harfbuzz-ng is not currently shipping in any product: | 86 # Harfbuzz-ng is not currently shipping in any product: |
| 87 os.path.join('third_party','harfbuzz-ng'), | 87 os.path.join('third_party','harfbuzz-ng'), |
| 88 ]) | 88 ]) |
| 89 | 89 |
| 90 # Directories we don't scan through. | 90 # Directories we don't scan through. |
| 91 PRUNE_DIRS = ('.svn', '.git', # VCS metadata | 91 PRUNE_DIRS = ('.svn', '.git', # VCS metadata |
| 92 'out', 'Debug', 'Release', # build files | 92 'out', 'Debug', 'Release', # build files |
| 93 'layout_tests') # lots of subdirs | 93 'layout_tests') # lots of subdirs |
| 94 | 94 |
| 95 ADDITIONAL_PATHS = ( | 95 ADDITIONAL_PATHS = ( |
| 96 os.path.join('googleurl'), |
| 97 os.path.join('native_client_sdk'), |
| 96 # The directory with the word list for Chinese and Japanese segmentation | 98 # The directory with the word list for Chinese and Japanese segmentation |
| 97 # with different license terms than ICU. | 99 # with different license terms than ICU. |
| 98 os.path.join('third_party','icu','source','data','brkitr'), | 100 os.path.join('third_party','icu','source','data','brkitr'), |
| 99 # Fake directory so we can include the strongtalk license. | 101 # Fake directory so we can include the strongtalk license. |
| 100 os.path.join('v8', 'strongtalk'), | 102 os.path.join('v8', 'strongtalk'), |
| 101 # Fake directory so we can include the google-url license. | |
| 102 'googleurl', | |
| 103 ) | 103 ) |
| 104 | 104 |
| 105 | 105 |
| 106 # Directories where we check out directly from upstream, and therefore | 106 # Directories where we check out directly from upstream, and therefore |
| 107 # can't provide a README.chromium. Please prefer a README.chromium | 107 # can't provide a README.chromium. Please prefer a README.chromium |
| 108 # wherever possible. | 108 # wherever possible. |
| 109 SPECIAL_CASES = { | 109 SPECIAL_CASES = { |
| 110 'googleurl': { | 110 'googleurl': { |
| 111 "Name": "google-url", | 111 "Name": "google-url", |
| 112 "URL": "http://code.google.com/p/google-url/", | 112 "URL": "http://code.google.com/p/google-url/", |
| 113 "License File": "LICENSE.txt", | 113 "License File": "LICENSE.txt", |
| 114 }, | 114 }, |
| 115 os.path.join('third_party', 'angle'): { | 115 os.path.join('third_party', 'angle'): { |
| 116 "Name": "Almost Native Graphics Layer Engine", | 116 "Name": "Almost Native Graphics Layer Engine", |
| 117 "URL": "http://code.google.com/p/angleproject/", | 117 "URL": "http://code.google.com/p/angleproject/", |
| 118 }, | 118 }, |
| 119 os.path.join('third_party', 'cros_system_api'): { |
| 120 "Name": "Chromium OS system API", |
| 121 "URL": "http://www.chromium.org/chromium-os", |
| 122 "License": "BSD", |
| 123 # Absolute path here is resolved as relative to the source root. |
| 124 "License File": "/LICENSE.chromium_os", |
| 125 }, |
| 126 os.path.join('third_party', 'GTM'): { |
| 127 "Name": "Google Toolbox for Mac", |
| 128 "URL": "http://code.google.com/p/google-toolbox-for-mac/", |
| 129 "License": "Apache 2.0", |
| 130 "License File": "COPYING", |
| 131 }, |
| 119 os.path.join('third_party', 'lss'): { | 132 os.path.join('third_party', 'lss'): { |
| 120 "Name": "linux-syscall-support", | 133 "Name": "linux-syscall-support", |
| 121 "URL": "http://code.google.com/p/lss/", | 134 "URL": "http://code.google.com/p/lss/", |
| 122 }, | 135 }, |
| 123 os.path.join('third_party', 'ots'): { | 136 os.path.join('third_party', 'ots'): { |
| 124 "Name": "OTS (OpenType Sanitizer)", | 137 "Name": "OTS (OpenType Sanitizer)", |
| 125 "URL": "http://code.google.com/p/ots/", | 138 "URL": "http://code.google.com/p/ots/", |
| 126 }, | 139 }, |
| 140 os.path.join('third_party', 'pdfsqueeze'): { |
| 141 "Name": "pdfsqueeze", |
| 142 "URL": "http://code.google.com/p/pdfsqueeze/", |
| 143 "License": "Apache 2.0", |
| 144 "License File": "COPYING", |
| 145 }, |
| 127 os.path.join('third_party', 'ppapi'): { | 146 os.path.join('third_party', 'ppapi'): { |
| 128 "Name": "ppapi", | 147 "Name": "ppapi", |
| 129 "URL": "http://code.google.com/p/ppapi/", | 148 "URL": "http://code.google.com/p/ppapi/", |
| 130 }, | 149 }, |
| 131 os.path.join('third_party', 'WebKit'): { | 150 os.path.join('third_party', 'scons-2.0.1'): { |
| 132 "Name": "WebKit", | 151 "Name": "scons-2.0.1", |
| 133 "URL": "http://webkit.org/", | 152 "URL": "http://www.scons.org", |
| 134 # Absolute path here is resolved as relative to the source root. | 153 "License": "MIT", |
| 135 "License File": "/webkit/LICENSE", | |
| 136 }, | 154 }, |
| 137 os.path.join('third_party', 'GTM'): { | 155 os.path.join('third_party', 'trace-viewer'): { |
| 138 "Name": "Google Toolbox for Mac", | 156 "Name": "trace-viewer", |
| 139 "URL": "http://code.google.com/p/google-toolbox-for-mac/", | 157 "URL": "http://code.google.com/p/trace-viewer", |
| 140 "License File": "COPYING", | 158 "License": "BSD", |
| 141 }, | |
| 142 os.path.join('third_party', 'pdfsqueeze'): { | |
| 143 "Name": "pdfsqueeze", | |
| 144 "URL": "http://code.google.com/p/pdfsqueeze/", | |
| 145 "License File": "COPYING", | |
| 146 }, | 159 }, |
| 147 os.path.join('third_party', 'v8-i18n'): { | 160 os.path.join('third_party', 'v8-i18n'): { |
| 148 "Name": "Internationalization Library for v8", | 161 "Name": "Internationalization Library for v8", |
| 149 "URL": "http://code.google.com/p/v8-i18n/", | 162 "URL": "http://code.google.com/p/v8-i18n/", |
| 150 }, | 163 }, |
| 164 os.path.join('third_party', 'WebKit'): { |
| 165 "Name": "WebKit", |
| 166 "URL": "http://webkit.org/", |
| 167 "License": "BSD and GPL v2", |
| 168 # Absolute path here is resolved as relative to the source root. |
| 169 "License File": "/webkit/LICENSE", |
| 170 }, |
| 171 os.path.join('third_party', 'webpagereplay'): { |
| 172 "Name": "webpagereplay", |
| 173 "URL": "http://code.google.com/p/web-page-replay", |
| 174 "License": "Apache 2.0", |
| 175 }, |
| 151 os.path.join('v8', 'strongtalk'): { | 176 os.path.join('v8', 'strongtalk'): { |
| 152 "Name": "Strongtalk", | 177 "Name": "Strongtalk", |
| 153 "URL": "http://www.strongtalk.org/", | 178 "URL": "http://www.strongtalk.org/", |
| 179 # Absolute path here is resolved as relative to the source root. |
| 154 "License File": "/v8/LICENSE.strongtalk", | 180 "License File": "/v8/LICENSE.strongtalk", |
| 155 }, | 181 }, |
| 156 } | 182 } |
| 157 | 183 |
| 158 class LicenseError(Exception): | 184 class LicenseError(Exception): |
| 159 """We raise this exception when a directory's licensing info isn't | 185 """We raise this exception when a directory's licensing info isn't |
| 160 fully filled out.""" | 186 fully filled out.""" |
| 161 pass | 187 pass |
| 162 | 188 |
| 163 def AbsolutePath(path, filename): | 189 def AbsolutePath(path, filename): |
| (...skipping 23 matching lines...) Expand all Loading... |
| 187 # Relative path to a file containing some html we're required to place in | 213 # Relative path to a file containing some html we're required to place in |
| 188 # about:credits. | 214 # about:credits. |
| 189 optional_keys = ["Required Text"] | 215 optional_keys = ["Required Text"] |
| 190 | 216 |
| 191 if path in SPECIAL_CASES: | 217 if path in SPECIAL_CASES: |
| 192 metadata.update(SPECIAL_CASES[path]) | 218 metadata.update(SPECIAL_CASES[path]) |
| 193 else: | 219 else: |
| 194 # Try to find README.chromium. | 220 # Try to find README.chromium. |
| 195 readme_path = os.path.join(path, 'README.chromium') | 221 readme_path = os.path.join(path, 'README.chromium') |
| 196 if not os.path.exists(readme_path): | 222 if not os.path.exists(readme_path): |
| 197 raise LicenseError("missing README.chromium") | 223 raise LicenseError("missing README.chromium or licenses.py " |
| 224 "SPECIAL_CASES entry") |
| 198 | 225 |
| 199 for line in open(readme_path): | 226 for line in open(readme_path): |
| 200 line = line.strip() | 227 line = line.strip() |
| 201 if not line: | 228 if not line: |
| 202 break | 229 break |
| 203 for key in metadata.keys() + optional_keys: | 230 for key in metadata.keys() + optional_keys: |
| 204 field = key + ": " | 231 field = key + ": " |
| 205 if line.startswith(field): | 232 if line.startswith(field): |
| 206 metadata[key] = line[len(field):] | 233 metadata[key] = line[len(field):] |
| 207 | 234 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 229 if "Required Text" in metadata: | 256 if "Required Text" in metadata: |
| 230 required_path = AbsolutePath(path, metadata["Required Text"]) | 257 required_path = AbsolutePath(path, metadata["Required Text"]) |
| 231 if required_path is not None: | 258 if required_path is not None: |
| 232 metadata["Required Text"] = required_path | 259 metadata["Required Text"] = required_path |
| 233 else: | 260 else: |
| 234 raise LicenseError("Required text file listed but not found.") | 261 raise LicenseError("Required text file listed but not found.") |
| 235 | 262 |
| 236 return metadata | 263 return metadata |
| 237 | 264 |
| 238 | 265 |
| 266 def ContainsFiles(path): |
| 267 """Determines whether any files exist in a directory or in any of its |
| 268 subdirectories.""" |
| 269 for _, _, files in os.walk(path): |
| 270 if files: |
| 271 return True |
| 272 return False |
| 273 |
| 274 |
| 239 def FindThirdPartyDirs(): | 275 def FindThirdPartyDirs(): |
| 240 """Find all third_party directories underneath the current directory.""" | 276 """Find all third_party directories underneath the current directory.""" |
| 241 third_party_dirs = [] | 277 third_party_dirs = [] |
| 242 for path, dirs, files in os.walk('.'): | 278 for path, dirs, files in os.walk('.'): |
| 243 path = path[len('./'):] # Pretty up the path. | 279 path = path[len('./'):] # Pretty up the path. |
| 244 | 280 |
| 245 if path in PRUNE_PATHS: | 281 if path in PRUNE_PATHS: |
| 246 dirs[:] = [] | 282 dirs[:] = [] |
| 247 continue | 283 continue |
| 248 | 284 |
| 249 # Prune out directories we want to skip. | 285 # Prune out directories we want to skip. |
| 250 # (Note that we loop over PRUNE_DIRS so we're not iterating over a | 286 # (Note that we loop over PRUNE_DIRS so we're not iterating over a |
| 251 # list that we're simultaneously mutating.) | 287 # list that we're simultaneously mutating.) |
| 252 for skip in PRUNE_DIRS: | 288 for skip in PRUNE_DIRS: |
| 253 if skip in dirs: | 289 if skip in dirs: |
| 254 dirs.remove(skip) | 290 dirs.remove(skip) |
| 255 | 291 |
| 256 if os.path.basename(path) == 'third_party': | 292 if os.path.basename(path) == 'third_party': |
| 257 # Add all subdirectories that are not marked for skipping. | 293 # Add all subdirectories that are not marked for skipping. |
| 258 for dir in dirs: | 294 for dir in dirs: |
| 259 dirpath = os.path.join(path, dir) | 295 dirpath = os.path.join(path, dir) |
| 260 if dirpath not in PRUNE_PATHS: | 296 if dirpath not in PRUNE_PATHS: |
| 261 third_party_dirs.append(dirpath) | 297 third_party_dirs.append(dirpath) |
| 262 | 298 |
| 263 # Don't recurse into any subdirs from here. | 299 # Don't recurse into any subdirs from here. |
| 264 dirs[:] = [] | 300 dirs[:] = [] |
| 265 continue | 301 continue |
| 266 | 302 |
| 303 # Don't recurse into paths in ADDITIONAL_PATHS, like we do with regular |
| 304 # third_party/foo paths. |
| 305 if path in ADDITIONAL_PATHS: |
| 306 dirs[:] = [] |
| 307 |
| 267 for dir in ADDITIONAL_PATHS: | 308 for dir in ADDITIONAL_PATHS: |
| 268 third_party_dirs.append(dir) | 309 third_party_dirs.append(dir) |
| 269 | 310 |
| 270 return third_party_dirs | 311 # If a directory contains no files, assume it's a DEPS directory for a |
| 312 # project not used by our current configuration and skip it. |
| 313 return [x for x in third_party_dirs if ContainsFiles(x)] |
| 271 | 314 |
| 272 | 315 |
| 273 def ScanThirdPartyDirs(): | 316 def ScanThirdPartyDirs(): |
| 274 """Scan a list of directories and report on any problems we find.""" | 317 """Scan a list of directories and report on any problems we find.""" |
| 275 third_party_dirs = FindThirdPartyDirs() | 318 third_party_dirs = FindThirdPartyDirs() |
| 276 | 319 |
| 277 errors = [] | 320 errors = [] |
| 278 for path in sorted(third_party_dirs): | 321 for path in sorted(third_party_dirs): |
| 279 try: | 322 try: |
| 280 metadata = ParseDir(path) | 323 metadata = ParseDir(path) |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 elif command == 'credits': | 384 elif command == 'credits': |
| 342 if not GenerateCredits(): | 385 if not GenerateCredits(): |
| 343 return 1 | 386 return 1 |
| 344 else: | 387 else: |
| 345 print __doc__ | 388 print __doc__ |
| 346 return 1 | 389 return 1 |
| 347 | 390 |
| 348 | 391 |
| 349 if __name__ == '__main__': | 392 if __name__ == '__main__': |
| 350 sys.exit(main()) | 393 sys.exit(main()) |
| OLD | NEW |