Get GenericScopedHandle::Set to preserve LastError code
[chromium-blink-merge.git] / tools / checklicenses / checklicenses.py
blobac44de59705d1f726e8e146a21a42fd15a979048
1 #!/usr/bin/env python
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
4 # found in the LICENSE file.
6 """Makes sure that all files contain proper licensing information."""
9 import json
10 import optparse
11 import os.path
12 import subprocess
13 import sys
16 def PrintUsage():
17 print """Usage: python checklicenses.py [--root <root>] [tocheck]
18 --root Specifies the repository root. This defaults to "../.." relative
19 to the script file. This will be correct given the normal location
20 of the script in "<root>/tools/checklicenses".
22 --ignore-suppressions Ignores path-specific license whitelist. Useful when
23 trying to remove a suppression/whitelist entry.
25 tocheck Specifies the directory, relative to root, to check. This defaults
26 to "." so it checks everything.
28 Examples:
29 python checklicenses.py
30 python checklicenses.py --root ~/chromium/src third_party"""
33 WHITELISTED_LICENSES = [
34 'Anti-Grain Geometry',
35 'Apache (v2.0)',
36 'Apache (v2.0) BSD (2 clause)',
37 'Apache (v2.0) GPL (v2)',
38 'Apple MIT', # https://fedoraproject.org/wiki/Licensing/Apple_MIT_License
39 'APSL (v2)',
40 'APSL (v2) BSD (4 clause)',
41 'BSD',
42 'BSD (2 clause)',
43 'BSD (2 clause) ISC',
44 'BSD (2 clause) MIT/X11 (BSD like)',
45 'BSD (3 clause)',
46 'BSD (3 clause) GPL (v2)',
47 'BSD (3 clause) ISC',
48 'BSD (3 clause) LGPL (v2 or later)',
49 'BSD (3 clause) LGPL (v2.1 or later)',
50 'BSD (3 clause) MIT/X11 (BSD like)',
51 'BSD (4 clause)',
52 'BSD-like',
54 # TODO(phajdan.jr): Make licensecheck not print BSD-like twice.
55 'BSD-like MIT/X11 (BSD like)',
57 'BSL (v1.0)',
58 'FreeType (BSD like)',
59 'FreeType (BSD like) with patent clause',
60 'GPL (v2) LGPL (v2.1 or later)',
61 'GPL (v2 or later) with Bison parser exception',
62 'GPL (v2 or later) with libtool exception',
63 'GPL (v3 or later) with Bison parser exception',
64 'GPL with Bison parser exception',
65 'Independent JPEG Group License',
66 'ISC',
67 'LGPL (unversioned/unknown version)',
68 'LGPL (v2)',
69 'LGPL (v2 or later)',
70 'LGPL (v2.1)',
71 'LGPL (v2.1 or later)',
72 'LGPL (v3 or later)',
73 'MIT/X11 (BSD like)',
74 'MIT/X11 (BSD like) LGPL (v2.1 or later)',
75 'MPL (v1.0) LGPL (v2 or later)',
76 'MPL (v1.1)',
77 'MPL (v1.1) BSD (3 clause) GPL (v2) LGPL (v2.1 or later)',
78 'MPL (v1.1) BSD (3 clause) LGPL (v2.1 or later)',
79 'MPL (v1.1) BSD-like',
80 'MPL (v1.1) BSD-like GPL (unversioned/unknown version)',
81 'MPL (v1.1) BSD-like GPL (v2) LGPL (v2.1 or later)',
82 'MPL (v1.1) GPL (v2)',
83 'MPL (v1.1) GPL (v2) LGPL (v2 or later)',
84 'MPL (v1.1) GPL (v2) LGPL (v2.1 or later)',
85 'MPL (v1.1) GPL (unversioned/unknown version)',
86 'MPL (v1.1) LGPL (v2 or later)',
87 'MPL (v1.1) LGPL (v2.1 or later)',
88 'MPL (v2.0)',
89 'Ms-PL',
90 'Public domain',
91 'Public domain BSD',
92 'Public domain BSD (3 clause)',
93 'Public domain BSD-like',
94 'Public domain LGPL (v2.1 or later)',
95 'libpng',
96 'zlib/libpng',
97 'SGI Free Software License B',
98 'SunSoft (BSD like)',
99 'University of Illinois/NCSA Open Source License (BSD like)',
100 ('University of Illinois/NCSA Open Source License (BSD like) '
101 'MIT/X11 (BSD like)'),
105 PATH_SPECIFIC_WHITELISTED_LICENSES = {
106 'base/third_party/icu': [ # http://crbug.com/98087
107 'UNKNOWN',
110 # http://code.google.com/p/google-breakpad/issues/detail?id=450
111 'breakpad/src': [
112 'UNKNOWN',
115 'buildtools/third_party/libc++/trunk/test': [
116 # http://llvm.org/bugs/show_bug.cgi?id=18291
117 'UNKNOWN',
120 'chrome/common/extensions/docs/examples': [ # http://crbug.com/98092
121 'UNKNOWN',
123 # This contains files copied from elsewhere from the tree. Since the copied
124 # directories might have suppressions below (like simplejson), whitelist the
125 # whole directory. This is also not shipped code.
126 'chrome/common/extensions/docs/server2/third_party': [
127 'UNKNOWN',
129 'courgette/third_party/bsdiff_create.cc': [ # http://crbug.com/98095
130 'UNKNOWN',
132 'courgette/third_party/qsufsort.h': [ # http://crbug.com/98095
133 'UNKNOWN',
135 'native_client': [ # http://crbug.com/98099
136 'UNKNOWN',
138 'native_client/toolchain': [
139 'BSD GPL (v2 or later)',
140 'BSD MIT/X11 (BSD like)',
141 'BSD (2 clause) GPL (v2 or later)',
142 'BSD (3 clause) GPL (v2 or later)',
143 'BSD (4 clause) ISC',
144 'BSL (v1.0) GPL',
145 'BSL (v1.0) GPL (v3.1)',
146 'GPL',
147 'GPL (unversioned/unknown version)',
148 'GPL (v2)',
149 'GPL (v2 or later)',
150 'GPL (v3.1)',
151 'GPL (v3 or later)',
152 'MPL (v1.1) LGPL (unversioned/unknown version)',
154 'third_party/WebKit': [
155 'UNKNOWN',
158 # http://code.google.com/p/angleproject/issues/detail?id=217
159 'third_party/angle': [
160 'UNKNOWN',
163 # http://crbug.com/222828
164 # http://bugs.python.org/issue17514
165 'third_party/chromite/third_party/argparse.py': [
166 'UNKNOWN',
169 # http://crbug.com/326117
170 # https://bitbucket.org/chrisatlee/poster/issue/21
171 'third_party/chromite/third_party/poster': [
172 'UNKNOWN',
175 # http://crbug.com/333508
176 'third_party/clang_format/script': [
177 'UNKNOWN',
180 # http://crbug.com/333508
181 'buildtools/clang_format/script': [
182 'UNKNOWN',
185 # https://mail.python.org/pipermail/cython-devel/2014-July/004062.html
186 'third_party/cython': [
187 'UNKNOWN',
190 'third_party/devscripts': [
191 'GPL (v2 or later)',
193 'third_party/catapult/tracing/third_party/devscripts': [
194 'GPL (v2 or later)',
197 # https://github.com/shazow/apiclient/issues/8
198 # MIT license.
199 'third_party/catapult/third_party/apiclient': [
200 'UNKNOWN',
202 'third_party/catapult/dashboard/third_party/apiclient': [
203 'UNKNOWN',
206 # https://bugs.launchpad.net/beautifulsoup/+bug/1481316
207 # MIT license.
208 'third_party/catapult/third_party/beautifulsoup': [
209 'UNKNOWN'
211 'third_party/catapult/dashboard/third_party/beautifulsoup': [
212 'UNKNOWN'
215 # https://code.google.com/p/graphy/issues/detail?id=6
216 # Apache (v2.0)
217 'third_party/catapult/third_party/graphy': [
218 'UNKNOWN',
220 'third_party/catapult/dashboard/third_party/graphy': [
221 'UNKNOWN',
224 # https://github.com/html5lib/html5lib-python/issues/125
225 # MIT license.
226 'third_party/catapult/third_party/html5lib-python': [
227 'UNKNOWN',
230 # https://github.com/jcgregorio/httplib2/issues/307
231 # MIT license.
232 'third_party/catapult/third_party/httplib2': [
233 'UNKNOWN',
235 'third_party/catapult/dashboard/third_party/httplib2': [
236 'UNKNOWN',
239 # https://github.com/GoogleCloudPlatform/appengine-mapreduce/issues/71
240 # Apache (v2.0)
241 'third_party/catapult/third_party/mapreduce': [
242 'UNKNOWN',
244 'third_party/catapult/dashboard/third_party/mapreduce': [
245 'UNKNOWN',
248 # https://code.google.com/p/webapp-improved/issues/detail?id=103
249 # Apache (v2.0).
250 'third_party/catapult/third_party/webapp2': [
251 'UNKNOWN',
253 'third_party/catapult/dashboard/third_party/webapp2': [
254 'UNKNOWN',
257 # https://github.com/Pylons/webob/issues/211
258 # MIT license.
259 'third_party/catapult/third_party/WebOb': [
260 'UNKNOWN',
262 'third_party/catapult/dashboard/third_party/WebOb': [
263 'UNKNOWN',
266 # https://github.com/Pylons/webtest/issues/141
267 # MIT license.
268 'third_party/catapult/third_party/webtest': [
269 'UNKNOWN',
271 'third_party/catapult/dashboard/third_party/webtest': [
272 'UNKNOWN',
275 # https://bitbucket.org/ianb/paste/issues/12/add-license-headers-to-source-files
276 # MIT license.
277 'third_party/catapult/third_party/Paste': [
278 'UNKNOWN',
280 'third_party/catapult/dashboard/third_party/Paste': [
281 'UNKNOWN',
284 # https://github.com/google/oauth2client/issues/231
285 # Apache v2.0.
286 'third_party/catapult/third_party/oauth2client': [
287 'UNKNOWN',
289 'third_party/catapult/dashboard/third_party/oauth2client': [
290 'UNKNOWN',
293 # https://bitbucket.org/gutworth/six/issues/129/add-license-headers-to-source-files
294 # MIT license.
295 'third_party/catapult/third_party/six': [
296 'UNKNOWN',
298 'third_party/catapult/dashboard/third_party/six': [
299 'UNKNOWN',
302 'third_party/expat/files/lib': [ # http://crbug.com/98121
303 'UNKNOWN',
305 'third_party/ffmpeg': [
306 'GPL',
307 'GPL (v2)',
308 'GPL (v2 or later)',
309 'GPL (v3 or later)',
310 'UNKNOWN', # http://crbug.com/98123
312 'third_party/fontconfig': [
313 # https://bugs.freedesktop.org/show_bug.cgi?id=73401
314 'UNKNOWN',
316 'third_party/freetype2': [ # http://crbug.com/177319
317 'UNKNOWN',
319 'third_party/hunspell': [ # http://crbug.com/98134
320 'UNKNOWN',
322 'third_party/iccjpeg': [ # http://crbug.com/98137
323 'UNKNOWN',
325 'third_party/icu': [ # http://crbug.com/98301
326 'UNKNOWN',
328 'third_party/jsoncpp/source': [
329 # https://github.com/open-source-parsers/jsoncpp/issues/234
330 'UNKNOWN',
332 'third_party/junit/src': [
333 # https://github.com/junit-team/junit/issues/1132
334 'UNKNOWN',
336 'third_party/lcov': [ # http://crbug.com/98304
337 'UNKNOWN',
339 'third_party/lcov/contrib/galaxy/genflat.pl': [
340 'GPL (v2 or later)',
342 'third_party/libevent': [ # http://crbug.com/98309
343 'UNKNOWN',
345 'third_party/libjingle/source/talk': [ # http://crbug.com/98310
346 'UNKNOWN',
348 'third_party/libjpeg_turbo': [ # http://crbug.com/98314
349 'UNKNOWN',
352 # Many liblouis files are mirrored but not used in the NaCl module.
353 # They are not excluded from the mirror because of lack of infrastructure
354 # support. Getting license headers added to the files where missing is
355 # tracked in https://github.com/liblouis/liblouis/issues/22.
356 'third_party/liblouis/src': [
357 'GPL (v3 or later)',
358 'UNKNOWN',
361 'third_party/libpng': [ # http://crbug.com/98318
362 'UNKNOWN',
365 # The following files lack license headers, but are trivial.
366 'third_party/libusb/src/libusb/os/poll_posix.h': [
367 'UNKNOWN',
370 'third_party/libvpx/source': [ # http://crbug.com/98319
371 'UNKNOWN',
373 'third_party/libxml': [
374 'UNKNOWN',
376 'third_party/libxslt': [
377 'UNKNOWN',
379 'third_party/lzma_sdk': [
380 'UNKNOWN',
382 'third_party/mesa/src': [
383 'GPL (v2)',
384 'GPL (v3 or later)',
385 'MIT/X11 (BSD like) GPL (v3 or later) with Bison parser exception',
386 'UNKNOWN', # http://crbug.com/98450
388 'third_party/modp_b64': [
389 'UNKNOWN',
391 'third_party/openmax_dl/dl' : [
392 'Khronos Group',
394 'third_party/openssl': [ # http://crbug.com/98451
395 'UNKNOWN',
397 'third_party/boringssl': [
398 # There are some files in BoringSSL which came from OpenSSL and have no
399 # license in them. We don't wish to add the license header ourselves
400 # thus we don't expect to pass license checks.
401 'UNKNOWN',
403 'third_party/ots/tools/ttf-checksum.py': [ # http://code.google.com/p/ots/issues/detail?id=2
404 'UNKNOWN',
406 'third_party/molokocacao': [ # http://crbug.com/98453
407 'UNKNOWN',
409 'third_party/ocmock/OCMock': [ # http://crbug.com/98454
410 'UNKNOWN',
412 'third_party/protobuf': [ # http://crbug.com/98455
413 'UNKNOWN',
416 # https://bitbucket.org/ned/coveragepy/issue/313/add-license-file-containing-2-3-or-4
417 # BSD 2-clause license.
418 'third_party/pycoverage': [
419 'UNKNOWN',
422 'third_party/pyelftools': [ # http://crbug.com/222831
423 'UNKNOWN',
425 'third_party/scons-2.0.1/engine/SCons': [ # http://crbug.com/98462
426 'UNKNOWN',
428 'third_party/simplejson': [
429 'UNKNOWN',
431 'third_party/skia': [ # http://crbug.com/98463
432 'UNKNOWN',
434 'third_party/snappy/src': [ # http://crbug.com/98464
435 'UNKNOWN',
437 'third_party/smhasher/src': [ # http://crbug.com/98465
438 'UNKNOWN',
440 'third_party/speech-dispatcher/libspeechd.h': [
441 'GPL (v2 or later)',
443 'third_party/sqlite': [
444 'UNKNOWN',
447 # http://crbug.com/334668
448 # MIT license.
449 'tools/swarming_client/third_party/httplib2': [
450 'UNKNOWN',
453 # http://crbug.com/334668
454 # Apache v2.0.
455 'tools/swarming_client/third_party/oauth2client': [
456 'UNKNOWN',
459 # http://crbug.com/471372
460 # BSD
461 'tools/swarming_client/third_party/pyasn1': [
462 'UNKNOWN',
465 # http://crbug.com/471372
466 # Apache v2.0.
467 'tools/swarming_client/third_party/rsa': [
468 'UNKNOWN',
471 # https://github.com/kennethreitz/requests/issues/1610
472 'tools/swarming_client/third_party/requests': [
473 'UNKNOWN',
476 'third_party/talloc': [
477 'GPL (v3 or later)',
478 'UNKNOWN', # http://crbug.com/98588
480 'third_party/tcmalloc': [
481 'UNKNOWN', # http://crbug.com/98589
483 'third_party/tlslite': [
484 'UNKNOWN',
486 'third_party/webdriver': [ # http://crbug.com/98590
487 'UNKNOWN',
490 # https://github.com/html5lib/html5lib-python/issues/125
491 # https://github.com/KhronosGroup/WebGL/issues/435
492 'third_party/webgl/src': [
493 'UNKNOWN',
496 'third_party/webrtc': [ # http://crbug.com/98592
497 'UNKNOWN',
499 'third_party/xdg-utils': [ # http://crbug.com/98593
500 'UNKNOWN',
502 'third_party/yasm/source': [ # http://crbug.com/98594
503 'UNKNOWN',
505 'third_party/zlib/contrib/minizip': [
506 'UNKNOWN',
508 'third_party/zlib/trees.h': [
509 'UNKNOWN',
511 'tools/emacs': [ # http://crbug.com/98595
512 'UNKNOWN',
514 'tools/gyp/test': [
515 'UNKNOWN',
517 'tools/python/google/__init__.py': [
518 'UNKNOWN',
520 'tools/stats_viewer/Properties/AssemblyInfo.cs': [
521 'UNKNOWN',
523 'tools/symsrc/pefile.py': [
524 'UNKNOWN',
526 # Not shipped, MIT license but the header files contain no licensing info.
527 'tools/telemetry/third_party/altgraph': [
528 'UNKNOWN',
530 # Not shipped, downloaded on trybots sometimes.
531 'tools/telemetry/third_party/gsutil': [
532 'BSD MIT/X11 (BSD like)',
533 'UNKNOWN',
535 # Not shipped, MIT license but the header files contain no licensing info.
536 'tools/telemetry/third_party/modulegraph': [
537 'UNKNOWN',
539 'tools/telemetry/third_party/pyserial': [
540 # https://sourceforge.net/p/pyserial/feature-requests/35/
541 'UNKNOWN',
543 'v8/test/cctest': [ # http://crbug.com/98597
544 'UNKNOWN',
546 'v8/src/third_party/kernel/tools/perf/util/jitdump.h': [ # http://crbug.com/391716
547 'UNKNOWN',
551 EXCLUDED_PATHS = [
552 # Don't check generated files
553 'out/',
555 # Don't check sysroot directories
556 'build/linux/debian_wheezy_amd64-sysroot',
557 'build/linux/debian_wheezy_arm-sysroot',
558 'build/linux/debian_wheezy_i386-sysroot',
559 'build/linux/debian_wheezy_mips-sysroot',
563 def check_licenses(options, args):
564 # Figure out which directory we have to check.
565 if len(args) == 0:
566 # No directory to check specified, use the repository root.
567 start_dir = options.base_directory
568 elif len(args) == 1:
569 # Directory specified. Start here. It's supposed to be relative to the
570 # base directory.
571 start_dir = os.path.abspath(os.path.join(options.base_directory, args[0]))
572 else:
573 # More than one argument, we don't handle this.
574 PrintUsage()
575 return 1
577 print "Using base directory:", options.base_directory
578 print "Checking:", start_dir
579 print
581 licensecheck_path = os.path.abspath(os.path.join(options.base_directory,
582 'third_party',
583 'devscripts',
584 'licensecheck.pl'))
586 licensecheck = subprocess.Popen([licensecheck_path,
587 '-l', '100',
588 '-r', start_dir],
589 stdout=subprocess.PIPE,
590 stderr=subprocess.PIPE)
591 stdout, stderr = licensecheck.communicate()
592 if options.verbose:
593 print '----------- licensecheck stdout -----------'
594 print stdout
595 print '--------- end licensecheck stdout ---------'
596 if licensecheck.returncode != 0 or stderr:
597 print '----------- licensecheck stderr -----------'
598 print stderr
599 print '--------- end licensecheck stderr ---------'
600 print "\nFAILED\n"
601 return 1
603 used_suppressions = set()
604 errors = []
606 for line in stdout.splitlines():
607 filename, license = line.split(':', 1)
608 filename = os.path.relpath(filename.strip(), options.base_directory)
610 # Check if the file belongs to one of the excluded paths.
611 if any((filename.startswith(path) for path in EXCLUDED_PATHS)):
612 continue
614 # For now we're just interested in the license.
615 license = license.replace('*No copyright*', '').strip()
617 # Skip generated files.
618 if 'GENERATED FILE' in license:
619 continue
621 if license in WHITELISTED_LICENSES:
622 continue
624 if not options.ignore_suppressions:
625 matched_prefixes = [
626 prefix for prefix in PATH_SPECIFIC_WHITELISTED_LICENSES
627 if filename.startswith(prefix) and
628 license in PATH_SPECIFIC_WHITELISTED_LICENSES[prefix]]
629 if matched_prefixes:
630 used_suppressions.update(set(matched_prefixes))
631 continue
633 errors.append({'filename': filename, 'license': license})
635 if options.json:
636 with open(options.json, 'w') as f:
637 json.dump(errors, f)
639 if errors:
640 for error in errors:
641 print "'%s' has non-whitelisted license '%s'" % (
642 error['filename'], error['license'])
643 print "\nFAILED\n"
644 print "Please read",
645 print "http://www.chromium.org/developers/adding-3rd-party-libraries"
646 print "for more info how to handle the failure."
647 print
648 print "Please respect OWNERS of checklicenses.py. Changes violating"
649 print "this requirement may be reverted."
651 # Do not print unused suppressions so that above message is clearly
652 # visible and gets proper attention. Too much unrelated output
653 # would be distracting and make the important points easier to miss.
655 return 1
657 print "\nSUCCESS\n"
659 if not len(args):
660 unused_suppressions = set(
661 PATH_SPECIFIC_WHITELISTED_LICENSES.iterkeys()).difference(
662 used_suppressions)
663 if unused_suppressions:
664 print "\nNOTE: unused suppressions detected:\n"
665 print '\n'.join(unused_suppressions)
667 return 0
670 def main():
671 default_root = os.path.abspath(
672 os.path.join(os.path.dirname(__file__), '..', '..'))
673 option_parser = optparse.OptionParser()
674 option_parser.add_option('--root', default=default_root,
675 dest='base_directory',
676 help='Specifies the repository root. This defaults '
677 'to "../.." relative to the script file, which '
678 'will normally be the repository root.')
679 option_parser.add_option('-v', '--verbose', action='store_true',
680 default=False, help='Print debug logging')
681 option_parser.add_option('--ignore-suppressions',
682 action='store_true',
683 default=False,
684 help='Ignore path-specific license whitelist.')
685 option_parser.add_option('--json', help='Path to JSON output file')
686 options, args = option_parser.parse_args()
687 return check_licenses(options, args)
690 if '__main__' == __name__:
691 sys.exit(main())