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."""
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.
29 python checklicenses.py
30 python checklicenses.py --root ~/chromium/src third_party"""
33 WHITELISTED_LICENSES
= [
34 'Anti-Grain Geometry',
36 'Apache (v2.0) BSD (2 clause)',
37 'Apache (v2.0) GPL (v2)',
38 'Apple MIT', # https://fedoraproject.org/wiki/Licensing/Apple_MIT_License
40 'APSL (v2) BSD (4 clause)',
44 'BSD (2 clause) MIT/X11 (BSD like)',
46 'BSD (3 clause) GPL (v2)',
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)',
54 # TODO(phajdan.jr): Make licensecheck not print BSD-like twice.
55 'BSD-like MIT/X11 (BSD like)',
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',
67 'LGPL (unversioned/unknown version)',
71 'LGPL (v2.1 or later)',
74 'MIT/X11 (BSD like) LGPL (v2.1 or later)',
75 'MPL (v1.0) LGPL (v2 or later)',
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)',
92 'Public domain BSD (3 clause)',
93 'Public domain BSD-like',
94 'Public domain LGPL (v2.1 or later)',
97 'SGI Free Software License B',
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
110 # http://code.google.com/p/google-breakpad/issues/detail?id=450
115 'buildtools/third_party/libc++/trunk/test': [
116 # http://llvm.org/bugs/show_bug.cgi?id=18291
120 'chrome/common/extensions/docs/examples': [ # http://crbug.com/98092
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': [
129 'courgette/third_party/bsdiff_create.cc': [ # http://crbug.com/98095
132 'courgette/third_party/qsufsort.h': [ # http://crbug.com/98095
135 'native_client': [ # http://crbug.com/98099
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',
145 'BSL (v1.0) GPL (v3.1)',
147 'GPL (unversioned/unknown version)',
152 'MPL (v1.1) LGPL (unversioned/unknown version)',
154 'third_party/WebKit': [
158 # http://code.google.com/p/angleproject/issues/detail?id=217
159 'third_party/angle': [
163 # http://crbug.com/222828
164 # http://bugs.python.org/issue17514
165 'third_party/chromite/third_party/argparse.py': [
169 # http://crbug.com/326117
170 # https://bitbucket.org/chrisatlee/poster/issue/21
171 'third_party/chromite/third_party/poster': [
175 # http://crbug.com/333508
176 'third_party/clang_format/script': [
180 # http://crbug.com/333508
181 'buildtools/clang_format/script': [
185 # https://mail.python.org/pipermail/cython-devel/2014-July/004062.html
186 'third_party/cython': [
190 'third_party/devscripts': [
193 'third_party/catapult/tracing/third_party/devscripts': [
197 # https://github.com/shazow/apiclient/issues/8
199 'third_party/catapult/third_party/apiclient': [
202 'third_party/catapult/dashboard/third_party/apiclient': [
206 # https://bugs.launchpad.net/beautifulsoup/+bug/1481316
208 'third_party/catapult/third_party/beautifulsoup': [
211 'third_party/catapult/dashboard/third_party/beautifulsoup': [
215 # https://code.google.com/p/graphy/issues/detail?id=6
217 'third_party/catapult/third_party/graphy': [
220 'third_party/catapult/dashboard/third_party/graphy': [
224 # https://github.com/GoogleCloudPlatform/appengine-mapreduce/issues/71
226 'third_party/catapult/third_party/mapreduce': [
229 'third_party/catapult/dashboard/third_party/mapreduce': [
233 # https://code.google.com/p/webapp-improved/issues/detail?id=103
235 'third_party/catapult/third_party/webapp2': [
238 'third_party/catapult/dashboard/third_party/webapp2': [
242 # https://github.com/Pylons/webob/issues/211
244 'third_party/catapult/third_party/WebOb': [
247 'third_party/catapult/dashboard/third_party/WebOb': [
251 # https://github.com/Pylons/webtest/issues/141
253 'third_party/catapult/third_party/webtest': [
256 'third_party/catapult/dashboard/third_party/webtest': [
260 # https://bitbucket.org/ianb/paste/issues/12/add-license-headers-to-source-files
262 'third_party/catapult/third_party/Paste': [
265 'third_party/catapult/dashboard/third_party/Paste': [
269 # https://github.com/google/oauth2client/issues/231
271 'third_party/catapult/third_party/oauth2client': [
274 'third_party/catapult/dashboard/third_party/oauth2client': [
278 # https://bitbucket.org/gutworth/six/issues/129/add-license-headers-to-source-files
280 'third_party/catapult/third_party/six': [
283 'third_party/catapult/dashboard/third_party/six': [
287 'third_party/expat/files/lib': [ # http://crbug.com/98121
290 'third_party/ffmpeg': [
295 'UNKNOWN', # http://crbug.com/98123
297 'third_party/fontconfig': [
298 # https://bugs.freedesktop.org/show_bug.cgi?id=73401
301 'third_party/freetype2': [ # http://crbug.com/177319
304 'third_party/hunspell': [ # http://crbug.com/98134
307 'third_party/iccjpeg': [ # http://crbug.com/98137
310 'third_party/icu': [ # http://crbug.com/98301
313 'third_party/jsoncpp/source': [
314 # https://github.com/open-source-parsers/jsoncpp/issues/234
317 'third_party/junit/src': [
318 # https://github.com/junit-team/junit/issues/1132
321 'third_party/lcov': [ # http://crbug.com/98304
324 'third_party/lcov/contrib/galaxy/genflat.pl': [
327 'third_party/libevent': [ # http://crbug.com/98309
330 'third_party/libjingle/source/talk': [ # http://crbug.com/98310
333 'third_party/libjpeg_turbo': [ # http://crbug.com/98314
337 # Many liblouis files are mirrored but not used in the NaCl module.
338 # They are not excluded from the mirror because of lack of infrastructure
339 # support. Getting license headers added to the files where missing is
340 # tracked in https://github.com/liblouis/liblouis/issues/22.
341 'third_party/liblouis/src': [
346 'third_party/libpng': [ # http://crbug.com/98318
350 # The following files lack license headers, but are trivial.
351 'third_party/libusb/src/libusb/os/poll_posix.h': [
355 'third_party/libvpx/source': [ # http://crbug.com/98319
358 'third_party/libxml': [
361 'third_party/libxslt': [
364 'third_party/lzma_sdk': [
367 'third_party/mesa/src': [
370 'MIT/X11 (BSD like) GPL (v3 or later) with Bison parser exception',
371 'UNKNOWN', # http://crbug.com/98450
373 'third_party/modp_b64': [
376 'third_party/openmax_dl/dl' : [
379 'third_party/openssl': [ # http://crbug.com/98451
382 'third_party/boringssl': [
383 # There are some files in BoringSSL which came from OpenSSL and have no
384 # license in them. We don't wish to add the license header ourselves
385 # thus we don't expect to pass license checks.
388 'third_party/ots/tools/ttf-checksum.py': [ # http://code.google.com/p/ots/issues/detail?id=2
391 'third_party/molokocacao': [ # http://crbug.com/98453
394 'third_party/ocmock/OCMock': [ # http://crbug.com/98454
397 'third_party/protobuf': [ # http://crbug.com/98455
401 # https://bitbucket.org/ned/coveragepy/issue/313/add-license-file-containing-2-3-or-4
402 # BSD 2-clause license.
403 'third_party/pycoverage': [
407 'third_party/pyelftools': [ # http://crbug.com/222831
410 'third_party/scons-2.0.1/engine/SCons': [ # http://crbug.com/98462
413 'third_party/simplejson': [
416 'third_party/skia': [ # http://crbug.com/98463
419 'third_party/snappy/src': [ # http://crbug.com/98464
422 'third_party/smhasher/src': [ # http://crbug.com/98465
425 'third_party/speech-dispatcher/libspeechd.h': [
428 'third_party/sqlite': [
432 # http://crbug.com/334668
434 'tools/swarming_client/third_party/httplib2': [
438 # http://crbug.com/334668
440 'tools/swarming_client/third_party/oauth2client': [
444 # http://crbug.com/471372
446 'tools/swarming_client/third_party/pyasn1': [
450 # http://crbug.com/471372
452 'tools/swarming_client/third_party/rsa': [
456 # https://github.com/kennethreitz/requests/issues/1610
457 'tools/swarming_client/third_party/requests': [
461 'third_party/talloc': [
463 'UNKNOWN', # http://crbug.com/98588
465 'third_party/tcmalloc': [
466 'UNKNOWN', # http://crbug.com/98589
468 'third_party/tlslite': [
471 'third_party/webdriver': [ # http://crbug.com/98590
475 # https://github.com/html5lib/html5lib-python/issues/125
476 # https://github.com/KhronosGroup/WebGL/issues/435
477 'third_party/webgl/src': [
481 'third_party/webrtc': [ # http://crbug.com/98592
484 'third_party/xdg-utils': [ # http://crbug.com/98593
487 'third_party/yasm/source': [ # http://crbug.com/98594
490 'third_party/zlib/contrib/minizip': [
493 'third_party/zlib/trees.h': [
496 'tools/emacs': [ # http://crbug.com/98595
502 'tools/python/google/__init__.py': [
505 'tools/stats_viewer/Properties/AssemblyInfo.cs': [
508 'tools/symsrc/pefile.py': [
511 # Not shipped, downloaded on trybots sometimes.
512 'tools/telemetry/third_party/gsutil': [
513 'BSD MIT/X11 (BSD like)',
516 'tools/telemetry/third_party/pyserial': [
517 # https://sourceforge.net/p/pyserial/feature-requests/35/
520 'v8/test/cctest': [ # http://crbug.com/98597
523 'v8/src/third_party/kernel/tools/perf/util/jitdump.h': [ # http://crbug.com/391716
529 def check_licenses(options
, args
):
530 # Figure out which directory we have to check.
532 # No directory to check specified, use the repository root.
533 start_dir
= options
.base_directory
535 # Directory specified. Start here. It's supposed to be relative to the
537 start_dir
= os
.path
.abspath(os
.path
.join(options
.base_directory
, args
[0]))
539 # More than one argument, we don't handle this.
543 print "Using base directory:", options
.base_directory
544 print "Checking:", start_dir
547 licensecheck_path
= os
.path
.abspath(os
.path
.join(options
.base_directory
,
552 licensecheck
= subprocess
.Popen([licensecheck_path
,
555 stdout
=subprocess
.PIPE
,
556 stderr
=subprocess
.PIPE
)
557 stdout
, stderr
= licensecheck
.communicate()
559 print '----------- licensecheck stdout -----------'
561 print '--------- end licensecheck stdout ---------'
562 if licensecheck
.returncode
!= 0 or stderr
:
563 print '----------- licensecheck stderr -----------'
565 print '--------- end licensecheck stderr ---------'
569 used_suppressions
= set()
572 for line
in stdout
.splitlines():
573 filename
, license
= line
.split(':', 1)
574 filename
= os
.path
.relpath(filename
.strip(), options
.base_directory
)
576 # All files in the build output directory are generated one way or another.
577 # There's no need to check them.
578 if filename
.startswith('out/'):
581 # For now we're just interested in the license.
582 license
= license
.replace('*No copyright*', '').strip()
584 # Skip generated files.
585 if 'GENERATED FILE' in license
:
588 if license
in WHITELISTED_LICENSES
:
591 if not options
.ignore_suppressions
:
593 prefix
for prefix
in PATH_SPECIFIC_WHITELISTED_LICENSES
594 if filename
.startswith(prefix
) and
595 license
in PATH_SPECIFIC_WHITELISTED_LICENSES
[prefix
]]
597 used_suppressions
.update(set(matched_prefixes
))
600 errors
.append({'filename': filename
, 'license': license
})
603 with
open(options
.json
, 'w') as f
:
608 print "'%s' has non-whitelisted license '%s'" % (
609 error
['filename'], error
['license'])
612 print "http://www.chromium.org/developers/adding-3rd-party-libraries"
613 print "for more info how to handle the failure."
615 print "Please respect OWNERS of checklicenses.py. Changes violating"
616 print "this requirement may be reverted."
618 # Do not print unused suppressions so that above message is clearly
619 # visible and gets proper attention. Too much unrelated output
620 # would be distracting and make the important points easier to miss.
627 unused_suppressions
= set(
628 PATH_SPECIFIC_WHITELISTED_LICENSES
.iterkeys()).difference(
630 if unused_suppressions
:
631 print "\nNOTE: unused suppressions detected:\n"
632 print '\n'.join(unused_suppressions
)
638 default_root
= os
.path
.abspath(
639 os
.path
.join(os
.path
.dirname(__file__
), '..', '..'))
640 option_parser
= optparse
.OptionParser()
641 option_parser
.add_option('--root', default
=default_root
,
642 dest
='base_directory',
643 help='Specifies the repository root. This defaults '
644 'to "../.." relative to the script file, which '
645 'will normally be the repository root.')
646 option_parser
.add_option('-v', '--verbose', action
='store_true',
647 default
=False, help='Print debug logging')
648 option_parser
.add_option('--ignore-suppressions',
651 help='Ignore path-specific license whitelist.')
652 option_parser
.add_option('--json', help='Path to JSON output file')
653 options
, args
= option_parser
.parse_args()
654 return check_licenses(options
, args
)
657 if '__main__' == __name__
: