Chromium Code Reviews| 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', 'GTM'): { | |
| 116 "Name": "Google Toolbox for Mac", | |
| 117 "URL": "http://code.google.com/p/google-toolbox-for-mac/", | |
| 118 "License": "Apache 2.0", | |
| 119 "License File": "COPYING", | |
| 120 }, | |
| 121 os.path.join('third_party', 'WebKit'): { | |
| 122 "Name": "WebKit", | |
| 123 "URL": "http://webkit.org/", | |
| 124 "License": "BSD and GPL v2", | |
| 125 # Absolute path here is resolved as relative to the source root. | |
| 126 "License File": "/webkit/LICENSE", | |
|
Nico
2012/07/26 19:45:04
nit: It looks like someone tried to keep these ord
Steve Block
2012/07/26 22:11:00
Hmm, they were still out of order, even if conside
| |
| 127 }, | |
| 115 os.path.join('third_party', 'angle'): { | 128 os.path.join('third_party', 'angle'): { |
| 116 "Name": "Almost Native Graphics Layer Engine", | 129 "Name": "Almost Native Graphics Layer Engine", |
| 117 "URL": "http://code.google.com/p/angleproject/", | 130 "URL": "http://code.google.com/p/angleproject/", |
| 118 }, | 131 }, |
| 132 os.path.join('third_party', 'cros_system_api'): { | |
| 133 "Name": "Chromium OS system API", | |
| 134 "URL": "http://code.google.com/apis/protocolbuffers", | |
|
Nico
2012/07/26 19:45:04
This looks wrong.
Steve Block
2012/07/26 22:11:00
This is from the README, but I guess it's specific
| |
| 135 "License": "BSD", | |
| 136 # Absolute path here is resolved as relative to the source root. | |
| 137 "License File": "/LICENSE.chromium_os", | |
| 138 }, | |
| 119 os.path.join('third_party', 'lss'): { | 139 os.path.join('third_party', 'lss'): { |
| 120 "Name": "linux-syscall-support", | 140 "Name": "linux-syscall-support", |
| 121 "URL": "http://code.google.com/p/lss/", | 141 "URL": "http://code.google.com/p/lss/", |
| 122 }, | 142 }, |
| 123 os.path.join('third_party', 'mozrunner'): { | 143 os.path.join('third_party', 'mozrunner'): { |
| 124 "Name": "mozrunner", | 144 "Name": "mozrunner", |
| 125 "URL": "http://pypi.python.org/packages/source/m/mozrunner", | 145 "URL": "http://pypi.python.org/packages/source/m/mozrunner", |
| 126 "License": "MPL 1.1/GPL 2.0/LGPL 2.1", | 146 "License": "MPL 1.1/GPL 2.0/LGPL 2.1", |
| 127 }, | 147 }, |
| 128 os.path.join('third_party', 'ots'): { | 148 os.path.join('third_party', 'ots'): { |
| 129 "Name": "OTS (OpenType Sanitizer)", | 149 "Name": "OTS (OpenType Sanitizer)", |
| 130 "URL": "http://code.google.com/p/ots/", | 150 "URL": "http://code.google.com/p/ots/", |
| 131 }, | 151 }, |
| 152 os.path.join('third_party', 'pdfsqueeze'): { | |
| 153 "Name": "pdfsqueeze", | |
| 154 "URL": "http://code.google.com/p/pdfsqueeze/", | |
| 155 "License": "Apache 2.0", | |
| 156 "License File": "COPYING", | |
| 157 }, | |
| 132 os.path.join('third_party', 'ppapi'): { | 158 os.path.join('third_party', 'ppapi'): { |
| 133 "Name": "ppapi", | 159 "Name": "ppapi", |
| 134 "URL": "http://code.google.com/p/ppapi/", | 160 "URL": "http://code.google.com/p/ppapi/", |
| 135 }, | 161 }, |
| 136 os.path.join('third_party', 'pylib_simplejson'): { | 162 os.path.join('third_party', 'pylib_simplejson'): { |
| 137 "Name": "simplejson", | 163 "Name": "simplejson", |
| 138 "URL": "http://pypi.python.org/packages/source/s/simplejson", | 164 "URL": "http://pypi.python.org/packages/source/s/simplejson", |
| 139 "License": "MIT", | 165 "License": "MIT", |
| 140 }, | 166 }, |
| 141 os.path.join('third_party', 'WebKit'): { | 167 os.path.join('third_party', 'scons-2.0.1'): { |
| 142 "Name": "WebKit", | 168 "Name": "scons-2.0.1", |
| 143 "URL": "http://webkit.org/", | 169 "URL": " http://www.scons.org", |
| 144 # Absolute path here is resolved as relative to the source root. | 170 "License": "MIT", |
| 145 "License File": "/webkit/LICENSE", | |
| 146 }, | 171 }, |
| 147 os.path.join('third_party', 'GTM'): { | 172 os.path.join('third_party', 'trace-viewer'): { |
| 148 "Name": "Google Toolbox for Mac", | 173 "Name": "trace-viewer", |
| 149 "URL": "http://code.google.com/p/google-toolbox-for-mac/", | 174 "URL": "http://code.google.com/p/trace-viewer", |
| 150 "License File": "COPYING", | 175 "License": "BSD", |
| 151 }, | |
| 152 os.path.join('third_party', 'pdfsqueeze'): { | |
| 153 "Name": "pdfsqueeze", | |
| 154 "URL": "http://code.google.com/p/pdfsqueeze/", | |
| 155 "License File": "COPYING", | |
| 156 }, | 176 }, |
| 157 os.path.join('third_party', 'v8-i18n'): { | 177 os.path.join('third_party', 'v8-i18n'): { |
| 158 "Name": "Internationalization Library for v8", | 178 "Name": "Internationalization Library for v8", |
| 159 "URL": "http://code.google.com/p/v8-i18n/", | 179 "URL": "http://code.google.com/p/v8-i18n/", |
| 160 }, | 180 }, |
| 181 os.path.join('third_party', 'webpagereplay'): { | |
| 182 "Name": "webpagereplay", | |
| 183 "URL": "http://code.google.com/p/web-page-replay", | |
| 184 "License": "Apache 2.0", | |
| 185 }, | |
| 161 os.path.join('v8', 'strongtalk'): { | 186 os.path.join('v8', 'strongtalk'): { |
| 162 "Name": "Strongtalk", | 187 "Name": "Strongtalk", |
| 163 "URL": "http://www.strongtalk.org/", | 188 "URL": "http://www.strongtalk.org/", |
| 189 # Absolute path here is resolved as relative to the source root. | |
| 164 "License File": "/v8/LICENSE.strongtalk", | 190 "License File": "/v8/LICENSE.strongtalk", |
| 165 }, | 191 }, |
| 166 } | 192 } |
| 167 | 193 |
| 168 class LicenseError(Exception): | 194 class LicenseError(Exception): |
| 169 """We raise this exception when a directory's licensing info isn't | 195 """We raise this exception when a directory's licensing info isn't |
| 170 fully filled out.""" | 196 fully filled out.""" |
| 171 pass | 197 pass |
| 172 | 198 |
| 173 def AbsolutePath(path, filename): | 199 def AbsolutePath(path, filename): |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 197 # Relative path to a file containing some html we're required to place in | 223 # Relative path to a file containing some html we're required to place in |
| 198 # about:credits. | 224 # about:credits. |
| 199 optional_keys = ["Required Text"] | 225 optional_keys = ["Required Text"] |
| 200 | 226 |
| 201 if path in SPECIAL_CASES: | 227 if path in SPECIAL_CASES: |
| 202 metadata.update(SPECIAL_CASES[path]) | 228 metadata.update(SPECIAL_CASES[path]) |
| 203 else: | 229 else: |
| 204 # Try to find README.chromium. | 230 # Try to find README.chromium. |
| 205 readme_path = os.path.join(path, 'README.chromium') | 231 readme_path = os.path.join(path, 'README.chromium') |
| 206 if not os.path.exists(readme_path): | 232 if not os.path.exists(readme_path): |
| 207 raise LicenseError("missing README.chromium") | 233 raise LicenseError("missing README.chromium or licenses.py " |
| 234 "SPECIAL_CASES entry") | |
| 208 | 235 |
| 209 for line in open(readme_path): | 236 for line in open(readme_path): |
| 210 line = line.strip() | 237 line = line.strip() |
| 211 if not line: | 238 if not line: |
| 212 break | 239 break |
| 213 for key in metadata.keys() + optional_keys: | 240 for key in metadata.keys() + optional_keys: |
| 214 field = key + ": " | 241 field = key + ": " |
| 215 if line.startswith(field): | 242 if line.startswith(field): |
| 216 metadata[key] = line[len(field):] | 243 metadata[key] = line[len(field):] |
| 217 | 244 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 239 if "Required Text" in metadata: | 266 if "Required Text" in metadata: |
| 240 required_path = AbsolutePath(path, metadata["Required Text"]) | 267 required_path = AbsolutePath(path, metadata["Required Text"]) |
| 241 if required_path is not None: | 268 if required_path is not None: |
| 242 metadata["Required Text"] = required_path | 269 metadata["Required Text"] = required_path |
| 243 else: | 270 else: |
| 244 raise LicenseError("Required text file listed but not found.") | 271 raise LicenseError("Required text file listed but not found.") |
| 245 | 272 |
| 246 return metadata | 273 return metadata |
| 247 | 274 |
| 248 | 275 |
| 276 def ContainsFiles(path): | |
| 277 """Determines whether a directory contains any files.""" | |
|
Nico
2012/07/26 19:45:04
"any files in any subdirectory"
Steve Block
2012/07/26 22:11:00
Done.
| |
| 278 for _, _, files in os.walk(path): | |
| 279 if files: | |
| 280 return True | |
| 281 return False | |
| 282 | |
| 283 | |
| 249 def FindThirdPartyDirs(): | 284 def FindThirdPartyDirs(): |
| 250 """Find all third_party directories underneath the current directory.""" | 285 """Find all third_party directories underneath the current directory.""" |
| 251 third_party_dirs = [] | 286 third_party_dirs = [] |
| 252 for path, dirs, files in os.walk('.'): | 287 for path, dirs, files in os.walk('.'): |
| 253 path = path[len('./'):] # Pretty up the path. | 288 path = path[len('./'):] # Pretty up the path. |
| 254 | 289 |
| 255 if path in PRUNE_PATHS: | 290 if path in PRUNE_PATHS: |
| 256 dirs[:] = [] | 291 dirs[:] = [] |
| 257 continue | 292 continue |
| 258 | 293 |
| 259 # Prune out directories we want to skip. | 294 # Prune out directories we want to skip. |
| 260 # (Note that we loop over PRUNE_DIRS so we're not iterating over a | 295 # (Note that we loop over PRUNE_DIRS so we're not iterating over a |
| 261 # list that we're simultaneously mutating.) | 296 # list that we're simultaneously mutating.) |
| 262 for skip in PRUNE_DIRS: | 297 for skip in PRUNE_DIRS: |
| 263 if skip in dirs: | 298 if skip in dirs: |
| 264 dirs.remove(skip) | 299 dirs.remove(skip) |
| 265 | 300 |
| 266 if os.path.basename(path) == 'third_party': | 301 if os.path.basename(path) == 'third_party': |
| 267 # Add all subdirectories that are not marked for skipping. | 302 # Add all subdirectories that are not marked for skipping. |
| 268 for dir in dirs: | 303 for dir in dirs: |
| 269 dirpath = os.path.join(path, dir) | 304 dirpath = os.path.join(path, dir) |
| 270 if dirpath not in PRUNE_PATHS: | 305 if dirpath not in PRUNE_PATHS: |
| 271 third_party_dirs.append(dirpath) | 306 third_party_dirs.append(dirpath) |
| 272 | 307 |
| 273 # Don't recurse into any subdirs from here. | 308 # Don't recurse into any subdirs from here. |
| 274 dirs[:] = [] | 309 dirs[:] = [] |
| 275 continue | 310 continue |
| 276 | 311 |
| 312 # Don't recurse into paths in ADDITIONAL_PATHS, like we do with regular | |
| 313 # third_party/foo paths. | |
| 314 if path in ADDITIONAL_PATHS: | |
| 315 dirs[:] = [] | |
| 316 | |
| 277 for dir in ADDITIONAL_PATHS: | 317 for dir in ADDITIONAL_PATHS: |
| 278 third_party_dirs.append(dir) | 318 third_party_dirs.append(dir) |
| 279 | 319 |
| 280 return third_party_dirs | 320 # If a directory contains no files, assume it's a DEPS directory for a |
| 321 # project not used by our current configuration and skip it. | |
| 322 return [x for x in third_party_dirs if ContainsFiles(x)] | |
| 281 | 323 |
| 282 | 324 |
| 283 def ScanThirdPartyDirs(): | 325 def ScanThirdPartyDirs(): |
| 284 """Scan a list of directories and report on any problems we find.""" | 326 """Scan a list of directories and report on any problems we find.""" |
| 285 third_party_dirs = FindThirdPartyDirs() | 327 third_party_dirs = FindThirdPartyDirs() |
| 286 | 328 |
| 287 errors = [] | 329 errors = [] |
| 288 for path in sorted(third_party_dirs): | 330 for path in sorted(third_party_dirs): |
| 289 try: | 331 try: |
| 290 metadata = ParseDir(path) | 332 metadata = ParseDir(path) |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 351 elif command == 'credits': | 393 elif command == 'credits': |
| 352 if not GenerateCredits(): | 394 if not GenerateCredits(): |
| 353 return 1 | 395 return 1 |
| 354 else: | 396 else: |
| 355 print __doc__ | 397 print __doc__ |
| 356 return 1 | 398 return 1 |
| 357 | 399 |
| 358 | 400 |
| 359 if __name__ == '__main__': | 401 if __name__ == '__main__': |
| 360 sys.exit(main()) | 402 sys.exit(main()) |
| OLD | NEW |