Commit | Line | Data |
---|---|---|
e9bdf92c JB |
1 | #! /usr/bin/env python |
2 | ||
ecd75fc8 | 3 | # Copyright (C) 2011-2014 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 | |
e9bdf92c JB |
34 | import os |
35 | import os.path | |
8ba098ad JB |
36 | import subprocess |
37 | ||
8ba098ad JB |
38 | |
39 | def get_update_list(): | |
40 | """Return the list of files to update. | |
41 | ||
42 | Assumes that the current working directory when called is the root | |
43 | of the GDB source tree (NOT the gdb/ subdirectory!). The names of | |
44 | the files are relative to that root directory. | |
e9bdf92c | 45 | """ |
8ba098ad JB |
46 | result = [] |
47 | for gdb_dir in ('gdb', 'sim', 'include/gdb'): | |
48 | for root, dirs, files in os.walk(gdb_dir, topdown=True): | |
49 | for dirname in dirs: | |
50 | reldirname = "%s/%s" % (root, dirname) | |
51 | if (dirname in EXCLUDE_ALL_LIST | |
52 | or reldirname in EXCLUDE_LIST | |
53 | or reldirname in NOT_FSF_LIST | |
54 | or reldirname in BY_HAND): | |
55 | # Prune this directory from our search list. | |
56 | dirs.remove(dirname) | |
57 | for filename in files: | |
58 | relpath = "%s/%s" % (root, filename) | |
59 | if (filename in EXCLUDE_ALL_LIST | |
60 | or relpath in EXCLUDE_LIST | |
61 | or relpath in NOT_FSF_LIST | |
62 | or relpath in BY_HAND): | |
63 | # Ignore this file. | |
64 | pass | |
65 | else: | |
66 | result.append(relpath) | |
67 | return result | |
68 | ||
69 | ||
70 | def update_files(update_list): | |
71 | """Update the copyright header of the files in the given list. | |
72 | ||
73 | We use gnulib's update-copyright script for that. | |
74 | """ | |
8ba85d85 JB |
75 | # We want to use year intervals in the copyright notices, and |
76 | # all years should be collapsed to one single year interval, | |
77 | # even if there are "holes" in the list of years found in the | |
78 | # original copyright notice (OK'ed by the FSF, case [gnu.org #719834]). | |
79 | os.environ['UPDATE_COPYRIGHT_USE_INTERVALS'] = '2' | |
8ba098ad JB |
80 | |
81 | # Perform the update, and save the output in a string. | |
399501a5 JB |
82 | update_cmd = ['bash', 'gdb/gnulib/import/extra/update-copyright'] |
83 | update_cmd += update_list | |
84 | ||
8ba098ad JB |
85 | p = subprocess.Popen(update_cmd, stdout=subprocess.PIPE, |
86 | stderr=subprocess.STDOUT) | |
87 | update_out = p.communicate()[0] | |
88 | ||
89 | # Process the output. Typically, a lot of files do not have | |
90 | # a copyright notice :-(. The update-copyright script prints | |
91 | # a well defined warning when it did not find the copyright notice. | |
92 | # For each of those, do a sanity check and see if they may in fact | |
93 | # have one. For the files that are found not to have one, we filter | |
94 | # the line out from the output, since there is nothing more to do, | |
95 | # short of looking at each file and seeing which notice is appropriate. | |
96 | # Too much work! (~4,000 files listed as of 2012-01-03). | |
97 | update_out = update_out.splitlines() | |
98 | warning_string = ': warning: copyright statement not found' | |
99 | warning_len = len(warning_string) | |
100 | ||
101 | for line in update_out: | |
102 | if line.endswith('\n'): | |
103 | line = line[:-1] | |
104 | if line.endswith(warning_string): | |
105 | filename = line[:-warning_len] | |
106 | if may_have_copyright_notice(filename): | |
107 | print line | |
108 | else: | |
109 | # Unrecognized file format. !?! | |
110 | print "*** " + line | |
111 | ||
112 | ||
113 | def may_have_copyright_notice(filename): | |
114 | """Check that the given file does not seem to have a copyright notice. | |
115 | ||
116 | The filename is relative to the root directory. | |
117 | This function assumes that the current working directory is that root | |
118 | directory. | |
e9bdf92c | 119 | |
8ba098ad JB |
120 | The algorigthm is fairly crude, meaning that it might return |
121 | some false positives. I do not think it will return any false | |
122 | negatives... We might improve this function to handle more | |
123 | complex cases later... | |
124 | """ | |
125 | # For now, it may have a copyright notice if we find the word | |
126 | # "Copyright" at the (reasonable) start of the given file, say | |
127 | # 50 lines... | |
128 | MAX_LINES = 50 | |
129 | ||
130 | fd = open(filename) | |
131 | ||
132 | lineno = 1 | |
133 | for line in fd: | |
134 | if 'Copyright' in line: | |
135 | return True | |
136 | lineno += 1 | |
137 | if lineno > 50: | |
138 | return False | |
139 | return False | |
140 | ||
141 | ||
142 | def main (): | |
143 | """The main subprogram.""" | |
399501a5 | 144 | if not os.path.isfile("gnulib/import/extra/update-copyright"): |
8ba098ad JB |
145 | print "Error: This script must be called from the gdb directory." |
146 | root_dir = os.path.dirname(os.getcwd()) | |
147 | os.chdir(root_dir) | |
148 | ||
149 | update_list = get_update_list() | |
150 | update_files (update_list) | |
151 | ||
152 | # Remind the user that some files need to be updated by HAND... | |
153 | if BY_HAND: | |
154 | ||
155 | print "\033[31mREMINDER: The following files must be updated by hand." \ | |
156 | "\033[0m" | |
3770a159 | 157 | for filename in BY_HAND + MULTIPLE_COPYRIGHT_HEADERS: |
8ba098ad JB |
158 | print " ", filename |
159 | ||
160 | ############################################################################ | |
161 | # | |
162 | # Some constants, placed at the end because they take up a lot of room. | |
163 | # The actual value of these constants is not significant to the understanding | |
164 | # of the script. | |
165 | # | |
166 | ############################################################################ | |
e9bdf92c | 167 | |
8ba098ad JB |
168 | # Files which should not be modified, either because they are |
169 | # generated, non-FSF, or otherwise special (e.g. license text, | |
170 | # or test cases which must be sensitive to line numbering). | |
171 | # | |
172 | # Filenames are relative to the root directory. | |
173 | EXCLUDE_LIST = ( | |
125f8a3d | 174 | 'gdb/nat/glibc_thread_db.h', |
e23d4a9c | 175 | 'gdb/CONTRIBUTE', |
c3b18ee7 | 176 | 'gdb/gnulib/import' |
8ba098ad | 177 | ) |
e9bdf92c JB |
178 | |
179 | # Files which should not be modified, either because they are | |
180 | # generated, non-FSF, or otherwise special (e.g. license text, | |
181 | # or test cases which must be sensitive to line numbering). | |
8ba098ad JB |
182 | # |
183 | # Matches any file or directory name anywhere. Use with caution. | |
184 | # This is mostly for files that can be found in multiple directories. | |
185 | # Eg: We want all files named COPYING to be left untouched. | |
186 | ||
187 | EXCLUDE_ALL_LIST = ( | |
188 | "COPYING", "COPYING.LIB", "CVS", "configure", "copying.c", | |
189 | "fdl.texi", "gpl.texi", "aclocal.m4", | |
190 | ) | |
191 | ||
192 | # The list of files to update by hand. | |
193 | BY_HAND = ( | |
194 | # These files are sensitive to line numbering. | |
195 | "gdb/testsuite/gdb.base/step-line.inp", | |
196 | "gdb/testsuite/gdb.base/step-line.c", | |
197 | ) | |
198 | ||
3770a159 JB |
199 | # Files containing multiple copyright headers. This script is only |
200 | # fixing the first one it finds, so we need to finish the update | |
201 | # by hand. | |
202 | MULTIPLE_COPYRIGHT_HEADERS = ( | |
203 | "gdb/doc/gdb.texinfo", | |
204 | "gdb/doc/refcard.tex", | |
bf6be9db | 205 | "gdb/gdbarch.sh", |
3770a159 JB |
206 | ) |
207 | ||
8ba098ad JB |
208 | # The list of file which have a copyright, but not head by the FSF. |
209 | # Filenames are relative to the root directory. | |
210 | NOT_FSF_LIST = ( | |
211 | "gdb/exc_request.defs", | |
8ba098ad JB |
212 | "gdb/gdbtk", |
213 | "gdb/testsuite/gdb.gdbtk/", | |
214 | "sim/arm/armemu.h", "sim/arm/armos.c", "sim/arm/gdbhost.c", | |
215 | "sim/arm/dbg_hif.h", "sim/arm/dbg_conf.h", "sim/arm/communicate.h", | |
216 | "sim/arm/armos.h", "sim/arm/armcopro.c", "sim/arm/armemu.c", | |
217 | "sim/arm/kid.c", "sim/arm/thumbemu.c", "sim/arm/armdefs.h", | |
218 | "sim/arm/armopts.h", "sim/arm/dbg_cp.h", "sim/arm/dbg_rdi.h", | |
219 | "sim/arm/parent.c", "sim/arm/armsupp.c", "sim/arm/armrdi.c", | |
220 | "sim/arm/bag.c", "sim/arm/armvirt.c", "sim/arm/main.c", "sim/arm/bag.h", | |
221 | "sim/arm/communicate.c", "sim/arm/gdbhost.h", "sim/arm/armfpe.h", | |
222 | "sim/arm/arminit.c", | |
ab39020b JB |
223 | "sim/common/cgen-fpu.c", "sim/common/cgen-fpu.h", |
224 | "sim/common/cgen-accfp.c", | |
8ba098ad JB |
225 | "sim/erc32/sis.h", "sim/erc32/erc32.c", "sim/erc32/func.c", |
226 | "sim/erc32/float.c", "sim/erc32/interf.c", "sim/erc32/sis.c", | |
227 | "sim/erc32/exec.c", | |
228 | "sim/mips/m16run.c", "sim/mips/sim-main.c", | |
8ba098ad JB |
229 | "sim/moxie/moxie-gdb.dts", |
230 | # Not a single file in sim/ppc/ appears to be copyright FSF :-(. | |
231 | "sim/ppc/filter.h", "sim/ppc/gen-support.h", "sim/ppc/ld-insn.h", | |
232 | "sim/ppc/hw_sem.c", "sim/ppc/hw_disk.c", "sim/ppc/idecode_branch.h", | |
233 | "sim/ppc/sim-endian.h", "sim/ppc/table.c", "sim/ppc/hw_core.c", | |
234 | "sim/ppc/gen-support.c", "sim/ppc/gen-semantics.h", "sim/ppc/cpu.h", | |
235 | "sim/ppc/sim_callbacks.h", "sim/ppc/RUN", "sim/ppc/Makefile.in", | |
236 | "sim/ppc/emul_chirp.c", "sim/ppc/hw_nvram.c", "sim/ppc/dc-test.01", | |
237 | "sim/ppc/hw_phb.c", "sim/ppc/hw_eeprom.c", "sim/ppc/bits.h", | |
238 | "sim/ppc/hw_vm.c", "sim/ppc/cap.h", "sim/ppc/os_emul.h", | |
239 | "sim/ppc/options.h", "sim/ppc/gen-idecode.c", "sim/ppc/filter.c", | |
240 | "sim/ppc/corefile-n.h", "sim/ppc/std-config.h", "sim/ppc/ld-decode.h", | |
241 | "sim/ppc/filter_filename.h", "sim/ppc/hw_shm.c", | |
242 | "sim/ppc/pk_disklabel.c", "sim/ppc/dc-simple", "sim/ppc/misc.h", | |
243 | "sim/ppc/device_table.h", "sim/ppc/ld-insn.c", "sim/ppc/inline.c", | |
244 | "sim/ppc/emul_bugapi.h", "sim/ppc/hw_cpu.h", "sim/ppc/debug.h", | |
245 | "sim/ppc/hw_ide.c", "sim/ppc/debug.c", "sim/ppc/gen-itable.h", | |
246 | "sim/ppc/interrupts.c", "sim/ppc/hw_glue.c", "sim/ppc/emul_unix.c", | |
247 | "sim/ppc/sim_calls.c", "sim/ppc/dc-complex", "sim/ppc/ld-cache.c", | |
248 | "sim/ppc/registers.h", "sim/ppc/dc-test.02", "sim/ppc/options.c", | |
249 | "sim/ppc/igen.h", "sim/ppc/registers.c", "sim/ppc/device.h", | |
250 | "sim/ppc/emul_chirp.h", "sim/ppc/hw_register.c", "sim/ppc/hw_init.c", | |
251 | "sim/ppc/sim-endian-n.h", "sim/ppc/filter_filename.c", | |
252 | "sim/ppc/bits.c", "sim/ppc/idecode_fields.h", "sim/ppc/hw_memory.c", | |
253 | "sim/ppc/misc.c", "sim/ppc/double.c", "sim/ppc/psim.h", | |
254 | "sim/ppc/hw_trace.c", "sim/ppc/emul_netbsd.h", "sim/ppc/psim.c", | |
255 | "sim/ppc/ppc-instructions", "sim/ppc/tree.h", "sim/ppc/README", | |
256 | "sim/ppc/gen-icache.h", "sim/ppc/gen-model.h", "sim/ppc/ld-cache.h", | |
257 | "sim/ppc/mon.c", "sim/ppc/corefile.h", "sim/ppc/vm.c", | |
258 | "sim/ppc/INSTALL", "sim/ppc/gen-model.c", "sim/ppc/hw_cpu.c", | |
259 | "sim/ppc/corefile.c", "sim/ppc/hw_opic.c", "sim/ppc/gen-icache.c", | |
260 | "sim/ppc/events.h", "sim/ppc/os_emul.c", "sim/ppc/emul_generic.c", | |
261 | "sim/ppc/main.c", "sim/ppc/hw_com.c", "sim/ppc/gen-semantics.c", | |
262 | "sim/ppc/emul_bugapi.c", "sim/ppc/device.c", "sim/ppc/emul_generic.h", | |
263 | "sim/ppc/tree.c", "sim/ppc/mon.h", "sim/ppc/interrupts.h", | |
264 | "sim/ppc/cap.c", "sim/ppc/cpu.c", "sim/ppc/hw_phb.h", | |
265 | "sim/ppc/device_table.c", "sim/ppc/lf.c", "sim/ppc/lf.c", | |
266 | "sim/ppc/dc-stupid", "sim/ppc/hw_pal.c", "sim/ppc/ppc-spr-table", | |
267 | "sim/ppc/emul_unix.h", "sim/ppc/words.h", "sim/ppc/basics.h", | |
268 | "sim/ppc/hw_htab.c", "sim/ppc/lf.h", "sim/ppc/ld-decode.c", | |
269 | "sim/ppc/sim-endian.c", "sim/ppc/gen-itable.c", | |
270 | "sim/ppc/idecode_expression.h", "sim/ppc/table.h", "sim/ppc/dgen.c", | |
271 | "sim/ppc/events.c", "sim/ppc/gen-idecode.h", "sim/ppc/emul_netbsd.c", | |
272 | "sim/ppc/igen.c", "sim/ppc/vm_n.h", "sim/ppc/vm.h", | |
273 | "sim/ppc/hw_iobus.c", "sim/ppc/inline.h", | |
274 | "sim/testsuite/sim/bfin/s21.s", "sim/testsuite/sim/mips/mips32-dsp2.s", | |
275 | ) | |
e9bdf92c JB |
276 | |
277 | if __name__ == "__main__": | |
8ba098ad | 278 | main() |
e9bdf92c | 279 |