예제 #1
0
class Foo1:
    foo2 = Inject('Foo2')

    def __init__(self, val):
        self.val = val

    def Start(self):
        print(self.foo2.val)
예제 #2
0
class Foo2:
    foo1 = Inject('Foo1')

    def __init__(self, val):
        self.val = val

    def Start(self):
        print('foo2 {0}, foo1 {1}'.format(self.val, self.foo1.val))
class Test2:
    qux = Inject('Qux')

    def __init__(self):
        self.X = 0

    def Run(self):
        print(self.qux.GetValue())
예제 #4
0
class ZipHelper:
    _sys = Inject('SystemHelper')
    _varMgr = Inject('VarManager')
    _log = Inject('Logger')

    def createZipFile(self, dirPath, zipFilePath):
        assertThat(zipFilePath.endswith('.zip'))

        dirPath = self._varMgr.expandPath(dirPath)
        zipFilePath = self._varMgr.expandPath(zipFilePath)

        self._sys.makeMissingDirectoriesInPath(zipFilePath)
        self._sys.removeFileIfExists(zipFilePath)

        self._log.debug("Writing directory '{0}' to zip at '{1}'", dirPath,
                        zipFilePath)
        self._writeDirectoryToZipFile(zipFilePath, dirPath)

    def _writeDirectoryToZipFile(self, zipFilePath, dirPath):
        with zipfile.ZipFile(zipFilePath, 'w', zipfile.ZIP_DEFLATED) as zipf:
            self._zipAddDir(zipf, dirPath, '')

    def _zipAddDir(self, zipf, dirPath, zipPathPrefix=None):
        dirPath = self._varMgr.expandPath(dirPath)

        assertThat(os.path.isdir(dirPath),
                   'Invalid directory given at "{0}"'.format(dirPath))

        if zipPathPrefix is None:
            zipPathPrefix = os.path.basename(dirPath)

        for root, dirs, files in os.walk(dirPath):
            for file in files:
                filePath = os.path.join(root, file)
                zipf.write(
                    filePath,
                    os.path.join(zipPathPrefix,
                                 os.path.relpath(filePath, dirPath)))
예제 #5
0
class ScriptRunner:
    _log = Inject('Logger')

    def runWrapper(self, runner):
        startTime = datetime.now()

        succeeded = False

        try:
            runner()
            succeeded = True

        except KeyboardInterrupt as e:
            self._log.endHeading()
            self._log.error('Operation aborted by user by hitting CTRL+C')

        except Exception as e:
            self._log.endHeading()
            self._log.error(str(e))

            if self._log.currentHeading:
                self._log.error("Failed while executing '" +
                                self._log.currentHeading + "'")

            # Only print stack trace if it's a build-script error
            if not isinstance(e, ProcessErrorCodeException) and not isinstance(
                    e, ProcessTimeoutException):
                self._log.debug('\n' + traceback.format_exc())

        totalSeconds = (datetime.now() - startTime).total_seconds()
        totalSecondsStr = Util.formatTimeDelta(totalSeconds)

        if succeeded:
            self._log.finished('Operation completed successfully.  Took ' +
                               totalSecondsStr + '.\n')
        else:
            self._log.finished('Operation completed with errors.  Took ' +
                               totalSecondsStr + '.\n')

        return succeeded
예제 #6
0
class Test2:
    title = Inject('Title', Assertions.IsInstanceOf(str))

    def Run(self):
        print('title: {0}'.format(self.title))
예제 #7
0
class Test1:
    con = Inject('Console', Assertions.HasMethods('WriteLine'))

    def Run(self):
        self.con.WriteLine('lorem ipsum')
예제 #8
0
class VisualStudioHelper:
    _log = Inject('Logger')
    _config = Inject('Config')
    _packageManager = Inject('PackageManager')
    _unityHelper = Inject('UnityHelper')
    _varMgr = Inject('VarManager')
    _sys = Inject('SystemHelper')
    _vsSolutionGenerator = Inject('VisualStudioSolutionGenerator')

    def openFile(self, filePath, lineNo, project, platform):
        if not lineNo or lineNo <= 0:
            lineNo = 1

        if MiscUtil.doesProcessExist('^devenv\.exe$'):
            self.openFileInExistingVisualStudioInstance(filePath, lineNo)

            # This works too but doesn't allow going to a specific line
            #self._sys.executeNoWait('[VisualStudioCommandLinePath] /edit "{0}"'.format(filePath))
        else:
            # Unfortunately, in this case we can't pass in the line number
            self.openCustomSolution(project, platform, filePath)

    def openFileInExistingVisualStudioInstance(self, filePath, lineNo):
        try:
            dte = win32com.client.GetActiveObject("VisualStudio.DTE.12.0")

            dte.MainWindow.Activate
            dte.ItemOperations.OpenFile(self._sys.canonicalizePath(filePath))
            dte.ActiveDocument.Selection.MoveToLineAndOffset(lineNo, 1)
        except Exception as error:
            raise Exception(
                "COM Error.  This is often triggered when given a bad line number. Details: {0}"
                .format(win32api.FormatMessage(error.excepinfo[5])))

    def openVisualStudioSolution(self, solutionPath, filePath=None):
        if not self._varMgr.hasKey('VisualStudioIdePath'):
            assertThat(
                False,
                "Path to visual studio has not been defined.  Please set <VisualStudioIdePath> within one of your {0} files",
                ConfigFileName)

        if self._sys.fileExists('[VisualStudioIdePath]'):
            self._sys.executeNoWait('"[VisualStudioIdePath]" {0} {1}'.format(
                self._sys.canonicalizePath(solutionPath),
                self._sys.canonicalizePath(filePath) if filePath else ""))
        else:
            assertThat(
                False,
                "Cannot find path to visual studio.  Expected to find it at '{0}'"
                .format(self._varMgr.expand('[VisualStudioIdePath]')))

    def updateCustomSolution(self, project, platform):
        self._vsSolutionGenerator.updateVisualStudioSolution(project, platform)

    def openCustomSolution(self, project, platform, filePath=None):
        self.openVisualStudioSolution(
            self._getCustomSolutionPath(project, platform), filePath)

    def buildCustomSolution(self, project, platform):
        solutionPath = self._getCustomSolutionPath(project, platform)

        if not self._sys.fileExists(solutionPath):
            self._log.warn(
                'Could not find generated custom solution.  Generating now.')
            self._vsSolutionGenerator.updateVisualStudioSolution(
                project, platform)

        self._log.heading('Building {0}-{1}.sln'.format(project, platform))
        self.buildVisualStudioProject(solutionPath, 'Debug')

    def buildVisualStudioProject(self, solutionPath, buildConfig):
        if self._config.getBool('Compilation', 'UseDevenv'):
            buildCommand = '"[VisualStudioCommandLinePath]" {0} /build "{1}"'.format(
                solutionPath, buildConfig)
        else:
            buildCommand = '"[MsBuildExePath]" /p:VisualStudioVersion=12.0'
            #if rebuild:
            #buildCommand += ' /t:Rebuild'
            buildCommand += ' /p:Configuration="{0}" "{1}"'.format(
                buildConfig, solutionPath)

        self._sys.executeAndWait(buildCommand)

    def _getCustomSolutionPath(self, project, platform):
        return '[UnityProjectsDir]/{0}/{0}-{1}.sln'.format(project, platform)

    def updateUnitySolution(self, projectName, platform):
        """
        Simply runs unity and then generates the monodevelop solution file using an editor script
        This is used when generating the Visual Studio Solution to get DLL references and defines etc.
        """
        self._log.heading(
            'Updating unity generated solution for project {0} ({1})'.format(
                projectName, platform))

        self._packageManager.checkProjectInitialized(projectName, platform)

        # This will generate the unity csproj files which we need to generate Modest3d.sln correctly
        # It's also necessary to run this first on clean checkouts to initialize unity properly
        self._unityHelper.runEditorFunction(
            projectName, platform,
            'Projeny.ProjenyEditorUtil.UpdateMonodevelopProject')
예제 #9
0
class ProcessRunner:
    _log = Inject('Logger')

    def execNoWait(self, vals, startDir):
        params = {}

        if startDir != None:
            params['cwd'] = startDir

        Popen(vals, **params)

    def waitForProcessOrTimeout(self, commandVals, seconds, startDir=None):

        params = {}
        params['stdout'] = subprocess.PIPE
        params['stderr'] = subprocess.STDOUT

        if startDir != None:
            params['cwd'] = startDir

        proc = Popen(commandVals, **params)

        # TODO - clean this up so there's only one thread, then
        # do the timeout logic on the main thread
        timeout = KillProcessThread(seconds, proc.pid)
        timeout.run()

        def enqueueOutput(out, queue):
            for line in iter(out.readline, b''):
                queue.put(line)
            out.close()

        # We use a queue here instead of just calling stdout.readline() on the main thread
        # so that we can catch the KeyboardInterrupt event, and force kill the process
        queue = Queue()
        thread = threading.Thread(target=enqueueOutput,
                                  args=(proc.stdout, queue))
        thread.daemon = True  # thread dies with the program
        thread.start()

        while True:
            try:
                try:
                    line = queue.get_nowait()
                    self._log.debug(line.decode('utf-8').rstrip())
                except Empty:
                    if not thread.isAlive():
                        break
                    time.sleep(0.2)
            except KeyboardInterrupt as e:
                self._log.error(
                    "Detected KeyboardInterrupt - killing process...")
                timeout.forceKill()
                raise e

        resultCode = proc.wait()

        timeout.cancel()

        if timeout.timeOutOccurred:
            return ResultType.TimedOut

        if resultCode != 0:
            return ResultType.Error

        return ResultType.Success

    # Note that in this case we pass the command as a string
    # This is recommended by the python docs here when using shell = True
    # https://docs.python.org/2/library/subprocess.html#subprocess.Popen
    def execShellCommand(self, commandStr, startDir=None):

        params = {}
        params['stdout'] = subprocess.PIPE
        params['stderr'] = subprocess.PIPE
        params['shell'] = True

        if startDir != None:
            params['cwd'] = startDir

        # Would be nice to get back output in real time but I can't figure
        # out a way to do this
        # This method should only be used for a few command-prompt specific
        # commands anyway so not a big loss
        proc = Popen(commandStr, **params)

        (stdoutData, stderrData) = proc.communicate()

        output = stdoutData.decode('utf-8').strip()
        errors = stderrData.decode('utf-8').strip()

        if output:
            for line in output.split('\n'):
                self._log.debug(line)

        if errors:
            self._log.error(
                'Error occurred during command "{0}":'.format(commandStr))
            for line in errors.split('\n'):
                self._log.error('    ' + line)

        exitStatus = proc.returncode

        if exitStatus != 0:
            return ResultType.Error

        return ResultType.Success
예제 #10
0
class Runner:
    _scriptRunner = Inject('ScriptRunner')
    _unityHelper = Inject('UnityHelper')
    _log = Inject('Logger')
    _sys = Inject('SystemHelper')
    _varManager = Inject('VarManager')
    _zipHelper = Inject('ZipHelper')

    def __init__(self):
        self._platform = Platforms.Windows

    def run(self, args):
        self._args = args
        success = self._scriptRunner.runWrapper(self._runInternal)

        if not success:
            sys.exit(1)

    def _runBuilds(self):

        if self._args.clearOutput:
            self._log.heading("Clearing output directory")
            self._sys.clearDirectoryContents('[OutputRootDir]')

        self._clearTempDirectory()
        self._copyToTempDirectory()

        if self._args.buildType == 'all' or self._args.buildType == 'pc':
            self._log.heading("Building windows")
            self._platform = Platforms.Windows
            self._createBuild()
            self._zipHelper.createZipFile('[OutputRootDir]/Windows',
                                          '[OutputRootDir]/Windows.zip')

        if self._args.buildType == 'all' or self._args.buildType == 'webgl':
            self._log.heading("Building WebGl")
            self._platform = Platforms.WebGl
            self._createBuild()
            self._sys.copyFile('[WebGlTemplate]',
                               '[OutputRootDir]/WebGl/Web.config')
            self._zipHelper.createZipFile(
                '[OutputRootDir]/WebGl',
                '[OutputRootDir]/GreatEggscapeWebGl.zip')

    def _clearTempDirectory(self):
        self._sys.deleteDirectoryIfExists('[TempDir]')
        self._sys.createDirectory('[TempDir]')
        self._sys.clearDirectoryContents('[TempDir]')

    def _copyToTempDirectory(self):
        self._log.info('Copying to temporary directory')
        try:
            self._sys.copyDirectory('[UnityProjectPath]',
                                    '[UnityProjectPathTempDir]')
        except:
            pass

    def _runInternal(self):

        if self._args.runBuilds:
            self._runBuilds()

        if self._args.openUnity:
            self._openUnity()

    def _createBuild(self):
        self._log.info("Creating build")
        self._runEditorFunction('BuildRelease')
        #self._runEditorFunction('BuildDebug')

    def _openUnity(self):
        self._unityHelper.openUnity('[UnityProjectPath]', self._platform)

    def _runEditorFunction(self, functionName):
        self._log.info("Calling Builder." + functionName)
        self._unityHelper.runEditorFunction('[UnityProjectPathTempDir]',
                                            'Builder.' + functionName,
                                            self._platform)
예제 #11
0
class SystemHelper:
    '''Responsibilities:
        - Miscellaneous file-handling/path-related operations
        - Wrapper to execute arbitrary commands
    '''
    _varManager = Inject('VarManager')
    _log = Inject('Logger')
    _processRunner = Inject('ProcessRunner')

    # Use an hour timeout
    def __init__(self, timeout = 60 * 60):
        self._timeout = timeout

    def canonicalizePath(self, pathStr):
        # Make one standard representation of the given path
        # This will remove ..\ and also change to always use back slashes since this is what os.path.join etc. uses
        return self._varManager.expandPath(pathStr)

    def executeAndWait(self, commandStr, startDir = None):
        expandedStr = self._varManager.expand(commandStr)

        self._log.debug("Executing '%s'" % expandedStr)

        vals = self._splitCommandStr(expandedStr)

        if startDir != None:
            startDir = self._varManager.expand(startDir)

        result = self._processRunner.waitForProcessOrTimeout(vals, self._timeout, startDir)

        if result == ResultType.Error:
            raise ProcessErrorCodeException('Command returned with error code while executing: %s' % expandedStr)

        if result == ResultType.TimedOut:
            raise ProcessTimeoutException('Timed out while waiting for command: %s' % expandedStr)

        assertThat(result == ResultType.Success)

    def executeNoWait(self, commandStr, startDir = None):
        expandedStr = self._varManager.expand(commandStr)

        self._log.debug("Executing '{0}'".format(expandedStr))

        vals = self._splitCommandStr(expandedStr)

        if startDir != None:
            startDir = self._varManager.expand(startDir)

        self._processRunner.execNoWait(vals, startDir)

    # This is only used to execute shell-specific commands like copy, mklink, etc.
    def executeShellCommand(self, commandStr, startDir = None):
        expandedStr = self._varManager.expand(commandStr)

        self._log.debug("Executing '%s'" % expandedStr)

        if startDir != None:
            startDir = self._varManager.expand(startDir)

        result = self._processRunner.execShellCommand(expandedStr, startDir)

        if result == ResultType.Error:
            raise ProcessErrorCodeException('Command returned with error code while executing: %s' % expandedStr)

        assertThat(result == ResultType.Success, "Expected success result but found '{0}'".format(result))

    def _splitCommandStr(self, commandStr):
        # Hacky but necessary since shlex.split will otherwise remove our backslashes
        if platform.platform().startswith('Windows'):
            commandStr = commandStr.replace(os.sep, os.sep + os.sep)

        # Convert command to argument list to avoid issues with escape characters, etc.
        # Based on an answer here: http://stackoverflow.com/questions/12081970/python-using-quotes-in-the-subprocess-popen
        return shlex.split(commandStr)

    def executeAndReturnOutput(self, commandStr):
        self._log.debug("Executing '%s'" % commandStr)
        return subprocess.getoutput(self._splitCommandStr(commandStr)).strip()

    def walkDir(self, dirPath):
        dirPath = self._varManager.expand(dirPath)
        return os.listdir(dirPath)

    def getParentDirectoriesWithSelf(self, path):
        yield path

        for parentDir in self.getParentDirectories(path):
            yield parentDir

    def getParentDirectories(self, path):
        path = self._varManager.expand(path)

        lastParentDir = None
        parentDir = os.path.dirname(path)

        while parentDir and parentDir != lastParentDir:
            yield parentDir

            lastParentDir = parentDir
            parentDir = os.path.dirname(parentDir)

    def createDirectory(self, dirPath):
        dirPath = self._varManager.expand(dirPath)
        assertThat(not self.directoryExists(dirPath), 'Tried to create a directory that already exists')
        os.makedirs(dirPath)

    def makeMissingDirectoriesInPath(self, dirPath):
        dirPath = self._varManager.expand(dirPath)
        try:
            os.makedirs(os.path.dirname(dirPath))
        except:
            pass

    def copyFile(self, fromPath, toPath):
        toPath = self._varManager.expand(toPath)
        fromPath = self._varManager.expand(fromPath)

        self.makeMissingDirectoriesInPath(toPath)
        shutil.copy2(fromPath, toPath)

    def move(self, fromPath, toPath):
        toPath = self._varManager.expand(toPath)
        fromPath = self._varManager.expand(fromPath)

        self.makeMissingDirectoriesInPath(toPath)
        shutil.move(fromPath, toPath)

    def IsDir(self, path):
        return os.path.isdir(self._varManager.expand(path))

    def clearDirectoryContents(self, dirPath):
        dirPath = self._varManager.expand(dirPath)

        if not os.path.exists(dirPath):
            return

        for fileName in os.listdir(dirPath):
            filePath = os.path.join(dirPath, fileName)
            if os.path.isfile(filePath):
                os.unlink(filePath)
            elif os.path.isdir(filePath):
                shutil.rmtree(filePath)

    def deleteDirectoryWaitIfNecessary(self, dirPath):
        dirPath = self._varManager.expand(dirPath)

        if not os.path.isdir(dirPath):
            # Already removed
            return

        attemptsLeft = 10

        while True:
            try:
                shutil.rmtree(dirPath)
            except Exception as e:
                self._log.warn('Could not delete directory at "{0}".  Waiting to try again...'.format(dirPath))
                time.sleep(5)
                attemptsLeft -= 1

                if attemptsLeft < 0:
                    raise e
                continue
            break

    def deleteDirectory(self, dirPath):
        dirPath = self._varManager.expand(dirPath)
        shutil.rmtree(dirPath)

    def deleteDirectoryIfExists(self, dirPath):
        dirPath = self._varManager.expand(dirPath)

        if os.path.exists(dirPath):
            shutil.rmtree(dirPath)
            return True

        return False

    def deleteEmptyDirectoriesUnder(self, dirPath):
        dirPath = self._varManager.expandPath(dirPath)

        if not os.path.isdir(dirPath):
            return 0

        # Can't process long paths on windows
        if len(dirPath) >= 256:
            return 0

        files = os.listdir(dirPath)

        numDirsDeleted = 0

        for fileName in files:
            fullpath = os.path.join(dirPath, fileName)

            if os.path.isdir(fullpath):
                numDirsDeleted += self.deleteEmptyDirectoriesUnder(fullpath)

        files = os.listdir(dirPath)

        if len(files) == 0:
            self._log.debug("Removing empty folder '%s'" % dirPath)
            os.rmdir(dirPath)
            numDirsDeleted += 1

            metaFilePath = dirPath + '/../' + os.path.basename(dirPath) + '.meta'

            if os.path.isfile(metaFilePath):
                self._log.debug("Removing meta file '%s'" % metaFilePath)
                os.remove(metaFilePath)

        return numDirsDeleted

    def fileExists(self, path):
        return os.path.isfile(self._varManager.expand(path))

    def directoryExists(self, dirPath):
        return os.path.exists(self._varManager.expand(dirPath))

    def copyDirectory(self, fromPath, toPath):
        fromPath = self._varManager.expand(fromPath)
        toPath = self._varManager.expand(toPath)

        self._log.debug("Copying directory '{0}' to '{1}'".format(fromPath, toPath))

        shutil.copytree(fromPath, toPath)

    def readFileAsText(self, path):
        with self.openInputFile(path) as f:
            return f.read()

    def writeFileAsText(self, path, text):
        with self.openOutputFile(path) as f:
            f.write(text)

    def openOutputFile(self, path):
        path = self._varManager.expand(path)
        self.makeMissingDirectoriesInPath(path)
        return open(path, 'w', encoding='utf-8', errors='ignore')

    def openInputFile(self, path):
        return open(self._varManager.expand(path), 'r', encoding='utf-8', errors='ignore')

    def removeFile(self, fileName):
        os.remove(self._varManager.expand(fileName))

    def removeFileIfExists(self, fileName):
        fullPath = self._varManager.expand(fileName)

        if os.path.isfile(fullPath):
            os.remove(fullPath)
            return True

        return False

    def findFilesByPattern(self, startDir, pattern):
        startDir = self._varManager.expand(startDir)

        for root, dirs, files in os.walk(startDir):
            for basename in files:
                if fnmatch.fnmatch(basename, pattern):
                    filename = os.path.join(root, basename)
                    yield filename

    def renameFile(self, currentName, newName):
        os.rename(self._varManager.expand(currentName), self._varManager.expand(newName))

    def removeFileWaitIfNecessary(self, fileName):
        outputPath = self._varManager.expand(fileName)

        if not os.path.isfile(outputPath):
            # File already removed
            return

        while True:
            try:
                os.remove(outputPath)
            except OSError:
                self._log.warn('Could not delete file at "{0}".  Waiting to try again...'.format(outputPath))
                time.sleep(5)
                continue
            break

    def removeByRegex(self, regex):
        regex = self._varManager.expand(regex)
        count = 0

        for filePath in glob(regex):
            os.unlink(filePath)
            count += 1

        self._log.debug("Removed %s files matching '%s'" % (count, regex))

    def makeMissingDirectoriesInPath(self, dirPath):
        dirPath = self._varManager.expand(dirPath)
        self._log.debug("Making missing directories in path '{0}'".format(dirPath))
        try:
            os.makedirs(os.path.dirname(dirPath))
        except:
            pass
예제 #12
0
class LogStreamConsole:
    _log = Inject('Logger')
    _sys = Inject('SystemHelper')
    _varManager = Inject('VarManager')
    _config = Inject('Config')

    def __init__(self, verbose, veryVerbose):
        self._verbose = verbose
        self._veryVerbose = veryVerbose

        self.headingPatterns = self._getPatterns('HeadingPatterns')
        self.headingMaps = self._getPatternMaps('HeadingPatternMaps')

        self.goodPatterns = self._getPatterns('GoodPatterns')
        self.goodMaps = self._getPatternMaps('GoodPatternMaps')

        self.infoPatterns = self._getPatterns('InfoPatterns')
        self.infoMaps = self._getPatternMaps('InfoPatternMaps')

        self.errorPatterns = self._getPatterns('ErrorPatterns')
        self.errorMaps = self._getPatternMaps('ErrorPatternMaps')

        self.warningPatterns = self._getPatterns('WarningPatterns')
        self.warningMaps = self._getPatternMaps('WarningPatternMaps')
        self.warningPatternsIgnore = self._getPatterns('WarningPatternsIgnore')

        self.debugPatterns = self._getPatterns('DebugPatterns')
        self.debugMaps = self._getPatternMaps('DebugPatternMaps')

        self._useColors = self._config.tryGetBool(False, 'Console',
                                                  'UseColors')

        self._fileStream = None
        if self._config.tryGetBool(False, 'Console', 'OutputToFilteredLog'):
            self._fileStream = self._getFileStream()

        if self._useColors:
            self._initColors()

    def _initColors(self):
        self._defaultColors = ColorConsole.get_text_attr()
        self._defaultBg = self._defaultColors & 0x0070
        self._defaultFg = self._defaultColors & 0x0007

    def log(self, logType, message):

        logType, message = self.classifyMessage(logType, message)

        if logType is not None:
            if logType == LogType.HeadingFailed or logType == LogType.Error:
                self._output(logType, message, sys.stderr, self._useColors)
            else:
                self._output(logType, message, sys.stdout, self._useColors)

            if self._fileStream:
                self._output(logType, message, self._fileStream, False)

    def _getFileStream(self):

        primaryPath = self._varManager.expand('[LogFilteredPath]')

        if not primaryPath:
            raise Exception("Could not find path for log file")

        previousPath = None
        if self._varManager.hasKey('LogFilteredPreviousPath'):
            previousPath = self._varManager.expand('[LogFilteredPreviousPath]')

        # Keep one old build log
        if os.path.isfile(primaryPath) and previousPath:
            shutil.copy2(primaryPath, previousPath)

        return open(primaryPath, 'w', encoding='utf-8', errors='ignore')

    def _output(self, logType, message, stream, useColors):

        stream.write('\n')

        if self._log.hasHeading and logType != LogType.Heading and logType != LogType.HeadingSucceeded and logType != LogType.HeadingFailed:
            stream.write('  ')

        if not useColors or logType == LogType.Info:
            stream.write(message)
            stream.flush()
        else:
            ColorConsole.set_text_attr(self._getColorAttrs(logType))
            stream.write(message)
            stream.flush()
            ColorConsole.set_text_attr(self._defaultColors)

    def _getColorAttrs(self, logType):
        if logType == LogType.Heading or logType == LogType.HeadingSucceeded:
            return ColorConsole.FOREGROUND_CYAN | self._defaultBg | ColorConsole.FOREGROUND_INTENSITY

        if logType == LogType.Good:
            return ColorConsole.FOREGROUND_GREEN | self._defaultBg | ColorConsole.FOREGROUND_INTENSITY

        if logType == LogType.Warn:
            return ColorConsole.FOREGROUND_YELLOW | self._defaultBg | ColorConsole.FOREGROUND_INTENSITY

        if logType == LogType.Error or logType == LogType.HeadingFailed:
            return ColorConsole.FOREGROUND_RED | self._defaultBg | ColorConsole.FOREGROUND_INTENSITY

        if logType == LogType.Debug:
            return ColorConsole.FOREGROUND_BLACK | self._defaultBg | ColorConsole.FOREGROUND_INTENSITY

        assertThat(False, 'Unrecognized log type "{0}"'.format(logType))

    def _getPatternMaps(self, settingName):
        maps = self._config.tryGetDictionary({}, 'Console', settingName)

        result = []
        for key, value in maps.items():
            regex = re.compile(key)
            logMap = LogMap(regex, value)
            result.append(logMap)

        return result

    def _getPatterns(self, settingName):
        patternStrings = self._config.tryGetList([], 'Console', settingName)

        result = []
        for pattern in patternStrings:
            result.append(re.compile('.*' + pattern + '.*'))

        return result

    def tryMatchPattern(self, message, maps, patterns):
        for logMap in maps:
            if logMap.regex.match(message):
                return logMap.regex.sub(logMap.sub, message)

        for pattern in patterns:
            match = pattern.match(message)

            if match:
                groups = match.groups()

                if len(groups) > 0:
                    return groups[0]

                return message

        return None

    def classifyMessage(self, logType, message):

        if logType == LogType.Info or logType == LogType.Heading or logType == LogType.HeadingFailed or logType == LogType.HeadingSucceeded or logType == LogType.Good or logType == LogType.Warn or logType == LogType.Error:
            return logType, message

        parsedMessage = self.tryMatchPattern(message, self.errorMaps,
                                             self.errorPatterns)
        if parsedMessage:
            return LogType.Error, parsedMessage

        if not any(p.match(message) for p in self.warningPatternsIgnore):
            parsedMessage = self.tryMatchPattern(message, self.warningMaps,
                                                 self.warningPatterns)
            if parsedMessage:
                return LogType.Warn, parsedMessage

        parsedMessage = self.tryMatchPattern(message, self.headingMaps,
                                             self.headingPatterns)
        if parsedMessage:
            return LogType.Heading, parsedMessage

        parsedMessage = self.tryMatchPattern(message, self.goodMaps,
                                             self.goodPatterns)
        if parsedMessage:
            return LogType.Good, parsedMessage

        parsedMessage = self.tryMatchPattern(message, self.infoMaps,
                                             self.infoPatterns)
        if parsedMessage:
            return LogType.Info, parsedMessage

        if self._verbose:
            parsedMessage = self.tryMatchPattern(message, self.debugMaps,
                                                 self.debugPatterns)
            if parsedMessage:
                return LogType.Debug, parsedMessage

        if self._veryVerbose:
            return LogType.Debug, message

        return None, message
class Test1:
    foo = Inject('Foo')
    bar = InjectOptional('Bar', 5)
예제 #14
0
class VarManager:
    _config = Inject('Config')
    '''
    Stores a dictionary of keys to values to replace path variables with
    '''
    def __init__(self, initialParams=None):
        self._params = initialParams if initialParams else {}
        self._params['StartCurrentDir'] = os.getcwd()
        self._params['ExecDir'] = MiscUtil.getExecDirectory().replace(
            '\\', '/')

        # We could just call self._config.getDictionary('PathVars') here but
        # then we wouldn't be able to use fallback (?) and override (!) characters in
        # our config

        self._regex = re.compile('^([^\[]*)(\[[^\]]*\])(.*)$')

    def hasKey(self, key):
        return key in self._params or self._config.tryGet('PathVars',
                                                          key) != None

    def get(self, key):
        if key in self._params:
            return self._params[key]

        return self._config.getString('PathVars', key)

    def tryGet(self, key):
        if key in self._params:
            return self._params[key]

        return self._config.tryGetString(None, 'PathVars', key)

    def set(self, key, value):
        self._params[key] = value

    def expandPath(self, text, extraVars=None):
        ''' Same as expand() except it cleans up the path to remove ../ '''
        return os.path.realpath(self.expand(text, extraVars))

    def expand(self, text, extraVars=None):

        if not extraVars:
            extraVars = {}

        allArgs = self._params.copy()
        allArgs.update(extraVars)

        while True:
            match = self._regex.match(text)

            if not match:
                break

            prefix = match.group(1)
            var = match.group(2)
            suffix = match.group(3)

            var = var[1:-1]

            if var in allArgs:
                replacement = allArgs[var]
            else:
                replacement = self.get(var)

            text = prefix + replacement + suffix

        if '[' in text:
            raise Exception(
                "Unable to find all keys in path '{0}'".format(text))

        return text
예제 #15
0
class UnityHelper:
    _log = Inject('Logger')
    _sys = Inject('SystemHelper')
    _varMgr = Inject('VarManager')

    def __init__(self):
        pass

    def onUnityLog(self, logStr):
        self._log.debug(logStr)

    def openUnity(self, projectPath, platform):
        self._sys.executeNoWait(
            '"[UnityExePath]" -buildTarget {0} -projectPath "{1}"'.format(
                self._getBuildTargetArg(platform), projectPath))

    def runEditorFunction(self,
                          projectPath,
                          editorCommand,
                          platform=Platforms.Windows,
                          batchMode=True,
                          quitAfter=True,
                          extraExtraArgs=''):
        extraArgs = ''

        if quitAfter:
            extraArgs += ' -quit'

        if batchMode:
            extraArgs += ' -batchmode -nographics'

        extraArgs += ' ' + extraExtraArgs

        self.runEditorFunctionRaw(projectPath, editorCommand, platform,
                                  extraArgs)

    def _getBuildTargetArg(self, platform):

        if platform == Platforms.Windows:
            return 'win32'

        if platform == Platforms.WebPlayer:
            return 'web'

        if platform == Platforms.Android:
            return 'android'

        if platform == Platforms.WebGl:
            return 'WebGl'

        if platform == Platforms.OsX:
            return 'osx'

        if platform == Platforms.Linux:
            return 'linux'

        if platform == Platforms.Ios:
            return 'ios'

        if platform == Platforms.WindowsStoreApp:
            return 'wsa'

        assertThat(False, "Unhandled platform {0}".format(platform))

    def runEditorFunctionRaw(self, projectPath, editorCommand, platform,
                             extraArgs):

        logPath = self._varMgr.expandPath(UnityLogFileLocation)

        logWatcher = LogWatcher(logPath, self.onUnityLog)
        logWatcher.start()

        assertThat(self._varMgr.hasKey('UnityExePath'),
                   "Could not find path variable 'UnityExePath'")

        try:
            command = '"[UnityExePath]" -buildTarget {0} -projectPath "{1}"'.format(
                self._getBuildTargetArg(platform), projectPath)

            if editorCommand:
                command += ' -executeMethod ' + editorCommand

            command += ' ' + extraArgs

            self._sys.executeAndWait(command)

        except ProcessErrorCodeException as e:
            raise UnityReturnedErrorCodeException(
                "Error while running Unity!  Command returned with error code."
            )

        except:
            raise UnityUnknownErrorException(
                "Unknown error occurred while running Unity!")

        finally:
            logWatcher.stop()

            while not logWatcher.isDone:
                time.sleep(0.1)