source: tests/pybin/tools.py @ 5bf1f3e

ADTarm-ehast-experimentalcleanup-dtorsenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 5bf1f3e was 5bf1f3e, checked in by tdelisle <tdelisle@…>, 5 years ago

Code review of test.py and pybin

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