source: tests/pybin/tools.py@ 2b10f95

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 2b10f95 was 2b10f95, checked in by tdelisle <tdelisle@…>, 6 years ago

Improved printing, added support for cpp tests and fix byte string concatenation error

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