blob: 28b0720fdd7cad6b3a7b0b2c5d7f63da04ebd57c [file] [log] [blame]
José Fonseca79631cd2011-05-11 14:56:36 +01001#!/usr/bin/env python
2##########################################################################
3#
4# Copyright 2011 VMware, Inc.
5# All Rights Reserved.
6#
7# Permission is hereby granted, free of charge, to any person obtaining a copy
8# of this software and associated documentation files (the 'Software'), to deal
9# in the Software without restriction, including without limitation the rights
10# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11# copies of the Software, and to permit persons to whom the Software is
12# furnished to do so, subject to the following conditions:
13#
14# The above copyright notice and this permission notice shall be included in
15# all copies or substantial portions of the Software.
16#
17# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23# THE SOFTWARE.
24#
25##########################################################################/
26
27'''Check a trace replays successfully or not.
28
29It is meant to be used with git bisect. See git bisect manpage for more
30details.
31'''
32
33
34import optparse
35import os.path
36import platform
37import re
38import subprocess
39import sys
40import traceback
41
42
43def good():
44 '''Tell git-bisect that this commit is good.'''
45
46 sys.stdout.write('GOOD\n')
47 sys.exit(0)
48
49
50def bad():
51 '''Tell git-bisect that this commit is bad.'''
52
53 sys.stdout.write('BAD\n')
54 sys.exit(1)
55
56
57def skip():
58 '''Tell git-bisect to skip this commit.'''
59
60 sys.stdout.write('SKIP\n')
61 sys.exit(125)
62
63
64def abort():
65 '''Tell git-bisect to abort.'''
66
67 sys.stdout.write('ABORT\n')
68 sys.exit(-1)
69
70
71def which(executable):
72 '''Search for the executable on the PATH.'''
73
74 if platform.system() == 'Windows':
75 exts = ['.exe']
76 else:
77 exts = ['']
78 dirs = os.environ['PATH'].split(os.path.pathsep)
79 for dir in dirs:
80 path = os.path.join(dir, executable)
81 for ext in exts:
82 if os.path.exists(path + ext):
83 return True
84 return False
85
86
87def main():
88 '''Main program.
89
90 It will always invoke sys.exit(), and never return normally.
91 '''
92
93 # Try to guess the build command.
94 if os.path.exists('SConstruct'):
95 default_build = 'scons'
96 elif os.path.exists('Makefile'):
97 default_build = 'make'
98 else:
99 default_build = None
100
101 # Parse command line options
102 optparser = optparse.OptionParser(
103 usage='\n\tgit bisect run %prog [options] -- [glretrace options] <trace>',
104 version='%%prog')
105 optparser.add_option(
106 '-b', '--build', metavar='COMMAND',
107 type='string', dest='build', default=default_build,
108 help='build command [default: %default]')
109 optparser.add_option(
110 '-r', '--retrace', metavar='PROGRAM',
111 type='string', dest='retrace', default='glretrace',
112 help='retrace command [default: %default]')
113 optparser.add_option(
114 '--gl-renderer', metavar='REGEXP',
115 type='string', dest='gl_renderer_re', default='^.*$',
116 help='require a matching GL_RENDERER string [default: %default]')
117
118 (options, args) = optparser.parse_args(sys.argv[1:])
119 if not args:
120 optparser.error("incorrect number of arguments")
121
122 # Build the source
123 if options.build:
124 sys.stdout.write(options.build + '\n')
125 sys.stdout.flush()
126 returncode = subprocess.call(options.build, shell=True)
127 if returncode:
128 skip()
129
130 # TODO: For this to be useful on Windows we'll also need an installation
131 # procedure here.
132
133 # Do some sanity checks. In particular we want to make sure that the GL
134 # implementation is usable, and is the right one (i.e., we didn't fallback
135 # to a different OpenGL implementation due to missing symbols).
136 if platform.system() != 'Windows' and which('glxinfo'):
137 p = subprocess.Popen(['glxinfo'], stdout=subprocess.PIPE)
138 stdout, stderr = p.communicate()
139 if p.returncode:
140 skip()
141
142 # Search for the GL_RENDERER string
143 gl_renderer_header = 'OpenGL renderer string: '
144 gl_renderer = ''
145 for line in stdout.split('\n'):
146 if line.startswith(gl_renderer_header):
147 gl_renderer = line[len(gl_renderer_header):]
148
149 # and match it against the regular expression specified in the command
150 # line.
151 if not re.search(options.gl_renderer_re, gl_renderer):
152 sys.stderr.write("GL_RENDERER mismatch: %r !~ /%s/\n" % (gl_renderer, options.gl_renderer_re))
153 skip()
154
155 # Run glretrace
156 retrace = [options.retrace] + args
157 sys.stdout.write(' '.join(retrace) + '\n')
158 sys.stdout.flush()
159 returncode = subprocess.call(retrace)
160 if returncode:
161 # TODO: allow other criterias here, such as, snapshot comparison or performance threshold
162 bad()
163
164 # Success
165 good()
166
167
168# Invoke main program, aborting the bisection on Ctrl+C or any uncaught Python
169# exception.
170if __name__ == '__main__':
171 try:
172 main()
173 except SystemExit:
174 raise
175 except KeyboardInterrupt:
176 abort()
177 except:
178 traceback.print_exc()
179 abort()