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."""
16 print """Usage: python checklicenses.py [--root <root>] [tocheck]
17 --root Specifies the repository root. This defaults to "../.." relative
18 to the script file. This will be correct given the normal location
19 of the script in "<root>/tools/checklicenses".
21 --ignore-suppressions Ignores path-specific license whitelist. Useful when
22 trying to remove a suppression/whitelist entry.
24 tocheck Specifies the directory, relative to root, to check. This defaults
25 to "." so it checks everything.
28 python checklicenses.py
29 python checklicenses.py --root ~/chromium/src third_party"""
32 WHITELISTED_LICENSES = [
34 'Apache (v2.0) BSD (2 clause)',
35 'Apache (v2.0) GPL (v2)',
36 'Apple MIT', # https://fedoraproject.org/wiki/Licensing/Apple_MIT_License
38 'APSL (v2) BSD (4 clause)',
42 'BSD (2 clause) MIT/X11 (BSD like)',
44 'BSD (3 clause) GPL (v2)',
46 'BSD (3 clause) LGPL (v2 or later)',
47 'BSD (3 clause) LGPL (v2.1 or later)',
48 'BSD (3 clause) MIT/X11 (BSD like)',
52 # TODO(phajdan.jr): Make licensecheck not print BSD-like twice.
53 'BSD-like MIT/X11 (BSD like)',
56 'GPL (v2) LGPL (v2.1 or later)',
57 'GPL (v2 or later) with Bison parser exception',
58 'GPL (v2 or later) with libtool exception',
59 'GPL (v3 or later) with Bison parser exception',
60 'GPL with Bison parser exception',
62 'LGPL (unversioned/unknown version)',
66 'LGPL (v2.1 or later)',
69 'MIT/X11 (BSD like) LGPL (v2.1 or later)',
70 'MPL (v1.0) LGPL (v2 or later)',
72 'MPL (v1.1) BSD (3 clause) GPL (v2) LGPL (v2.1 or later)',
73 'MPL (v1.1) BSD (3 clause) LGPL (v2.1 or later)',
74 'MPL (v1.1) BSD-like',
75 'MPL (v1.1) BSD-like GPL (unversioned/unknown version)',
76 'MPL (v1.1) BSD-like GPL (v2) LGPL (v2.1 or later)',
77 'MPL (v1.1) GPL (v2)',
78 'MPL (v1.1) GPL (v2) LGPL (v2 or later)',
79 'MPL (v1.1) GPL (v2) LGPL (v2.1 or later)',
80 'MPL (v1.1) GPL (unversioned/unknown version)',
81 'MPL (v1.1) LGPL (v2 or later)',
82 'MPL (v1.1) LGPL (v2.1 or later)',
87 'Public domain BSD (3 clause)',
88 'Public domain BSD-like',
89 'Public domain LGPL (v2.1 or later)',
92 'SGI Free Software License B',
93 'University of Illinois/NCSA Open Source License (BSD like)',
94 ('University of Illinois/NCSA Open Source License (BSD like) '
95 'MIT/X11 (BSD like)'),
99 PATH_SPECIFIC_WHITELISTED_LICENSES = {
100 'base/hash.cc': [ # http://crbug.com/98100
103 'base/third_party/icu': [ # http://crbug.com/98087
107 # http://code.google.com/p/google-breakpad/issues/detail?id=450
112 'chrome/common/extensions/docs/examples': [ # http://crbug.com/98092
115 'chrome/test/data/gpu/vt': [
118 'courgette/third_party/bsdiff_create.cc': [ # http://crbug.com/98095
121 'data/tab_switching': [
124 'native_client': [ # http://crbug.com/98099
127 'native_client/toolchain': [
128 'BSD GPL (v2 or later)',
129 'BSD (2 clause) GPL (v2 or later)',
130 'BSD (3 clause) GPL (v2 or later)',
132 'BSL (v1.0) GPL (v3.1)',
134 'GPL (unversioned/unknown version)',
140 'net/tools/spdyshark': [
144 'third_party/WebKit': [
148 # http://code.google.com/p/angleproject/issues/detail?id=217
149 'third_party/angle': [
153 # http://crbug.com/222828
154 # http://bugs.python.org/issue17514
155 'third_party/chromite/third_party/argparse.py': [
159 # http://crbug.com/326117
160 # https://bitbucket.org/chrisatlee/poster/issue/21
161 'third_party/chromite/third_party/poster': [
165 # http://crbug.com/333508
166 'third_party/clang_format/script': [
169 'third_party/clang_format/scripts': [
173 # Not used. http://crbug.com/156020
174 # Using third_party/cros_dbus_cplusplus/cros_dbus_cplusplus.gyp instead.
175 'third_party/cros_dbus_cplusplus/source/autogen.sh': [
178 # Included in the source tree but not built. http://crbug.com/156020
179 'third_party/cros_dbus_cplusplus/source/examples': [
182 'third_party/devscripts': [
185 'third_party/expat/files/lib': [ # http://crbug.com/98121
188 'third_party/ffmpeg': [
192 'UNKNOWN', # http://crbug.com/98123
194 'third_party/fontconfig': [
195 # https://bugs.freedesktop.org/show_bug.cgi?id=73401
198 'third_party/freetype2': [ # http://crbug.com/177319
201 'third_party/gles2_conform/GTF_ES': [ # http://crbug.com/98131
204 'third_party/hunspell': [ # http://crbug.com/98134
207 'third_party/iccjpeg': [ # http://crbug.com/98137
210 'third_party/icu': [ # http://crbug.com/98301
213 'third_party/jemalloc': [ # http://crbug.com/98302
216 'third_party/JSON': [
217 'Perl', # Build-only.
218 # License missing upstream on 3 minor files.
219 'UNKNOWN', # https://rt.cpan.org/Public/Bug/Display.html?id=85915
221 'third_party/lcov': [ # http://crbug.com/98304
224 'third_party/lcov/contrib/galaxy/genflat.pl': [
227 'third_party/libc++/trunk/include/support/solaris': [
228 # http://llvm.org/bugs/show_bug.cgi?id=18291
231 'third_party/libc++/trunk/src/support/solaris/xlocale.c': [
232 # http://llvm.org/bugs/show_bug.cgi?id=18291
235 'third_party/libc++/trunk/test': [
236 # http://llvm.org/bugs/show_bug.cgi?id=18291
239 'third_party/libevent': [ # http://crbug.com/98309
242 'third_party/libjingle/source/talk': [ # http://crbug.com/98310
245 'third_party/libjpeg': [ # http://crbug.com/98313
248 'third_party/libjpeg_turbo': [ # http://crbug.com/98314
251 'third_party/libpng': [ # http://crbug.com/98318
255 # The following files lack license headers, but are trivial.
256 'third_party/libusb/src/libusb/os/poll_posix.h': [
260 'third_party/libvpx/source': [ # http://crbug.com/98319
263 'third_party/libvpx/source/libvpx/examples/includes': [
266 'third_party/libxml': [
269 'third_party/libxslt': [
272 'third_party/lzma_sdk': [
275 'third_party/mesa/src': [
278 'MIT/X11 (BSD like) GPL (v3 or later) with Bison parser exception',
279 'UNKNOWN', # http://crbug.com/98450
281 'third_party/modp_b64': [
284 'third_party/openmax_dl/dl' : [
287 'third_party/openssl': [ # http://crbug.com/98451
290 'third_party/ots/tools/ttf-checksum.py': [ # http://code.google.com/p/ots/issues/detail?id=2
293 'third_party/molokocacao': [ # http://crbug.com/98453
296 'third_party/npapi/npspy': [
299 'third_party/ocmock/OCMock': [ # http://crbug.com/98454
302 'third_party/ply/__init__.py': [
305 'third_party/protobuf': [ # http://crbug.com/98455
309 # http://crbug.com/222831
310 # https://bitbucket.org/eliben/pyelftools/issue/12
311 'third_party/pyelftools': [
315 'third_party/scons-2.0.1/engine/SCons': [ # http://crbug.com/98462
318 'third_party/simplejson': [
321 'third_party/skia': [ # http://crbug.com/98463
324 'third_party/snappy/src': [ # http://crbug.com/98464
327 'third_party/smhasher/src': [ # http://crbug.com/98465
330 'third_party/speech-dispatcher/libspeechd.h': [
333 'third_party/sqlite': [
337 # https://code.google.com/p/colorama/issues/detail?id=44
338 'tools/swarming_client/third_party/colorama': [
342 # http://crbug.com/334668
344 'tools/swarming_client/third_party/httplib2': [
348 # http://crbug.com/334668
350 'tools/swarming_client/third_party/oauth2client': [
354 # https://github.com/kennethreitz/requests/issues/1610
355 'tools/swarming_client/third_party/requests': [
359 'third_party/swig/Lib/linkruntime.c': [ # http://crbug.com/98585
362 'third_party/talloc': [
364 'UNKNOWN', # http://crbug.com/98588
366 'third_party/tcmalloc': [
367 'UNKNOWN', # http://crbug.com/98589
369 'third_party/tlslite': [
372 'third_party/webdriver': [ # http://crbug.com/98590
376 # https://github.com/html5lib/html5lib-python/issues/125
377 # https://github.com/KhronosGroup/WebGL/issues/435
378 'third_party/webgl/src': [
382 'third_party/webrtc': [ # http://crbug.com/98592
385 'third_party/xdg-utils': [ # http://crbug.com/98593
388 'third_party/yasm/source': [ # http://crbug.com/98594
391 'third_party/zlib/contrib/minizip': [
394 'third_party/zlib/trees.h': [
397 'tools/emacs': [ # http://crbug.com/98595
403 'tools/histograms': [
406 'tools/python/google/__init__.py': [
409 'tools/stats_viewer/Properties/AssemblyInfo.cs': [
412 'tools/symsrc/pefile.py': [
415 'tools/telemetry/third_party/pyserial': [
416 # https://sourceforge.net/p/pyserial/feature-requests/35/
419 'v8/test/cctest': [ # http://crbug.com/98597
425 def check_licenses(options, args):
426 # Figure out which directory we have to check.
428 # No directory to check specified, use the repository root.
429 start_dir = options.base_directory
431 # Directory specified. Start here. It's supposed to be relative to the
433 start_dir = os.path.abspath(os.path.join(options.base_directory, args[0]))
435 # More than one argument, we don't handle this.
439 print "Using base directory:", options.base_directory
440 print "Checking:", start_dir
443 licensecheck_path = os.path.abspath(os.path.join(options.base_directory,
448 licensecheck = subprocess.Popen([licensecheck_path,
451 stdout=subprocess.PIPE,
452 stderr=subprocess.PIPE)
453 stdout, stderr = licensecheck.communicate()
455 print '----------- licensecheck stdout -----------'
457 print '--------- end licensecheck stdout ---------'
458 if licensecheck.returncode != 0 or stderr:
459 print '----------- licensecheck stderr -----------'
461 print '--------- end licensecheck stderr ---------'
465 used_suppressions = set()
468 for line in stdout.splitlines():
469 filename, license = line.split(':', 1)
470 filename = os.path.relpath(filename.strip(), options.base_directory)
472 # All files in the build output directory are generated one way or another.
473 # There's no need to check them.
474 if filename.startswith('out/'):
477 # For now we're just interested in the license.
478 license = license.replace('*No copyright*', '').strip()
480 # Skip generated files.
481 if 'GENERATED FILE' in license:
484 if license in WHITELISTED_LICENSES:
487 if not options.ignore_suppressions:
489 prefix for prefix in PATH_SPECIFIC_WHITELISTED_LICENSES
490 if filename.startswith(prefix) and
491 license in PATH_SPECIFIC_WHITELISTED_LICENSES[prefix]]
493 used_suppressions.update(set(matched_prefixes))
496 print "'%s' has non-whitelisted license '%s'" % (filename, license)
502 unused_suppressions = set(
503 PATH_SPECIFIC_WHITELISTED_LICENSES.keys()).difference(used_suppressions)
504 if unused_suppressions:
505 print "\nNOTE: unused suppressions detected:\n"
506 print '\n'.join(unused_suppressions)
512 print "http://www.chromium.org/developers/adding-3rd-party-libraries"
513 print "for more info how to handle the failure."
515 print "Please respect OWNERS of checklicenses.py. Changes violating"
516 print "this requirement may be reverted."
518 # Do not print unused suppressions so that above message is clearly
519 # visible and gets proper attention. Too much unrelated output
520 # would be distracting and make the important points easier to miss.
526 default_root = os.path.abspath(
527 os.path.join(os.path.dirname(__file__), '..', '..'))
528 option_parser = optparse.OptionParser()
529 option_parser.add_option('--root', default=default_root,
530 dest='base_directory',
531 help='Specifies the repository root. This defaults '
532 'to "../.." relative to the script file, which '
533 'will normally be the repository root.')
534 option_parser.add_option('-v', '--verbose', action='store_true',
535 default=False, help='Print debug logging')
536 option_parser.add_option('--ignore-suppressions',
539 help='Ignore path-specific license whitelist.')
540 options, args = option_parser.parse_args()
541 return check_licenses(options, args)
544 if '__main__' == __name__: