def test_dsc_parse_file_on_package_path(self):
        ''' This tests whether includes work properly if no fail mode is on'''
        workspace = tempfile.mkdtemp()
        working_dir_name = "working"
        working2_dir_name = "working2"

        working_folder = os.path.join(workspace, working_dir_name)
        working2_folder = os.path.join(working_folder, working2_dir_name)
        os.makedirs(working_folder, exist_ok=True)
        os.makedirs(working2_folder, exist_ok=True)

        file1_name = "file1.dsc"
        file1_path = os.path.join(working2_folder, file1_name)
        file1_short_path = os.path.join(working2_dir_name, file1_name)
        file1_data = "[Defines]\n INCLUDED=TRUE"

        TestDscParserIncludes.write_to_file(file1_path, file1_data)
        with self.assertRaises(FileNotFoundError):
            parser = DscParser()
            parser.SetBaseAbsPath(workspace)
            parser.ParseFile(file1_short_path)

        parser = DscParser()
        parser.SetBaseAbsPath(workspace)
        parser.SetPackagePaths([
            working_folder,
        ])
        parser.ParseFile(file1_short_path)
        self.assertEqual(parser.LocalVars["INCLUDED"],
                         "TRUE")  # make sure we got the defines
    def test_dsc_include_single_file(self):
        ''' This tests whether includes work properly '''
        workspace = tempfile.mkdtemp()

        file1_name = "file1.dsc"
        file2_name = "file2.dsc"
        file1_path = os.path.join(workspace, file1_name)
        file2_path = os.path.join(workspace, file2_name)

        file1_data = f"!include {file2_name}"
        file2_data = "[Defines]\nINCLUDED = TRUE"

        TestDscParserIncludes.write_to_file(file1_path, file1_data)
        TestDscParserIncludes.write_to_file(file2_path, file2_data)

        parser = DscParser()
        parser.SetBaseAbsPath(workspace)
        parser.ParseFile(file1_path)

        # test to make sure we did it right
        self.assertEqual(len(parser.LocalVars),
                         1)  # make sure we only have one define
        self.assertEqual(parser.LocalVars["INCLUDED"],
                         "TRUE")  # make sure we got the defines
        self.assertEqual(len(parser.GetAllDscPaths()),
                         2)  # make sure we have two dsc paths
    def ParseDscFile(self):
        if self.env.GetValue("ACTIVE_PLATFORM") is None:
            logging.error(
                "The DSC file was not set. Please set ACTIVE_PLATFORM")
            return -1
        dsc_file_path = self.mws.join(self.ws,
                                      self.env.GetValue("ACTIVE_PLATFORM"))
        if (os.path.isfile(dsc_file_path)):
            # parse DSC File
            logging.debug(
                "Parse Active Platform DSC file: {0}".format(dsc_file_path))

            # Get the vars from the environment that are not build keys
            input_vars = self.env.GetAllNonBuildKeyValues()
            # Update with special environment set build keys
            input_vars.update(self.env.GetAllBuildKeyValues())

            dscp = DscParser().SetBaseAbsPath(self.ws).SetPackagePaths(
                self.pp.split(os.pathsep)).SetInputVars(input_vars)
            dscp.ParseFile(dsc_file_path)
            for key, value in dscp.LocalVars.items():
                # set env as overrideable
                self.env.SetValue(key, value, "From Platform DSC File", True)
        else:
            logging.error("Failed to find DSC file")
            return -1

        return 0
    def test_dsc_include_missing_file(self):
        ''' This tests whether includes work properly '''
        workspace = tempfile.gettempdir()

        file1_name = "file1.dsc"
        file1_path = os.path.join(workspace, file1_name)

        file1_data = f"!include BAD_FILE.dsc"

        TestDscParserIncludes.write_to_file(file1_path, file1_data)

        parser = DscParser()
        parser.SetBaseAbsPath(workspace)
        with self.assertRaises(FileNotFoundError):
            parser.ParseFile(file1_path)
    def test_dsc_include_missing_file_no_fail_mode(self):
        ''' This tests whether includes work properly if no fail mode is on'''
        workspace = tempfile.mkdtemp()

        file1_name = "file1.dsc"
        file1_path = os.path.join(workspace, file1_name)

        file1_data = "!include BAD_FILE.dsc"

        TestDscParserIncludes.write_to_file(file1_path, file1_data)

        parser = DscParser()
        parser.SetNoFailMode()
        parser.SetBaseAbsPath(workspace)
        parser.ParseFile(file1_path)
Example #6
0
    def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None):
        self._env = environment

        # Parse the config for required DscPath element
        if "DscPath" not in pkgconfig:
            tc.SetSkipped()
            tc.LogStdError("DscPath not found in config file.  Nothing to compile.")
            return -1

        AP = Edk2pathObj.GetAbsolutePathOnThisSystemFromEdk2RelativePath(packagename)

        APDSC = os.path.join(AP, pkgconfig["DscPath"].strip())
        AP_Path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(APDSC)
        if AP is None or AP_Path is None or not os.path.isfile(APDSC):
            tc.SetSkipped()
            tc.LogStdError("Package Dsc not found.")
            return -1

        logging.info("Building {0}".format(AP_Path))
        self._env.SetValue("ACTIVE_PLATFORM", AP_Path, "Set in Compiler Plugin")

        # Parse DSC to check for SUPPORTED_ARCHITECTURES
        dp = DscParser()
        dp.SetBaseAbsPath(Edk2pathObj.WorkspacePath)
        dp.SetPackagePaths(Edk2pathObj.PackagePathList)
        dp.ParseFile(AP_Path)
        if "SUPPORTED_ARCHITECTURES" in dp.LocalVars:
            SUPPORTED_ARCHITECTURES = dp.LocalVars["SUPPORTED_ARCHITECTURES"].split('|')
            TARGET_ARCHITECTURES = environment.GetValue("TARGET_ARCH").split(' ')

            # Skip if there is no intersection between SUPPORTED_ARCHITECTURES and TARGET_ARCHITECTURES
            if len(set(SUPPORTED_ARCHITECTURES) & set(TARGET_ARCHITECTURES)) == 0:
                tc.SetSkipped()
                tc.LogStdError("No supported architecutres to build")
                return -1

        uefiBuilder = UefiBuilder()
        # do all the steps
        # WorkSpace, PackagesPath, PInHelper, PInManager
        ret = uefiBuilder.Go(Edk2pathObj.WorkspacePath, os.pathsep.join(Edk2pathObj.PackagePathList), PLMHelper, PLM)
        if ret != 0:  # failure:
            tc.SetFailed("Compile failed for {0}".format(packagename), "Compile_FAILED")
            tc.LogStdError("{0} Compile failed with error code {1} ".format(AP_Path, ret))
            return 1

        else:
            tc.SetSuccess()
            return 0
    def test_dsc_include_relative_path(self):
        ''' This tests whether includes work properly with a relative path'''
        workspace = tempfile.mkdtemp()
        outside_folder = os.path.join(workspace, "outside")
        inside_folder = os.path.join(outside_folder, "inside")
        inside2_folder = os.path.join(outside_folder, "inside2")
        random_folder = os.path.join(outside_folder, "random")
        os.makedirs(inside_folder, exist_ok=True)
        os.makedirs(inside2_folder, exist_ok=True)
        os.makedirs(random_folder, exist_ok=True)
        cwd = os.getcwd()
        os.chdir(random_folder)
        try:

            file1_name = "file1.dsc"
            file1_path = os.path.join(outside_folder, file1_name)

            file2_name = "file2.dsc"
            file2_path = os.path.join(inside_folder, file2_name)

            file3_name = "file3.dsc"
            file3_path = os.path.join(inside2_folder, file3_name)

            file1_data = "!include " + os.path.relpath(
                file2_path, os.path.dirname(file1_path)).replace("\\", "/")
            file2_data = "!include " + os.path.relpath(
                file3_path, os.path.dirname(file2_path)).replace("\\", "/")
            file3_data = "[Defines]\n INCLUDED=TRUE"

            print(f"{file1_path}: {file1_data}")
            print(f"{file2_path}: {file2_data}")
            print(f"{file3_path}: {file3_data}")

            TestDscParserIncludes.write_to_file(file1_path, file1_data)
            TestDscParserIncludes.write_to_file(file2_path, file2_data)
            TestDscParserIncludes.write_to_file(file3_path, file3_data)

            parser = DscParser()
            parser.SetBaseAbsPath(workspace)
            parser.ParseFile(file1_path)

            self.assertEqual(parser.LocalVars["INCLUDED"],
                             "TRUE")  # make sure we got the defines
        finally:
            os.chdir(cwd)
    def ParseDscFile(self):
        dsc_file_path = self.mws.join(self.ws,
                                      self.env.GetValue("ACTIVE_PLATFORM"))
        if (os.path.isfile(dsc_file_path)):
            # parse DSC File
            logging.debug(
                "Parse Active Platform DSC file: {0}".format(dsc_file_path))
            dscp = DscParser().SetBaseAbsPath(self.ws).SetPackagePaths(
                self.pp.split(os.pathsep)).SetInputVars(
                    self.env.GetAllBuildKeyValues())
            dscp.ParseFile(dsc_file_path)
            for key, value in dscp.LocalVars.items():
                # set env as overrideable
                self.env.SetValue(key, value, "From Platform DSC File", True)

        else:
            logging.error("Failed to find DSC file")
            return -1

        return 0
    def ParseFdfFile(self):
        if (self.env.GetValue("FLASH_DEFINITION") is None):
            logging.debug("No flash definition set")
            return 0
        if (os.path.isfile(
                self.mws.join(self.ws,
                              self.env.GetValue("FLASH_DEFINITION")))):
            # parse the FDF file- fdf files have similar syntax to DSC and therefore parser works for both.
            logging.debug("Parse Active Flash Definition (FDF) file")
            fdf_parser = DscParser().SetBaseAbsPath(self.ws).SetPackagePaths(
                self.pp.split(os.pathsep)).SetInputVars(
                    self.env.GetAllBuildKeyValues())
            pa = self.mws.join(self.ws, self.env.GetValue("FLASH_DEFINITION"))
            fdf_parser.ParseFile(pa)
            for key, value in fdf_parser.LocalVars.items():
                self.env.SetValue(key, value, "From Platform FDF File", True)

        else:
            logging.error("Failed to find FDF file")
            return -2

        return 0
Example #10
0
    def RunBuildPlugin(self,
                       packagename,
                       Edk2pathObj,
                       pkgconfig,
                       environment,
                       PLM,
                       PLMHelper,
                       tc,
                       output_stream=None):
        overall_status = 0

        # Parse the config for required DscPath element
        if "DscPath" not in pkgconfig:
            tc.SetSkipped()
            tc.LogStdError(
                "DscPath not found in config file.  Nothing to check.")
            return -1

        abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(
            packagename)
        abs_dsc_path = os.path.join(abs_pkg_path, pkgconfig["DscPath"].strip())
        wsr_dsc_path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(
            abs_dsc_path)

        if abs_dsc_path is None or wsr_dsc_path == "" or not os.path.isfile(
                abs_dsc_path):
            tc.SetSkipped()
            tc.LogStdError("Package Host Unit Test Dsc not found")
            return 0

        # Get INF Files
        INFFiles = self.WalkDirectoryForExtension([".inf"], abs_pkg_path)
        INFFiles = [
            Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(x)
            for x in INFFiles
        ]  # make edk2relative path so can compare with DSC

        # remove ignores

        if "IgnoreInf" in pkgconfig:
            for a in pkgconfig["IgnoreInf"]:
                a = a.replace(os.sep, "/")
                try:
                    tc.LogStdOut("Ignoring INF {0}".format(a))
                    INFFiles.remove(a)
                except:
                    tc.LogStdError(
                        "HostUnitTestDscCompleteCheck.IgnoreInf -> {0} not found in filesystem.  Invalid ignore file"
                        .format(a))
                    logging.info(
                        "HostUnitTestDscCompleteCheck.IgnoreInf -> {0} not found in filesystem.  Invalid ignore file"
                        .format(a))

        # DSC Parser
        dp = DscParser()
        dp.SetBaseAbsPath(Edk2pathObj.WorkspacePath)
        dp.SetPackagePaths(Edk2pathObj.PackagePathList)
        dp.SetInputVars(environment.GetAllBuildKeyValues())
        dp.ParseFile(wsr_dsc_path)

        # Check if INF in component section
        for INF in INFFiles:
            if not any(INF.strip() in x for x in dp.ThreeMods) and \
               not any(INF.strip() in x for x in dp.SixMods) and \
               not any(INF.strip() in x for x in dp.OtherMods):

                infp = InfParser().SetBaseAbsPath(Edk2pathObj.WorkspacePath)
                infp.SetPackagePaths(Edk2pathObj.PackagePathList)
                infp.ParseFile(INF)
                if ("MODULE_TYPE" not in infp.Dict):
                    tc.LogStdOut(
                        "Ignoring INF. Missing key for MODULE_TYPE {0}".format(
                            INF))
                    continue

                if (infp.Dict["MODULE_TYPE"] == "HOST_APPLICATION"):
                    # should compile test a library that is declared type HOST_APPLICATION
                    pass

                elif len(infp.SupportedPhases) > 0 and \
                        "HOST_APPLICATION" in infp.SupportedPhases:
                    # should compile test a library that supports HOST_APPLICATION but
                    # require it to be an explicit opt-in
                    pass

                else:
                    tc.LogStdOut(
                        "Ignoring INF. MODULE_TYPE or suppored phases not HOST_APPLICATION {0}"
                        .format(INF))
                    continue

                logging.critical(INF + " not in " + wsr_dsc_path)
                tc.LogStdError("{0} not in {1}".format(INF, wsr_dsc_path))
                overall_status = overall_status + 1

        # If XML object exists, add result
        if overall_status != 0:
            tc.SetFailed(
                "HostUnitTestDscCompleteCheck {0} Failed.  Errors {1}".format(
                    wsr_dsc_path, overall_status), "CHECK_FAILED")
        else:
            tc.SetSuccess()
        return overall_status
    def RunBuildPlugin(self,
                       packagename,
                       Edk2pathObj,
                       pkgconfig,
                       environment,
                       PLM,
                       PLMHelper,
                       tc,
                       output_stream=None):
        self._env = environment
        environment.SetValue("CI_BUILD_TYPE", "host_unit_test",
                             "Set in HostUnitTestCompilerPlugin")

        # Parse the config for required DscPath element
        if "DscPath" not in pkgconfig:
            tc.SetSkipped()
            tc.LogStdError(
                "DscPath not found in config file.  Nothing to compile for HostBasedUnitTests."
            )
            return -1

        AP = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(
            packagename)

        APDSC = os.path.join(AP, pkgconfig["DscPath"].strip())
        AP_Path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(APDSC)
        if AP is None or AP_Path is None or not os.path.isfile(APDSC):
            tc.SetSkipped()
            tc.LogStdError("Package HostBasedUnitTest Dsc not found.")
            return -1

        logging.info("Building {0}".format(AP_Path))
        self._env.SetValue("ACTIVE_PLATFORM", AP_Path,
                           "Set in Compiler Plugin")
        num, RUNNABLE_ARCHITECTURES = self.__GetHostUnitTestArch(environment)
        if (num == 0):
            tc.SetSkipped()
            tc.LogStdError("No host architecture compatibility")
            return -1

        if not environment.SetValue(
                "TARGET_ARCH", RUNNABLE_ARCHITECTURES,
                "Update Target Arch based on Host Support"):
            #use AllowOverride function since this is a controlled attempt to change
            environment.AllowOverride("TARGET_ARCH")
            if not environment.SetValue(
                    "TARGET_ARCH", RUNNABLE_ARCHITECTURES,
                    "Update Target Arch based on Host Support"):
                raise RuntimeError("Can't Change TARGET_ARCH as required")

        # Parse DSC to check for SUPPORTED_ARCHITECTURES
        dp = DscParser()
        dp.SetBaseAbsPath(Edk2pathObj.WorkspacePath)
        dp.SetPackagePaths(Edk2pathObj.PackagePathList)
        dp.ParseFile(AP_Path)
        if "SUPPORTED_ARCHITECTURES" in dp.LocalVars:
            SUPPORTED_ARCHITECTURES = dp.LocalVars[
                "SUPPORTED_ARCHITECTURES"].split('|')
            TARGET_ARCHITECTURES = environment.GetValue("TARGET_ARCH").split(
                ' ')

            # Skip if there is no intersection between SUPPORTED_ARCHITECTURES and TARGET_ARCHITECTURES
            if len(set(SUPPORTED_ARCHITECTURES)
                   & set(TARGET_ARCHITECTURES)) == 0:
                tc.SetSkipped()
                tc.LogStdError(
                    "No supported architecutres to build for host unit tests")
                return -1

        uefiBuilder = UefiBuilder()
        # do all the steps
        # WorkSpace, PackagesPath, PInHelper, PInManager
        ret = uefiBuilder.Go(Edk2pathObj.WorkspacePath,
                             os.pathsep.join(Edk2pathObj.PackagePathList),
                             PLMHelper, PLM)
        if ret != 0:  # failure:
            tc.SetFailed("Compile failed for {0}".format(packagename),
                         "Compile_FAILED")
            tc.LogStdError("{0} Compile failed with error code {1} ".format(
                AP_Path, ret))
            return 1

        else:
            tc.SetSuccess()
            return 0
Example #12
0
    def get_packages_to_build(self, possible_packages: list) -> dict:
        self.parsed_dec_cache = {}
        (rc, files) = self._get_files_that_changed_in_this_pr(self.pr_target)
        if rc != 0:
            return {}

        remaining_packages = possible_packages.copy(
        )  # start with all possible packages and remove each
        # package once it is determined to be build.  This optimization
        # avoids checking packages that already will be built.

        packages_to_build = {
        }  # packages to build.  Key = pkg name, Value = 1st reason for build

        #
        # Policy 1 - CI Settings file defined
        #
        after = self.PlatformSettings.FilterPackagesToTest(
            files, remaining_packages)
        for a in after:
            if a not in remaining_packages:
                raise ValueError(
                    f"PlatformSettings.FilterPackagesToTest returned package not allowed {a}"
                )
            packages_to_build[
                a] = "Policy 1 - PlatformSettings - Filter Packages"
            remaining_packages.remove(a)

        #
        # Policy 2: Build any package that has changed
        #
        for f in files:
            try:
                pkg = self.edk2_path_obj.GetContainingPackage(
                    os.path.abspath(f))

            except Exception as e:
                self.logger.error(
                    f"Failed to get package for file {f}.  Exception {e}")
                # Ignore a file in which we fail to get the package
                continue

            if (pkg not in packages_to_build.keys()
                    and pkg in remaining_packages):
                packages_to_build[
                    pkg] = "Policy 2 - Build any package that has changed"
                remaining_packages.remove(pkg)

        #
        # Policy 3: If a file change is a public file then build all packages that
        #           are dependent on that package.
        #

        # list of packages with public files that have changed
        public_package_changes = []

        # Get all public files in packages
        for f in files:
            try:
                pkg = self.edk2_path_obj.GetContainingPackage(
                    os.path.abspath(f))

            except Exception as e:
                self.logger.error(
                    f"Failed to get package for file {f}.  Exception {e}")
                # Ignore a file in which we fail to get the package
                continue

            if self._is_public_file(f):
                public_package_changes.append(pkg)
        # de-duplicate list
        public_package_changes = list(set(public_package_changes))

        # Now check all remaining packages to see if they depend on the set of packages
        # with public file changes.
        # NOTE: future enhancement could be to check actual file dependencies
        for a in public_package_changes:
            for p in remaining_packages[:]:  # slice so we can delete as we go
                if (self._does_pkg_depend_on_package(p, a)):
                    packages_to_build[p] = f"Policy 3 - Package depends on {a}"
                    remaining_packages.remove(
                        p)  # remove from remaining packages

        #
        # Policy 4: If a file changed in a module and that module is used in the provided dsc file
        # then the package of the dSC file must be built
        #
        PlatformDscInfo = self.PlatformSettings.GetPlatformDscAndConfig()
        if PlatformDscInfo is not None and len(remaining_packages) > 0:
            if len(remaining_packages) != 1:
                raise Exception(
                    "Policy 4 can only be used by builds for a single package")

            # files are all the files changed edk2 workspace root relative path
            changed_modules = self._get_unique_module_infs_changed(files)

            # now check DSC
            dsc = DscParser()
            dsc.SetBaseAbsPath(self.edk2_path_obj.WorkspacePath)
            dsc.SetPackagePaths(self.edk2_path_obj.PackagePathList)
            dsc.SetInputVars(PlatformDscInfo[1])
            dsc.ParseFile(PlatformDscInfo[0])
            allinfs = dsc.OtherMods + dsc.ThreeMods + dsc.SixMods + dsc.Libs  # get list of all INF files

            #
            # Note: for now we assume that remaining_packages has only 1 package and that it corresponds
            # to the DSC file provided.
            #
            for p in remaining_packages[:]:  # slice so we can delete as we go
                for cm in changed_modules:
                    if cm in allinfs:  # is the changed module listed in the DSC file?
                        packages_to_build[
                            p] = f"Policy 4 - Package Dsc depends on {cm}"
                        remaining_packages.remove(
                            p)  # remove from remaining packages
                        break

        return packages_to_build