Commit | Line | Data |
---|---|---|
5f4def5c | 1 | #! /usr/bin/env python3 |
e9bdf92c | 2 | |
3666a048 | 3 | # Copyright (C) 2011-2021 Free Software Foundation, Inc. |
8ba098ad JB |
4 | # |
5 | # This file is part of GDB. | |
6 | # | |
7 | # This program is free software; you can redistribute it and/or modify | |
8 | # it under the terms of the GNU General Public License as published by | |
9 | # the Free Software Foundation; either version 3 of the License, or | |
10 | # (at your option) any later version. | |
11 | # | |
12 | # This program is distributed in the hope that it will be useful, | |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | # GNU General Public License for more details. | |
16 | # | |
17 | # You should have received a copy of the GNU General Public License | |
18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | ||
e9bdf92c JB |
20 | """copyright.py |
21 | ||
8ba098ad JB |
22 | This script updates the list of years in the copyright notices in |
23 | most files maintained by the GDB project. | |
24 | ||
25 | Usage: cd src/gdb && python copyright.py | |
e9bdf92c | 26 | |
8ba098ad JB |
27 | Always review the output of this script before committing it! |
28 | A useful command to review the output is: | |
29 | % filterdiff -x \*.c -x \*.cc -x \*.h -x \*.exp updates.diff | |
30 | This removes the bulk of the changes which are most likely to be correct. | |
e9bdf92c JB |
31 | """ |
32 | ||
33 | import datetime | |
5f4def5c | 34 | import locale |
e9bdf92c JB |
35 | import os |
36 | import os.path | |
8ba098ad | 37 | import subprocess |
5fb651f2 | 38 | import sys |
8ba098ad | 39 | |
8ba098ad JB |
40 | |
41 | def get_update_list(): | |
42 | """Return the list of files to update. | |
43 | ||
44 | Assumes that the current working directory when called is the root | |
45 | of the GDB source tree (NOT the gdb/ subdirectory!). The names of | |
46 | the files are relative to that root directory. | |
e9bdf92c | 47 | """ |
8ba098ad | 48 | result = [] |
ff7e39b6 | 49 | for gdb_dir in ( |
13123da8 SM |
50 | "gdb", |
51 | "gdbserver", | |
52 | "gdbsupport", | |
53 | "gnulib", | |
54 | "sim", | |
55 | "include/gdb", | |
ff7e39b6 | 56 | ): |
8ba098ad JB |
57 | for root, dirs, files in os.walk(gdb_dir, topdown=True): |
58 | for dirname in dirs: | |
59 | reldirname = "%s/%s" % (root, dirname) | |
13123da8 SM |
60 | if ( |
61 | dirname in EXCLUDE_ALL_LIST | |
8ba098ad JB |
62 | or reldirname in EXCLUDE_LIST |
63 | or reldirname in NOT_FSF_LIST | |
13123da8 SM |
64 | or reldirname in BY_HAND |
65 | ): | |
8ba098ad JB |
66 | # Prune this directory from our search list. |
67 | dirs.remove(dirname) | |
68 | for filename in files: | |
69 | relpath = "%s/%s" % (root, filename) | |
13123da8 SM |
70 | if ( |
71 | filename in EXCLUDE_ALL_LIST | |
8ba098ad JB |
72 | or relpath in EXCLUDE_LIST |
73 | or relpath in NOT_FSF_LIST | |
13123da8 SM |
74 | or relpath in BY_HAND |
75 | ): | |
8ba098ad JB |
76 | # Ignore this file. |
77 | pass | |
78 | else: | |
79 | result.append(relpath) | |
80 | return result | |
81 | ||
82 | ||
83 | def update_files(update_list): | |
84 | """Update the copyright header of the files in the given list. | |
85 | ||
86 | We use gnulib's update-copyright script for that. | |
87 | """ | |
8ba85d85 JB |
88 | # We want to use year intervals in the copyright notices, and |
89 | # all years should be collapsed to one single year interval, | |
90 | # even if there are "holes" in the list of years found in the | |
91 | # original copyright notice (OK'ed by the FSF, case [gnu.org #719834]). | |
13123da8 | 92 | os.environ["UPDATE_COPYRIGHT_USE_INTERVALS"] = "2" |
8ba098ad JB |
93 | |
94 | # Perform the update, and save the output in a string. | |
13123da8 | 95 | update_cmd = ["bash", "gnulib/import/extra/update-copyright"] |
399501a5 JB |
96 | update_cmd += update_list |
97 | ||
13123da8 SM |
98 | p = subprocess.Popen( |
99 | update_cmd, | |
100 | stdout=subprocess.PIPE, | |
101 | stderr=subprocess.STDOUT, | |
102 | encoding=locale.getpreferredencoding(), | |
103 | ) | |
8ba098ad JB |
104 | update_out = p.communicate()[0] |
105 | ||
106 | # Process the output. Typically, a lot of files do not have | |
107 | # a copyright notice :-(. The update-copyright script prints | |
108 | # a well defined warning when it did not find the copyright notice. | |
109 | # For each of those, do a sanity check and see if they may in fact | |
110 | # have one. For the files that are found not to have one, we filter | |
111 | # the line out from the output, since there is nothing more to do, | |
112 | # short of looking at each file and seeing which notice is appropriate. | |
113 | # Too much work! (~4,000 files listed as of 2012-01-03). | |
5f4def5c | 114 | update_out = update_out.splitlines(keepends=False) |
13123da8 | 115 | warning_string = ": warning: copyright statement not found" |
8ba098ad JB |
116 | warning_len = len(warning_string) |
117 | ||
118 | for line in update_out: | |
8ba098ad JB |
119 | if line.endswith(warning_string): |
120 | filename = line[:-warning_len] | |
121 | if may_have_copyright_notice(filename): | |
5f4def5c | 122 | print(line) |
8ba098ad JB |
123 | else: |
124 | # Unrecognized file format. !?! | |
5f4def5c | 125 | print("*** " + line) |
8ba098ad JB |
126 | |
127 | ||
128 | def may_have_copyright_notice(filename): | |
129 | """Check that the given file does not seem to have a copyright notice. | |
130 | ||
131 | The filename is relative to the root directory. | |
132 | This function assumes that the current working directory is that root | |
133 | directory. | |
e9bdf92c | 134 | |
8ba098ad JB |
135 | The algorigthm is fairly crude, meaning that it might return |
136 | some false positives. I do not think it will return any false | |
137 | negatives... We might improve this function to handle more | |
138 | complex cases later... | |
139 | """ | |
140 | # For now, it may have a copyright notice if we find the word | |
141 | # "Copyright" at the (reasonable) start of the given file, say | |
142 | # 50 lines... | |
143 | MAX_LINES = 50 | |
144 | ||
5f4def5c JB |
145 | # We don't really know what encoding each file might be following, |
146 | # so just open the file as a byte stream. We only need to search | |
147 | # for a pattern that should be the same regardless of encoding, | |
148 | # so that should be good enough. | |
13123da8 | 149 | fd = open(filename, "rb") |
8ba098ad JB |
150 | |
151 | lineno = 1 | |
152 | for line in fd: | |
13123da8 | 153 | if b"Copyright" in line: |
8ba098ad JB |
154 | return True |
155 | lineno += 1 | |
156 | if lineno > 50: | |
157 | return False | |
158 | return False | |
159 | ||
160 | ||
13123da8 | 161 | def main(): |
8ba098ad | 162 | """The main subprogram.""" |
8ba098ad JB |
163 | root_dir = os.path.dirname(os.getcwd()) |
164 | os.chdir(root_dir) | |
165 | ||
13123da8 SM |
166 | if not ( |
167 | os.path.isdir("gdb") and os.path.isfile("gnulib/import/extra/update-copyright") | |
168 | ): | |
5f4def5c | 169 | print("Error: This script must be called from the gdb directory.") |
51fd4002 JB |
170 | sys.exit(1) |
171 | ||
8ba098ad | 172 | update_list = get_update_list() |
13123da8 | 173 | update_files(update_list) |
8ba098ad JB |
174 | |
175 | # Remind the user that some files need to be updated by HAND... | |
0f0c98a8 JB |
176 | |
177 | if MULTIPLE_COPYRIGHT_HEADERS: | |
5f4def5c | 178 | print() |
13123da8 SM |
179 | print( |
180 | "\033[31m" | |
181 | "REMINDER: Multiple copyright headers must be updated by hand:" | |
182 | "\033[0m" | |
183 | ) | |
0f0c98a8 | 184 | for filename in MULTIPLE_COPYRIGHT_HEADERS: |
5f4def5c | 185 | print(" ", filename) |
0f0c98a8 | 186 | |
8ba098ad | 187 | if BY_HAND: |
5f4def5c | 188 | print() |
13123da8 SM |
189 | print( |
190 | "\033[31mREMINDER: The following files must be updated by hand." "\033[0m" | |
191 | ) | |
0f0c98a8 | 192 | for filename in BY_HAND: |
5f4def5c | 193 | print(" ", filename) |
8ba098ad | 194 | |
13123da8 | 195 | |
8ba098ad JB |
196 | ############################################################################ |
197 | # | |
198 | # Some constants, placed at the end because they take up a lot of room. | |
199 | # The actual value of these constants is not significant to the understanding | |
200 | # of the script. | |
201 | # | |
202 | ############################################################################ | |
e9bdf92c | 203 | |
8ba098ad JB |
204 | # Files which should not be modified, either because they are |
205 | # generated, non-FSF, or otherwise special (e.g. license text, | |
206 | # or test cases which must be sensitive to line numbering). | |
207 | # | |
208 | # Filenames are relative to the root directory. | |
209 | EXCLUDE_LIST = ( | |
13123da8 SM |
210 | "gdb/nat/glibc_thread_db.h", |
211 | "gdb/CONTRIBUTE", | |
212 | "gnulib/import", | |
213 | "gnulib/config.in", | |
214 | "gnulib/Makefile.in", | |
8ba098ad | 215 | ) |
e9bdf92c JB |
216 | |
217 | # Files which should not be modified, either because they are | |
218 | # generated, non-FSF, or otherwise special (e.g. license text, | |
219 | # or test cases which must be sensitive to line numbering). | |
8ba098ad JB |
220 | # |
221 | # Matches any file or directory name anywhere. Use with caution. | |
222 | # This is mostly for files that can be found in multiple directories. | |
223 | # Eg: We want all files named COPYING to be left untouched. | |
224 | ||
225 | EXCLUDE_ALL_LIST = ( | |
13123da8 SM |
226 | "COPYING", |
227 | "COPYING.LIB", | |
228 | "CVS", | |
229 | "configure", | |
230 | "copying.c", | |
231 | "fdl.texi", | |
232 | "gpl.texi", | |
233 | "aclocal.m4", | |
8ba098ad JB |
234 | ) |
235 | ||
236 | # The list of files to update by hand. | |
237 | BY_HAND = ( | |
1690bb24 | 238 | # Nothing at the moment :-). |
8ba098ad JB |
239 | ) |
240 | ||
3770a159 JB |
241 | # Files containing multiple copyright headers. This script is only |
242 | # fixing the first one it finds, so we need to finish the update | |
243 | # by hand. | |
244 | MULTIPLE_COPYRIGHT_HEADERS = ( | |
245 | "gdb/doc/gdb.texinfo", | |
246 | "gdb/doc/refcard.tex", | |
bf6be9db | 247 | "gdb/gdbarch.sh", |
3770a159 JB |
248 | ) |
249 | ||
8ba098ad JB |
250 | # The list of file which have a copyright, but not head by the FSF. |
251 | # Filenames are relative to the root directory. | |
252 | NOT_FSF_LIST = ( | |
253 | "gdb/exc_request.defs", | |
8ba098ad JB |
254 | "gdb/gdbtk", |
255 | "gdb/testsuite/gdb.gdbtk/", | |
13123da8 SM |
256 | "sim/arm/armemu.h", |
257 | "sim/arm/armos.c", | |
258 | "sim/arm/gdbhost.c", | |
259 | "sim/arm/dbg_hif.h", | |
260 | "sim/arm/dbg_conf.h", | |
261 | "sim/arm/communicate.h", | |
262 | "sim/arm/armos.h", | |
263 | "sim/arm/armcopro.c", | |
264 | "sim/arm/armemu.c", | |
265 | "sim/arm/kid.c", | |
266 | "sim/arm/thumbemu.c", | |
267 | "sim/arm/armdefs.h", | |
268 | "sim/arm/armopts.h", | |
269 | "sim/arm/dbg_cp.h", | |
270 | "sim/arm/dbg_rdi.h", | |
271 | "sim/arm/parent.c", | |
272 | "sim/arm/armsupp.c", | |
273 | "sim/arm/armrdi.c", | |
274 | "sim/arm/bag.c", | |
275 | "sim/arm/armvirt.c", | |
276 | "sim/arm/main.c", | |
277 | "sim/arm/bag.h", | |
278 | "sim/arm/communicate.c", | |
279 | "sim/arm/gdbhost.h", | |
280 | "sim/arm/armfpe.h", | |
8ba098ad | 281 | "sim/arm/arminit.c", |
13123da8 SM |
282 | "sim/common/cgen-fpu.c", |
283 | "sim/common/cgen-fpu.h", | |
ab39020b | 284 | "sim/common/cgen-accfp.c", |
13123da8 SM |
285 | "sim/mips/m16run.c", |
286 | "sim/mips/sim-main.c", | |
8ba098ad JB |
287 | "sim/moxie/moxie-gdb.dts", |
288 | # Not a single file in sim/ppc/ appears to be copyright FSF :-(. | |
13123da8 SM |
289 | "sim/ppc/filter.h", |
290 | "sim/ppc/gen-support.h", | |
291 | "sim/ppc/ld-insn.h", | |
292 | "sim/ppc/hw_sem.c", | |
293 | "sim/ppc/hw_disk.c", | |
294 | "sim/ppc/idecode_branch.h", | |
295 | "sim/ppc/sim-endian.h", | |
296 | "sim/ppc/table.c", | |
297 | "sim/ppc/hw_core.c", | |
298 | "sim/ppc/gen-support.c", | |
299 | "sim/ppc/gen-semantics.h", | |
300 | "sim/ppc/cpu.h", | |
301 | "sim/ppc/sim_callbacks.h", | |
302 | "sim/ppc/RUN", | |
303 | "sim/ppc/Makefile.in", | |
304 | "sim/ppc/emul_chirp.c", | |
305 | "sim/ppc/hw_nvram.c", | |
306 | "sim/ppc/dc-test.01", | |
307 | "sim/ppc/hw_phb.c", | |
308 | "sim/ppc/hw_eeprom.c", | |
309 | "sim/ppc/bits.h", | |
310 | "sim/ppc/hw_vm.c", | |
311 | "sim/ppc/cap.h", | |
312 | "sim/ppc/os_emul.h", | |
313 | "sim/ppc/options.h", | |
314 | "sim/ppc/gen-idecode.c", | |
315 | "sim/ppc/filter.c", | |
316 | "sim/ppc/corefile-n.h", | |
317 | "sim/ppc/std-config.h", | |
318 | "sim/ppc/ld-decode.h", | |
319 | "sim/ppc/filter_filename.h", | |
320 | "sim/ppc/hw_shm.c", | |
321 | "sim/ppc/pk_disklabel.c", | |
322 | "sim/ppc/dc-simple", | |
323 | "sim/ppc/misc.h", | |
324 | "sim/ppc/device_table.h", | |
325 | "sim/ppc/ld-insn.c", | |
326 | "sim/ppc/inline.c", | |
327 | "sim/ppc/emul_bugapi.h", | |
328 | "sim/ppc/hw_cpu.h", | |
329 | "sim/ppc/debug.h", | |
330 | "sim/ppc/hw_ide.c", | |
331 | "sim/ppc/debug.c", | |
332 | "sim/ppc/gen-itable.h", | |
333 | "sim/ppc/interrupts.c", | |
334 | "sim/ppc/hw_glue.c", | |
335 | "sim/ppc/emul_unix.c", | |
336 | "sim/ppc/sim_calls.c", | |
337 | "sim/ppc/dc-complex", | |
338 | "sim/ppc/ld-cache.c", | |
339 | "sim/ppc/registers.h", | |
340 | "sim/ppc/dc-test.02", | |
341 | "sim/ppc/options.c", | |
342 | "sim/ppc/igen.h", | |
343 | "sim/ppc/registers.c", | |
344 | "sim/ppc/device.h", | |
345 | "sim/ppc/emul_chirp.h", | |
346 | "sim/ppc/hw_register.c", | |
347 | "sim/ppc/hw_init.c", | |
348 | "sim/ppc/sim-endian-n.h", | |
349 | "sim/ppc/filter_filename.c", | |
350 | "sim/ppc/bits.c", | |
351 | "sim/ppc/idecode_fields.h", | |
352 | "sim/ppc/hw_memory.c", | |
353 | "sim/ppc/misc.c", | |
354 | "sim/ppc/double.c", | |
355 | "sim/ppc/psim.h", | |
356 | "sim/ppc/hw_trace.c", | |
357 | "sim/ppc/emul_netbsd.h", | |
358 | "sim/ppc/psim.c", | |
359 | "sim/ppc/ppc-instructions", | |
360 | "sim/ppc/tree.h", | |
361 | "sim/ppc/README", | |
362 | "sim/ppc/gen-icache.h", | |
363 | "sim/ppc/gen-model.h", | |
364 | "sim/ppc/ld-cache.h", | |
365 | "sim/ppc/mon.c", | |
366 | "sim/ppc/corefile.h", | |
367 | "sim/ppc/vm.c", | |
368 | "sim/ppc/INSTALL", | |
369 | "sim/ppc/gen-model.c", | |
370 | "sim/ppc/hw_cpu.c", | |
371 | "sim/ppc/corefile.c", | |
372 | "sim/ppc/hw_opic.c", | |
373 | "sim/ppc/gen-icache.c", | |
374 | "sim/ppc/events.h", | |
375 | "sim/ppc/os_emul.c", | |
376 | "sim/ppc/emul_generic.c", | |
377 | "sim/ppc/main.c", | |
378 | "sim/ppc/hw_com.c", | |
379 | "sim/ppc/gen-semantics.c", | |
380 | "sim/ppc/emul_bugapi.c", | |
381 | "sim/ppc/device.c", | |
382 | "sim/ppc/emul_generic.h", | |
383 | "sim/ppc/tree.c", | |
384 | "sim/ppc/mon.h", | |
385 | "sim/ppc/interrupts.h", | |
386 | "sim/ppc/cap.c", | |
387 | "sim/ppc/cpu.c", | |
388 | "sim/ppc/hw_phb.h", | |
389 | "sim/ppc/device_table.c", | |
390 | "sim/ppc/lf.c", | |
391 | "sim/ppc/lf.c", | |
392 | "sim/ppc/dc-stupid", | |
393 | "sim/ppc/hw_pal.c", | |
394 | "sim/ppc/ppc-spr-table", | |
395 | "sim/ppc/emul_unix.h", | |
396 | "sim/ppc/words.h", | |
397 | "sim/ppc/basics.h", | |
398 | "sim/ppc/hw_htab.c", | |
399 | "sim/ppc/lf.h", | |
400 | "sim/ppc/ld-decode.c", | |
401 | "sim/ppc/sim-endian.c", | |
402 | "sim/ppc/gen-itable.c", | |
403 | "sim/ppc/idecode_expression.h", | |
404 | "sim/ppc/table.h", | |
405 | "sim/ppc/dgen.c", | |
406 | "sim/ppc/events.c", | |
407 | "sim/ppc/gen-idecode.h", | |
408 | "sim/ppc/emul_netbsd.c", | |
409 | "sim/ppc/igen.c", | |
410 | "sim/ppc/vm_n.h", | |
411 | "sim/ppc/vm.h", | |
412 | "sim/ppc/hw_iobus.c", | |
413 | "sim/ppc/inline.h", | |
0e7620dc | 414 | "sim/testsuite/sim/mips/mips32-dsp2.s", |
8ba098ad | 415 | ) |
e9bdf92c JB |
416 | |
417 | if __name__ == "__main__": | |
8ba098ad | 418 | main() |