source: tests/pybin/tools.py @ ea62265

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

test now print better in dry-run mode

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