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

ADTarm-ehast-experimentalcleanup-dtorsenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 2b10f95 was 2b10f95, checked in by tdelisle <tdelisle@…>, 5 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
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 :
[2b10f95]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)
[c07d724]50
[f85bc15]51def is_ascii(fname):
[202ad72]52        if settings.dry_run:
53                print("is_ascii: %s" % fname)
54                return True
55
[f85bc15]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
[e1bdccb]68        return match.group(1).startswith("ASCII text")
[f85bc15]69
[5bf1f3e]70def is_exe(fname):
71        return os.path.isfile(fname) and os.access(fname, os.X_OK)
72
[c07d724]73# Remove 1 or more files silently
[bacc36c]74def rm( files ):
[5b993e0]75        if isinstance(files, str ): files = [ files ]
76        for file in files:
77                sh("rm -f %s > /dev/null 2>&1" % file )
[c07d724]78
[a95c117]79# Create 1 or more directory
80def mkdir( files ):
[5b993e0]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) )
[28582b2]86
[a95c117]87
[c07d724]88def chdir( dest = __main__.__file__ ):
89        abspath = os.path.abspath(dest)
90        dname = os.path.dirname(abspath)
91        os.chdir(dname)
92
[bacc36c]93# diff two files
94def diff( lhs, rhs ):
95        # diff the output of the files
[5ea5b28]96        diff_cmd = ("diff --text "
[5bf1f3e]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")
[bacc36c]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,
[575a6e5]121                settings.arch.flags,
[f3b9efc]122                settings.debug.flags,
[a5121bf]123                settings.install.flags,
[bacc36c]124                flags,
125                target,
126                redirects
127        ])
128        return sh(cmd)
129
[ed45af6]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
[0c13238]142
[bacc36c]143################################################################################
144#               file handling
145################################################################################
[0c13238]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
[bacc36c]155
[c07d724]156# helper function to replace patterns in a file
157def file_replace(fname, pat, s_after):
[202ad72]158        if settings.dry_run:
159                print("replacing '%s' with '%s' in %s" % (pat, s_after, fname))
160                return
161
[f85bc15]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()
[c07d724]166
[0ad0c55]167# helper function to check if a files contains only a specific string
[5bf1f3e]168def file_contains_only(file, text) :
[c07d724]169        with open(file) as f:
170                ff = f.read().strip()
171                result = ff == text.strip()
172
[5bf1f3e]173                return result
[c07d724]174
[bacc36c]175# transform path to canonical form
[5bf1f3e]176def canonical_path(path):
[f85bc15]177        abspath = os.path.abspath(__main__.__file__)
178        dname = os.path.dirname(abspath)
179        return os.path.join(dname, os.path.normpath(path) )
[c07d724]180
[bacc36c]181# compare path even if form is different
[5bf1f3e]182def path_cmp(lhs, rhs):
183        return canonical_path( lhs ) == canonical_path( rhs )
[c07d724]184
[bacc36c]185# walk all files in a path
[5bf1f3e]186def path_walk( op ):
[56de5932]187        dname = settings.SRCDIR
[5b993e0]188        for dirname, _, names in os.walk(dname):
189                for name in names:
190                        path = os.path.join(dirname, name)
191                        op( path )
[bacc36c]192
193################################################################################
194#               system
195################################################################################
196# count number of jobs to create
[5bf1f3e]197def job_count( options, tests ):
[bacc36c]198        # check if the user already passed in a number of jobs for multi-threading
[d142ec5]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()
[bacc36c]209        else :
[d142ec5]210                force = True
[bacc36c]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
[d142ec5]217        return min( options.jobs, len(tests) ), force
[bacc36c]218
[0c13238]219# enable core dumps for all the test children
220resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY))
221
[bacc36c]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)
[f3b9efc]233
[ed45af6]234def fancy_print(text):
235        column = which('column')
236        if column:
[1bb2488]237                subprocess.run(column, input=bytes(text + "\n", "UTF-8"))
[ed45af6]238        else:
239                print(text)
[0c13238]240
241
[5bf1f3e]242def core_info(path):
[0c13238]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.