Initial commit
[yaffs-website] / node_modules / node-gyp / gyp / gyptest.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2012 Google Inc. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6
7 __doc__ = """
8 gyptest.py -- test runner for GYP tests.
9 """
10
11 import os
12 import optparse
13 import subprocess
14 import sys
15
16 class CommandRunner(object):
17   """
18   Executor class for commands, including "commands" implemented by
19   Python functions.
20   """
21   verbose = True
22   active = True
23
24   def __init__(self, dictionary={}):
25     self.subst_dictionary(dictionary)
26
27   def subst_dictionary(self, dictionary):
28     self._subst_dictionary = dictionary
29
30   def subst(self, string, dictionary=None):
31     """
32     Substitutes (via the format operator) the values in the specified
33     dictionary into the specified command.
34
35     The command can be an (action, string) tuple.  In all cases, we
36     perform substitution on strings and don't worry if something isn't
37     a string.  (It's probably a Python function to be executed.)
38     """
39     if dictionary is None:
40       dictionary = self._subst_dictionary
41     if dictionary:
42       try:
43         string = string % dictionary
44       except TypeError:
45         pass
46     return string
47
48   def display(self, command, stdout=None, stderr=None):
49     if not self.verbose:
50       return
51     if type(command) == type(()):
52       func = command[0]
53       args = command[1:]
54       s = '%s(%s)' % (func.__name__, ', '.join(map(repr, args)))
55     if type(command) == type([]):
56       # TODO:  quote arguments containing spaces
57       # TODO:  handle meta characters?
58       s = ' '.join(command)
59     else:
60       s = self.subst(command)
61     if not s.endswith('\n'):
62       s += '\n'
63     sys.stdout.write(s)
64     sys.stdout.flush()
65
66   def execute(self, command, stdout=None, stderr=None):
67     """
68     Executes a single command.
69     """
70     if not self.active:
71       return 0
72     if type(command) == type(''):
73       command = self.subst(command)
74       cmdargs = shlex.split(command)
75       if cmdargs[0] == 'cd':
76          command = (os.chdir,) + tuple(cmdargs[1:])
77     if type(command) == type(()):
78       func = command[0]
79       args = command[1:]
80       return func(*args)
81     else:
82       if stdout is sys.stdout:
83         # Same as passing sys.stdout, except python2.4 doesn't fail on it.
84         subout = None
85       else:
86         # Open pipe for anything else so Popen works on python2.4.
87         subout = subprocess.PIPE
88       if stderr is sys.stderr:
89         # Same as passing sys.stderr, except python2.4 doesn't fail on it.
90         suberr = None
91       elif stderr is None:
92         # Merge with stdout if stderr isn't specified.
93         suberr = subprocess.STDOUT
94       else:
95         # Open pipe for anything else so Popen works on python2.4.
96         suberr = subprocess.PIPE
97       p = subprocess.Popen(command,
98                            shell=(sys.platform == 'win32'),
99                            stdout=subout,
100                            stderr=suberr)
101       p.wait()
102       if stdout is None:
103         self.stdout = p.stdout.read()
104       elif stdout is not sys.stdout:
105         stdout.write(p.stdout.read())
106       if stderr not in (None, sys.stderr):
107         stderr.write(p.stderr.read())
108       return p.returncode
109
110   def run(self, command, display=None, stdout=None, stderr=None):
111     """
112     Runs a single command, displaying it first.
113     """
114     if display is None:
115       display = command
116     self.display(display)
117     return self.execute(command, stdout, stderr)
118
119
120 class Unbuffered(object):
121   def __init__(self, fp):
122     self.fp = fp
123   def write(self, arg):
124     self.fp.write(arg)
125     self.fp.flush()
126   def __getattr__(self, attr):
127     return getattr(self.fp, attr)
128
129 sys.stdout = Unbuffered(sys.stdout)
130 sys.stderr = Unbuffered(sys.stderr)
131
132
133 def is_test_name(f):
134   return f.startswith('gyptest') and f.endswith('.py')
135
136
137 def find_all_gyptest_files(directory):
138   result = []
139   for root, dirs, files in os.walk(directory):
140     if '.svn' in dirs:
141       dirs.remove('.svn')
142     result.extend([ os.path.join(root, f) for f in files if is_test_name(f) ])
143   result.sort()
144   return result
145
146
147 def main(argv=None):
148   if argv is None:
149     argv = sys.argv
150
151   usage = "gyptest.py [-ahlnq] [-f formats] [test ...]"
152   parser = optparse.OptionParser(usage=usage)
153   parser.add_option("-a", "--all", action="store_true",
154             help="run all tests")
155   parser.add_option("-C", "--chdir", action="store", default=None,
156             help="chdir to the specified directory")
157   parser.add_option("-f", "--format", action="store", default='',
158             help="run tests with the specified formats")
159   parser.add_option("-G", '--gyp_option', action="append", default=[],
160             help="Add -G options to the gyp command line")
161   parser.add_option("-l", "--list", action="store_true",
162             help="list available tests and exit")
163   parser.add_option("-n", "--no-exec", action="store_true",
164             help="no execute, just print the command line")
165   parser.add_option("--passed", action="store_true",
166             help="report passed tests")
167   parser.add_option("--path", action="append", default=[],
168             help="additional $PATH directory")
169   parser.add_option("-q", "--quiet", action="store_true",
170             help="quiet, don't print test command lines")
171   opts, args = parser.parse_args(argv[1:])
172
173   if opts.chdir:
174     os.chdir(opts.chdir)
175
176   if opts.path:
177     extra_path = [os.path.abspath(p) for p in opts.path]
178     extra_path = os.pathsep.join(extra_path)
179     os.environ['PATH'] = extra_path + os.pathsep + os.environ['PATH']
180
181   if not args:
182     if not opts.all:
183       sys.stderr.write('Specify -a to get all tests.\n')
184       return 1
185     args = ['test']
186
187   tests = []
188   for arg in args:
189     if os.path.isdir(arg):
190       tests.extend(find_all_gyptest_files(os.path.normpath(arg)))
191     else:
192       if not is_test_name(os.path.basename(arg)):
193         print >>sys.stderr, arg, 'is not a valid gyp test name.'
194         sys.exit(1)
195       tests.append(arg)
196
197   if opts.list:
198     for test in tests:
199       print test
200     sys.exit(0)
201
202   CommandRunner.verbose = not opts.quiet
203   CommandRunner.active = not opts.no_exec
204   cr = CommandRunner()
205
206   os.environ['PYTHONPATH'] = os.path.abspath('test/lib')
207   if not opts.quiet:
208     sys.stdout.write('PYTHONPATH=%s\n' % os.environ['PYTHONPATH'])
209
210   passed = []
211   failed = []
212   no_result = []
213
214   if opts.format:
215     format_list = opts.format.split(',')
216   else:
217     # TODO:  not duplicate this mapping from pylib/gyp/__init__.py
218     format_list = {
219       'aix5':     ['make'],
220       'freebsd7': ['make'],
221       'freebsd8': ['make'],
222       'openbsd5': ['make'],
223       'cygwin':   ['msvs'],
224       'win32':    ['msvs', 'ninja'],
225       'linux2':   ['make', 'ninja'],
226       'linux3':   ['make', 'ninja'],
227       'darwin':   ['make', 'ninja', 'xcode', 'xcode-ninja'],
228     }[sys.platform]
229
230   for format in format_list:
231     os.environ['TESTGYP_FORMAT'] = format
232     if not opts.quiet:
233       sys.stdout.write('TESTGYP_FORMAT=%s\n' % format)
234
235     gyp_options = []
236     for option in opts.gyp_option:
237       gyp_options += ['-G', option]
238     if gyp_options and not opts.quiet:
239       sys.stdout.write('Extra Gyp options: %s\n' % gyp_options)
240
241     for test in tests:
242       status = cr.run([sys.executable, test] + gyp_options,
243                       stdout=sys.stdout,
244                       stderr=sys.stderr)
245       if status == 2:
246         no_result.append(test)
247       elif status:
248         failed.append(test)
249       else:
250         passed.append(test)
251
252   if not opts.quiet:
253     def report(description, tests):
254       if tests:
255         if len(tests) == 1:
256           sys.stdout.write("\n%s the following test:\n" % description)
257         else:
258           fmt = "\n%s the following %d tests:\n"
259           sys.stdout.write(fmt % (description, len(tests)))
260         sys.stdout.write("\t" + "\n\t".join(tests) + "\n")
261
262     if opts.passed:
263       report("Passed", passed)
264     report("Failed", failed)
265     report("No result from", no_result)
266
267   if failed:
268     return 1
269   else:
270     return 0
271
272
273 if __name__ == "__main__":
274   sys.exit(main())