Merged revisions 1826-1882 via svnmerge from
[scons.git] / src / test_strings.py
1 #!/usr/bin/env python
2 #
3 # __COPYRIGHT__
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 #
24
25 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
26
27 """
28 Verify that we have proper strings like Copyright notices on all the
29 right files in our distributions.
30
31 Note that this is a source file and packaging test, not a functional test,
32 so the name of this script doesn't end in *Tests.py.
33 """
34
35 import fnmatch
36 import os
37 import os.path
38 import re
39 import string
40
41 import TestCmd
42 import TestSCons
43
44 # Use TestCmd, not TestSCons, so we don't chdir to a temporary directory.
45 test = TestCmd.TestCmd()
46
47 scons_version = TestSCons.SConsVersion
48
49 def build_path(*args):
50     return apply(os.path.join, ('build',)+args)
51
52 build_scons     = build_path('scons')
53 build_local     = build_path('scons-local', 'scons-local-'+scons_version)
54 build_src       = build_path('scons-src')
55
56 class Checker:
57     def __init__(self, directory,
58                  search_list = [],
59                  remove_list = [],
60                  remove_patterns = []):
61         self.directory = directory
62         self.search_list = search_list
63         self.remove_dict = {}
64         for r in remove_list:
65             self.remove_dict[os.path.join(directory, r)] = 1
66         self.remove_patterns = remove_patterns
67
68     def directory_exists(self):
69         return os.path.exists(self.directory)
70
71     def remove_this(self, name, path):
72         if self.remove_dict.get(path):
73             return 1
74         else:
75             for pattern in self.remove_patterns:
76                 if fnmatch.fnmatch(name, pattern):
77                     return 1
78         return 0
79
80     def search_this(self, path):
81         if self.search_list:
82             for pattern in self.search_list:
83                 if fnmatch.fnmatch(path, pattern):
84                     return 1
85             return None
86         else:
87             return os.path.isfile(path)
88
89     def visit(self, result, dirname, names):
90         make_path_tuple = lambda n, d=dirname: (n, os.path.join(d, n))
91         for name, path in map(make_path_tuple, names):
92             if self.remove_this(name, path):
93                 names.remove(name)
94             elif self.search_this(path):
95                 body = open(path, 'r').read()
96                 for expr in self.expressions:
97                     if not expr.search(body):
98                         msg = '%s: missing %s' % (path, repr(expr.pattern))
99                         result.append(msg)
100
101     def find_missing(self):
102         result = []
103         os.path.walk(self.directory, self.visit, result)
104         return result
105
106 class CheckUnexpandedStrings(Checker):
107     expressions = [
108         re.compile('__COPYRIGHT__'),
109         re.compile('__FILE__ __REVISION__ __DATE__ __DEVELOPER__'),
110     ]
111     def must_be_built(self):
112         return None
113
114 class CheckExpandedCopyright(Checker):
115     expressions = [
116         re.compile('Copyright.*The SCons Foundation'),
117     ]
118     def must_be_built(self):
119         return 1
120
121 check_list = [
122
123     CheckUnexpandedStrings(
124         'src',
125         search_list = [ '*.py' ],
126         remove_list = [
127             'engine/SCons/compat/_scons_sets.py',
128             'engine/SCons/compat/_scons_sets15.py',
129             'engine/SCons/compat/_scons_subprocess.py',
130             'engine/SCons/Conftest.py',
131             'engine/SCons/dblite.py',
132             'engine/SCons/Optik',
133         ],
134     ),
135
136     CheckUnexpandedStrings(
137         'test',
138         search_list = [ '*.py' ],
139     ),
140
141     CheckExpandedCopyright(
142         build_scons,
143         remove_list = [
144             'build',
145             'build-stamp',
146             'configure-stamp',
147             'debian',
148             'dist',
149             'gentoo',
150             'engine/SCons/compat/_scons_sets.py',
151             'engine/SCons/compat/_scons_sets15.py',
152             'engine/SCons/compat/_scons_subprocess.py',
153             'engine/SCons/Conftest.py',
154             'engine/SCons/dblite.py',
155             'engine/SCons/Optik',
156             'MANIFEST',
157             'os_spawnv_fix.diff',
158             'setup.cfg',
159         ],
160         # We run epydoc on the *.py files, which generates *.pyc files.
161         remove_patterns = [
162             '*.pyc'
163         ]
164     ),
165
166     CheckExpandedCopyright(
167         build_local,
168         remove_list = [
169             'SCons/compat/_scons_sets.py',
170             'SCons/compat/_scons_sets15.py',
171             'SCons/compat/_scons_subprocess.py',
172             'SCons/Conftest.py',
173             'SCons/dblite.py',
174             'SCons/Optik',
175         ],
176     ),
177
178     CheckExpandedCopyright(
179         build_src,
180         remove_list = [
181             'bin',
182             'config',
183             'debian',
184             'gentoo',
185             'doc/design',
186             'doc/MANIFEST',
187             'doc/python10',
188             'doc/reference',
189             'doc/developer/MANIFEST',
190             'doc/man/MANIFEST',
191             'doc/user/cons.pl',
192             'doc/user/MANIFEST',
193             'doc/user/SCons-win32-install-1.jpg',
194             'doc/user/SCons-win32-install-2.jpg',
195             'doc/user/SCons-win32-install-3.jpg',
196             'doc/user/SCons-win32-install-4.jpg',
197             'gentoo',
198             'QMTest/classes.qmc',
199             'QMTest/configuration',
200             'QMTest/TestCmd.py',
201             'QMTest/TestCommon.py',
202             'QMTest/unittest.py',
203             'src/os_spawnv_fix.diff',
204             'src/MANIFEST.in',
205             'src/setup.cfg',
206             'src/engine/MANIFEST.in',
207             'src/engine/MANIFEST-xml.in',
208             'src/engine/setup.cfg',
209             'src/engine/SCons/compat/_scons_sets.py',
210             'src/engine/SCons/compat/_scons_sets15.py',
211             'src/engine/SCons/compat/_scons_subprocess.py',
212             'src/engine/SCons/Conftest.py',
213             'src/engine/SCons/dblite.py',
214             'src/engine/SCons/Optik',
215             'src/script/MANIFEST.in',
216             'src/script/setup.cfg',
217         ],
218     ),
219
220 ]
221
222 missing_strings = []
223 not_built = []
224
225 for collector in check_list:
226     if collector.directory_exists():
227         missing_strings.extend(collector.find_missing())
228     elif collector.must_be_built():
229         not_built.append(collector.directory)
230
231 if missing_strings:
232     print "Found the following files with missing strings:"
233     print "\t" + string.join(missing_strings, "\n\t")
234     test.fail_test(1)
235
236 if not_built:
237     print "Cannot check all strings, the following have apparently not been built:"
238     print "\t" + string.join(not_built, "\n\t")
239     test.no_result(1)
240
241 test.pass_test()