source: tests/pybin/tools.py@ 8dbfb7e

ADT arm-eh ast-experimental cleanup-dtors enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since 8dbfb7e was 1bb2488, checked in by tdelisle <tdelisle@…>, 7 years ago

No longer need to use popen and signal handling in test.py

  • Property mode set to 100644
File size: 6.9 KB
RevLine 
[c07d724]1import __main__
2import argparse
[0c13238]3import fileinput
[bacc36c]4import multiprocessing
[c07d724]5import os
6import re
[0c13238]7import resource
[bacc36c]8import signal
[c07d724]9import stat
[1bb2488]10import subprocess
[bacc36c]11import sys
[0c13238]12import time
[5b993e0]13import types
[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
[1bb2488]23def sh(cmd, print2stdout = True, timeout = False, output = None, input = None):
[bacc36c]24 # add input redirection if needed
25 if input and os.path.isfile(input):
26 cmd += " < %s" % input
27
[1bb2488]28 # add output redirection if needed
29 if output:
30 cmd += " > %s" % output
31
[bacc36c]32 # if this is a dry_run, only print the commands that would be ran
33 if settings.dry_run :
[c07d724]34 print("cmd: %s" % cmd)
35 return 0, None
[bacc36c]36
37 # otherwise create a pipe and run the desired command
38 else :
[1bb2488]39 proc = subprocess.run(
40 cmd,
41 stdout=None if print2stdout else PIPE,
42 stderr=STDOUT,
43 shell=True,
44 timeout=settings.timeout.single if timeout else None
45 )
46 return proc.returncode, proc.stdout
[c07d724]47
[f85bc15]48def is_ascii(fname):
[202ad72]49 if settings.dry_run:
50 print("is_ascii: %s" % fname)
51 return True
52
[f85bc15]53 if not os.path.isfile(fname):
54 return False
55
56 code, out = sh("file %s" % fname, print2stdout = False)
57 if code != 0:
58 return False
59
60 match = re.search(".*: (.*)", out)
61
62 if not match:
63 return False
64
[e1bdccb]65 return match.group(1).startswith("ASCII text")
[f85bc15]66
[5bf1f3e]67def is_exe(fname):
68 return os.path.isfile(fname) and os.access(fname, os.X_OK)
69
[c07d724]70# Remove 1 or more files silently
[bacc36c]71def rm( files ):
[5b993e0]72 if isinstance(files, str ): files = [ files ]
73 for file in files:
74 sh("rm -f %s > /dev/null 2>&1" % file )
[c07d724]75
[a95c117]76# Create 1 or more directory
77def mkdir( files ):
[5b993e0]78 if isinstance(files, str ): files = [ files ]
79 for file in files:
80 p = os.path.normpath( file )
81 d = os.path.dirname ( p )
82 sh( "mkdir -p {}".format(d) )
[28582b2]83
[a95c117]84
[c07d724]85def chdir( dest = __main__.__file__ ):
86 abspath = os.path.abspath(dest)
87 dname = os.path.dirname(abspath)
88 os.chdir(dname)
89
[bacc36c]90# diff two files
91def diff( lhs, rhs ):
92 # diff the output of the files
[5ea5b28]93 diff_cmd = ("diff --text "
[5bf1f3e]94 "--old-group-format='\t\tmissing lines :\n"
95 "%%<' \\\n"
96 "--new-group-format='\t\tnew lines :\n"
97 "%%>' \\\n"
98 "--unchanged-group-format='%%=' \\"
99 "--changed-group-format='\t\texpected :\n"
100 "%%<"
101 "\t\tgot :\n"
102 "%%>\n' \\\n"
103 "--new-line-format='\t\t%%dn\t%%L' \\\n"
104 "--old-line-format='\t\t%%dn\t%%L' \\\n"
105 "--unchanged-line-format='' \\\n"
106 "%s %s")
[bacc36c]107
108 # fetch return code and error from the diff command
109 return sh(diff_cmd % (lhs, rhs), False)
110
111# call make
112def make(target, flags = '', redirects = '', error_file = None, silent = False):
113 test_param = """test="%s" """ % (error_file) if error_file else ''
114 cmd = ' '.join([
115 settings.make,
116 '-s' if silent else '',
117 test_param,
[575a6e5]118 settings.arch.flags,
[f3b9efc]119 settings.debug.flags,
[a5121bf]120 settings.install.flags,
[bacc36c]121 flags,
122 target,
123 redirects
124 ])
125 return sh(cmd)
126
[ed45af6]127def which(program):
128 fpath, fname = os.path.split(program)
129 if fpath:
130 if is_exe(program):
131 return program
132 else:
133 for path in os.environ["PATH"].split(os.pathsep):
134 exe_file = os.path.join(path, program)
135 if is_exe(exe_file):
136 return exe_file
137
138 return None
[0c13238]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
[5bf1f3e]165def file_contains_only(file, text) :
[c07d724]166 with open(file) as f:
167 ff = f.read().strip()
168 result = ff == text.strip()
169
[5bf1f3e]170 return result
[c07d724]171
[bacc36c]172# transform path to canonical form
[5bf1f3e]173def canonical_path(path):
[f85bc15]174 abspath = os.path.abspath(__main__.__file__)
175 dname = os.path.dirname(abspath)
176 return os.path.join(dname, os.path.normpath(path) )
[c07d724]177
[bacc36c]178# compare path even if form is different
[5bf1f3e]179def path_cmp(lhs, rhs):
180 return canonical_path( lhs ) == canonical_path( rhs )
[c07d724]181
[bacc36c]182# walk all files in a path
[5bf1f3e]183def path_walk( op ):
[56de5932]184 dname = settings.SRCDIR
[5b993e0]185 for dirname, _, names in os.walk(dname):
186 for name in names:
187 path = os.path.join(dirname, name)
188 op( path )
[bacc36c]189
190################################################################################
191# system
192################################################################################
193# count number of jobs to create
[5bf1f3e]194def job_count( options, tests ):
[bacc36c]195 # check if the user already passed in a number of jobs for multi-threading
[d142ec5]196 if not options.jobs:
197 make_flags = os.environ.get('MAKEFLAGS')
198 force = bool(make_flags)
199 make_jobs_fds = re.search("--jobserver-(auth|fds)=\s*([0-9]+),([0-9]+)", make_flags) if make_flags else None
200 if make_jobs_fds :
201 tokens = os.read(int(make_jobs_fds.group(2)), 1024)
202 options.jobs = len(tokens)
203 os.write(int(make_jobs_fds.group(3)), tokens)
204 else :
205 options.jobs = multiprocessing.cpu_count()
[bacc36c]206 else :
[d142ec5]207 force = True
[bacc36c]208
209 # make sure we have a valid number of jobs that corresponds to user input
210 if options.jobs <= 0 :
211 print('ERROR: Invalid number of jobs', file=sys.stderr)
212 sys.exit(1)
213
[d142ec5]214 return min( options.jobs, len(tests) ), force
[bacc36c]215
[0c13238]216# enable core dumps for all the test children
217resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY))
218
[bacc36c]219################################################################################
220# misc
221################################################################################
222
223# check if arguments is yes or no
224def yes_no(string):
225 if string == "yes" :
226 return True
227 if string == "no" :
228 return False
229 raise argparse.ArgumentTypeError(msg)
[f3b9efc]230
[ed45af6]231def fancy_print(text):
232 column = which('column')
233 if column:
[1bb2488]234 subprocess.run(column, input=bytes(text + "\n", "UTF-8"))
[ed45af6]235 else:
236 print(text)
[0c13238]237
238
[5bf1f3e]239def core_info(path):
[0c13238]240 cmd = os.path.join(settings.SRCDIR, "pybin/print-core.gdb")
241 if not os.path.isfile(cmd):
242 return 1, "ERR Printing format for core dumps not found"
243
244 dname = os.path.dirname(path)
245 core = os.path.join(dname, "core" )
246 if not os.path.isfile(path):
247 return 1, "ERR Executable path is wrong"
248
249 if not os.path.isfile(core):
250 return 1, "ERR No core dump"
251
252 return sh("gdb -n %s %s -batch -x %s" % (path, core, cmd), print2stdout=False)
253
254class Timed:
255 def __enter__(self):
256 self.start = time.time()
257 return self
258
259 def __exit__(self, *args):
260 self.end = time.time()
261 self.duration = self.end - self.start
Note: See TracBrowser for help on using the repository browser.