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