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