source: tests/pybin/tools.py @ c018b85

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprno_listpersistent-indexerpthread-emulationqualifiedEnum
Last change on this file since c018b85 was 25cdca5, checked in by Thierry Delisle <tdelisle@…>, 5 years ago

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

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