source: tests/pybin/tools.py@ 524ed86

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr no_list persistent-indexer pthread-emulation qualifiedEnum
Last change on this file since 524ed86 was 28582b2, checked in by Thierry Delisle <tdelisle@…>, 7 years ago

Better handling of missing configurations

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