]>
Commit | Line | Data |
---|---|---|
3b25e835 | 1 | #!/usr/bin/env python3 |
240d6348 | 2 | # |
e528bf8d | 3 | # Copyright (C) 2013-2020 Free Software Foundation, Inc. |
240d6348 RS |
4 | # |
5 | # This script is free software; you can redistribute it and/or modify | |
6 | # it under the terms of the GNU General Public License as published by | |
7 | # the Free Software Foundation; either version 3, or (at your option) | |
8 | # any later version. | |
9 | ||
10 | # This script adjusts the copyright notices at the top of source files | |
11 | # so that they have the form: | |
12 | # | |
13 | # Copyright XXXX-YYYY Free Software Foundation, Inc. | |
14 | # | |
15 | # It doesn't change code that is known to be maintained elsewhere or | |
16 | # that carries a non-FSF copyright. | |
17 | # | |
18 | # The script also doesn't change testsuite files, except those in | |
19 | # libstdc++-v3. This is because libstdc++-v3 has a conformance testsuite, | |
20 | # while most tests in other directories are just things that failed at some | |
21 | # point in the past. | |
22 | # | |
23 | # Pass --this-year to the script if you want it to add the current year | |
24 | # to all applicable notices. Pass --quilt if you are using quilt and | |
25 | # want files to be added to the quilt before being changed. | |
26 | # | |
27 | # By default the script will update all directories for which the | |
28 | # output has been vetted. You can instead pass the names of individual | |
29 | # directories, including those that haven't been approved. So: | |
30 | # | |
23075ebe | 31 | # update-copyright.py --this-year |
240d6348 RS |
32 | # |
33 | # is the command that would be used at the beginning of a year to update | |
34 | # all copyright notices (and possibly at other times to check whether | |
35 | # new files have been added with old years). On the other hand: | |
36 | # | |
23075ebe | 37 | # update-copyright.py --this-year libitm |
240d6348 | 38 | # |
ae12c0f0 | 39 | # would run the script on just libitm/. |
240d6348 RS |
40 | # |
41 | # Note that things like --version output strings must be updated before | |
42 | # this script is run. There's already a separate procedure for that. | |
43 | ||
44 | import os | |
45 | import re | |
46 | import sys | |
47 | import time | |
48 | import subprocess | |
49 | ||
50 | class Errors: | |
51 | def __init__ (self): | |
52 | self.num_errors = 0 | |
53 | ||
54 | def report (self, filename, string): | |
55 | if filename: | |
56 | string = filename + ': ' + string | |
57 | sys.stderr.write (string + '\n') | |
58 | self.num_errors += 1 | |
59 | ||
60 | def ok (self): | |
61 | return self.num_errors == 0 | |
62 | ||
63 | class GenericFilter: | |
64 | def __init__ (self): | |
65 | self.skip_files = set() | |
66 | self.skip_dirs = set() | |
3b25e835 ML |
67 | self.skip_extensions = set([ |
68 | '.png', | |
69 | '.pyc', | |
70 | ]) | |
240d6348 RS |
71 | self.fossilised_files = set() |
72 | self.own_files = set() | |
73 | ||
74 | self.skip_files |= set ([ | |
75 | # Skip licence files. | |
76 | 'COPYING', | |
77 | 'COPYING.LIB', | |
78 | 'COPYING3', | |
79 | 'COPYING3.LIB', | |
80 | 'LICENSE', | |
e528bf8d | 81 | 'LICENSE.txt', |
240d6348 RS |
82 | 'fdl.texi', |
83 | 'gpl_v3.texi', | |
84 | 'fdl-1.3.xml', | |
85 | 'gpl-3.0.xml', | |
86 | ||
87 | # Skip auto- and libtool-related files | |
88 | 'aclocal.m4', | |
89 | 'compile', | |
90 | 'config.guess', | |
91 | 'config.sub', | |
92 | 'depcomp', | |
93 | 'install-sh', | |
94 | 'libtool.m4', | |
95 | 'ltmain.sh', | |
96 | 'ltoptions.m4', | |
97 | 'ltsugar.m4', | |
98 | 'ltversion.m4', | |
99 | 'lt~obsolete.m4', | |
100 | 'missing', | |
101 | 'mkdep', | |
102 | 'mkinstalldirs', | |
103 | 'move-if-change', | |
104 | 'shlibpath.m4', | |
105 | 'symlink-tree', | |
106 | 'ylwrap', | |
107 | ||
108 | # Skip FSF mission statement, etc. | |
109 | 'gnu.texi', | |
110 | 'funding.texi', | |
111 | 'appendix_free.xml', | |
112 | ||
113 | # Skip imported texinfo files. | |
114 | 'texinfo.tex', | |
115 | ]) | |
116 | ||
117 | ||
118 | def get_line_filter (self, dir, filename): | |
119 | if filename.startswith ('ChangeLog'): | |
120 | # Ignore references to copyright in changelog entries. | |
121 | return re.compile ('\t') | |
122 | ||
123 | return None | |
124 | ||
125 | def skip_file (self, dir, filename): | |
126 | if filename in self.skip_files: | |
127 | return True | |
128 | ||
129 | (base, extension) = os.path.splitext (os.path.join (dir, filename)) | |
130 | if extension in self.skip_extensions: | |
131 | return True | |
132 | ||
133 | if extension == '.in': | |
134 | # Skip .in files produced by automake. | |
135 | if os.path.exists (base + '.am'): | |
136 | return True | |
137 | ||
138 | # Skip files produced by autogen | |
139 | if (os.path.exists (base + '.def') | |
140 | and os.path.exists (base + '.tpl')): | |
141 | return True | |
142 | ||
143 | # Skip configure files produced by autoconf | |
144 | if filename == 'configure': | |
145 | if os.path.exists (base + '.ac'): | |
146 | return True | |
147 | if os.path.exists (base + '.in'): | |
148 | return True | |
149 | ||
150 | return False | |
151 | ||
152 | def skip_dir (self, dir, subdir): | |
153 | return subdir in self.skip_dirs | |
154 | ||
155 | def is_fossilised_file (self, dir, filename): | |
156 | if filename in self.fossilised_files: | |
157 | return True | |
158 | # Only touch current current ChangeLogs. | |
159 | if filename != 'ChangeLog' and filename.find ('ChangeLog') >= 0: | |
160 | return True | |
161 | return False | |
162 | ||
163 | def by_package_author (self, dir, filename): | |
164 | return filename in self.own_files | |
165 | ||
166 | class Copyright: | |
167 | def __init__ (self, errors): | |
168 | self.errors = errors | |
169 | ||
170 | # Characters in a range of years. Include '.' for typos. | |
171 | ranges = '[0-9](?:[-0-9.,\s]|\s+and\s+)*[0-9]' | |
172 | ||
173 | # Non-whitespace characters in a copyright holder's name. | |
174 | name = '[\w.,-]' | |
175 | ||
176 | # Matches one year. | |
177 | self.year_re = re.compile ('[0-9]+') | |
178 | ||
179 | # Matches part of a year or copyright holder. | |
180 | self.continuation_re = re.compile (ranges + '|' + name) | |
181 | ||
182 | # Matches a full copyright notice: | |
183 | self.copyright_re = re.compile ( | |
184 | # 1: 'Copyright (C)', etc. | |
185 | '([Cc]opyright' | |
186 | '|[Cc]opyright\s+\([Cc]\)' | |
187 | '|[Cc]opyright\s+%s' | |
188 | '|[Cc]opyright\s+©' | |
189 | '|[Cc]opyright\s+@copyright{}' | |
8fced9b9 | 190 | '|copyright = u\'' |
240d6348 RS |
191 | '|@set\s+copyright[\w-]+)' |
192 | ||
193 | # 2: the years. Include the whitespace in the year, so that | |
194 | # we can remove any excess. | |
195 | '(\s*(?:' + ranges + ',?' | |
196 | '|@value\{[^{}]*\})\s*)' | |
197 | ||
198 | # 3: 'by ', if used | |
199 | '(by\s+)?' | |
200 | ||
201 | # 4: the copyright holder. Don't allow multiple consecutive | |
202 | # spaces, so that right-margin gloss doesn't get caught | |
203 | # (e.g. gnat_ugn.texi). | |
204 | '(' + name + '(?:\s?' + name + ')*)?') | |
205 | ||
206 | # A regexp for notices that might have slipped by. Just matching | |
207 | # 'copyright' is too noisy, and 'copyright.*[0-9]' falls foul of | |
208 | # HTML header markers, so check for 'copyright' and two digits. | |
209 | self.other_copyright_re = re.compile ('copyright.*[0-9][0-9]', | |
210 | re.IGNORECASE) | |
211 | self.comment_re = re.compile('#+|[*]+|;+|%+|//+|@c |dnl ') | |
212 | self.holders = { '@copying': '@copying' } | |
213 | self.holder_prefixes = set() | |
214 | ||
215 | # True to 'quilt add' files before changing them. | |
216 | self.use_quilt = False | |
217 | ||
218 | # If set, force all notices to include this year. | |
219 | self.max_year = None | |
220 | ||
221 | # Goes after the year(s). Could be ', '. | |
222 | self.separator = ' ' | |
223 | ||
224 | def add_package_author (self, holder, canon_form = None): | |
225 | if not canon_form: | |
226 | canon_form = holder | |
227 | self.holders[holder] = canon_form | |
228 | index = holder.find (' ') | |
229 | while index >= 0: | |
230 | self.holder_prefixes.add (holder[:index]) | |
231 | index = holder.find (' ', index + 1) | |
232 | ||
233 | def add_external_author (self, holder): | |
234 | self.holders[holder] = None | |
235 | ||
236 | class BadYear(): | |
237 | def __init__ (self, year): | |
238 | self.year = year | |
239 | ||
240 | def __str__ (self): | |
241 | return 'unrecognised year: ' + self.year | |
242 | ||
243 | def parse_year (self, string): | |
244 | year = int (string) | |
245 | if len (string) == 2: | |
246 | if year > 70: | |
247 | return year + 1900 | |
248 | elif len (string) == 4: | |
249 | return year | |
250 | raise self.BadYear (string) | |
251 | ||
252 | def year_range (self, years): | |
253 | year_list = [self.parse_year (year) | |
254 | for year in self.year_re.findall (years)] | |
255 | assert len (year_list) > 0 | |
256 | return (min (year_list), max (year_list)) | |
257 | ||
258 | def set_use_quilt (self, use_quilt): | |
259 | self.use_quilt = use_quilt | |
260 | ||
261 | def include_year (self, year): | |
262 | assert not self.max_year | |
263 | self.max_year = year | |
264 | ||
265 | def canonicalise_years (self, dir, filename, filter, years): | |
266 | # Leave texinfo variables alone. | |
267 | if years.startswith ('@value'): | |
268 | return years | |
269 | ||
270 | (min_year, max_year) = self.year_range (years) | |
271 | ||
272 | # Update the upper bound, if enabled. | |
273 | if self.max_year and not filter.is_fossilised_file (dir, filename): | |
274 | max_year = max (max_year, self.max_year) | |
275 | ||
276 | # Use a range. | |
277 | if min_year == max_year: | |
278 | return '%d' % min_year | |
279 | else: | |
280 | return '%d-%d' % (min_year, max_year) | |
281 | ||
282 | def strip_continuation (self, line): | |
283 | line = line.lstrip() | |
284 | match = self.comment_re.match (line) | |
285 | if match: | |
286 | line = line[match.end():].lstrip() | |
287 | return line | |
288 | ||
289 | def is_complete (self, match): | |
290 | holder = match.group (4) | |
291 | return (holder | |
292 | and (holder not in self.holder_prefixes | |
293 | or holder in self.holders)) | |
294 | ||
295 | def update_copyright (self, dir, filename, filter, file, line, match): | |
296 | orig_line = line | |
297 | next_line = None | |
298 | pathname = os.path.join (dir, filename) | |
299 | ||
300 | intro = match.group (1) | |
301 | if intro.startswith ('@set'): | |
302 | # Texinfo year variables should always be on one line | |
303 | after_years = line[match.end (2):].strip() | |
304 | if after_years != '': | |
305 | self.errors.report (pathname, | |
306 | 'trailing characters in @set: ' | |
307 | + after_years) | |
308 | return (False, orig_line, next_line) | |
309 | else: | |
310 | # If it looks like the copyright is incomplete, add the next line. | |
311 | while not self.is_complete (match): | |
312 | try: | |
3b25e835 | 313 | next_line = file.readline() |
240d6348 RS |
314 | except StopIteration: |
315 | break | |
316 | ||
317 | # If the next line doesn't look like a proper continuation, | |
318 | # assume that what we've got is complete. | |
319 | continuation = self.strip_continuation (next_line) | |
320 | if not self.continuation_re.match (continuation): | |
321 | break | |
322 | ||
323 | # Merge the lines for matching purposes. | |
324 | orig_line += next_line | |
325 | line = line.rstrip() + ' ' + continuation | |
326 | next_line = None | |
327 | ||
328 | # Rematch with the longer line, at the original position. | |
329 | match = self.copyright_re.match (line, match.start()) | |
330 | assert match | |
331 | ||
332 | holder = match.group (4) | |
333 | ||
334 | # Use the filter to test cases where markup is getting in the way. | |
335 | if filter.by_package_author (dir, filename): | |
336 | assert holder not in self.holders | |
337 | ||
338 | elif not holder: | |
339 | self.errors.report (pathname, 'missing copyright holder') | |
340 | return (False, orig_line, next_line) | |
341 | ||
342 | elif holder not in self.holders: | |
343 | self.errors.report (pathname, | |
344 | 'unrecognised copyright holder: ' + holder) | |
345 | return (False, orig_line, next_line) | |
346 | ||
347 | else: | |
348 | # See whether the copyright is associated with the package | |
349 | # author. | |
350 | canon_form = self.holders[holder] | |
351 | if not canon_form: | |
352 | return (False, orig_line, next_line) | |
353 | ||
354 | # Make sure the author is given in a consistent way. | |
355 | line = (line[:match.start (4)] | |
356 | + canon_form | |
357 | + line[match.end (4):]) | |
358 | ||
359 | # Remove any 'by' | |
360 | line = line[:match.start (3)] + line[match.end (3):] | |
361 | ||
362 | # Update the copyright years. | |
363 | years = match.group (2).strip() | |
364 | try: | |
365 | canon_form = self.canonicalise_years (dir, filename, filter, years) | |
366 | except self.BadYear as e: | |
367 | self.errors.report (pathname, str (e)) | |
368 | return (False, orig_line, next_line) | |
369 | ||
370 | line = (line[:match.start (2)] | |
8fced9b9 RS |
371 | + ('' if intro.startswith ('copyright = ') else ' ') |
372 | + canon_form + self.separator | |
240d6348 RS |
373 | + line[match.end (2):]) |
374 | ||
375 | # Use the standard (C) form. | |
376 | if intro.endswith ('right'): | |
377 | intro += ' (C)' | |
378 | elif intro.endswith ('(c)'): | |
379 | intro = intro[:-3] + '(C)' | |
380 | line = line[:match.start (1)] + intro + line[match.end (1):] | |
381 | ||
382 | # Strip trailing whitespace | |
383 | line = line.rstrip() + '\n' | |
384 | ||
385 | return (line != orig_line, line, next_line) | |
386 | ||
3b25e835 ML |
387 | def guess_encoding (self, pathname): |
388 | for encoding in ('utf8', 'iso8859'): | |
389 | try: | |
390 | open(pathname, 'r', encoding=encoding).read() | |
391 | return encoding | |
392 | except UnicodeDecodeError: | |
393 | pass | |
394 | return None | |
395 | ||
240d6348 RS |
396 | def process_file (self, dir, filename, filter): |
397 | pathname = os.path.join (dir, filename) | |
398 | if filename.endswith ('.tmp'): | |
399 | # Looks like something we tried to create before. | |
400 | try: | |
401 | os.remove (pathname) | |
402 | except OSError: | |
403 | pass | |
404 | return | |
405 | ||
406 | lines = [] | |
407 | changed = False | |
408 | line_filter = filter.get_line_filter (dir, filename) | |
357a7731 | 409 | mode = None |
3b25e835 ML |
410 | encoding = self.guess_encoding(pathname) |
411 | with open (pathname, 'r', encoding=encoding) as file: | |
240d6348 | 412 | prev = None |
357a7731 | 413 | mode = os.fstat (file.fileno()).st_mode |
240d6348 RS |
414 | for line in file: |
415 | while line: | |
416 | next_line = None | |
417 | # Leave filtered-out lines alone. | |
418 | if not (line_filter and line_filter.match (line)): | |
419 | match = self.copyright_re.search (line) | |
420 | if match: | |
421 | res = self.update_copyright (dir, filename, filter, | |
422 | file, line, match) | |
423 | (this_changed, line, next_line) = res | |
424 | changed = changed or this_changed | |
425 | ||
426 | # Check for copyright lines that might have slipped by. | |
427 | elif self.other_copyright_re.search (line): | |
428 | self.errors.report (pathname, | |
429 | 'unrecognised copyright: %s' | |
430 | % line.strip()) | |
431 | lines.append (line) | |
432 | line = next_line | |
433 | ||
434 | # If something changed, write the new file out. | |
435 | if changed and self.errors.ok(): | |
436 | tmp_pathname = pathname + '.tmp' | |
3b25e835 | 437 | with open (tmp_pathname, 'w', encoding=encoding) as file: |
240d6348 RS |
438 | for line in lines: |
439 | file.write (line) | |
357a7731 | 440 | os.fchmod (file.fileno(), mode) |
240d6348 RS |
441 | if self.use_quilt: |
442 | subprocess.call (['quilt', 'add', pathname]) | |
443 | os.rename (tmp_pathname, pathname) | |
444 | ||
445 | def process_tree (self, tree, filter): | |
446 | for (dir, subdirs, filenames) in os.walk (tree): | |
447 | # Don't recurse through directories that should be skipped. | |
3b25e835 | 448 | for i in range (len (subdirs) - 1, -1, -1): |
240d6348 RS |
449 | if filter.skip_dir (dir, subdirs[i]): |
450 | del subdirs[i] | |
451 | ||
452 | # Handle the files in this directory. | |
453 | for filename in filenames: | |
454 | if filter.skip_file (dir, filename): | |
455 | sys.stdout.write ('Skipping %s\n' | |
456 | % os.path.join (dir, filename)) | |
457 | else: | |
458 | self.process_file (dir, filename, filter) | |
459 | ||
460 | class CmdLine: | |
461 | def __init__ (self, copyright = Copyright): | |
462 | self.errors = Errors() | |
463 | self.copyright = copyright (self.errors) | |
464 | self.dirs = [] | |
465 | self.default_dirs = [] | |
466 | self.chosen_dirs = [] | |
467 | self.option_handlers = dict() | |
468 | self.option_help = [] | |
469 | ||
470 | self.add_option ('--help', 'Print this help', self.o_help) | |
471 | self.add_option ('--quilt', '"quilt add" files before changing them', | |
472 | self.o_quilt) | |
473 | self.add_option ('--this-year', 'Add the current year to every notice', | |
474 | self.o_this_year) | |
475 | ||
476 | def add_option (self, name, help, handler): | |
477 | self.option_help.append ((name, help)) | |
478 | self.option_handlers[name] = handler | |
479 | ||
480 | def add_dir (self, dir, filter = GenericFilter()): | |
481 | self.dirs.append ((dir, filter)) | |
482 | ||
483 | def o_help (self, option = None): | |
484 | sys.stdout.write ('Usage: %s [options] dir1 dir2...\n\n' | |
485 | 'Options:\n' % sys.argv[0]) | |
486 | format = '%-15s %s\n' | |
487 | for (what, help) in self.option_help: | |
488 | sys.stdout.write (format % (what, help)) | |
489 | sys.stdout.write ('\nDirectories:\n') | |
490 | ||
491 | format = '%-25s' | |
492 | i = 0 | |
493 | for (dir, filter) in self.dirs: | |
494 | i += 1 | |
495 | if i % 3 == 0 or i == len (self.dirs): | |
496 | sys.stdout.write (dir + '\n') | |
497 | else: | |
498 | sys.stdout.write (format % dir) | |
499 | sys.exit (0) | |
500 | ||
501 | def o_quilt (self, option): | |
502 | self.copyright.set_use_quilt (True) | |
503 | ||
504 | def o_this_year (self, option): | |
505 | self.copyright.include_year (time.localtime().tm_year) | |
506 | ||
507 | def main (self): | |
508 | for arg in sys.argv[1:]: | |
509 | if arg[:1] != '-': | |
510 | self.chosen_dirs.append (arg) | |
511 | elif arg in self.option_handlers: | |
512 | self.option_handlers[arg] (arg) | |
513 | else: | |
514 | self.errors.report (None, 'unrecognised option: ' + arg) | |
515 | if self.errors.ok(): | |
516 | if len (self.chosen_dirs) == 0: | |
517 | self.chosen_dirs = self.default_dirs | |
518 | if len (self.chosen_dirs) == 0: | |
519 | self.o_help() | |
520 | else: | |
521 | for chosen_dir in self.chosen_dirs: | |
522 | canon_dir = os.path.join (chosen_dir, '') | |
523 | count = 0 | |
524 | for (dir, filter) in self.dirs: | |
525 | if (dir + os.sep).startswith (canon_dir): | |
526 | count += 1 | |
527 | self.copyright.process_tree (dir, filter) | |
528 | if count == 0: | |
529 | self.errors.report (None, 'unrecognised directory: ' | |
530 | + chosen_dir) | |
531 | sys.exit (0 if self.errors.ok() else 1) | |
532 | ||
533 | #---------------------------------------------------------------------------- | |
534 | ||
535 | class TopLevelFilter (GenericFilter): | |
536 | def skip_dir (self, dir, subdir): | |
537 | return True | |
538 | ||
539 | class ConfigFilter (GenericFilter): | |
540 | def __init__ (self): | |
541 | GenericFilter.__init__ (self) | |
542 | ||
543 | def skip_file (self, dir, filename): | |
544 | if filename.endswith ('.m4'): | |
545 | pathname = os.path.join (dir, filename) | |
546 | with open (pathname) as file: | |
547 | # Skip files imported from gettext. | |
548 | if file.readline().find ('gettext-') >= 0: | |
549 | return True | |
550 | return GenericFilter.skip_file (self, dir, filename) | |
551 | ||
552 | class GCCFilter (GenericFilter): | |
553 | def __init__ (self): | |
554 | GenericFilter.__init__ (self) | |
555 | ||
556 | self.skip_files |= set ([ | |
557 | # Not part of GCC | |
558 | 'math-68881.h', | |
559 | ]) | |
560 | ||
561 | self.skip_dirs |= set ([ | |
562 | # Better not create a merge nightmare for the GNAT folks. | |
563 | 'ada', | |
564 | ||
565 | # Handled separately. | |
566 | 'testsuite', | |
567 | ]) | |
568 | ||
569 | self.skip_extensions |= set ([ | |
570 | # Maintained by the translation project. | |
571 | '.po', | |
572 | ||
573 | # Automatically-generated. | |
574 | '.pot', | |
575 | ]) | |
576 | ||
577 | self.fossilised_files |= set ([ | |
578 | # Old news won't be updated. | |
579 | 'ONEWS', | |
580 | ]) | |
581 | ||
582 | class TestsuiteFilter (GenericFilter): | |
583 | def __init__ (self): | |
584 | GenericFilter.__init__ (self) | |
585 | ||
586 | self.skip_extensions |= set ([ | |
587 | # Don't change the tests, which could be woend by anyone. | |
588 | '.c', | |
589 | '.C', | |
590 | '.cc', | |
80de5ef9 | 591 | '.d', |
240d6348 RS |
592 | '.h', |
593 | '.hs', | |
594 | '.f', | |
595 | '.f90', | |
596 | '.go', | |
597 | '.inc', | |
598 | '.java', | |
599 | ]) | |
600 | ||
601 | def skip_file (self, dir, filename): | |
602 | # g++.niklas/README contains historical copyright information | |
603 | # and isn't updated. | |
604 | if filename == 'README' and os.path.basename (dir) == 'g++.niklas': | |
605 | return True | |
ae12c0f0 JJ |
606 | # Similarly params/README. |
607 | if filename == 'README' and os.path.basename (dir) == 'params': | |
608 | return True | |
ada38d5f | 609 | if filename == 'pdt_5.f03' and os.path.basename (dir) == 'gfortran.dg': |
2a680610 | 610 | return True |
240d6348 RS |
611 | return GenericFilter.skip_file (self, dir, filename) |
612 | ||
613 | class LibCppFilter (GenericFilter): | |
614 | def __init__ (self): | |
615 | GenericFilter.__init__ (self) | |
616 | ||
617 | self.skip_extensions |= set ([ | |
618 | # Maintained by the translation project. | |
619 | '.po', | |
620 | ||
621 | # Automatically-generated. | |
622 | '.pot', | |
623 | ]) | |
624 | ||
625 | class LibGCCFilter (GenericFilter): | |
626 | def __init__ (self): | |
627 | GenericFilter.__init__ (self) | |
628 | ||
629 | self.skip_dirs |= set ([ | |
630 | # Imported from GLIBC. | |
631 | 'soft-fp', | |
632 | ]) | |
633 | ||
80de5ef9 IB |
634 | class LibPhobosFilter (GenericFilter): |
635 | def __init__ (self): | |
636 | GenericFilter.__init__ (self) | |
637 | ||
638 | self.skip_files |= set ([ | |
639 | # Source module imported from upstream. | |
640 | 'object.d', | |
641 | ]) | |
642 | ||
643 | self.skip_dirs |= set ([ | |
644 | # Contains sources imported from upstream. | |
645 | 'core', | |
646 | 'etc', | |
647 | 'gc', | |
648 | 'gcstub', | |
649 | 'rt', | |
650 | 'std', | |
651 | ]) | |
652 | ||
240d6348 RS |
653 | class LibStdCxxFilter (GenericFilter): |
654 | def __init__ (self): | |
655 | GenericFilter.__init__ (self) | |
656 | ||
657 | self.skip_files |= set ([ | |
658 | # Contains no copyright of its own, but quotes the GPL. | |
659 | 'intro.xml', | |
660 | ]) | |
661 | ||
662 | self.skip_dirs |= set ([ | |
663 | # Contains automatically-generated sources. | |
664 | 'html', | |
665 | ||
666 | # The testsuite data files shouldn't be changed. | |
667 | 'data', | |
668 | ||
669 | # Contains imported images | |
670 | 'images', | |
671 | ]) | |
672 | ||
673 | self.own_files |= set ([ | |
674 | # Contains markup around the copyright owner. | |
675 | 'spine.xml', | |
676 | ]) | |
677 | ||
678 | def get_line_filter (self, dir, filename): | |
679 | if filename == 'boost_concept_check.h': | |
680 | return re.compile ('// \(C\) Copyright Jeremy Siek') | |
681 | return GenericFilter.get_line_filter (self, dir, filename) | |
682 | ||
683 | class GCCCopyright (Copyright): | |
684 | def __init__ (self, errors): | |
685 | Copyright.__init__ (self, errors) | |
686 | ||
687 | canon_fsf = 'Free Software Foundation, Inc.' | |
688 | self.add_package_author ('Free Software Foundation', canon_fsf) | |
689 | self.add_package_author ('Free Software Foundation.', canon_fsf) | |
690 | self.add_package_author ('Free Software Foundation Inc.', canon_fsf) | |
691 | self.add_package_author ('Free Software Foundation, Inc', canon_fsf) | |
692 | self.add_package_author ('Free Software Foundation, Inc.', canon_fsf) | |
693 | self.add_package_author ('The Free Software Foundation', canon_fsf) | |
694 | self.add_package_author ('The Free Software Foundation, Inc.', canon_fsf) | |
695 | self.add_package_author ('Software Foundation, Inc.', canon_fsf) | |
696 | ||
697 | self.add_external_author ('ARM') | |
698 | self.add_external_author ('AdaCore') | |
c00e2af3 | 699 | self.add_external_author ('Advanced Micro Devices Inc.') |
240d6348 RS |
700 | self.add_external_author ('Ami Tavory and Vladimir Dreizin, IBM-HRL.') |
701 | self.add_external_author ('Cavium Networks.') | |
702 | self.add_external_author ('Faraday Technology Corp.') | |
703 | self.add_external_author ('Florida State University') | |
b5fcfdba | 704 | self.add_external_author ('Gerard Jungman') |
240d6348 RS |
705 | self.add_external_author ('Greg Colvin and Beman Dawes.') |
706 | self.add_external_author ('Hewlett-Packard Company') | |
68edb9ba | 707 | self.add_external_author ('Intel Corporation') |
240d6348 RS |
708 | self.add_external_author ('Information Technology Industry Council.') |
709 | self.add_external_author ('James Theiler, Brian Gough') | |
710 | self.add_external_author ('Makoto Matsumoto and Takuji Nishimura,') | |
e528bf8d | 711 | self.add_external_author ('Mentor Graphics Corporation') |
240d6348 | 712 | self.add_external_author ('National Research Council of Canada.') |
f29fa917 | 713 | self.add_external_author ('NVIDIA Corporation') |
240d6348 RS |
714 | self.add_external_author ('Peter Dimov and Multi Media Ltd.') |
715 | self.add_external_author ('Peter Dimov') | |
716 | self.add_external_author ('Pipeline Associates, Inc.') | |
717 | self.add_external_author ('Regents of the University of California.') | |
718 | self.add_external_author ('Silicon Graphics Computer Systems, Inc.') | |
719 | self.add_external_author ('Silicon Graphics') | |
720 | self.add_external_author ('Stephen L. Moshier') | |
721 | self.add_external_author ('Sun Microsystems, Inc. All rights reserved.') | |
80de5ef9 | 722 | self.add_external_author ('The D Language Foundation, All Rights Reserved') |
240d6348 RS |
723 | self.add_external_author ('The Go Authors. All rights reserved.') |
724 | self.add_external_author ('The Go Authors. All rights reserved.') | |
725 | self.add_external_author ('The Go Authors.') | |
726 | self.add_external_author ('The Regents of the University of California.') | |
c00e2af3 | 727 | self.add_external_author ('Ulf Adams') |
240d6348 RS |
728 | self.add_external_author ('Unicode, Inc.') |
729 | self.add_external_author ('University of Toronto.') | |
e528bf8d | 730 | self.add_external_author ('Yoshinori Sato') |
240d6348 RS |
731 | |
732 | class GCCCmdLine (CmdLine): | |
733 | def __init__ (self): | |
734 | CmdLine.__init__ (self, GCCCopyright) | |
735 | ||
736 | self.add_dir ('.', TopLevelFilter()) | |
737 | # boehm-gc is imported from upstream. | |
c9a089ca | 738 | self.add_dir ('c++tools') |
240d6348 RS |
739 | self.add_dir ('config', ConfigFilter()) |
740 | # contrib isn't really part of GCC. | |
741 | self.add_dir ('fixincludes') | |
742 | self.add_dir ('gcc', GCCFilter()) | |
743 | self.add_dir (os.path.join ('gcc', 'testsuite'), TestsuiteFilter()) | |
744 | self.add_dir ('gnattools') | |
48eae472 | 745 | self.add_dir ('gotools') |
240d6348 | 746 | self.add_dir ('include') |
48eae472 | 747 | # intl is imported from upstream. |
240d6348 RS |
748 | self.add_dir ('libada') |
749 | self.add_dir ('libatomic') | |
750 | self.add_dir ('libbacktrace') | |
48eae472 | 751 | self.add_dir ('libcc1') |
240d6348 RS |
752 | self.add_dir ('libcpp', LibCppFilter()) |
753 | self.add_dir ('libdecnumber') | |
754 | # libffi is imported from upstream. | |
755 | self.add_dir ('libgcc', LibGCCFilter()) | |
756 | self.add_dir ('libgfortran') | |
48eae472 | 757 | # libgo is imported from upstream. |
240d6348 RS |
758 | self.add_dir ('libgomp') |
759 | self.add_dir ('libiberty') | |
760 | self.add_dir ('libitm') | |
240d6348 | 761 | self.add_dir ('libobjc') |
48eae472 | 762 | # liboffloadmic is imported from upstream. |
80de5ef9 | 763 | self.add_dir ('libphobos', LibPhobosFilter()) |
240d6348 | 764 | self.add_dir ('libquadmath') |
48eae472 | 765 | # libsanitizer is imported from upstream. |
240d6348 RS |
766 | self.add_dir ('libssp') |
767 | self.add_dir ('libstdc++-v3', LibStdCxxFilter()) | |
dfa37515 | 768 | self.add_dir ('libvtv') |
240d6348 | 769 | self.add_dir ('lto-plugin') |
48eae472 | 770 | # maintainer-scripts maintainer-scripts |
240d6348 RS |
771 | # zlib is imported from upstream. |
772 | ||
773 | self.default_dirs = [ | |
c9a089ca | 774 | 'c++tools', |
240d6348 | 775 | 'gcc', |
d0a0bfd9 | 776 | 'include', |
240d6348 RS |
777 | 'libada', |
778 | 'libatomic', | |
779 | 'libbacktrace', | |
d0a0bfd9 | 780 | 'libcc1', |
240d6348 | 781 | 'libcpp', |
b96299a1 | 782 | 'libdecnumber', |
240d6348 RS |
783 | 'libgcc', |
784 | 'libgfortran', | |
785 | 'libgomp', | |
d0a0bfd9 | 786 | 'libiberty', |
240d6348 | 787 | 'libitm', |
240d6348 | 788 | 'libobjc', |
80de5ef9 | 789 | 'libphobos', |
d0a0bfd9 | 790 | 'libssp', |
240d6348 | 791 | 'libstdc++-v3', |
d0a0bfd9 JJ |
792 | 'libvtv', |
793 | 'lto-plugin', | |
240d6348 RS |
794 | ] |
795 | ||
796 | GCCCmdLine().main() |