source: src/tests/pybin/tools.py @ f85bc15

aaron-thesisarm-ehcleanup-dtorsdeferred_resndemanglerjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprno_listpersistent-indexer
Last change on this file since f85bc15 was f85bc15, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

Test now work outside of tree except for io2

  • Property mode set to 100644
File size: 6.9 KB
Line 
1from __future__ import print_function
2
3import __main__
4import argparse
5import multiprocessing
6import os
7import re
8import signal
9import stat
10import sys
11import fileinput
12
13from pybin import settings
14from subprocess import Popen, PIPE, STDOUT
15
16################################################################################
17#               shell helpers
18################################################################################
19
20# helper functions to run terminal commands
21def sh(cmd, print2stdout = True, input = None):
22        # add input redirection if needed
23        if input and os.path.isfile(input):
24                cmd += " < %s" % input
25
26        # if this is a dry_run, only print the commands that would be ran
27        if settings.dry_run :
28                print("cmd: %s" % cmd)
29                return 0, None
30
31        # otherwise create a pipe and run the desired command
32        else :
33                proc = Popen(cmd, stdout=None if print2stdout else PIPE, stderr=STDOUT, shell=True)
34                out, err = proc.communicate()
35                return proc.returncode, out
36
37def is_ascii(fname):
38        if not os.path.isfile(fname):
39                return False
40
41        code, out = sh("file %s" % fname, print2stdout = False)
42        if code != 0:
43                return False
44
45        match = re.search(".*: (.*)", out)
46
47        if not match:
48                return False
49
50        return match.group(1) == "ASCII text"
51
52# Remove 1 or more files silently
53def rm( files ):
54        try:
55                for file in files:
56                        sh("rm -f %s > /dev/null 2>&1" % file )
57        except TypeError:
58                sh("rm -f %s > /dev/null 2>&1" % files )
59
60def chdir( dest = __main__.__file__ ):
61        abspath = os.path.abspath(dest)
62        dname = os.path.dirname(abspath)
63        os.chdir(dname)
64
65# diff two files
66def diff( lhs, rhs ):
67        # diff the output of the files
68        diff_cmd = ("diff --ignore-all-space "
69                                "--ignore-blank-lines "
70                                "--old-group-format='\t\tmissing lines :\n"
71                                "%%<' \\\n"
72                                "--new-group-format='\t\tnew lines :\n"
73                                "%%>' \\\n"
74                                "--unchanged-group-format='%%=' \\"
75                                "--changed-group-format='\t\texpected :\n"
76                                "%%<"
77                                "\t\tgot :\n"
78                                "%%>\n' \\\n"
79                                "--new-line-format='\t\t%%dn\t%%L' \\\n"
80                                "--old-line-format='\t\t%%dn\t%%L' \\\n"
81                                "--unchanged-line-format='' \\\n"
82                                "%s %s")
83
84        # fetch return code and error from the diff command
85        return sh(diff_cmd % (lhs, rhs), False)
86
87# call make
88def make(target, flags = '', redirects = '', error_file = None, silent = False):
89        test_param = """test="%s" """ % (error_file) if error_file else ''
90        cmd = ' '.join([
91                settings.make,
92                '-s' if silent else '',
93                test_param,
94                settings.debug.flags,
95                flags,
96                target,
97                redirects
98        ])
99        return sh(cmd)
100
101def which(program):
102    import os
103    def is_exe(fpath):
104        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
105
106    fpath, fname = os.path.split(program)
107    if fpath:
108        if is_exe(program):
109            return program
110    else:
111        for path in os.environ["PATH"].split(os.pathsep):
112            exe_file = os.path.join(path, program)
113            if is_exe(exe_file):
114                return exe_file
115
116    return None
117################################################################################
118#               file handling
119################################################################################
120
121# helper function to replace patterns in a file
122def file_replace(fname, pat, s_after):
123        file = fileinput.FileInput(fname, inplace=True, backup='.bak')
124        for line in file:
125                print(line.replace(pat, s_after), end='')
126        file.close()
127
128# helper function to check if a files contains only a specific string
129def fileContainsOnly(file, text) :
130        with open(file) as f:
131                ff = f.read().strip()
132                result = ff == text.strip()
133
134                return result;
135
136# check whether or not a file is executable
137def fileIsExecutable(file) :
138        try :
139                fileinfo = os.stat(file)
140                return bool(fileinfo.st_mode & stat.S_IXUSR)
141        except Exception as inst:
142                print(type(inst))    # the exception instance
143                print(inst.args)     # arguments stored in .args
144                print(inst)
145                return False
146
147# transform path to canonical form
148def canonicalPath(path):
149        abspath = os.path.abspath(__main__.__file__)
150        dname = os.path.dirname(abspath)
151        return os.path.join(dname, os.path.normpath(path) )
152
153# compare path even if form is different
154def pathCmp(lhs, rhs):
155        return canonicalPath( lhs ) == canonicalPath( rhs )
156
157# walk all files in a path
158def pathWalk( op ):
159        def step(_, dirname, names):
160                for name in names:
161                        path = os.path.join(dirname, name)
162                        op( path )
163
164        # Start the walk
165        abspath = os.path.abspath(__main__.__file__)
166        dname = os.path.dirname(abspath)
167        os.path.walk(dname, step, '')
168
169################################################################################
170#               system
171################################################################################
172
173# parses the Makefile to find the machine type (32-bit / 64-bit)
174def getMachineType():
175        sh('echo "void ?{}(int&a,int b){}int main(){return 0;}" > .dummy.c')
176        ret, out = make('.dummy', silent = True)
177
178        if ret != 0:
179                print("Failed to identify architecture:")
180                print(out)
181                print("Stopping")
182                rm( (".dummy.c",".dummy") )
183                sys.exit(1)
184
185        _, out = sh("file .dummy", print2stdout=False)
186        rm( (".dummy.c",".dummy") )
187
188        if settings.dry_run :
189                return 'x64'
190
191        return re.search(r"[^,]+,([^,]+),", out).group(1).strip()
192
193# count number of jobs to create
194def jobCount( options, tests ):
195        # check if the user already passed in a number of jobs for multi-threading
196        if not options.jobs:
197                make_flags = os.environ.get('MAKEFLAGS')
198                force = bool(make_flags)
199                make_jobs_fds = re.search("--jobserver-(auth|fds)=\s*([0-9]+),([0-9]+)", make_flags) if make_flags else None
200                if make_jobs_fds :
201                        tokens = os.read(int(make_jobs_fds.group(2)), 1024)
202                        options.jobs = len(tokens)
203                        os.write(int(make_jobs_fds.group(3)), tokens)
204                else :
205                        options.jobs = multiprocessing.cpu_count()
206        else :
207                force = True
208
209        # make sure we have a valid number of jobs that corresponds to user input
210        if options.jobs <= 0 :
211                print('ERROR: Invalid number of jobs', file=sys.stderr)
212                sys.exit(1)
213
214        return min( options.jobs, len(tests) ), force
215
216# setup a proper processor pool with correct signal handling
217def setupPool(jobs):
218        original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
219        pool = multiprocessing.Pool(jobs)
220        signal.signal(signal.SIGINT, original_sigint_handler)
221
222        return pool
223
224# handle signals in scope
225class SignalHandling():
226        def __enter__(self):
227                # enable signal handling
228                signal.signal(signal.SIGINT, signal.SIG_DFL)
229
230        def __exit__(self, type, value, traceback):
231                # disable signal handling
232                signal.signal(signal.SIGINT, signal.SIG_IGN)
233
234################################################################################
235#               misc
236################################################################################
237
238# check if arguments is yes or no
239def yes_no(string):
240        if string == "yes" :
241                return True
242        if string == "no" :
243                return False
244        raise argparse.ArgumentTypeError(msg)
245        return False
246
247def fancy_print(text):
248        column = which('column')
249        if column:
250                cmd = "%s 2> /dev/null" % column
251                print(cmd)
252                proc = Popen(cmd, stdin=PIPE, stderr=None, shell=True)
253                proc.communicate(input=text)
254        else:
255                print(text)
256
257settings.set_machine_default( getMachineType )
Note: See TracBrowser for help on using the repository browser.