# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file # for details. All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. # This file contains a set of utilities functions used by other Python-based # scripts. import commands import os import platform import Queue import re import StringIO import subprocess import sys import threading import time # Try to guess the host operating system. def GuessOS(): id = platform.system() if id == "Linux": return "linux" elif id == "Darwin": return "macos" elif id == "Windows" or id == "Microsoft": # On Windows Vista platform.system() can return "Microsoft" with some # versions of Python, see http://bugs.python.org/issue1082 for details. return "win32" elif id == 'FreeBSD': return 'freebsd' elif id == 'OpenBSD': return 'openbsd' elif id == 'SunOS': return 'solaris' else: return None # Try to guess the host architecture. def GuessArchitecture(): id = platform.machine() if id.startswith('arm'): return 'arm' elif (not id) or (not re.match('(x|i[3-6])86', id) is None): return 'ia32' elif id == 'i86pc': return 'ia32' else: return None # Try to guess the number of cpus on this machine. def GuessCpus(): if os.path.exists("/proc/cpuinfo"): return int(commands.getoutput("GREP_OPTIONS= grep -E '^processor' /proc/cpuinfo | wc -l")) if os.path.exists("/usr/bin/hostinfo"): return int(commands.getoutput('/usr/bin/hostinfo | GREP_OPTIONS= grep "processors are logically available." | awk "{ print \$1 }"')) win_cpu_count = os.getenv("NUMBER_OF_PROCESSORS") if win_cpu_count: return int(win_cpu_count) return int(os.getenv("DART_NUMBER_OF_CORES", 2)) # Returns true if we're running under Windows. def IsWindows(): return GuessOS() == 'win32' # Reads a text file into an array of strings - one for each # line. Strips comments in the process. def ReadLinesFrom(name): result = [] for line in open(name): if '#' in line: line = line[:line.find('#')] line = line.strip() if len(line) == 0: continue result.append(line) return result # Filters out all arguments until the next '--' argument # occurs. def ListArgCallback(option, opt_str, value, parser): if value is None: value = [] for arg in parser.rargs: if arg[:2].startswith('--'): break value.append(arg) del parser.rargs[:len(value)] setattr(parser.values, option.dest, value) # Filters out all argument until the first non '-' or the # '--' argument occurs. def ListDashArgCallback(option, opt_str, value, parser): if value is None: value = [] for arg in parser.rargs: if arg[:2].startswith('--') or arg[0] != '-': break value.append(arg) del parser.rargs[:len(value)] setattr(parser.values, option.dest, value) # Mapping table between build mode and build configuration. BUILD_MODES = { 'debug': 'Debug', 'release': 'Release', } # Mapping table between OS and build output location. BUILD_ROOT = { 'linux': os.path.join('out'), 'freebsd': os.path.join('out'), 'macos': os.path.join('xcodebuild'), } def GetBuildMode(mode): global BUILD_MODES return BUILD_MODES[mode] def GetBuildConf(mode, arch): return GetBuildMode(mode) + arch.upper() def GetBuildRoot(host_os, mode=None, arch=None): global BUILD_ROOT if mode: return os.path.join(BUILD_ROOT[host_os], GetBuildConf(mode, arch)) else: return BUILD_ROOT[host_os] def RunCommand(command, input=None, pollFn=None, outStream=None, errStream=None, killOnEarlyReturn=True, verbose=False, debug=False, printErrorInfo=False): """ Run a command, with optional input and polling function. Args: command: list of the command and its arguments. input: optional string of input to feed to the command, it should be short enough to fit in an i/o pipe buffer. pollFn: if present will be called occasionally to check if the command should be finished early. If pollFn() returns true then the command will finish early. outStream: if present, the stdout output of the command will be written to outStream. errStream: if present, the stderr output of the command will be written to errStream. killOnEarlyReturn: if true and pollFn returns true, then the subprocess will be killed, otherwise the subprocess will be detached. verbose: if true, the command is echoed to stderr. debug: if true, prints debugging information to stderr. printErrorInfo: if true, prints error information when the subprocess returns a non-zero exit code. Returns: the output of the subprocess. Exceptions: Raises Error if the subprocess returns an error code. Raises ValueError if called with invalid arguments. """ if verbose: sys.stderr.write("command %s\n" % command) stdin = None if input: stdin = subprocess.PIPE try: process = subprocess.Popen(args=command, stdin=stdin, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError as e: if not isinstance(command, basestring): command = ' '.join(command) if printErrorInfo: sys.stderr.write("Command failed: '%s'\n" % command) raise Error(e) def StartThread(out): queue = Queue.Queue() def EnqueueOutput(out, queue): for line in iter(out.readline, b''): queue.put(line) out.close() thread = threading.Thread(target=EnqueueOutput, args=(out, queue)) thread.daemon = True thread.start() return queue outQueue = StartThread(process.stdout) errQueue = StartThread(process.stderr) def ReadQueue(queue, out, out2): try: while True: line = queue.get(False) out.write(line) if out2 != None: out2.write(line) except Queue.Empty: pass outBuf = StringIO.StringIO() errorBuf = StringIO.StringIO() if input: process.stdin.write(input) while True: returncode = process.poll() if returncode != None: break ReadQueue(errQueue, errorBuf, errStream) ReadQueue(outQueue, outBuf, outStream) if pollFn != None and pollFn(): returncode = 0 if killOnEarlyReturn: process.kill() break time.sleep(0.1) # Drain queue ReadQueue(errQueue, errorBuf, errStream) ReadQueue(outQueue, outBuf, outStream) out = outBuf.getvalue(); error = errorBuf.getvalue(); if returncode: if not isinstance(command, basestring): command = ' '.join(command) if printErrorInfo: sys.stderr.write("Command failed: '%s'\n" % command) sys.stderr.write(" stdout: '%s'\n" % out) sys.stderr.write(" stderr: '%s'\n" % error) sys.stderr.write(" returncode: %d\n" % returncode) raise Error("Command failed: %s" % command) if debug: sys.stderr.write("output: %s\n" % out) return out def Main(argv): print "GuessOS() -> ", GuessOS() print "GuessArchitecture() -> ", GuessArchitecture() print "GuessCpus() -> ", GuessCpus() print "IsWindows() -> ", IsWindows() class Error(Exception): pass if __name__ == "__main__": import sys Main(sys.argv)