]> git.proxmox.com Git - mirror_edk2.git/blob - .pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py
5dafcbc13f8adc4362cd5aa4ccc538d82ec38346
[mirror_edk2.git] / .pytool / Plugin / LibraryClassCheck / LibraryClassCheck.py
1 # @file LibraryClassCheck.py
2 #
3 # Copyright (c) Microsoft Corporation.
4 # SPDX-License-Identifier: BSD-2-Clause-Patent
5 ##
6 import logging
7 import os
8 from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin
9 from edk2toollib.uefi.edk2.parsers.dec_parser import DecParser
10 from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser
11 from edk2toolext.environment.var_dict import VarDict
12
13
14 class LibraryClassCheck(ICiBuildPlugin):
15 """
16 A CiBuildPlugin that scans the code tree and library classes for undeclared
17 files
18
19 Configuration options:
20 "LibraryClassCheck": {
21 IgnoreHeaderFile: [], # Ignore a file found on disk
22 IgnoreLibraryClass: [] # Ignore a declaration found in dec file
23 }
24 """
25
26 def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
27 """ Provide the testcase name and classname for use in reporting
28 testclassname: a descriptive string for the testcase can include whitespace
29 classname: should be patterned <packagename>.<plugin>.<optionally any unique condition>
30
31 Args:
32 packagename: string containing name of package to build
33 environment: The VarDict for the test to run in
34 Returns:
35 a tuple containing the testcase name and the classname
36 (testcasename, classname)
37 """
38 return ("Check library class declarations in " + packagename, packagename + ".LibraryClassCheck")
39
40 def __GetPkgDec(self, rootpath):
41 try:
42 allEntries = os.listdir(rootpath)
43 for entry in allEntries:
44 if entry.lower().endswith(".dec"):
45 return(os.path.join(rootpath, entry))
46 except Exception:
47 logging.error("Unable to find DEC for package:{0}".format(rootpath))
48
49 return None
50
51 ##
52 # External function of plugin. This function is used to perform the task of the MuBuild Plugin
53 #
54 # - package is the edk2 path to package. This means workspace/packagepath relative.
55 # - edk2path object configured with workspace and packages path
56 # - PkgConfig Object (dict) for the pkg
57 # - EnvConfig Object
58 # - Plugin Manager Instance
59 # - Plugin Helper Obj Instance
60 # - Junit Logger
61 # - output_stream the StringIO output stream from this plugin via logging
62 def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None):
63 overall_status = 0
64 LibraryClassIgnore = []
65
66 abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagename)
67 abs_dec_path = self.__GetPkgDec(abs_pkg_path)
68 wsr_dec_path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(abs_dec_path)
69
70 if abs_dec_path is None or wsr_dec_path is "" or not os.path.isfile(abs_dec_path):
71 tc.SetSkipped()
72 tc.LogStdError("No DEC file {0} in package {1}".format(abs_dec_path, abs_pkg_path))
73 return -1
74
75 # Get all include folders
76 dec = DecParser()
77 dec.SetBaseAbsPath(Edk2pathObj.WorkspacePath).SetPackagePaths(Edk2pathObj.PackagePathList)
78 dec.ParseFile(wsr_dec_path)
79
80 AllHeaderFiles = []
81
82 for includepath in dec.IncludePaths:
83 ## Get all header files in the library folder
84 AbsLibraryIncludePath = os.path.join(abs_pkg_path, includepath, "Library")
85 if(not os.path.isdir(AbsLibraryIncludePath)):
86 continue
87
88 hfiles = self.WalkDirectoryForExtension([".h"], AbsLibraryIncludePath)
89 hfiles = [os.path.relpath(x,abs_pkg_path) for x in hfiles] # make package root relative path
90 hfiles = [x.replace("\\", "/") for x in hfiles] # make package relative path
91
92 AllHeaderFiles.extend(hfiles)
93
94 if len(AllHeaderFiles) == 0:
95 tc.SetSkipped()
96 tc.LogStdError(f"No Library include folder in any Include path")
97 return -1
98
99 # Remove ignored paths
100 if "IgnoreHeaderFile" in pkgconfig:
101 for a in pkgconfig["IgnoreHeaderFile"]:
102 try:
103 tc.LogStdOut("Ignoring Library Header File {0}".format(a))
104 AllHeaderFiles.remove(a)
105 except:
106 tc.LogStdError("LibraryClassCheck.IgnoreHeaderFile -> {0} not found. Invalid Header File".format(a))
107 logging.info("LibraryClassCheck.IgnoreHeaderFile -> {0} not found. Invalid Header File".format(a))
108
109 if "IgnoreLibraryClass" in pkgconfig:
110 LibraryClassIgnore = pkgconfig["IgnoreLibraryClass"]
111
112
113 ## Attempt to find library classes
114 for lcd in dec.LibraryClasses:
115 ## Check for correct file path separator
116 if "\\" in lcd.path:
117 tc.LogStdError("LibraryClassCheck.DecFilePathSeparator -> {0} invalid.".format(lcd.path))
118 logging.error("LibraryClassCheck.DecFilePathSeparator -> {0} invalid.".format(lcd.path))
119 overall_status += 1
120 continue
121
122 if lcd.name in LibraryClassIgnore:
123 tc.LogStdOut("Ignoring Library Class Name {0}".format(lcd.name))
124 LibraryClassIgnore.remove(lcd.name)
125 continue
126
127 logging.debug(f"Looking for Library Class {lcd.path}")
128 try:
129 AllHeaderFiles.remove(lcd.path)
130
131 except ValueError:
132 tc.LogStdError(f"Library {lcd.name} with path {lcd.path} not found in package filesystem")
133 logging.error(f"Library {lcd.name} with path {lcd.path} not found in package filesystem")
134 overall_status += 1
135
136 ## any remaining AllHeaderFiles are not described in DEC
137 for h in AllHeaderFiles:
138 tc.LogStdError(f"Library Header File {h} not declared in package DEC {wsr_dec_path}")
139 logging.error(f"Library Header File {h} not declared in package DEC {wsr_dec_path}")
140 overall_status += 1
141
142 ## Warn about any invalid library class names in the ignore list
143 for r in LibraryClassIgnore:
144 tc.LogStdError("LibraryClassCheck.IgnoreLibraryClass -> {0} not found. Library Class not found".format(r))
145 logging.info("LibraryClassCheck.IgnoreLibraryClass -> {0} not found. Library Class not found".format(r))
146
147
148 # If XML object exists, add result
149 if overall_status is not 0:
150 tc.SetFailed("LibraryClassCheck {0} Failed. Errors {1}".format(wsr_dec_path, overall_status), "CHECK_FAILED")
151 else:
152 tc.SetSuccess()
153 return overall_status