25 ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]),
'../..'))
29 argp = argparse.ArgumentParser(description=
'copyright checker')
30 argp.add_argument(
'-o',
33 choices=[
'list',
'details'])
34 argp.add_argument(
'-s',
'--skips', default=0, action=
'store_const', const=1)
35 argp.add_argument(
'-a',
'--ancient', default=0, action=
'store_const', const=1)
36 argp.add_argument(
'--precommit', action=
'store_true')
37 argp.add_argument(
'--fix', action=
'store_true')
38 args = argp.parse_args()
41 with open(
'NOTICE.txt')
as f:
42 LICENSE_NOTICE = f.read().splitlines()
50 '.c':
r'\s*(?://|\*)\s*',
51 '.cc':
r'\s*(?://|\*)\s*',
52 '.h':
r'\s*(?://|\*)\s*',
69 'Dockerfile':
r'#\s*',
79 LICENSE_PREFIX_TEXT = {
80 '.bat': (
None,
'@rem',
None),
81 '.c': (
None,
'//',
None),
82 '.cc': (
None,
'//',
None),
83 '.h': (
None,
'//',
None),
84 '.m': (
'/**',
' *',
' */'),
85 '.mm': (
'/**',
' *',
' */'),
86 '.php': (
'/**',
' *',
' */'),
87 '.js': (
'/**',
' *',
' */'),
88 '.py': (
None,
'#',
None),
89 '.pyx': (
None,
'#',
None),
90 '.pxd': (
None,
'#',
None),
91 '.pxi': (
None,
'#',
None),
92 '.rb': (
None,
'#',
None),
93 '.sh': (
None,
'#',
None),
94 '.proto': (
None,
'//',
None),
95 '.cs': (
None,
'//',
None),
96 '.mak': (
None,
'#',
None),
97 '.bazel': (
None,
'#',
None),
98 '.bzl': (
None,
'#',
None),
99 'Makefile': (
None,
'#',
None),
100 'Dockerfile': (
None,
'#',
None),
101 'BUILD': (
None,
'#',
None),
104 _EXEMPT = frozenset((
106 'examples/python/helloworld/helloworld_pb2.py',
107 'examples/python/helloworld/helloworld_pb2_grpc.py',
108 'examples/python/multiplex/helloworld_pb2.py',
109 'examples/python/multiplex/helloworld_pb2_grpc.py',
110 'examples/python/multiplex/route_guide_pb2.py',
111 'examples/python/multiplex/route_guide_pb2_grpc.py',
112 'examples/python/route_guide/route_guide_pb2.py',
113 'examples/python/route_guide/route_guide_pb2_grpc.py',
116 'tools/doxygen/Doxyfile.php',
119 'src/php/tests/bootstrap.php',
121 'tools/grpcz/census.proto',
123 'src/proto/grpc/status/status.proto',
126 'examples/android/helloworld/gradlew.bat',
127 'src/android/test/interop/gradlew.bat',
130 'examples/csharp/HelloworldXamarin/Droid/Resources/Resource.designer.cs',
131 'examples/csharp/HelloworldXamarin/iOS/ViewController.designer.cs',
135 'src/boringssl/boringssl_prefix_symbols.h',
138 RE_YEAR =
r'Copyright (?P<first_year>[0-9]+\-)?(?P<last_year>[0-9]+) ([Tt]he )?gRPC [Aa]uthors(\.|)'
140 (k,
r'\n'.join(LICENSE_PREFIX_RE[k] +
141 (RE_YEAR
if re.search(RE_YEAR, line)
else re.escape(line))
142 for line
in LICENSE_NOTICE))
143 for k, v
in list(LICENSE_PREFIX_RE.items()))
145 YEAR = datetime.datetime.now().year
147 LICENSE_YEAR = f
'Copyright {YEAR} gRPC authors.'
151 text = (header +
'\n')
if header
else ""
153 def add_prefix(prefix, line):
156 return prefix + (
'' if len(line) == 0
else ' ') + line
159 add_prefix(prefix, (LICENSE_YEAR
if re.search(RE_YEAR, line)
else line))
160 for line
in LICENSE_NOTICE)
163 text += footer +
'\n'
170 LICENSE_PREFIX_TEXT[k][2], LICENSE_NOTICE))
171 for k, v
in list(LICENSE_PREFIX_TEXT.items()))
174 FILE_LIST_COMMAND =
'git status -z | grep -Poz \'(?<=^[MARC][MARCD ] )[^\s]+\''
176 FILE_LIST_COMMAND =
'git ls-tree -r --name-only -r HEAD | ' \
177 'grep -v ^third_party/ |' \
178 'grep -v "\(ares_config.h\|ares_build.h\)"'
182 with open(name)
as f:
187 with open(name,
'w')
as f:
191 assert (re.search(RE_LICENSE[
'Makefile'],
load(
'Makefile')))
194 def log(cond, why, filename):
197 if args.output ==
'details':
198 print((
'%s: %s' % (why, filename)))
205 lines = file_text.split(
"\n")
206 if lines
and lines[0].startswith(
"#!"):
207 shebang = lines[0] +
"\n"
208 file_text = file_text[
len(shebang):]
210 rewritten_text = shebang + license_text +
"\n" + file_text
211 with open(filename,
'w')
as f:
212 f.write(rewritten_text)
219 filename_list = subprocess.check_output(FILE_LIST_COMMAND,
220 shell=
True).
decode().splitlines()
221 except subprocess.CalledProcessError:
224 for filename
in filename_list:
225 if filename
in _EXEMPT:
228 if (filename.endswith(
'.upb.h')
or filename.endswith(
'.upb.c')
or
229 filename.endswith(
'.upbdefs.h')
or filename.endswith(
'.upbdefs.c')):
231 ext = os.path.splitext(filename)[1]
232 base = os.path.basename(filename)
233 if ext
in RE_LICENSE:
234 re_license = RE_LICENSE[ext]
235 license_text = LICENSE_TEXT[ext]
236 elif base
in RE_LICENSE:
237 re_license = RE_LICENSE[base]
238 license_text = LICENSE_TEXT[base]
240 log(args.skips,
'skip', filename)
246 m = re.search(re_license, text)
249 elif 'DO NOT EDIT' not in text:
252 log(1,
'copyright missing (fixed)', filename)
254 log(1,
'copyright missing', filename)
257 if not ok
and not args.fix:
259 'You may use following command to automatically fix copyright headers:')
260 print(
' tools/distrib/check_copyright.py --fix')
262 sys.exit(0
if ok
else 1)