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## 9import logging 10import os 11from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin 12from edk2toollib.uefi.edk2.parsers.dsc_parser import DscParser 13from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser 14from edk2toolext.environment.var_dict import VarDict 15 16 17class 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.GetAbsolutePathOnThisSytemFromEdk2RelativePath( 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: 121 # should compile test a library that supports HOST_APPLICATION but 122 # require it to be an explicit opt-in 123 pass 124 125 else: 126 tc.LogStdOut( 127 "Ignoring INF. MODULE_TYPE or suppored phases not HOST_APPLICATION {0}".format(INF)) 128 continue 129 130 logging.critical(INF + " not in " + wsr_dsc_path) 131 tc.LogStdError("{0} not in {1}".format(INF, wsr_dsc_path)) 132 overall_status = overall_status + 1 133 134 # If XML object exists, add result 135 if overall_status != 0: 136 tc.SetFailed("HostUnitTestDscCompleteCheck {0} Failed. Errors {1}".format( 137 wsr_dsc_path, overall_status), "CHECK_FAILED") 138 else: 139 tc.SetSuccess() 140 return overall_status 141