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@…>, 6 years ago

test now print better in dry-run mode

  • Property mode set to 100644
File size: 7.6 KB
Line 
1import __main__
2import argparse
3import contextlib
4import fileinput
5import multiprocessing
6import os
7import re
8import resource
9import signal
10import stat
11import subprocess
12import sys
13import time
14import types
15
16from pybin import settings
17from subprocess import Popen, PIPE, STDOUT
18
19################################################################################
20#               shell helpers
21################################################################################
22
23# helper functions to run terminal commands
24def sh(*cmd, timeout = False, output = None, input = None, error = subprocess.STDOUT):
25        cmd = list(cmd)
26
27        # if this is a dry_run, only print the commands that would be ran
28        if settings.dry_run :
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)
43                return 0, None
44
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
60                try:
61                        proc = subprocess.run(
62                                cmd,
63                                stdin =input,
64                                stdout=output,
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)
71
72def is_ascii(fname):
73        if settings.dry_run:
74                print("is_ascii: %s" % fname)
75                return True
76
77        if not os.path.isfile(fname):
78                return False
79
80        code, out = sh("file %s" % fname, output=subprocess.PIPE)
81        if code != 0:
82                return False
83
84        match = re.search(".*: (.*)", out)
85
86        if not match:
87                return False
88
89        return match.group(1).startswith("ASCII text")
90
91def is_exe(fname):
92        return os.path.isfile(fname) and os.access(fname, os.X_OK)
93
94# Remove 1 or more files silently
95def rm( files ):
96        if isinstance(files, str ): files = [ files ]
97        for file in files:
98                sh( 'rm', '-f', file, output=subprocess.DEVNULL, error=subprocess.DEVNULL )
99
100# Create 1 or more directory
101def mkdir( files ):
102        if isinstance(files, str ): files = [ files ]
103        for file in files:
104                p = os.path.normpath( file )
105                d = os.path.dirname ( p )
106                sh( 'mkdir', '-p', d, output=subprocess.DEVNULL, error=subprocess.DEVNULL )
107
108
109def chdir( dest = __main__.__file__ ):
110        abspath = os.path.abspath(dest)
111        dname = os.path.dirname(abspath)
112        os.chdir(dname)
113
114# diff two files
115def diff( lhs, rhs ):
116        # fetch return code and error from the diff command
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        )
131
132# call make
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,
138                test_param,
139                settings.arch.flags,
140                settings.debug.flags,
141                settings.install.flags,
142                flags,
143                target
144        ]
145        cmd = [s for s in cmd if s]
146        return sh(*cmd, output=output, error=error)
147
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
160
161################################################################################
162#               file handling
163################################################################################
164# move a file
165def mv(source, dest):
166        ret, _ = sh("mv", source, dest)
167        return ret
168
169# cat one file into the other
170def cat(source, dest):
171        ret, _ = sh("cat", source, output=dest)
172        return ret
173
174# helper function to replace patterns in a file
175def file_replace(fname, pat, s_after):
176        if settings.dry_run:
177                print("replacing '%s' with '%s' in %s" % (pat, s_after, fname))
178                return
179
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()
184
185# helper function to check if a files contains only a specific string
186def file_contains_only(file, text) :
187        with open(file) as f:
188                ff = f.read().strip()
189                result = ff == text.strip()
190
191                return result
192
193# transform path to canonical form
194def canonical_path(path):
195        abspath = os.path.abspath(__main__.__file__)
196        dname = os.path.dirname(abspath)
197        return os.path.join(dname, os.path.normpath(path) )
198
199# compare path even if form is different
200def path_cmp(lhs, rhs):
201        return canonical_path( lhs ) == canonical_path( rhs )
202
203# walk all files in a path
204def path_walk( op ):
205        dname = settings.SRCDIR
206        for dirname, _, names in os.walk(dname):
207                for name in names:
208                        path = os.path.join(dirname, name)
209                        op( path )
210
211################################################################################
212#               system
213################################################################################
214# count number of jobs to create
215def job_count( options, tests ):
216        # check if the user already passed in a number of jobs for multi-threading
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()
227        else :
228                force = True
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
235        return min( options.jobs, len(tests) ), force
236
237# enable core dumps for all the test children
238resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY))
239
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)
251
252def fancy_print(text):
253        column = which('column')
254        if column:
255                subprocess.run(column, input=bytes(text + "\n", "UTF-8"))
256        else:
257                print(text)
258
259
260def core_info(path):
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
273        return sh('gdb', '-n', path, core, '-batch', '-x', cmd, output=subprocess.PIPE)
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.