14 path = os.path.realpath(path)
15 path = os.path.normpath(path)
16 path = os.path.normcase(path)
22 # Python 2 and Python 3 are different here.
23 return isinstance(value, basestring)
25 return isinstance(value, str)
28 def pythonize_bool(value):
31 if type(value) is bool:
33 if isinstance(value, numbers.Number):
36 if value.lower() in ('1', 'true', 'on', 'yes'):
38 if value.lower() in ('', '0', 'false', 'off', 'no'):
40 raise ValueError('"{}" is not a valid boolean'.format(value))
43 def make_word_regex(word):
44 return r'\b' + word + r'\b'
48 """Return the parameter as type 'bytes', possibly encoding it.
50 In Python2, the 'bytes' type is the same as 'str'. In Python3, they
54 if isinstance(s, bytes):
55 # In Python2, this branch is taken for both 'str' and 'bytes'.
56 # In Python3, this branch is taken only for 'bytes'.
58 # In Python2, 's' is a 'unicode' object.
59 # In Python3, 's' is a 'str' object.
60 # Encode to UTF-8 to get 'bytes' data.
61 return s.encode('utf-8')
65 """Return the parameter as type 'str', possibly encoding it.
67 In Python2, the 'str' type is the same as 'bytes'. In Python3, the
68 'str' type is (essentially) Python2's 'unicode' type, and 'bytes' is
72 if isinstance(b, str):
73 # In Python2, this branch is taken for types 'str' and 'bytes'.
74 # In Python3, this branch is taken only for 'str'.
76 if isinstance(b, bytes):
77 # In Python2, this branch is never taken ('bytes' is handled as 'str').
78 # In Python3, this is true only for 'bytes'.
80 return b.decode('utf-8')
81 except UnicodeDecodeError:
82 # If the value is not valid Unicode, return the default
86 # By this point, here's what we *don't* have:
89 # - 'str' or 'bytes' (1st branch above)
91 # - 'str' (1st branch above)
92 # - 'bytes' (2nd branch above)
94 # The last type we might expect is the Python2 'unicode' type. There is no
95 # 'unicode' type in Python3 (all the Python3 cases were already handled). In
96 # order to get a 'str' object, we need to encode the 'unicode' object.
98 return b.encode('utf-8')
99 except AttributeError:
100 raise TypeError('not sure how to convert %s to %s' % (type(b), str))
104 """Detects the number of CPUs on a system.
109 # Linux, Unix and MacOS:
110 if hasattr(os, 'sysconf'):
111 if 'SC_NPROCESSORS_ONLN' in os.sysconf_names:
113 ncpus = os.sysconf('SC_NPROCESSORS_ONLN')
114 if isinstance(ncpus, int) and ncpus > 0:
117 return int(subprocess.check_output(['sysctl', '-n', 'hw.ncpu'],
118 stderr=subprocess.STDOUT))
120 if 'NUMBER_OF_PROCESSORS' in os.environ:
121 ncpus = int(os.environ['NUMBER_OF_PROCESSORS'])
123 # With more than 32 processes, process creation often fails with
124 # "Too many open files". FIXME: Check if there's a better fix.
125 return min(ncpus, 32)
130 """mkdir_p(path) - Make the "path" directory, if it does not exist; this
131 will also make directories for any missing parent directories."""
132 if not path or os.path.exists(path):
135 parent = os.path.dirname(path)
142 e = sys.exc_info()[1]
143 # Ignore EEXIST, which may occur during a race condition.
144 if e.errno != errno.EEXIST:
148 def listdir_files(dirname, suffixes=None, exclude_filenames=None):
149 """Yields files in a directory.
151 Filenames that are not excluded by rules below are yielded one at a time, as
152 basenames (i.e., without dirname).
154 Files starting with '.' are always skipped.
156 If 'suffixes' is not None, then only filenames ending with one of its
157 members will be yielded. These can be extensions, like '.exe', or strings,
158 like 'Test'. (It is a lexicographic check; so an empty sequence will yield
159 nothing, but a single empty string will yield all filenames.)
161 If 'exclude_filenames' is not None, then none of the file basenames in it
164 If specified, the containers for 'suffixes' and 'exclude_filenames' must
165 support membership checking for strs.
168 dirname: a directory path.
169 suffixes: (optional) a sequence of strings (set, list, etc.).
170 exclude_filenames: (optional) a sequence of strings.
173 Filenames as returned by os.listdir (generally, str).
176 if exclude_filenames is None:
177 exclude_filenames = set()
180 for filename in os.listdir(dirname):
181 if (os.path.isdir(os.path.join(dirname, filename)) or
182 filename.startswith('.') or
183 filename in exclude_filenames or
184 not any(filename.endswith(sfx) for sfx in suffixes)):
189 def which(command, paths=None):
190 """which(command, [paths]) - Look up the given command in the paths string
191 (or the PATH environment variable, if unspecified)."""
194 paths = os.environ.get('PATH', '')
196 # Check for absolute match first.
197 if os.path.isabs(command) and os.path.isfile(command):
198 return os.path.normpath(command)
200 # Would be nice if Python had a lib function for this.
204 # Get suffixes to search.
205 # On Cygwin, 'PATHEXT' may exist but it should not be used.
206 if os.pathsep == ';':
207 pathext = os.environ.get('PATHEXT', '').split(';')
211 # Search the paths...
212 for path in paths.split(os.pathsep):
214 p = os.path.join(path, command + ext)
215 if os.path.exists(p) and not os.path.isdir(p):
216 return os.path.normpath(p)
221 def checkToolsPath(dir, tools):
223 if not os.path.exists(os.path.join(dir, tool)):
228 def whichTools(tools, paths):
229 for path in paths.split(os.pathsep):
230 if checkToolsPath(path, tools):
235 def printHistogram(items, title='Items'):
236 items.sort(key=lambda item: item[1])
238 maxValue = max([v for _, v in items])
240 # Select first "nice" bar height that produces more than 10 bars.
241 power = int(math.ceil(math.log(maxValue, 10)))
242 for inc in itertools.cycle((5, 2, 2.5, 1)):
243 barH = inc * 10**power
244 N = int(math.ceil(maxValue / barH))
250 histo = [set() for i in range(N)]
251 for name, v in items:
252 bin = min(int(N * v / maxValue), N - 1)
256 hr = '-' * (barW + 34)
257 print('\nSlowest %s:' % title)
259 for name, value in items[-20:]:
260 print('%.2fs: %s' % (value, name))
261 print('\n%s Times:' % title)
263 pDigits = int(math.ceil(math.log(maxValue, 10)))
264 pfDigits = max(0, 3 - pDigits)
266 pDigits += pfDigits + 1
267 cDigits = int(math.ceil(math.log(len(items), 10)))
268 print('[%s] :: [%s] :: [%s]' % ('Range'.center((pDigits + 1) * 2 + 3),
269 'Percentage'.center(barW),
270 'Count'.center(cDigits * 2 + 1)))
272 for i, row in enumerate(histo):
273 pct = float(len(row)) / len(items)
275 print('[%*.*fs,%*.*fs) :: [%s%s] :: [%*d/%*d]' % (
276 pDigits, pfDigits, i * barH, pDigits, pfDigits, (i + 1) * barH,
277 '*' * w, ' ' * (barW - w), cDigits, len(row), cDigits, len(items)))
280 class ExecuteCommandTimeoutException(Exception):
281 def __init__(self, msg, out, err, exitCode):
282 assert isinstance(msg, str)
283 assert isinstance(out, str)
284 assert isinstance(err, str)
285 assert isinstance(exitCode, int)
289 self.exitCode = exitCode
292 # Close extra file handles on UNIX (on Windows this cannot be done while
293 # also redirecting input).
294 kUseCloseFDs = not (platform.system() == 'Windows')
297 def executeCommand(command, cwd=None, env=None, input=None, timeout=0):
298 """Execute command ``command`` (list of arguments or string) with.
300 * working directory ``cwd`` (str), use None to use the current
302 * environment ``env`` (dict), use None for none
303 * Input to the command ``input`` (str), use string to pass
305 * Max execution time ``timeout`` (int) seconds. Use 0 for no timeout.
307 Returns a tuple (out, err, exitCode) where
308 * ``out`` (str) is the standard output of running the command
309 * ``err`` (str) is the standard error of running the command
310 * ``exitCode`` (int) is the exitCode of running the command
312 If the timeout is hit an ``ExecuteCommandTimeoutException``
316 if input is not None:
317 input = to_bytes(input)
318 p = subprocess.Popen(command, cwd=cwd,
319 stdin=subprocess.PIPE,
320 stdout=subprocess.PIPE,
321 stderr=subprocess.PIPE,
322 env=env, close_fds=kUseCloseFDs)
324 # FIXME: Because of the way nested function scopes work in Python 2.x we
325 # need to use a reference to a mutable object rather than a plain
326 # bool. In Python 3 we could use the "nonlocal" keyword but we need
327 # to support Python 2 as well.
332 # We may be invoking a shell so we need to kill the
333 # process and all its children.
335 killProcessAndChildren(p.pid)
337 timerObject = threading.Timer(timeout, killProcess)
340 out, err = p.communicate(input=input)
343 if timerObject != None:
346 # Ensure the resulting output is always of string type.
351 raise ExecuteCommandTimeoutException(
352 msg='Reached timeout of {} seconds'.format(timeout),
358 # Detect Ctrl-C in subprocess.
359 if exitCode == -signal.SIGINT:
360 raise KeyboardInterrupt
362 return out, err, exitCode
365 def usePlatformSdkOnDarwin(config, lit_config):
366 # On Darwin, support relocatable SDKs by providing Clang with a
367 # default system root path.
368 if 'darwin' in config.target_triple:
370 cmd = subprocess.Popen(['xcrun', '--show-sdk-path', '--sdk', 'macosx'],
371 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
372 out, err = cmd.communicate()
379 lit_config.note('using SDKROOT: %r' % sdk_path)
380 config.environment['SDKROOT'] = sdk_path
383 def findPlatformSdkVersionOnMacOS(config, lit_config):
384 if 'darwin' in config.target_triple:
386 cmd = subprocess.Popen(['xcrun', '--show-sdk-version', '--sdk', 'macosx'],
387 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
388 out, err = cmd.communicate()
398 def killProcessAndChildren(pid):
399 """This function kills a process with ``pid`` and all its running children
400 (recursively). It is currently implemented using the psutil module which
401 provides a simple platform neutral implementation.
403 TODO: Reimplement this without using psutil so we can remove
404 our dependency on it.
409 psutilProc = psutil.Process(pid)
410 # Handle the different psutil API versions
413 children_iterator = psutilProc.children(recursive=True)
414 except AttributeError:
416 children_iterator = psutilProc.get_children(recursive=True)
417 for child in children_iterator:
420 except psutil.NoSuchProcess:
423 except psutil.NoSuchProcess: