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 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
166 if filename.startswith('/'): | 166 if filename.startswith('/'): |
167 # Absolute-looking paths are relative to the source root | 167 # Absolute-looking paths are relative to the source root |
168 # (which is the directory we're run from). | 168 # (which is the directory we're run from). |
169 absolute_path = os.path.join(os.getcwd(), filename[1:]) | 169 absolute_path = os.path.join(os.getcwd(), filename[1:]) |
170 else: | 170 else: |
171 absolute_path = os.path.join(path, filename) | 171 absolute_path = os.path.join(path, filename) |
172 if os.path.exists(absolute_path): | 172 if os.path.exists(absolute_path): |
173 return absolute_path | 173 return absolute_path |
174 return None | 174 return None |
175 | 175 |
176 def ParseDir(path): | 176 def ParseDir(path, raise_on_error): |
177 """Examine a third_party/foo component and extract its metadata.""" | 177 """Examine a third_party/foo component and extract its metadata. |
178 Args: | |
179 path the path to the component to examine | |
180 raise_on_error whether to raise an exception if an error occurs | |
181 Returns: | |
182 metadata for the component | |
183 """ | |
178 | 184 |
179 # Parse metadata fields out of README.chromium. | 185 # Parse metadata fields out of README.chromium. |
180 # We examine "LICENSE" for the license file by default. | 186 # We examine "LICENSE" for the license file by default. |
181 metadata = { | 187 metadata = { |
182 "License File": "LICENSE", # Relative path to license text. | 188 "License File": "LICENSE", # Relative path to license text. |
183 "Name": None, # Short name (for header on about:credits). | 189 "Name": None, # Short name (for header on about:credits). |
184 "URL": None, # Project home page. | 190 "URL": None, # Project home page. |
185 } | 191 } |
186 | 192 |
187 # Relative path to a file containing some html we're required to place in | 193 # Relative path to a file containing some html we're required to place in |
188 # about:credits. | 194 # about:credits. |
189 optional_keys = ["Required Text"] | 195 optional_keys = ["Required Text"] |
190 | 196 |
191 if path in SPECIAL_CASES: | 197 if path in SPECIAL_CASES: |
192 metadata.update(SPECIAL_CASES[path]) | 198 metadata.update(SPECIAL_CASES[path]) |
193 else: | 199 else: |
194 # Try to find README.chromium. | 200 # Try to find README.chromium. |
195 readme_path = os.path.join(path, 'README.chromium') | 201 readme_path = os.path.join(path, 'README.chromium') |
196 if not os.path.exists(readme_path): | 202 if not os.path.exists(readme_path): |
197 raise LicenseError("missing README.chromium") | 203 if raise_on_error: |
198 | 204 raise LicenseError("missing README.chromium") |
199 for line in open(readme_path): | 205 else: |
200 line = line.strip() | 206 for line in open(readme_path): |
201 if not line: | 207 line = line.strip() |
202 break | 208 if not line: |
203 for key in metadata.keys() + optional_keys: | 209 break |
204 field = key + ": " | 210 for key in metadata.keys() + optional_keys: |
205 if line.startswith(field): | 211 field = key + ": " |
206 metadata[key] = line[len(field):] | 212 if line.startswith(field): |
213 metadata[key] = line[len(field):] | |
207 | 214 |
208 # Check that all expected metadata is present. | 215 # Check that all expected metadata is present. |
209 for key, value in metadata.iteritems(): | 216 if raise_on_error: |
210 if not value: | 217 for key, value in metadata.iteritems(): |
211 raise LicenseError("couldn't find '" + key + "' line " | 218 if not value: |
212 "in README.chromium or licences.py " | 219 raise LicenseError("couldn't find '" + key + "' line " |
213 "SPECIAL_CASES") | 220 "in README.chromium or licences.py " |
221 "SPECIAL_CASES") | |
214 | 222 |
215 # Check that the license file exists. | 223 # Check that the license file exists. |
216 for filename in (metadata["License File"], "COPYING"): | 224 for filename in (metadata["License File"], "COPYING"): |
217 license_path = AbsolutePath(path, filename) | 225 license_path = AbsolutePath(path, filename) |
218 if license_path is not None: | 226 if license_path is not None: |
219 metadata["License File"] = license_path | 227 metadata["License File"] = license_path |
220 break | 228 break |
221 | 229 |
222 if not license_path: | 230 if raise_on_error and not license_path: |
223 raise LicenseError("License file not found. " | 231 raise LicenseError("License file not found. " |
224 "Either add a file named LICENSE, " | 232 "Either add a file named LICENSE, " |
225 "import upstream's COPYING if available, " | 233 "import upstream's COPYING if available, " |
226 "or add a 'License File:' line to README.chromium " | 234 "or add a 'License File:' line to README.chromium " |
227 "with the appropriate path.") | 235 "with the appropriate path.") |
228 | 236 |
229 if "Required Text" in metadata: | 237 if "Required Text" in metadata: |
230 required_path = AbsolutePath(path, metadata["Required Text"]) | 238 required_path = AbsolutePath(path, metadata["Required Text"]) |
231 if required_path is not None: | 239 if required_path is not None: |
232 metadata["Required Text"] = required_path | 240 metadata["Required Text"] = required_path |
233 else: | 241 elif raise_on_error: |
234 raise LicenseError("Required text file listed but not found.") | 242 raise LicenseError("Required text file listed but not found.") |
235 | 243 |
236 return metadata | 244 return metadata |
237 | 245 |
238 | 246 |
239 def FindThirdPartyDirs(): | 247 def FindThirdPartyDirs(): |
240 """Find all third_party directories underneath the current directory.""" | 248 """Find all third_party directories underneath the current directory.""" |
241 third_party_dirs = [] | 249 third_party_dirs = [] |
242 for path, dirs, files in os.walk('.'): | 250 for path, dirs, files in os.walk('.'): |
243 path = path[len('./'):] # Pretty up the path. | 251 path = path[len('./'):] # Pretty up the path. |
(...skipping 26 matching lines...) Expand all Loading... | |
270 return third_party_dirs | 278 return third_party_dirs |
271 | 279 |
272 | 280 |
273 def ScanThirdPartyDirs(): | 281 def ScanThirdPartyDirs(): |
274 """Scan a list of directories and report on any problems we find.""" | 282 """Scan a list of directories and report on any problems we find.""" |
275 third_party_dirs = FindThirdPartyDirs() | 283 third_party_dirs = FindThirdPartyDirs() |
276 | 284 |
277 errors = [] | 285 errors = [] |
278 for path in sorted(third_party_dirs): | 286 for path in sorted(third_party_dirs): |
279 try: | 287 try: |
280 metadata = ParseDir(path) | 288 metadata = ParseDir(path, True) |
Evan Martin
2012/07/24 19:41:28
Consider something like:
ParseDir(path, raise_on
Steve Block
2012/07/24 21:20:58
Regarding a try block, this approach doesn't work
| |
281 except LicenseError, e: | 289 except LicenseError, e: |
282 errors.append((path, e.args[0])) | 290 errors.append((path, e.args[0])) |
283 continue | 291 continue |
284 | 292 |
285 for path, error in sorted(errors): | 293 for path, error in sorted(errors): |
286 print path + ": " + error | 294 print path + ": " + error |
287 | 295 |
288 return len(errors) == 0 | 296 return len(errors) == 0 |
289 | 297 |
290 | 298 |
291 def GenerateCredits(): | 299 def GenerateCredits(): |
292 """Generate about:credits, dumping the result to stdout.""" | 300 """Generate about:credits, dumping the result to stdout.""" |
293 | 301 |
294 def EvaluateTemplate(template, env, escape=True): | 302 def EvaluateTemplate(template, env, escape=True): |
295 """Expand a template with variables like {{foo}} using a | 303 """Expand a template with variables like {{foo}} using a |
296 dictionary of expansions.""" | 304 dictionary of expansions.""" |
297 for key, val in env.items(): | 305 for key, val in env.items(): |
298 if escape and not key.endswith("_unescaped"): | 306 if escape and not key.endswith("_unescaped"): |
299 val = cgi.escape(val) | 307 val = cgi.escape(val) |
300 template = template.replace('{{%s}}' % key, val) | 308 template = template.replace('{{%s}}' % key, val) |
301 return template | 309 return template |
302 | 310 |
303 third_party_dirs = FindThirdPartyDirs() | 311 third_party_dirs = FindThirdPartyDirs() |
304 | 312 |
305 entry_template = open('chrome/browser/resources/about_credits_entry.tmpl', | 313 entry_template = open('chrome/browser/resources/about_credits_entry.tmpl', |
306 'rb').read() | 314 'rb').read() |
307 entries = [] | 315 entries = [] |
308 for path in sorted(third_party_dirs): | 316 for path in sorted(third_party_dirs): |
309 try: | 317 try: |
310 metadata = ParseDir(path) | 318 metadata = ParseDir(path, True) |
311 except LicenseError: | 319 except LicenseError: |
312 print >>sys.stderr, ("WARNING: licensing info for " + path + | 320 print >>sys.stderr, ("WARNING: licensing info for " + path + |
313 " is incomplete, skipping.") | 321 " is incomplete, skipping.") |
314 continue | 322 continue |
315 env = { | 323 env = { |
316 'name': metadata['Name'], | 324 'name': metadata['Name'], |
317 'url': metadata['URL'], | 325 'url': metadata['URL'], |
318 'license': open(metadata['License File'], 'rb').read(), | 326 'license': open(metadata['License File'], 'rb').read(), |
319 'license_unescaped': '', | 327 'license_unescaped': '', |
320 } | 328 } |
(...skipping 20 matching lines...) Expand all Loading... | |
341 elif command == 'credits': | 349 elif command == 'credits': |
342 if not GenerateCredits(): | 350 if not GenerateCredits(): |
343 return 1 | 351 return 1 |
344 else: | 352 else: |
345 print __doc__ | 353 print __doc__ |
346 return 1 | 354 return 1 |
347 | 355 |
348 | 356 |
349 if __name__ == '__main__': | 357 if __name__ == '__main__': |
350 sys.exit(main()) | 358 sys.exit(main()) |
OLD | NEW |