| Index: third_party/grpc/tools/distrib/check_copyright.py
|
| diff --git a/third_party/grpc/tools/distrib/check_copyright.py b/third_party/grpc/tools/distrib/check_copyright.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..99771f9632cfaa67728dafd15e4dda50350d6072
|
| --- /dev/null
|
| +++ b/third_party/grpc/tools/distrib/check_copyright.py
|
| @@ -0,0 +1,179 @@
|
| +#!/usr/bin/env python2.7
|
| +
|
| +# Copyright 2015-2016, Google Inc.
|
| +# All rights reserved.
|
| +#
|
| +# Redistribution and use in source and binary forms, with or without
|
| +# modification, are permitted provided that the following conditions are
|
| +# met:
|
| +#
|
| +# * Redistributions of source code must retain the above copyright
|
| +# notice, this list of conditions and the following disclaimer.
|
| +# * Redistributions in binary form must reproduce the above
|
| +# copyright notice, this list of conditions and the following disclaimer
|
| +# in the documentation and/or other materials provided with the
|
| +# distribution.
|
| +# * Neither the name of Google Inc. nor the names of its
|
| +# contributors may be used to endorse or promote products derived from
|
| +# this software without specific prior written permission.
|
| +#
|
| +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| +
|
| +import argparse
|
| +import datetime
|
| +import os
|
| +import re
|
| +import sys
|
| +import subprocess
|
| +
|
| +# find our home
|
| +ROOT = os.path.abspath(
|
| + os.path.join(os.path.dirname(sys.argv[0]), '../..'))
|
| +os.chdir(ROOT)
|
| +
|
| +# parse command line
|
| +argp = argparse.ArgumentParser(description='copyright checker')
|
| +argp.add_argument('-o', '--output',
|
| + default='details',
|
| + choices=['list', 'details'])
|
| +argp.add_argument('-s', '--skips',
|
| + default=0,
|
| + action='store_const',
|
| + const=1)
|
| +argp.add_argument('-a', '--ancient',
|
| + default=0,
|
| + action='store_const',
|
| + const=1)
|
| +argp.add_argument('-f', '--fix',
|
| + default=False,
|
| + action='store_true');
|
| +argp.add_argument('--precommit',
|
| + default=False,
|
| + action='store_true')
|
| +args = argp.parse_args()
|
| +
|
| +# open the license text
|
| +with open('LICENSE') as f:
|
| + LICENSE = f.read().splitlines()
|
| +
|
| +# license format by file extension
|
| +# key is the file extension, value is a format string
|
| +# that given a line of license text, returns what should
|
| +# be in the file
|
| +LICENSE_PREFIX = {
|
| + '.c': r'\s*(?://|\*)\s*',
|
| + '.cc': r'\s*(?://|\*)\s*',
|
| + '.h': r'\s*(?://|\*)\s*',
|
| + '.m': r'\s*\*\s*',
|
| + '.php': r'\s*\*\s*',
|
| + '.js': r'\s*\*\s*',
|
| + '.py': r'#\s*',
|
| + '.pyx': r'#\s*',
|
| + '.pxd': r'#\s*',
|
| + '.pxi': r'#\s*',
|
| + '.rb': r'#\s*',
|
| + '.sh': r'#\s*',
|
| + '.proto': r'//\s*',
|
| + '.cs': r'//\s*',
|
| + '.mak': r'#\s*',
|
| + 'Makefile': r'#\s*',
|
| + 'Dockerfile': r'#\s*',
|
| + 'LICENSE': '',
|
| +}
|
| +
|
| +KNOWN_BAD = set([
|
| + 'src/php/tests/bootstrap.php',
|
| +])
|
| +
|
| +
|
| +RE_YEAR = r'Copyright (?P<first_year>[0-9]+\-)?(?P<last_year>[0-9]+), Google Inc\.'
|
| +RE_LICENSE = dict(
|
| + (k, r'\n'.join(
|
| + LICENSE_PREFIX[k] +
|
| + (RE_YEAR if re.search(RE_YEAR, line) else re.escape(line))
|
| + for line in LICENSE))
|
| + for k, v in LICENSE_PREFIX.iteritems())
|
| +
|
| +if args.precommit:
|
| + FILE_LIST_COMMAND = 'git diff --name-only HEAD | grep -v ^third_party/'
|
| +else:
|
| + FILE_LIST_COMMAND = 'git ls-tree -r --name-only -r HEAD | grep -v ^third_party/'
|
| +
|
| +def load(name):
|
| + with open(name) as f:
|
| + return f.read()
|
| +
|
| +def save(name, text):
|
| + with open(name, 'w') as f:
|
| + f.write(text)
|
| +
|
| +assert(re.search(RE_LICENSE['LICENSE'], load('LICENSE')))
|
| +assert(re.search(RE_LICENSE['Makefile'], load('Makefile')))
|
| +
|
| +
|
| +def log(cond, why, filename):
|
| + if not cond: return
|
| + if args.output == 'details':
|
| + print '%s: %s' % (why, filename)
|
| + else:
|
| + print filename
|
| +
|
| +
|
| +# scan files, validate the text
|
| +ok = True
|
| +filename_list = []
|
| +try:
|
| + filename_list = subprocess.check_output(FILE_LIST_COMMAND,
|
| + shell=True).splitlines()
|
| +except subprocess.CalledProcessError:
|
| + sys.exit(0)
|
| +
|
| +for filename in filename_list:
|
| + if filename in KNOWN_BAD: continue
|
| + ext = os.path.splitext(filename)[1]
|
| + base = os.path.basename(filename)
|
| + if ext in RE_LICENSE:
|
| + re_license = RE_LICENSE[ext]
|
| + elif base in RE_LICENSE:
|
| + re_license = RE_LICENSE[base]
|
| + else:
|
| + log(args.skips, 'skip', filename)
|
| + continue
|
| + try:
|
| + text = load(filename)
|
| + except:
|
| + continue
|
| + m = re.search(re_license, text)
|
| + if m:
|
| + gdict = m.groupdict()
|
| + last_modified = int(subprocess.check_output('git log -1 --format="%ad" --date=short -- ' + filename, shell=True)[0:4])
|
| + latest_claimed = int(gdict['last_year'])
|
| + if last_modified > latest_claimed:
|
| + print '%s modified %d but copyright only extends to %d' % (filename, last_modified, latest_claimed)
|
| + ok = False
|
| + if args.fix:
|
| + span_start, span_end = m.span(2)
|
| + if not gdict['first_year']:
|
| + # prepend the old year to the current one.
|
| + text = '{}-{}{}'.format(text[:span_end], last_modified, text[span_end:])
|
| + else: # already a year range
|
| + # simply update the last year
|
| + text = '{}{}{}'.format(text[:span_start], last_modified, text[span_end:])
|
| + save(filename, text)
|
| + print 'Fixed!'
|
| + ok = True
|
| + elif 'DO NOT EDIT' not in text and 'AssemblyInfo.cs' not in filename and filename != 'src/boringssl/err_data.c':
|
| + log(1, 'copyright missing', filename)
|
| + ok = False
|
| +
|
| +sys.exit(0 if ok else 1)
|
|
|