def PostBuild(self):
        edk2_logging.log_progress("Running Post Build")
        #
        # Run the platform post-build steps.
        #
        ret = self.PlatformPostBuild()

        if (ret != 0):
            logging.critical("PlatformPostBuild failed %d" % ret)
            return ret

        #
        # run all loaded UefiBuild Plugins
        #
        for Descriptor in self.pm.GetPluginsOfClass(IUefiBuildPlugin):
            rc = Descriptor.Obj.do_post_build(self)
            if (rc != 0):
                if (rc is None):
                    logging.error("Plugin Failed: %s returned NoneType" %
                                  Descriptor.Name)
                    ret = -1
                else:
                    logging.error("Plugin Failed: %s returned %d" %
                                  (Descriptor.Name, rc))
                    ret = rc
                break  # fail on plugin error
            else:
                logging.debug("Plugin Success: %s" % Descriptor.Name)

        return ret
    def CleanTree(self, RemoveConfTemplateFilesToo=False):
        ret = 0
        # loop thru each build target set.
        edk2_logging.log_progress("Cleaning All Output for Build")

        d = self.env.GetValue("BUILD_OUTPUT_BASE")
        if (os.path.isdir(d)):
            logging.debug("Removing [%s]", d)
            # if the folder is opened in Explorer do not fail the entire Rebuild
            try:
                shutil.rmtree(d)
            except WindowsError as wex:
                logging.debug(wex)

        else:
            logging.debug("Directory [%s] already clean" % d)

        # delete the conf .dbcache
        # this needs to be removed in case build flags changed
        d = os.path.join(self.ws, "Conf", ".cache")
        if (os.path.isdir(d)):
            shutil.rmtree(d)
            logging.debug("Removing [%s]" % d)

        if (RemoveConfTemplateFilesToo):
            for a in ["target.txt", "build_rule.txt", "tools_def.txt"]:
                d = os.path.join(self.ws, "Conf", a)
                if (os.path.isfile(d)):
                    os.remove(d)
                    logging.debug("Removing [%s]" % d)

        return ret
    def Build(self):
        BuildType = self.env.GetValue("TARGET")
        edk2_logging.log_progress("Running Build %s" % BuildType)

        # set target, arch, toolchain, threads, and platform
        params = "-p " + self.env.GetValue("ACTIVE_PLATFORM")
        params += " -b " + BuildType
        params += " -t " + self.env.GetValue("TOOL_CHAIN_TAG")
        # Thread number is now optional and not set in default tianocore target.txt
        if self.env.GetValue("MAX_CONCURRENT_THREAD_NUMBER") is not None:
            params += " -n " + self.env.GetValue(
                "MAX_CONCURRENT_THREAD_NUMBER")

        # Set the arch flags.  Multiple are split by space
        rt = self.env.GetValue("TARGET_ARCH").split(" ")
        for t in rt:
            params += " -a " + t

        # get the report options and setup the build command
        if (self.env.GetValue("BUILDREPORTING") == "TRUE"):
            params += " -y " + self.env.GetValue("BUILDREPORT_FILE")
            rt = self.env.GetValue("BUILDREPORT_TYPES").split(" ")
            for t in rt:
                params += " -Y " + t

        # add special processing to handle building a single module
        mod = self.env.GetValue("BUILDMODULE")
        if (mod is not None and len(mod.strip()) > 0):
            params += " -m " + mod
            edk2_logging.log_progress("Single Module Build: " + mod)
            self.SkipPostBuild = True
            self.FlashImage = False

        # attach the generic build vars
        buildvars = self.env.GetAllBuildKeyValues(BuildType)
        for key, value in buildvars.items():
            params += " -D " + key + "=" + value
        output_stream = edk2_logging.create_output_stream()

        env = shell_environment.ShellEnvironment()
        # WORKAROUND - Pin the PYTHONHASHSEED so that TianoCore build tools
        #               have consistent ordering. Addresses incremental builds.
        pre_build_env_chk = env.checkpoint()
        env.set_shell_var('PYTHONHASHSEED', '0')
        env.log_environment()
        ret = RunCmd("build", params)
        # WORKAROUND - Undo the workaround.
        env.restore_checkpoint(pre_build_env_chk)

        problems = edk2_logging.scan_compiler_output(output_stream)
        edk2_logging.remove_output_stream(output_stream)
        for level, problem in problems:
            logging.log(level, problem)

        if (ret != 0):
            return ret

        return 0
示例#4
0
    def Go(self):
        ret = 0
        env = shell_environment.GetBuildVars()
        env.SetValue("PRODUCT_NAME", self.PlatformSettings.GetName(),
                     "Platform Hardcoded")
        env.SetValue("BLD_*_BUILDID_STRING", "201905", "Current Version")
        env.SetValue("BUILDREPORTING", "TRUE", "Platform Hardcoded")
        env.SetValue("BUILDREPORT_TYPES", 'PCD DEPEX LIBRARY BUILD_FLAGS',
                     "Platform Hardcoded")

        # make sure python_command is set
        python_command = sys.executable
        if " " in python_command:
            python_command = '"' + python_command + '"'
        shell_environment.GetEnvironment().set_shell_var(
            "PYTHON_COMMAND", python_command)

        # Run pre build hook
        ret += self.PlatformSettings.PreFirstBuildHook()
        ws = self.GetWorkspaceRoot()
        pp = self.PlatformSettings.GetModulePkgsPath()
        # run each configuration
        ret = 0
        try:
            for config in self.PlatformSettings.GetConfigurations():
                pre_ret = self.PlatformSettings.PreBuildHook(
                )  # run pre build hook
                if pre_ret != 0:
                    ret = pre_ret
                    raise RuntimeError("We failed in prebuild hook")
                edk2_logging.log_progress(f"--Running next configuration--")
                logging.info(config)
                shell_environment.CheckpointBuildVars(
                )  # checkpoint our config
                env = shell_environment.GetBuildVars()
                # go through the config and apply to environement
                for key in config:
                    env.SetValue(key, config[key], "provided by configuration")
                # make sure to set this after in case the config did
                env.SetValue("TOOL_CHAIN_TAG", "VS2017", "provided by builder")
                platformBuilder = UefiBuilder()  # create our builder
                build_ret = platformBuilder.Go(ws, pp, self.helper,
                                               self.plugin_manager)
                # we always want to run the post build hook
                post_ret = self.PlatformSettings.PostBuildHook(ret)
                if build_ret != 0:
                    ret = build_ret
                    raise RuntimeError("We failed in build")
                if post_ret != 0:
                    ret = post_ret
                    raise RuntimeError("We failed in postbuild hook")
                shell_environment.RevertBuildVars()
        except RuntimeError:
            pass
        finally:
            # make sure to do our final build hook
            self.PlatformSettings.PostFinalBuildHook(ret)
        return ret
示例#5
0
    def Invoke(self):
        ''' Main process function.  Should not need to be overwritten '''

        self.ParseCommandLineOptions()
        self.ConfigureLogging()
        self.InputParametersConfiguredCallback()

        logging.log(edk2_logging.SECTION, "Init SDE")

        #
        # Next, get the environment set up.
        #
        (build_env,
         shell_env) = self_describing_environment.BootstrapEnvironment(
             self.GetWorkspaceRoot(), self.GetActiveScopes())

        # Make sure the environment verifies IF it is required for this invocation
        if self.GetVerifyCheckRequired(
        ) and not self_describing_environment.VerifyEnvironment(
                self.GetWorkspaceRoot(), self.GetActiveScopes()):
            raise RuntimeError(
                "SDE is not current.  Please update your env before running this tool."
            )

        # Load plugins
        logging.log(edk2_logging.SECTION, "Loading Plugins")

        self.plugin_manager = plugin_manager.PluginManager()
        failedPlugins = self.plugin_manager.SetListOfEnvironmentDescriptors(
            build_env.plugins)
        if failedPlugins:
            logging.critical(
                "One or more plugins failed to load. Halting build.")
            for a in failedPlugins:
                logging.error("Failed Plugin: {0}".format(a["name"]))
            raise Exception("One or more plugins failed to load.")

        self.helper = HelperFunctions()
        if (self.helper.LoadFromPluginManager(self.plugin_manager) > 0):
            raise Exception("One or more helper plugins failed to load.")

        logging.log(edk2_logging.SECTION, "Start Invocable Tool")
        retcode = self.Go()
        logging.log(edk2_logging.SECTION, "Summary")
        if (retcode != 0):
            edk2_logging.log_progress("Error")
        else:
            edk2_logging.log_progress("Success")

        logging.shutdown()
        sys.exit(retcode)
    def Go(self):
        required_submodules = self.PlatformSettings.GetRequiredSubmodules()
        workspace_path = self.GetWorkspaceRoot()
        # Make sure git is installed
        return_buffer = StringIO()
        RunCmd("git",
               "--version",
               outstream=return_buffer,
               raise_exception_on_nonzero=True)
        git_version = return_buffer.getvalue().strip()
        return_buffer.close()
        version_aggregator.GetVersionAggregator().ReportVersion(
            "Git", git_version, version_aggregator.VersionTypes.TOOL)
        min_git = "2.11.0"
        # This code is highly specific to the return value of "git version"...
        cur_git = ".".join(git_version.split(' ')[2].split(".")[:3])
        if version_compare(min_git, cur_git) > 0:
            raise RuntimeError(
                "Please upgrade Git! Current version is %s. Minimum is %s." %
                (cur_git, min_git))

        # Pre-setup cleaning if "--force" is specified.
        if self.force_it:
            try:
                # Clean and reset the main repo.
                edk2_logging.log_progress("## Cleaning the root repo...")
                RunCmd("git",
                       "reset --hard",
                       workingdir=workspace_path,
                       logging_level=logging.DEBUG,
                       raise_exception_on_nonzero=True)
                # Because logging is running right now, we have to skip the files that are open.
                ignore_files = "-e Build/%s.txt -e Build/%s.md" % (
                    self.GetLoggingFileName('txt'),
                    self.GetLoggingFileName('md'))
                RunCmd("git",
                       "clean -xffd %s" % ignore_files,
                       workingdir=workspace_path,
                       logging_level=logging.DEBUG,
                       raise_exception_on_nonzero=True)
                edk2_logging.log_progress("Done.\n")

                # Clean any submodule repos.
                if required_submodules:
                    for required_submodule in required_submodules:
                        edk2_logging.log_progress(
                            "## Cleaning Git repository: %s..." %
                            required_submodule.path)
                        required_submodule_path = os.path.normpath(
                            os.path.join(workspace_path,
                                         required_submodule.path))
                        RunCmd("git",
                               "reset --hard",
                               workingdir=required_submodule_path,
                               logging_level=logging.DEBUG,
                               raise_exception_on_nonzero=True)
                        RunCmd("git",
                               "clean -xffd",
                               workingdir=required_submodule_path,
                               logging_level=logging.DEBUG,
                               raise_exception_on_nonzero=True)

                        edk2_logging.log_progress("Done.\n")

            except RuntimeError as e:
                logging.error("FAILED!\n")
                logging.error("Error while trying to clean the environment!")
                logging.error(str(e))
                return

        # Grab the remaining Git repos.
        if required_submodules and len(required_submodules) > 0:

            # Git Repos: STEP 1 --------------------------------------
            # Make sure that the repos are all synced.
            try:
                submodule_string = " ".join(
                    [x.path for x in required_submodules])
                edk2_logging.log_progress(
                    f"## Syncing Git repositories: {submodule_string}...")
                RunCmd("git",
                       f'submodule sync -- {submodule_string}',
                       workingdir=workspace_path,
                       logging_level=logging.DEBUG,
                       raise_exception_on_nonzero=True)

                edk2_logging.log_progress("Done.\n")
            except RuntimeError as e:
                logging.error("FAILED!\n")
                logging.error(
                    "Error while trying to synchronize the environment!")
                logging.error(str(e))
                return

            # Git Repos: STEP 2 --------------------------------------
            # Iterate through all repos and see whether they should be fetched.
            for required_submodule in required_submodules:
                try:
                    edk2_logging.log_progress(
                        f"## Checking Git repository: {required_submodule.path}..."
                    )

                    # Git Repos: STEP 2a ---------------------------------
                    # Need to determine whether to skip this repo.
                    required_submodule_path = os.path.normpath(
                        os.path.join(workspace_path, required_submodule.path))
                    skip_repo = False
                    # If the repo exists (and we're not forcing things) make
                    # sure that it's not in a "dirty" state.
                    if os.path.exists(
                            required_submodule_path) and not self.force_it:
                        return_buffer = StringIO()
                        RunCmd("git",
                               'diff ' + required_submodule.path,
                               outstream=return_buffer,
                               workingdir=workspace_path,
                               logging_level=logging.DEBUG,
                               raise_exception_on_nonzero=True)
                        git_data = return_buffer.getvalue().strip()
                        return_buffer.close()
                        # If anything was returned, we should skip processing the repo.
                        # It is either on a different commit or it has local changes.
                        if git_data != "":
                            logging.info(
                                "-- NOTE: Repo currently exists and appears to have local changes!"
                            )
                            logging.info("-- Skipping fetch!")
                            skip_repo = True

                    # Git Repos: STEP 2b ---------------------------------
                    # If we're not skipping, grab it.
                    if not skip_repo or self.force_it:
                        logging.info("## Fetching repo.")
                        cmd_string = "submodule update --init"
                        if required_submodule.recursive:
                            cmd_string += " --recursive"
                        cmd_string += " --progress"
                        if self.omnicache_path is not None:
                            cmd_string += " --reference " + self.omnicache_path
                        cmd_string += " " + required_submodule.path
                        ret = RunCmd('git',
                                     cmd_string,
                                     workingdir=workspace_path,
                                     logging_level=logging.DEBUG,
                                     raise_exception_on_nonzero=False)
                        if ret != 0:
                            logging.error("We failed to fetch " +
                                          required_submodule)
                            raise RuntimeError(
                                "Unable to checkout repo due to error")

                    edk2_logging.log_progress("Done.\n")

                except RuntimeError as e:
                    logging.error("FAILED!\n")
                    logging.error("Failed to fetch required repository!\n")
                    logging.error(str(e))

        return 0
    def Go(self):
        log_directory = os.path.join(self.GetWorkspaceRoot(),
                                     self.GetLoggingFolderRelativeToRoot())

        # SET PACKAGE PATH
        #
        # Get Package Path from config file
        pplist = self.PlatformSettings.GetPackagesPath(
        ) if self.PlatformSettings.GetPackagesPath() else []

        # Check Dependencies for Repo
        for dependency in self.PlatformSettings.GetDependencies():
            pplist.append(dependency["Path"])

        # make Edk2Path object to handle all path operations
        try:
            edk2path = Edk2Path(self.GetWorkspaceRoot(), pplist)
        except Exception as e:
            logging.error(
                "You need to run stewart_ci_setup to resolve all repos.")
            raise e

        logging.info(f"Running CI Build: {self.PlatformSettings.GetName()}")
        logging.info(f"WorkSpace: {self.GetWorkspaceRoot()}")
        logging.info(
            f"Package Path: {self.PlatformSettings.GetPackagesPath()}")
        # logging.info("mu_build version: {0}".format(pkg_resources.get_distribution("mu_build").version))
        # logging.info("mu_python_library version: " + pkg_resources.get_distribution("mu_python_library").version)
        # logging.info("mu_environment version: " + pkg_resources.get_distribution("mu_environment").version)
        # Bring up the common minimum environment.
        logging.log(edk2_logging.SECTION, "Getting Enviroment")
        (build_env,
         shell_env) = self_describing_environment.BootstrapEnvironment(
             self.GetWorkspaceRoot(), self.GetActiveScopes())
        env = shell_environment.GetBuildVars()

        # Bind our current execution environment into the shell vars.
        ph = os.path.dirname(sys.executable)
        if " " in ph:
            ph = '"' + ph + '"'
        shell_env.set_shell_var("PYTHON_HOME", ph)
        # PYTHON_COMMAND is required to be set for using edk2 python builds.
        # todo: work with edk2 to remove the bat file and move to native python calls
        pc = sys.executable
        if " " in pc:
            pc = '"' + pc + '"'
        shell_env.set_shell_var("PYTHON_COMMAND", pc)

        archSupported = " ".join(self.PlatformSettings.GetArchSupported())
        env.SetValue("TARGET_ARCH", archSupported,
                     "from PlatformSettings.GetArchSupported()")

        _targets = " ".join(self.PlatformSettings.GetTargetsSupported())

        # Generate consumable XML object- junit format
        JunitReport = JunitTestReport()

        # Keep track of failures
        failure_num = 0
        total_num = 0

        # Load plugins
        logging.log(edk2_logging.SECTION, "Loading plugins")

        pluginList = self.plugin_manager.GetPluginsOfClass(ICiBuildPlugin)
        if len(self.packageList) == 0:
            self.packageList.extend(self.PlatformSettings.GetPackages())

        for pkgToRunOn in self.packageList:
            #
            # run all loaded Edk2CiBuild Plugins/Tests
            #
            logging.log(edk2_logging.SECTION, f"Building {pkgToRunOn} Package")
            logging.info(f"Running on Package: {pkgToRunOn}")
            ts = JunitReport.create_new_testsuite(
                pkgToRunOn,
                f"Edk2CiBuild.{self.PlatformSettings.GetGroupName()}.{pkgToRunOn}"
            )
            packagebuildlog_path = os.path.join(log_directory, pkgToRunOn)
            _, txthandle = edk2_logging.setup_txt_logger(
                packagebuildlog_path,
                f"BUILDLOG_{pkgToRunOn}",
                logging_level=logging.DEBUG,
                isVerbose=True)
            _, mdhandle = edk2_logging.setup_markdown_logger(
                packagebuildlog_path,
                f"BUILDLOG_{pkgToRunOn}",
                logging_level=logging.DEBUG,
                isVerbose=True)
            loghandle = [txthandle, mdhandle]
            shell_environment.CheckpointBuildVars()
            env = shell_environment.GetBuildVars()

            # load the package level .mu.json
            pkg_config_file = edk2path.GetAbsolutePathOnThisSytemFromEdk2RelativePath(
                os.path.join(pkgToRunOn, pkgToRunOn + ".mu.yaml"))
            if (pkg_config_file):
                with open(pkg_config_file, 'r') as f:
                    pkg_config = yaml.safe_load(f)
            else:
                logging.info(f"No Pkg Config file for {pkgToRunOn}")
                pkg_config = dict()

            # check the resulting configuration
            config_validator.check_package_confg(pkgToRunOn, pkg_config,
                                                 pluginList)

            # get all the defines from the package configuration
            if "Defines" in pkg_config:
                for definition_key in pkg_config["Defines"]:
                    definition = pkg_config["Defines"][definition_key]
                    env.SetValue(definition_key, definition,
                                 "Edk2CiBuild.py from PkgConfig yaml", False)

            for Descriptor in pluginList:
                # Get our targets
                targets = ["DEBUG"]
                if Descriptor.Obj.IsTargetDependent() and _targets:
                    targets = self.PlatformSettings.GetTargetsSupported()

                for target in targets:
                    edk2_logging.log_progress(
                        f"--Running {pkgToRunOn}: {Descriptor.Name} {target} --"
                    )
                    total_num += 1
                    shell_environment.CheckpointBuildVars()
                    env = shell_environment.GetBuildVars()

                    env.SetValue("TARGET", target,
                                 "Edk2CiBuild.py before RunBuildPlugin")
                    (testcasename, testclassname) = Descriptor.Obj.GetTestName(
                        pkgToRunOn, env)
                    tc = ts.create_new_testcase(testcasename, testclassname)

                    # create the stream for the build log
                    plugin_output_stream = edk2_logging.create_output_stream()

                    # merge the repo level and package level for this specific plugin
                    pkg_plugin_configuration = merge_config(
                        self.PlatformSettings.GetPluginSettings(), pkg_config,
                        Descriptor.descriptor)

                    # perhaps we should ask the validator to run on the package for this target

                    # Still need to see if the package decided this should be skipped
                    if pkg_plugin_configuration is None or\
                            "skip" in pkg_plugin_configuration and pkg_plugin_configuration["skip"]:
                        tc.SetSkipped()
                        edk2_logging.log_progress(
                            "--->Test Skipped by package! %s" %
                            Descriptor.Name)

                    else:
                        try:
                            #   - package is the edk2 path to package.  This means workspace/packagepath relative.
                            #   - edk2path object configured with workspace and packages path
                            #   - any additional command line args
                            #   - RepoConfig Object (dict) for the build
                            #   - PkgConfig Object (dict)
                            #   - EnvConfig Object
                            #   - Plugin Manager Instance
                            #   - Plugin Helper Obj Instance
                            #   - testcase Object used for outputing junit results
                            #   - output_stream the StringIO output stream from this plugin
                            rc = Descriptor.Obj.RunBuildPlugin(
                                pkgToRunOn, edk2path, pkg_plugin_configuration,
                                env, self.plugin_manager, self.helper, tc,
                                plugin_output_stream)
                        except Exception as exp:
                            exc_type, exc_value, exc_traceback = sys.exc_info()
                            logging.critical("EXCEPTION: {0}".format(exp))
                            exceptionPrint = traceback.format_exception(
                                type(exp), exp, exc_traceback)
                            logging.critical(" ".join(exceptionPrint))
                            tc.SetError("Exception: {0}".format(exp),
                                        "UNEXPECTED EXCEPTION")
                            rc = 1

                        if (rc != 0):
                            failure_num += 1
                            if (rc is None):
                                logging.error(
                                    "--->Test Failed: %s returned NoneType" %
                                    Descriptor.Name)
                            else:
                                logging.error(
                                    "--->Test Failed: %s returned %d" %
                                    (Descriptor.Name, rc))
                        else:
                            edk2_logging.log_progress(
                                f"--->Test Success {Descriptor.Name} {target}")

                    # revert to the checkpoint we created previously
                    shell_environment.RevertBuildVars()
                    # remove the logger
                    edk2_logging.remove_output_stream(plugin_output_stream)
                # finished target loop
            # Finished plugin loop

            edk2_logging.stop_logging(
                loghandle)  # stop the logging for this particular buildfile
            shell_environment.RevertBuildVars()
        # Finished buildable file loop

        JunitReport.Output(
            os.path.join(self.GetWorkspaceRoot(), "Build", "TestSuites.xml"))

        # Print Overall Success
        if (failure_num != 0):
            logging.error("Overall Build Status: Error")
            edk2_logging.log_progress(
                f"There were {failure_num} failures out of {total_num} attempts"
            )
        else:
            edk2_logging.log_progress("Overall Build Status: Success")

        return failure_num
    def Go(self):
        log_directory = os.path.join(self.GetWorkspaceRoot(),
                                     self.GetLoggingFolderRelativeToRoot())

        Edk2CiBuild.collect_python_pip_info()

        #
        # Get Package Path from config file
        pplist = self.PlatformSettings.GetPackagesPath(
        ) if self.PlatformSettings.GetPackagesPath() else []

        # make Edk2Path object to handle all path operations
        try:
            edk2path = Edk2Path(self.GetWorkspaceRoot(), pplist)
        except Exception as e:
            logging.error("Src Tree is invalid.  Did you Setup correctly?")
            raise e

        logging.info(f"Running CI Build: {self.PlatformSettings.GetName()}")
        logging.info(f"WorkSpace: {self.GetWorkspaceRoot()}")
        logging.info(f"Package Path: {pplist}")
        # Bring up the common minimum environment.
        logging.log(edk2_logging.SECTION, "Getting Environment")
        (build_env,
         shell_env) = self_describing_environment.BootstrapEnvironment(
             self.GetWorkspaceRoot(), self.GetActiveScopes())
        env = shell_environment.GetBuildVars()

        # Bind our current execution environment into the shell vars.
        ph = os.path.dirname(sys.executable)
        if " " in ph:
            ph = '"' + ph + '"'
        shell_env.set_shell_var("PYTHON_HOME", ph)
        # PYTHON_COMMAND is required to be set for using edk2 python builds.
        # todo: work with edk2 to remove the bat file and move to native python calls.
        #       This would be better in an edk2 plugin so that it could be modified/controlled
        #       more easily
        #
        pc = sys.executable
        if " " in pc:
            pc = '"' + pc + '"'
        shell_env.set_shell_var("PYTHON_COMMAND", pc)

        env.SetValue("TARGET_ARCH", " ".join(self.requested_architecture_list),
                     "from edk2 ci build.py")

        # Generate consumable XML object- junit format
        JunitReport = JunitTestReport()

        # Keep track of failures
        failure_num = 0
        total_num = 0

        # Load plugins
        logging.log(edk2_logging.SECTION, "Loading plugins")

        pluginList = self.plugin_manager.GetPluginsOfClass(ICiBuildPlugin)

        for pkgToRunOn in self.requested_package_list:
            #
            # run all loaded Edk2CiBuild Plugins/Tests
            #
            logging.log(edk2_logging.SECTION, f"Building {pkgToRunOn} Package")
            logging.info(f"Running on Package: {pkgToRunOn}")
            package_class_name = f"Edk2CiBuild.{self.PlatformSettings.GetName()}.{pkgToRunOn}"
            ts = JunitReport.create_new_testsuite(pkgToRunOn,
                                                  package_class_name)
            packagebuildlog_path = os.path.join(log_directory, pkgToRunOn)
            _, txt_handle = edk2_logging.setup_txt_logger(
                packagebuildlog_path,
                f"BUILDLOG_{pkgToRunOn}",
                logging_level=logging.DEBUG,
                isVerbose=True)
            _, md_handle = edk2_logging.setup_markdown_logger(
                packagebuildlog_path,
                f"BUILDLOG_{pkgToRunOn}",
                logging_level=logging.DEBUG,
                isVerbose=True)
            loghandle = [txt_handle, md_handle]
            shell_environment.CheckpointBuildVars()
            env = shell_environment.GetBuildVars()

            # load the package level .ci.yaml
            pkg_config_file = edk2path.GetAbsolutePathOnThisSytemFromEdk2RelativePath(
                os.path.join(pkgToRunOn, pkgToRunOn + ".ci.yaml"))
            if (pkg_config_file):
                with open(pkg_config_file, 'r') as f:
                    pkg_config = yaml.safe_load(f)
            else:
                logging.info(f"No Pkg Config file for {pkgToRunOn}")
                pkg_config = dict()

            # get all the defines from the package configuration
            if "Defines" in pkg_config:
                for definition_key in pkg_config["Defines"]:
                    definition = pkg_config["Defines"][definition_key]
                    env.SetValue(definition_key, definition,
                                 "Edk2CiBuild.py from PkgConfig yaml", False)

            # For each plugin
            for Descriptor in pluginList:
                # For each target
                for target in self.requested_target_list:

                    if (target not in Descriptor.Obj.RunsOnTargetList()):
                        continue

                    edk2_logging.log_progress(
                        f"--Running {pkgToRunOn}: {Descriptor.Name} {target} --"
                    )
                    total_num += 1
                    shell_environment.CheckpointBuildVars()
                    env = shell_environment.GetBuildVars()

                    env.SetValue("TARGET", target,
                                 "Edk2CiBuild.py before RunBuildPlugin")
                    (testcasename, testclassname) = Descriptor.Obj.GetTestName(
                        package_class_name, env)
                    tc = ts.create_new_testcase(testcasename, testclassname)

                    # create the stream for the build log
                    plugin_output_stream = edk2_logging.create_output_stream()

                    # merge the repo level and package level for this specific plugin
                    pkg_plugin_configuration = self.merge_config(
                        self.PlatformSettings.GetPluginSettings(), pkg_config,
                        Descriptor.descriptor)

                    # Still need to see if the package decided this should be skipped
                    if pkg_plugin_configuration is None or\
                            "skip" in pkg_plugin_configuration and pkg_plugin_configuration["skip"]:
                        tc.SetSkipped()
                        edk2_logging.log_progress(
                            "--->Test Skipped by package! %s" %
                            Descriptor.Name)

                    else:
                        try:
                            #   - package is the edk2 path to package.  This means workspace/package path relative.
                            #   - edk2path object configured with workspace and packages path
                            #   - any additional command line args
                            #   - RepoConfig Object (dict) for the build
                            #   - PkgConfig Object (dict)
                            #   - EnvConfig Object
                            #   - Plugin Manager Instance
                            #   - Plugin Helper Obj Instance
                            #   - testcase Object used for outputing junit results
                            #   - output_stream the StringIO output stream from this plugin
                            rc = Descriptor.Obj.RunBuildPlugin(
                                pkgToRunOn, edk2path, pkg_plugin_configuration,
                                env, self.plugin_manager, self.helper, tc,
                                plugin_output_stream)
                        except Exception as exp:
                            exc_type, exc_value, exc_traceback = sys.exc_info()
                            logging.critical("EXCEPTION: {0}".format(exp))
                            exceptionPrint = traceback.format_exception(
                                type(exp), exp, exc_traceback)
                            logging.critical(" ".join(exceptionPrint))
                            tc.SetError("Exception: {0}".format(exp),
                                        "UNEXPECTED EXCEPTION")
                            rc = 1

                        if (rc > 0):
                            failure_num += 1
                            if (rc is None):
                                logging.error(
                                    f"--->Test Failed: {Descriptor.Name} {target} returned NoneType"
                                )
                            else:
                                logging.error(
                                    f"--->Test Failed: {Descriptor.Name} {target} returned {rc}"
                                )
                        elif (rc < 0):
                            logging.warn(
                                f"--->Test Skipped: in plugin! {Descriptor.Name} {target}"
                            )
                        else:
                            edk2_logging.log_progress(
                                f"--->Test Success: {Descriptor.Name} {target}"
                            )

                    # revert to the checkpoint we created previously
                    shell_environment.RevertBuildVars()
                    # remove the logger
                    edk2_logging.remove_output_stream(plugin_output_stream)
                # finished target loop
            # Finished plugin loop

            edk2_logging.stop_logging(
                loghandle)  # stop the logging for this particular buildfile
            shell_environment.RevertBuildVars()
        # Finished buildable file loop

        JunitReport.Output(
            os.path.join(self.GetWorkspaceRoot(), "Build", "TestSuites.xml"))

        # Print Overall Success
        if (failure_num != 0):
            logging.error("Overall Build Status: Error")
            edk2_logging.log_progress(
                f"There were {failure_num} failures out of {total_num} attempts"
            )
        else:
            edk2_logging.log_progress("Overall Build Status: Success")

        return failure_num
    def SetEnv(self):
        edk2_logging.log_progress("Setting up the Environment")
        shell_environment.GetEnvironment().set_shell_var("WORKSPACE", self.ws)
        shell_environment.GetBuildVars().SetValue("WORKSPACE", self.ws,
                                                  "Set in SetEnv")

        if (self.pp is not None):
            shell_environment.GetEnvironment().set_shell_var(
                "PACKAGES_PATH", self.pp)
            shell_environment.GetBuildVars().SetValue("PACKAGES_PATH", self.pp,
                                                      "Set in SetEnv")

        # process platform parameters defined in platform build file
        ret = self.SetPlatformEnv()
        if (ret != 0):
            logging.critical("Set Platform Env failed")
            return ret

        # set some basic defaults
        self.SetBasicDefaults()

        # Handle all the template files for workspace/conf/ Allow override
        TemplateDirList = [self.env.GetValue("EDK_TOOLS_PATH")
                           ]  # set to edk2 BaseTools
        PlatTemplatesForConf = self.env.GetValue(
            "CONF_TEMPLATE_DIR")  # get platform defined additional path
        if (PlatTemplatesForConf is not None):
            PlatTemplatesForConf = self.mws.join(self.ws, PlatTemplatesForConf)
            TemplateDirList.insert(0, PlatTemplatesForConf)
            logging.debug(
                f"Platform defined override for Template Conf Files: {PlatTemplatesForConf}"
            )

        conf_dir = os.path.join(self.ws, "Conf")
        conf_mgmt.ConfMgmt().populate_conf_dir(conf_dir, self.UpdateConf,
                                               TemplateDirList)

        # parse target file
        ret = self.ParseTargetFile()
        if (ret != 0):
            logging.critical("ParseTargetFile failed")
            return ret

        # parse DSC file
        ret = self.ParseDscFile()
        if (ret != 0):
            logging.critical("ParseDscFile failed")
            return ret

        # parse FDF file
        ret = self.ParseFdfFile()
        if (ret != 0):
            logging.critical("ParseFdfFile failed")
            return ret

        # set build output base envs for all builds
        if self.env.GetValue("OUTPUT_DIRECTORY") is None:
            logging.warn("OUTPUT_DIRECTORY was not found, defaulting to Build")
            self.env.SetValue("OUTPUT_DIRECTORY", "Build",
                              "default from uefi_build", True)
        self.env.SetValue(
            "BUILD_OUT_TEMP",
            os.path.join(self.ws, self.env.GetValue("OUTPUT_DIRECTORY")),
            "Computed in SetEnv")

        target = self.env.GetValue("TARGET")
        self.env.SetValue(
            "BUILD_OUTPUT_BASE",
            os.path.join(self.env.GetValue("BUILD_OUT_TEMP"),
                         target + "_" + self.env.GetValue("TOOL_CHAIN_TAG")),
            "Computed in SetEnv")

        # We have our build target now.  Give platform build one more chance for target specific settings.
        ret = self.SetPlatformEnvAfterTarget()
        if (ret != 0):
            logging.critical("SetPlatformEnvAfterTarget failed")
            return ret

        # set the build report file
        self.env.SetValue(
            "BUILDREPORT_FILE",
            os.path.join(self.env.GetValue("BUILD_OUTPUT_BASE"),
                         "BUILD_REPORT.TXT"), True)

        # set environment variables for the build process
        os.environ["EFI_SOURCE"] = self.ws

        return 0
    def Go(self, WorkSpace, PackagesPath, PInHelper, PInManager):
        self.env = shell_environment.GetBuildVars()
        self.mws = MultipleWorkspace()
        self.mws.setWs(WorkSpace, PackagesPath)
        self.ws = WorkSpace
        self.pp = PackagesPath  # string using os.pathsep
        self.Helper = PInHelper
        self.pm = PInManager

        try:
            edk2_logging.log_progress("Start time: {0}".format(
                datetime.datetime.now()))
            start_time = time.perf_counter()

            self.Helper.DebugLogRegisteredFunctions()

            ret = self.SetEnv()
            if (ret != 0):
                logging.critical("SetEnv failed")
                return ret

            # clean
            if (self.Clean):
                edk2_logging.log_progress("Cleaning")
                ret = self.CleanTree()
                if (ret != 0):
                    logging.critical("Clean failed")
                    return ret

            # prebuild
            if (self.SkipPreBuild):
                edk2_logging.log_progress("Skipping Pre Build")
            else:
                ret = self.PreBuild()
                if (ret != 0):
                    logging.critical("Pre Build failed")
                    return ret

            # Output Build Environment to File - this is mostly for debug of build
            # issues or adding other build features using existing variables
            if (self.OutputConfig is not None):
                edk2_logging.log_progress("Writing Build Env Info out to File")
                logging.debug("Found an Output Build Env File: " +
                              self.OutputConfig)
                self.env.PrintAll(self.OutputConfig)

            if (self.env.GetValue("GATEDBUILD")
                    is not None) and (self.env.GetValue("GATEDBUILD").upper()
                                      == "TRUE"):
                ShouldGatedBuildRun = self.PlatformGatedBuildShouldHappen()
                logging.debug("Platform Gated Build Should Run returned: %s" %
                              str(ShouldGatedBuildRun))
                if (not self.SkipBuild):
                    self.SkipBuild = not ShouldGatedBuildRun
                if (not self.SkipPostBuild):
                    self.SkipPostBuild = not ShouldGatedBuildRun

            # build
            if (self.SkipBuild):
                edk2_logging.log_progress("Skipping Build")
            else:
                ret = self.Build()

                if (ret != 0):
                    logging.critical("Build failed")
                    return ret

            # postbuild
            if (self.SkipPostBuild):
                edk2_logging.log_progress("Skipping Post Build")
            else:
                ret = self.PostBuild()
                if (ret != 0):
                    logging.critical("Post Build failed")
                    return ret

            # flash
            if (self.FlashImage):
                edk2_logging.log_progress("Flashing Image")
                ret = self.FlashRomImage()
                if (ret != 0):
                    logging.critical("Flash Image failed")
                    return ret

        except:
            logging.critical("Build Process Exception")
            logging.error(traceback.format_exc())
            return -1
        finally:
            end_time = time.perf_counter()
            elapsed_time_s = int((end_time - start_time))
            edk2_logging.log_progress(
                "End time: {0}\t Total time Elapsed: {1}".format(
                    datetime.datetime.now(),
                    datetime.timedelta(seconds=elapsed_time_s)))

        return 0
    def SetEnv(self):
        edk2_logging.log_progress("Setting up the Environment")
        shell_environment.GetEnvironment().set_shell_var("WORKSPACE", self.ws)
        shell_environment.GetBuildVars().SetValue("WORKSPACE", self.ws,
                                                  "Set in SetEnv")

        if (self.pp is not None):
            shell_environment.GetEnvironment().set_shell_var(
                "PACKAGES_PATH", self.pp)
            shell_environment.GetBuildVars().SetValue("PACKAGES_PATH", self.pp,
                                                      "Set in SetEnv")

        # process platform parameters defined in platform build file
        ret = self.SetPlatformEnv()
        if (ret != 0):
            logging.critical("Set Platform Env failed")
            return ret

        # set some basic defaults
        self.SetBasicDefaults()

        # Handle all the template files for workspace/conf/ Allow override
        TemplatesForConf = self.env.GetValue("CONF_TEMPLATE_DIR")
        if (TemplatesForConf is not None):
            TemplatesForConf = self.mws.join(self.ws, TemplatesForConf)
            logging.debug(
                "Platform defined override for Template Conf Files: %s",
                TemplatesForConf)
        e = conf_mgmt.ConfMgmt(self.UpdateConf, TemplatesForConf)

        # parse target file
        ret = self.ParseTargetFile()
        if (ret != 0):
            logging.critical("ParseTargetFile failed")
            return ret

        ret = e.ToolsDefConfigure()
        if (ret != 0):
            logging.critical("ParseTargetFile failed")
            return ret

        # parse DSC file
        ret = self.ParseDscFile()
        if (ret != 0):
            logging.critical("ParseDscFile failed")
            return ret

        # parse FDF file
        ret = self.ParseFdfFile()
        if (ret != 0):
            logging.critical("ParseFdfFile failed")
            return ret

        # set build output base envs for all builds
        self.env.SetValue(
            "BUILD_OUT_TEMP",
            os.path.join(self.ws, self.env.GetValue("OUTPUT_DIRECTORY")),
            "Computed in SetEnv")

        target = self.env.GetValue("TARGET")
        self.env.SetValue(
            "BUILD_OUTPUT_BASE",
            os.path.join(self.env.GetValue("BUILD_OUT_TEMP"),
                         target + "_" + self.env.GetValue("TOOL_CHAIN_TAG")),
            "Computed in SetEnv")

        # We have our build target now.  Give platform build one more chance for target specific settings.
        ret = self.SetPlatformEnvAfterTarget()
        if (ret != 0):
            logging.critical("SetPlatformEnvAfterTarget failed")
            return ret

        # set the build report file
        self.env.SetValue(
            "BUILDREPORT_FILE",
            os.path.join(self.env.GetValue("BUILD_OUTPUT_BASE"),
                         "BUILD_REPORT.TXT"), True)

        # set environment variables for the build process
        os.environ["EFI_SOURCE"] = self.ws

        return 0