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