Rename bin/linecount to bin/linecount.py and provide finer-grained
[scons.git] / bin / scons-test.py
1 #!/usr/bin/env python
2 #
3 # A script that takes an scons-src-{version}.zip file, unwraps it in
4 # a temporary location, and calls runtest.py to execute one or more of
5 # its tests.
6 #
7 # The default is to download the latest scons-src archive from the SCons
8 # web site, and to execute all of the tests.
9 #
10 # With a little more work, this will become the basis of an automated
11 # testing and reporting system that anyone will be able to use to
12 # participate in testing SCons on their system and regularly reporting
13 # back the results.  A --xml option is a stab at gathering a lot of
14 # relevant information about the system, the Python version, etc.,
15 # so that problems on different platforms can be identified sooner.
16 #
17
18 import getopt
19 import imp
20 import os
21 import os.path
22 import string
23 import sys
24 import tempfile
25 import time
26 import urllib
27 import zipfile
28
29 helpstr = """\
30 Usage: scons-test.py [-f zipfile] [-o outdir] [-v] [--xml] [runtest arguments]
31 Options:
32   -f FILE                     Specify input .zip FILE name
33   -o DIR, --out DIR           Change output directory name to DIR
34   -v, --verbose               Print file names when extracting
35   --xml                       XML output
36 """
37
38 opts, args = getopt.getopt(sys.argv[1:],
39                            "f:o:v",
40                            ['file=', 'out=', 'verbose', 'xml'])
41
42 format = None
43 outdir = None
44 printname = lambda x: x
45 inputfile = 'http://scons.sourceforge.net/scons-src-latest.zip'
46
47 for o, a in opts:
48     if o == '-f' or o == '--file':
49         inputfile = a
50     elif o == '-o' or o == '--out':
51         outdir = a
52     elif o == '-v' or o == '--verbose':
53         def printname(x):
54             print x
55     elif o == '--xml':
56         format = o
57
58 startdir = os.getcwd()
59
60 tempfile.template = 'scons-test.'
61 tempdir = tempfile.mktemp()
62
63 if not os.path.exists(tempdir):
64     os.mkdir(tempdir)
65     def cleanup(tempdir=tempdir):
66         import shutil
67         os.chdir(startdir)
68         shutil.rmtree(tempdir)
69     sys.exitfunc = cleanup
70
71 # Fetch the input file if it happens to be across a network somewhere.
72 # Ohmigod, does Python make this simple...
73 inputfile, headers = urllib.urlretrieve(inputfile)
74
75 # Unzip the header file in the output directory.  We use our own code
76 # (lifted from scons-unzip.py) to make the output subdirectory name
77 # match the basename of the .zip file.
78 zf = zipfile.ZipFile(inputfile, 'r')
79
80 if outdir is None:
81     name, _ = os.path.splitext(os.path.basename(inputfile))
82     outdir = os.path.join(tempdir, name)
83
84 def outname(n, outdir=outdir):
85     l = []
86     while 1:
87         n, tail = os.path.split(n)
88         if not n:
89             break
90         l.append(tail)
91     l.append(outdir)
92     l.reverse()
93     return apply(os.path.join, l)
94
95 for name in zf.namelist():
96     dest = outname(name)
97     dir = os.path.dirname(dest)
98     try:
99         os.makedirs(dir)
100     except:
101         pass
102     printname(dest)
103     # if the file exists, then delete it before writing
104     # to it so that we don't end up trying to write to a symlink:
105     if os.path.isfile(dest) or os.path.islink(dest):
106         os.unlink(dest)
107     if not os.path.isdir(dest):
108         open(dest, 'w').write(zf.read(name))
109
110 os.chdir(outdir)
111
112 # Load (by hand) the SCons modules we just unwrapped so we can
113 # extract their version information.  Note that we have to override
114 # SCons.Script.main() with a do_nothing() function, because loading up
115 # the 'scons' script will actually try to execute SCons...
116 src_script = os.path.join(outdir, 'src', 'script')
117 src_engine = os.path.join(outdir, 'src', 'engine')
118 src_engine_SCons = os.path.join(src_engine, 'SCons')
119
120 fp, pname, desc = imp.find_module('SCons', [src_engine])
121 SCons = imp.load_module('SCons', fp, pname, desc)
122
123 fp, pname, desc = imp.find_module('Script', [src_engine_SCons])
124 SCons.Script = imp.load_module('Script', fp, pname, desc)
125
126 def do_nothing():
127     pass
128 SCons.Script.main = do_nothing
129
130 fp, pname, desc = imp.find_module('scons', [src_script])
131 scons = imp.load_module('scons', fp, pname, desc)
132 fp.close()
133
134 # Default is to run all the tests by passing the -a flags to runtest.py.
135 if not args:
136     runtest_args = '-a'
137 else:
138     runtest_args = string.join(args)
139
140 if format == '--xml':
141
142     print "<scons_test_run>"
143     print "  <sys>"
144     sys_keys = ['byteorder', 'exec_prefix', 'executable', 'maxint', 'maxunicode', 'platform', 'prefix', 'version', 'version_info']
145     for k in sys_keys:
146         print "    <%s>%s</%s>" % (k, sys.__dict__[k], k)
147     print "  </sys>"
148
149     fmt = '%a %b %d %H:%M:%S %Y'
150     print "  <time>"
151     print "    <gmtime>%s</gmtime>" % time.strftime(fmt, time.gmtime())
152     print "    <localtime>%s</localtime>" % time.strftime(fmt, time.localtime())
153     print "  </time>"
154
155     print "  <tempdir>%s</tempdir>" % tempdir
156
157     def print_version_info(tag, module):
158         print "    <%s>" % tag
159         print "      <version>%s</version>" % module.__version__
160         print "      <build>%s</build>" % module.__build__
161         print "      <buildsys>%s</buildsys>" % module.__buildsys__
162         print "      <date>%s</date>" % module.__date__
163         print "      <developer>%s</developer>" % module.__developer__
164         print "    </%s>" % tag
165
166     print "  <scons>"
167     print_version_info("script", scons)
168     print_version_info("engine", SCons)
169     print "  </scons>"
170
171     environ_keys = [
172         'PATH',
173         'SCONSFLAGS',
174         'SCONS_LIB_DIR',
175         'PYTHON_ROOT',
176         'QTDIR',
177
178         'COMSPEC',
179         'INTEL_LICENSE_FILE',
180         'INCLUDE',
181         'LIB',
182         'MSDEVDIR',
183         'OS',
184         'PATHEXT',
185         'SystemRoot',
186         'TEMP',
187         'TMP',
188         'USERNAME',
189         'VXDOMNTOOLS',
190         'WINDIR',
191         'XYZZY'
192
193         'ENV',
194         'HOME',
195         'LANG',
196         'LANGUAGE',
197         'LOGNAME',
198         'MACHINE',
199         'OLDPWD',
200         'PWD',
201         'OPSYS',
202         'SHELL',
203         'TMPDIR',
204         'USER',
205     ]
206
207     print "  <environment>"
208     #keys = os.environ.keys()
209     keys = environ_keys
210     keys.sort()
211     for key in keys:
212         value = os.environ.get(key)
213         if value:
214             print "    <variable>"
215             print "      <name>%s</name>" % key
216             print "      <value>%s</value>" % value
217             print "    </variable>"
218     print "  </environment>"
219
220     command = '"%s" runtest.py -q -o - --xml %s' % (sys.executable, runtest_args)
221     #print command
222     os.system(command)
223     print "</scons_test_run>"
224
225 else:
226
227     def print_version_info(tag, module):
228         print "\t%s: v%s.%s, %s, by %s on %s" % (tag,
229                                                  module.__version__,
230                                                  module.__build__,
231                                                  module.__date__,
232                                                  module.__developer__,
233                                                  module.__buildsys__)
234
235     print "SCons by Steven Knight et al.:"
236     print_version_info("script", scons)
237     print_version_info("engine", SCons)
238
239     command = '"%s" runtest.py %s' % (sys.executable, runtest_args)
240     #print command
241     os.system(command)
242
243 # Local Variables:
244 # tab-width:4
245 # indent-tabs-mode:nil
246 # End:
247 # vim: set expandtab tabstop=4 shiftwidth=4: