source: tests/pybin/tools.py @ 709e0e0

ADTarm-ehast-experimentalcleanup-dtorsenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 709e0e0 was 0c13238, checked in by Thierry Delisle <tdelisle@…>, 5 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.