def Run(appFlowFactory: AToolAppFlowFactory,
        allowStandaloneMode: bool = False) -> None:
    strToolAppTitle = "{0} V{1} Build {2}".format(appFlowFactory.GetTitle(),
                                                  CurrentVersionString,
                                                  CurrentBuildString)
    appShortDesc = appFlowFactory.GetShortDesc()
    if appShortDesc is not None:
        strToolAppTitle = "{0} - {1}".format(strToolAppTitle, appShortDesc)

    toolCommonArgConfig = appFlowFactory.GetToolCommonArgConfig()

    lowLevelToolConfig = __EarlyArgumentParser(allowStandaloneMode)
    if lowLevelToolConfig is None:
        sys.exit(1)

    if not lowLevelToolConfig.ProfilerEnabled:
        if not lowLevelToolConfig.StandaloneEnabled:
            __Run(appFlowFactory, strToolAppTitle, toolCommonArgConfig,
                  lowLevelToolConfig, allowStandaloneMode)
        else:
            __RunStandalone(appFlowFactory, strToolAppTitle,
                            toolCommonArgConfig, lowLevelToolConfig)
    else:
        try:
            import cProfile
            import pstats

            if not lowLevelToolConfig.StandaloneEnabled:
                cProfile.runctx(
                    '__Run(appFlowFactory, strToolAppTitle, toolCommonArgConfig, lowLevelToolConfig, allowStandaloneMode)',
                    globals(), locals(), 'restats')
            else:
                cProfile.runctx(
                    '__RunStandalone(appFlowFactory, strToolAppTitle, toolCommonArgConfig, lowLevelToolConfig)',
                    globals(), locals(), 'restats')
            p = pstats.Stats('restats')
            p.strip_dirs().sort_stats(-1)
            p.print_stats()
            p.sort_stats('cumulative')
            p.print_stats(10)
            p.sort_stats('time')
            p.print_stats(10)
            p.sort_stats('tottime')
            p.print_stats(100)
        except ImportError:
            raise Exception(
                "Standard python package cProfile or pstats is not available. So profiling is not available."
            )
def __Run(appFlowFactory: AToolAppFlowFactory, strToolAppTitle: str,
          toolCommonArgConfig: ToolCommonArgConfig,
          lowLevelToolConfig: LowLevelToolConfig,
          allowStandaloneMode: bool) -> None:

    log = Log(strToolAppTitle,
              lowLevelToolConfig.VerbosityLevel,
              showAppTitleIfVerbose=True)

    generatorIds = __PrepareGeneratorPlugins(lowLevelToolConfig,
                                             toolCommonArgConfig)

    try:
        defaultPlatform = DetectBuildPlatform()
    except (Exception) as ex:
        print("ERROR: {0}".format(ex))
        if lowLevelToolConfig.DebugEnabled:
            raise
        sys.exit(1)

    ### Do the actual command line parsing
    parser = __CreateParser(toolCommonArgConfig, allowStandaloneMode)
    if toolCommonArgConfig.AddPlatformArg:
        parser.add_argument('-p',
                            '--platform',
                            default=defaultPlatform,
                            help='Select build platform: {0}'.format(
                                ", ".join(generatorIds)))
    if toolCommonArgConfig.AllowForceClaimInstallArea:
        parser.add_argument(
            '--ForceClaimInstallArea',
            action='store_true',
            help=
            'Override the security checks on the install area allowing us to use it even though its not empty. This means the existing content can be lost.'
        )

    #parser.add_argument('--NativeGen', action='store_true',  help='Force use the native build generator')

    toolConfig = None
    baseConfig = None
    try:
        basicConfig = BasicConfig(log)
        currentDir = lowLevelToolConfig.CurrentDir

        # Try to locate a project root configuration file
        projectRootConfig = GetProjectRootConfig(lowLevelToolConfig,
                                                 basicConfig, currentDir)
        toolConfigFile = projectRootConfig.ToolConfigFile

        # Get the path to the toolconfig file if necessary and load the tool config file
        toolConfigPath = __GetToolConfigPath(toolConfigFile)
        toolConfig = ToolConfig(basicConfig, toolConfigPath, projectRootConfig)
        baseConfig = BaseConfig(log, toolConfig)
    except (Exception) as ex:
        print("ERROR: {0}".format(ex))
        if lowLevelToolConfig.DebugEnabled:
            raise
        sys.exit(1)

    buildTiming = None
    try:
        defaultVSVersion = toolConfig.GetVisualStudioDefaultVersion()
        #if toolCommonArgConfig.AllowVSVersion:
        parser.add_argument(
            '--VSVersion',
            default=str(defaultVSVersion),
            help=
            'Choose a specific visual studio version (2015,2017), This project defaults to: {0}'
            .format(defaultVSVersion))

        userTag = appFlowFactory.CreateUserTag(baseConfig)
        appFlowFactory.AddCustomArguments(parser, toolConfig, userTag)

        args = parser.parse_args()

        #if toolCommonArgConfig.AllowVSVersion:
        PluginConfig.SetVSVersion(args.VSVersion)

        #if toolCommonArgConfig.AddPlatformArg and args.platform.lower() != PluginSharedValues.PLATFORM_ID_ALL:
        #PluginConfig.SetForceUseNativeGenerator(True)
        #PluginConfig.SetForceUseNativeGenerator(args.NativeGen)

        if toolCommonArgConfig.ProcessRemainingArgs:
            args.RemainingArgs = __ProcessRemainingArgs(args.RemainingArgs)
        if toolCommonArgConfig.SupportBuildTime and args.BuildTime:
            buildTiming = BuildTimer()

        if toolCommonArgConfig.AddBuildFiltering and args.Recipes == DefaultValue.Recipes:
            if projectRootConfig.XmlExperimental is not None:
                tmpResult = projectRootConfig.XmlExperimental.TryGetRecipesDefaultValue(
                    defaultPlatform)
                if tmpResult is not None:
                    args.Recipes = "[{0}]".format(tmpResult)

        toolAppConfig = __CreateToolAppConfig(args, defaultPlatform,
                                              toolCommonArgConfig,
                                              defaultVSVersion)
        toolAppContext = ToolAppContext(log, lowLevelToolConfig, toolAppConfig)
        toolAppFlow = appFlowFactory.Create(toolAppContext)
        toolAppFlow.ProcessFromCommandLine(args, currentDir, toolConfig,
                                           userTag)

        if buildTiming:
            PrintBuildTiming(buildTiming)
    except GroupedException as ex:
        if buildTiming:
            PrintBuildTiming(buildTiming)
        for entry in ex.ExceptionList:
            print("ERROR: {0}".format(entry))
        if lowLevelToolConfig.DebugEnabled:
            raise
        for entry in ex.ExceptionList:
            if isinstance(entry, ExitException):
                sys.exit(entry.ExitCode)
        sys.exit(1)
    except AggregateException as ex:
        if buildTiming:
            PrintBuildTiming(buildTiming)
        for entry in ex.ExceptionList:
            print("ERROR: {0}".format(entry))
        if lowLevelToolConfig.DebugEnabled:
            if len(ex.ExceptionList) > 0:
                raise ex.ExceptionList[0]
            raise
        for entry in ex.ExceptionList:
            if isinstance(entry, ExitException):
                sys.exit(entry.ExitCode)
        sys.exit(1)
    except ExitException as ex:
        sys.exit(ex.ExitCode)
    except Exception as ex:
        if buildTiming:
            PrintBuildTiming(buildTiming)
        print("ERROR: {0}".format(ex))
        if lowLevelToolConfig.DebugEnabled:
            raise
        sys.exit(1)
def __RunStandalone(appFlowFactory: AToolAppFlowFactory, strToolAppTitle: str,
                    toolCommonArgConfig: ToolCommonArgConfig,
                    lowLevelToolConfig: LowLevelToolConfig) -> None:
    log = Log(strToolAppTitle,
              lowLevelToolConfig.VerbosityLevel,
              showAppTitleIfVerbose=True)

    generatorIds = __PrepareGeneratorPlugins(lowLevelToolConfig,
                                             toolCommonArgConfig)

    ### Do the actual command line parsing
    parser = __CreateParser(toolCommonArgConfig, True)
    if toolCommonArgConfig.AddPlatformArg:
        parser.add_argument('-p',
                            '--platform',
                            required=True,
                            help='Select build platform: {0}'.format(
                                ", ".join(generatorIds)))

    buildTiming = None
    try:
        userTag = appFlowFactory.CreateStandaloneUserTag()
        appFlowFactory.AddCustomStandaloneArguments(parser, userTag)

        args = parser.parse_args()

        if toolCommonArgConfig.ProcessRemainingArgs:
            args.RemainingArgs = __ProcessRemainingArgs(args.RemainingArgs)
        if toolCommonArgConfig.SupportBuildTime and args.BuildTime:
            buildTiming = BuildTimer()

        currentDir = lowLevelToolConfig.CurrentDir

        toolAppConfig = __CreateToolAppConfig(args, args.platform,
                                              toolCommonArgConfig, 0)
        toolAppContext = ToolAppContext(log, lowLevelToolConfig, toolAppConfig)
        toolAppFlow = appFlowFactory.Create(toolAppContext)

        toolAppFlow.ProcessFromStandaloneCommandLine(args, currentDir, userTag)

        if buildTiming:
            PrintBuildTiming(buildTiming)
    except GroupedException as ex:
        if buildTiming:
            PrintBuildTiming(buildTiming)
        for entry in ex.ExceptionList:
            print("ERROR: {0}".format(entry))
        if lowLevelToolConfig.DebugEnabled:
            raise
        for entry in ex.ExceptionList:
            if isinstance(entry, ExitException):
                sys.exit(entry.ExitCode)
        sys.exit(1)
    except AggregateException as ex:
        if buildTiming:
            PrintBuildTiming(buildTiming)
        for entry in ex.ExceptionList:
            print("ERROR: {0}".format(entry))
        if lowLevelToolConfig.DebugEnabled:
            if len(ex.ExceptionList) > 0:
                raise ex.ExceptionList[0]
            raise
        for entry in ex.ExceptionList:
            if isinstance(entry, ExitException):
                sys.exit(entry.ExitCode)
        sys.exit(1)
    except ExitException as ex:
        sys.exit(ex.ExitCode)
    except Exception as ex:
        if buildTiming:
            PrintBuildTiming(buildTiming)
        print("ERROR: {0}".format(ex))
        if lowLevelToolConfig.DebugEnabled:
            raise
        sys.exit(1)