source: tests/pybin/tools.py@ 029e330

ADT arm-eh ast-experimental cleanup-dtors enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since 029e330 was 202ad72, checked in by Thierry Delisle <tdelisle@…>, 7 years ago

Implemented dry-run for output fixing and fix outputs on regenerate as well

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