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