source: tests/pybin/tools.py @ 1d76f8a4

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 1d76f8a4 was 35a408b7, checked in by Thierry Delisle <tdelisle@…>, 5 years ago

Fixed global timeout

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