1 | # @file HostUnitTestDscCompleteCheck.py
|
---|
2 | #
|
---|
3 | # This is a copy of DscCompleteCheck with different filtering logic.
|
---|
4 | # It should be discussed if this should be one plugin
|
---|
5 | #
|
---|
6 | # Copyright (c) Microsoft Corporation.
|
---|
7 | # SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
8 | ##
|
---|
9 | import logging
|
---|
10 | import os
|
---|
11 | from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin
|
---|
12 | from edk2toollib.uefi.edk2.parsers.dsc_parser import DscParser
|
---|
13 | from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser, AllPhases
|
---|
14 | from edk2toolext.environment.var_dict import VarDict
|
---|
15 |
|
---|
16 |
|
---|
17 | class HostUnitTestDscCompleteCheck(ICiBuildPlugin):
|
---|
18 | """
|
---|
19 | A CiBuildPlugin that scans the package Host Unit Test dsc file and confirms all Host application modules (inf files) are
|
---|
20 | listed in the components sections.
|
---|
21 |
|
---|
22 | Configuration options:
|
---|
23 | "HostUnitTestDscCompleteCheck": {
|
---|
24 | "DscPath": "", # Path to Host based unit test DSC file
|
---|
25 | "IgnoreInf": [] # Ignore INF if found in filesystem but not dsc
|
---|
26 | }
|
---|
27 | """
|
---|
28 |
|
---|
29 | def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
|
---|
30 | """ Provide the testcase name and classname for use in reporting
|
---|
31 |
|
---|
32 | Args:
|
---|
33 | packagename: string containing name of package to build
|
---|
34 | environment: The VarDict for the test to run in
|
---|
35 | Returns:
|
---|
36 | a tuple containing the testcase name and the classname
|
---|
37 | (testcasename, classname)
|
---|
38 | testclassname: a descriptive string for the testcase can include whitespace
|
---|
39 | classname: should be patterned <packagename>.<plugin>.<optionally any unique condition>
|
---|
40 | """
|
---|
41 | return ("Check the " + packagename + " Host Unit Test DSC for a being complete", packagename + ".HostUnitTestDscCompleteCheck")
|
---|
42 |
|
---|
43 | ##
|
---|
44 | # External function of plugin. This function is used to perform the task of the MuBuild Plugin
|
---|
45 | #
|
---|
46 | # - package is the edk2 path to package. This means workspace/packagepath relative.
|
---|
47 | # - edk2path object configured with workspace and packages path
|
---|
48 | # - PkgConfig Object (dict) for the pkg
|
---|
49 | # - VarDict containing the shell environment Build Vars
|
---|
50 | # - Plugin Manager Instance
|
---|
51 | # - Plugin Helper Obj Instance
|
---|
52 | # - Junit Logger
|
---|
53 | # - output_stream the StringIO output stream from this plugin via logging
|
---|
54 | def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None):
|
---|
55 | overall_status = 0
|
---|
56 |
|
---|
57 | # Parse the config for required DscPath element
|
---|
58 | if "DscPath" not in pkgconfig:
|
---|
59 | tc.SetSkipped()
|
---|
60 | tc.LogStdError(
|
---|
61 | "DscPath not found in config file. Nothing to check.")
|
---|
62 | return -1
|
---|
63 |
|
---|
64 | abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSystemFromEdk2RelativePath(
|
---|
65 | packagename)
|
---|
66 | abs_dsc_path = os.path.join(abs_pkg_path, pkgconfig["DscPath"].strip())
|
---|
67 | wsr_dsc_path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(
|
---|
68 | abs_dsc_path)
|
---|
69 |
|
---|
70 | if abs_dsc_path is None or wsr_dsc_path == "" or not os.path.isfile(abs_dsc_path):
|
---|
71 | tc.SetSkipped()
|
---|
72 | tc.LogStdError("Package Host Unit Test Dsc not found")
|
---|
73 | return 0
|
---|
74 |
|
---|
75 | # Get INF Files
|
---|
76 | INFFiles = self.WalkDirectoryForExtension([".inf"], abs_pkg_path)
|
---|
77 | INFFiles = [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(
|
---|
78 | x) for x in INFFiles] # make edk2relative path so can compare with DSC
|
---|
79 |
|
---|
80 | # remove ignores
|
---|
81 |
|
---|
82 | if "IgnoreInf" in pkgconfig:
|
---|
83 | for a in pkgconfig["IgnoreInf"]:
|
---|
84 | a = a.replace(os.sep, "/")
|
---|
85 | try:
|
---|
86 | tc.LogStdOut("Ignoring INF {0}".format(a))
|
---|
87 | INFFiles.remove(a)
|
---|
88 | except:
|
---|
89 | tc.LogStdError(
|
---|
90 | "HostUnitTestDscCompleteCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a))
|
---|
91 | logging.info(
|
---|
92 | "HostUnitTestDscCompleteCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a))
|
---|
93 |
|
---|
94 | # DSC Parser
|
---|
95 | dp = DscParser()
|
---|
96 | dp.SetBaseAbsPath(Edk2pathObj.WorkspacePath)
|
---|
97 | dp.SetPackagePaths(Edk2pathObj.PackagePathList)
|
---|
98 | dp.SetInputVars(environment.GetAllBuildKeyValues())
|
---|
99 | dp.ParseFile(wsr_dsc_path)
|
---|
100 |
|
---|
101 | # Check if INF in component section
|
---|
102 | for INF in INFFiles:
|
---|
103 | if not any(INF.strip() in x for x in dp.ThreeMods) and \
|
---|
104 | not any(INF.strip() in x for x in dp.SixMods) and \
|
---|
105 | not any(INF.strip() in x for x in dp.OtherMods):
|
---|
106 |
|
---|
107 | infp = InfParser().SetBaseAbsPath(Edk2pathObj.WorkspacePath)
|
---|
108 | infp.SetPackagePaths(Edk2pathObj.PackagePathList)
|
---|
109 | infp.ParseFile(INF)
|
---|
110 | if("MODULE_TYPE" not in infp.Dict):
|
---|
111 | tc.LogStdOut(
|
---|
112 | "Ignoring INF. Missing key for MODULE_TYPE {0}".format(INF))
|
---|
113 | continue
|
---|
114 |
|
---|
115 | if(infp.Dict["MODULE_TYPE"] == "HOST_APPLICATION"):
|
---|
116 | # should compile test a library that is declared type HOST_APPLICATION
|
---|
117 | pass
|
---|
118 |
|
---|
119 | elif (len(infp.SupportedPhases) > 0 and
|
---|
120 | "HOST_APPLICATION" in infp.SupportedPhases and
|
---|
121 | infp.SupportedPhases != AllPhases):
|
---|
122 | # should compile test a library that supports HOST_APPLICATION but
|
---|
123 | # require it to be an explicit opt-in
|
---|
124 | pass
|
---|
125 |
|
---|
126 | else:
|
---|
127 | tc.LogStdOut(
|
---|
128 | "Ignoring INF. MODULE_TYPE or suppored phases not HOST_APPLICATION {0}".format(INF))
|
---|
129 | continue
|
---|
130 |
|
---|
131 | logging.critical(INF + " not in " + wsr_dsc_path)
|
---|
132 | tc.LogStdError("{0} not in {1}".format(INF, wsr_dsc_path))
|
---|
133 | overall_status = overall_status + 1
|
---|
134 |
|
---|
135 | # If XML object exists, add result
|
---|
136 | if overall_status != 0:
|
---|
137 | tc.SetFailed("HostUnitTestDscCompleteCheck {0} Failed. Errors {1}".format(
|
---|
138 | wsr_dsc_path, overall_status), "CHECK_FAILED")
|
---|
139 | else:
|
---|
140 | tc.SetSuccess()
|
---|
141 | return overall_status
|
---|