source: tests/pybin/tools.py@ 7abee38

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr persistent-indexer pthread-emulation qualifiedEnum
Last change on this file since 7abee38 was 0c13238, checked in by Thierry Delisle <tdelisle@…>, 7 years ago

Aborts now create core dumps which are printed by the test harness.

  • printing is done with gdb, print-core.gdb is the list of commands that will print
  • since all core dumps are assumed to be call 'core' this doesn't handle fancy core patterns and has race conditions if multiple program core dump.
  • Property mode set to 100644
File size: 7.9 KB
RevLine 
[bacc36c]1from __future__ import print_function
2
[c07d724]3import __main__
4import argparse
[0c13238]5import fileinput
[bacc36c]6import multiprocessing
[c07d724]7import os
8import re
[0c13238]9import resource
[bacc36c]10import signal
[c07d724]11import stat
[bacc36c]12import sys
[0c13238]13import time
[c07d724]14
[bacc36c]15from pybin import settings
[c07d724]16from subprocess import Popen, PIPE, STDOUT
17
[bacc36c]18################################################################################
19# shell helpers
20################################################################################
21
[c07d724]22# helper functions to run terminal commands
[bacc36c]23def sh(cmd, print2stdout = True, input = None):
24 # add input redirection if needed
25 if input and os.path.isfile(input):
26 cmd += " < %s" % input
27
28 # if this is a dry_run, only print the commands that would be ran
29 if settings.dry_run :
[c07d724]30 print("cmd: %s" % cmd)
31 return 0, None
[bacc36c]32
33 # otherwise create a pipe and run the desired command
34 else :
[c07d724]35 proc = Popen(cmd, stdout=None if print2stdout else PIPE, stderr=STDOUT, shell=True)
36 out, err = proc.communicate()
37 return proc.returncode, out
38
[f85bc15]39def is_ascii(fname):
[202ad72]40 if settings.dry_run:
41 print("is_ascii: %s" % fname)
42 return True
43
[f85bc15]44 if not os.path.isfile(fname):
45 return False
46
47 code, out = sh("file %s" % fname, print2stdout = False)
48 if code != 0:
49 return False
50
51 match = re.search(".*: (.*)", out)
52
53 if not match:
54 return False
55
[e1bdccb]56 return match.group(1).startswith("ASCII text")
[f85bc15]57
[c07d724]58# Remove 1 or more files silently
[bacc36c]59def rm( files ):
[28582b2]60 if isinstance( files, basestring ):
61 sh("rm -f %s > /dev/null 2>&1" % files )
62 else:
[c07d724]63 for file in files:
[bacc36c]64 sh("rm -f %s > /dev/null 2>&1" % file )
[c07d724]65
[a95c117]66# Create 1 or more directory
67def mkdir( files ):
[28582b2]68 if isinstance( files, basestring ):
69 sh("mkdir -p %s" % os.path.dirname(files) )
70 else:
[a95c117]71 for file in files:
72 sh("mkdir -p %s" % os.path.dirname(file) )
[28582b2]73
[a95c117]74
[c07d724]75def chdir( dest = __main__.__file__ ):
76 abspath = os.path.abspath(dest)
77 dname = os.path.dirname(abspath)
78 os.chdir(dname)
79
[bacc36c]80# diff two files
81def diff( lhs, rhs ):
82 # diff the output of the files
[5ea5b28]83 diff_cmd = ("diff --text "
84# "--ignore-all-space "
85# "--ignore-blank-lines "
[bacc36c]86 "--old-group-format='\t\tmissing lines :\n"
87 "%%<' \\\n"
88 "--new-group-format='\t\tnew lines :\n"
89 "%%>' \\\n"
90 "--unchanged-group-format='%%=' \\"
91 "--changed-group-format='\t\texpected :\n"
92 "%%<"
93 "\t\tgot :\n"
94 "%%>\n' \\\n"
95 "--new-line-format='\t\t%%dn\t%%L' \\\n"
96 "--old-line-format='\t\t%%dn\t%%L' \\\n"
97 "--unchanged-line-format='' \\\n"
98 "%s %s")
99
100 # fetch return code and error from the diff command
101 return sh(diff_cmd % (lhs, rhs), False)
102
103# call make
104def make(target, flags = '', redirects = '', error_file = None, silent = False):
105 test_param = """test="%s" """ % (error_file) if error_file else ''
106 cmd = ' '.join([
107 settings.make,
108 '-s' if silent else '',
109 test_param,
[575a6e5]110 settings.arch.flags,
[f3b9efc]111 settings.debug.flags,
[a5121bf]112 settings.install.flags,
[bacc36c]113 flags,
114 target,
115 redirects
116 ])
117 return sh(cmd)
118
[ed45af6]119def which(program):
120 import os
121 def is_exe(fpath):
122 return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
123
124 fpath, fname = os.path.split(program)
125 if fpath:
126 if is_exe(program):
127 return program
128 else:
129 for path in os.environ["PATH"].split(os.pathsep):
130 exe_file = os.path.join(path, program)
131 if is_exe(exe_file):
132 return exe_file
133
134 return None
[0c13238]135
136def run(exe, output, input):
137 ret, _ = sh("timeout %d %s > %s 2>&1" % (settings.timeout.single, exe, output), input = input)
138 return ret
139
[bacc36c]140################################################################################
141# file handling
142################################################################################
[0c13238]143# move a file
144def mv(source, dest):
145 ret, _ = sh("mv %s %s" % (source, dest))
146 return ret
147
148# cat one file into the other
149def cat(source, dest):
150 ret, _ = sh("cat %s > %s" % (source, dest))
151 return ret
[bacc36c]152
[c07d724]153# helper function to replace patterns in a file
154def file_replace(fname, pat, s_after):
[202ad72]155 if settings.dry_run:
156 print("replacing '%s' with '%s' in %s" % (pat, s_after, fname))
157 return
158
[f85bc15]159 file = fileinput.FileInput(fname, inplace=True, backup='.bak')
160 for line in file:
161 print(line.replace(pat, s_after), end='')
162 file.close()
[c07d724]163
[0ad0c55]164# helper function to check if a files contains only a specific string
[c07d724]165def fileContainsOnly(file, text) :
166 with open(file) as f:
167 ff = f.read().strip()
168 result = ff == text.strip()
169
170 return result;
171
172# check whether or not a file is executable
173def fileIsExecutable(file) :
174 try :
175 fileinfo = os.stat(file)
176 return bool(fileinfo.st_mode & stat.S_IXUSR)
177 except Exception as inst:
178 print(type(inst)) # the exception instance
179 print(inst.args) # arguments stored in .args
180 print(inst)
181 return False
182
[bacc36c]183# transform path to canonical form
184def canonicalPath(path):
[f85bc15]185 abspath = os.path.abspath(__main__.__file__)
186 dname = os.path.dirname(abspath)
187 return os.path.join(dname, os.path.normpath(path) )
[c07d724]188
[bacc36c]189# compare path even if form is different
190def pathCmp(lhs, rhs):
191 return canonicalPath( lhs ) == canonicalPath( rhs )
[c07d724]192
[bacc36c]193# walk all files in a path
194def pathWalk( op ):
195 def step(_, dirname, names):
196 for name in names:
197 path = os.path.join(dirname, name)
198 op( path )
199
200 # Start the walk
[56de5932]201 dname = settings.SRCDIR
[f85bc15]202 os.path.walk(dname, step, '')
[bacc36c]203
204################################################################################
205# system
206################################################################################
207# count number of jobs to create
208def jobCount( options, tests ):
209 # check if the user already passed in a number of jobs for multi-threading
[d142ec5]210 if not options.jobs:
211 make_flags = os.environ.get('MAKEFLAGS')
212 force = bool(make_flags)
213 make_jobs_fds = re.search("--jobserver-(auth|fds)=\s*([0-9]+),([0-9]+)", make_flags) if make_flags else None
214 if make_jobs_fds :
215 tokens = os.read(int(make_jobs_fds.group(2)), 1024)
216 options.jobs = len(tokens)
217 os.write(int(make_jobs_fds.group(3)), tokens)
218 else :
219 options.jobs = multiprocessing.cpu_count()
[bacc36c]220 else :
[d142ec5]221 force = True
[bacc36c]222
223 # make sure we have a valid number of jobs that corresponds to user input
224 if options.jobs <= 0 :
225 print('ERROR: Invalid number of jobs', file=sys.stderr)
226 sys.exit(1)
227
[d142ec5]228 return min( options.jobs, len(tests) ), force
[bacc36c]229
230# setup a proper processor pool with correct signal handling
231def setupPool(jobs):
232 original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
233 pool = multiprocessing.Pool(jobs)
234 signal.signal(signal.SIGINT, original_sigint_handler)
235
236 return pool
237
238# handle signals in scope
239class SignalHandling():
240 def __enter__(self):
241 # enable signal handling
242 signal.signal(signal.SIGINT, signal.SIG_DFL)
243
244 def __exit__(self, type, value, traceback):
245 # disable signal handling
246 signal.signal(signal.SIGINT, signal.SIG_IGN)
247
[0c13238]248
249# enable core dumps for all the test children
250resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY))
251
[bacc36c]252################################################################################
253# misc
254################################################################################
255
256# check if arguments is yes or no
257def yes_no(string):
258 if string == "yes" :
259 return True
260 if string == "no" :
261 return False
262 raise argparse.ArgumentTypeError(msg)
[f3b9efc]263 return False
264
[ed45af6]265def fancy_print(text):
266 column = which('column')
267 if column:
268 cmd = "%s 2> /dev/null" % column
269 proc = Popen(cmd, stdin=PIPE, stderr=None, shell=True)
[84b4d607]270 proc.communicate(input=text + "\n")
[ed45af6]271 else:
272 print(text)
[0c13238]273
274
275def coreInfo(path):
276 cmd = os.path.join(settings.SRCDIR, "pybin/print-core.gdb")
277 if not os.path.isfile(cmd):
278 return 1, "ERR Printing format for core dumps not found"
279
280 dname = os.path.dirname(path)
281 core = os.path.join(dname, "core" )
282 if not os.path.isfile(path):
283 return 1, "ERR Executable path is wrong"
284
285 if not os.path.isfile(core):
286 return 1, "ERR No core dump"
287
288 return sh("gdb -n %s %s -batch -x %s" % (path, core, cmd), print2stdout=False)
289
290class Timed:
291 def __enter__(self):
292 self.start = time.time()
293 return self
294
295 def __exit__(self, *args):
296 self.end = time.time()
297 self.duration = self.end - self.start
Note: See TracBrowser for help on using the repository browser.