]> git.cworth.org Git - apitrace/blob - scripts/tracecheck.py
Add helper script to use with git-bisect.
[apitrace] / scripts / tracecheck.py
1 #!/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
29 It is meant to be used with git bisect.  See git bisect manpage for more
30 details.
31 '''
32
33
34 import optparse
35 import os.path
36 import platform
37 import re
38 import subprocess
39 import sys
40 import traceback
41
42
43 def good():
44     '''Tell git-bisect that this commit is good.'''
45
46     sys.stdout.write('GOOD\n')
47     sys.exit(0)
48
49
50 def bad():
51     '''Tell git-bisect that this commit is bad.'''
52
53     sys.stdout.write('BAD\n')
54     sys.exit(1)
55
56
57 def skip():
58     '''Tell git-bisect to skip this commit.'''
59
60     sys.stdout.write('SKIP\n')
61     sys.exit(125)
62
63
64 def abort():
65     '''Tell git-bisect to abort.'''
66
67     sys.stdout.write('ABORT\n')
68     sys.exit(-1)
69
70
71 def 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
87 def 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.
170 if __name__ == '__main__':
171     try:
172         main()
173     except SystemExit:
174         raise
175     except KeyboardInterrupt:
176         abort()
177     except:
178         traceback.print_exc()
179         abort()