summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/.pytool/Plugin/LibraryClassCheck
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/.pytool/Plugin/LibraryClassCheck')
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py153
-rw-r--r--src/VBox/Devices/EFI/Firmware/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck_plug_in.yaml11
-rw-r--r--src/VBox/Devices/EFI/Firmware/.pytool/Plugin/LibraryClassCheck/Readme.md25
3 files changed, 189 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py b/src/VBox/Devices/EFI/Firmware/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py
new file mode 100755
index 00000000..57020856
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py
@@ -0,0 +1,153 @@
+# @file LibraryClassCheck.py
+#
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+import logging
+import os
+from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin
+from edk2toollib.uefi.edk2.parsers.dec_parser import DecParser
+from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser
+from edk2toolext.environment.var_dict import VarDict
+
+
+class LibraryClassCheck(ICiBuildPlugin):
+ """
+ A CiBuildPlugin that scans the code tree and library classes for undeclared
+ files
+
+ Configuration options:
+ "LibraryClassCheck": {
+ IgnoreHeaderFile: [], # Ignore a file found on disk
+ IgnoreLibraryClass: [] # Ignore a declaration found in dec file
+ }
+ """
+
+ def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
+ """ Provide the testcase name and classname for use in reporting
+ testclassname: a descriptive string for the testcase can include whitespace
+ classname: should be patterned <packagename>.<plugin>.<optionally any unique condition>
+
+ Args:
+ packagename: string containing name of package to build
+ environment: The VarDict for the test to run in
+ Returns:
+ a tuple containing the testcase name and the classname
+ (testcasename, classname)
+ """
+ return ("Check library class declarations in " + packagename, packagename + ".LibraryClassCheck")
+
+ def __GetPkgDec(self, rootpath):
+ try:
+ allEntries = os.listdir(rootpath)
+ for entry in allEntries:
+ if entry.lower().endswith(".dec"):
+ return(os.path.join(rootpath, entry))
+ except Exception:
+ logging.error("Unable to find DEC for package:{0}".format(rootpath))
+
+ return None
+
+ ##
+ # External function of plugin. This function is used to perform the task of the MuBuild Plugin
+ #
+ # - package is the edk2 path to package. This means workspace/packagepath relative.
+ # - edk2path object configured with workspace and packages path
+ # - PkgConfig Object (dict) for the pkg
+ # - EnvConfig Object
+ # - Plugin Manager Instance
+ # - Plugin Helper Obj Instance
+ # - Junit Logger
+ # - output_stream the StringIO output stream from this plugin via logging
+ def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None):
+ overall_status = 0
+ LibraryClassIgnore = []
+
+ abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagename)
+ abs_dec_path = self.__GetPkgDec(abs_pkg_path)
+ wsr_dec_path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(abs_dec_path)
+
+ if abs_dec_path is None or wsr_dec_path == "" or not os.path.isfile(abs_dec_path):
+ tc.SetSkipped()
+ tc.LogStdError("No DEC file {0} in package {1}".format(abs_dec_path, abs_pkg_path))
+ return -1
+
+ # Get all include folders
+ dec = DecParser()
+ dec.SetBaseAbsPath(Edk2pathObj.WorkspacePath).SetPackagePaths(Edk2pathObj.PackagePathList)
+ dec.ParseFile(wsr_dec_path)
+
+ AllHeaderFiles = []
+
+ for includepath in dec.IncludePaths:
+ ## Get all header files in the library folder
+ AbsLibraryIncludePath = os.path.join(abs_pkg_path, includepath, "Library")
+ if(not os.path.isdir(AbsLibraryIncludePath)):
+ continue
+
+ hfiles = self.WalkDirectoryForExtension([".h"], AbsLibraryIncludePath)
+ hfiles = [os.path.relpath(x,abs_pkg_path) for x in hfiles] # make package root relative path
+ hfiles = [x.replace("\\", "/") for x in hfiles] # make package relative path
+
+ AllHeaderFiles.extend(hfiles)
+
+ if len(AllHeaderFiles) == 0:
+ tc.SetSkipped()
+ tc.LogStdError(f"No Library include folder in any Include path")
+ return -1
+
+ # Remove ignored paths
+ if "IgnoreHeaderFile" in pkgconfig:
+ for a in pkgconfig["IgnoreHeaderFile"]:
+ try:
+ tc.LogStdOut("Ignoring Library Header File {0}".format(a))
+ AllHeaderFiles.remove(a)
+ except:
+ tc.LogStdError("LibraryClassCheck.IgnoreHeaderFile -> {0} not found. Invalid Header File".format(a))
+ logging.info("LibraryClassCheck.IgnoreHeaderFile -> {0} not found. Invalid Header File".format(a))
+
+ if "IgnoreLibraryClass" in pkgconfig:
+ LibraryClassIgnore = pkgconfig["IgnoreLibraryClass"]
+
+
+ ## Attempt to find library classes
+ for lcd in dec.LibraryClasses:
+ ## Check for correct file path separator
+ if "\\" in lcd.path:
+ tc.LogStdError("LibraryClassCheck.DecFilePathSeparator -> {0} invalid.".format(lcd.path))
+ logging.error("LibraryClassCheck.DecFilePathSeparator -> {0} invalid.".format(lcd.path))
+ overall_status += 1
+ continue
+
+ if lcd.name in LibraryClassIgnore:
+ tc.LogStdOut("Ignoring Library Class Name {0}".format(lcd.name))
+ LibraryClassIgnore.remove(lcd.name)
+ continue
+
+ logging.debug(f"Looking for Library Class {lcd.path}")
+ try:
+ AllHeaderFiles.remove(lcd.path)
+
+ except ValueError:
+ tc.LogStdError(f"Library {lcd.name} with path {lcd.path} not found in package filesystem")
+ logging.error(f"Library {lcd.name} with path {lcd.path} not found in package filesystem")
+ overall_status += 1
+
+ ## any remaining AllHeaderFiles are not described in DEC
+ for h in AllHeaderFiles:
+ tc.LogStdError(f"Library Header File {h} not declared in package DEC {wsr_dec_path}")
+ logging.error(f"Library Header File {h} not declared in package DEC {wsr_dec_path}")
+ overall_status += 1
+
+ ## Warn about any invalid library class names in the ignore list
+ for r in LibraryClassIgnore:
+ tc.LogStdError("LibraryClassCheck.IgnoreLibraryClass -> {0} not found. Library Class not found".format(r))
+ logging.info("LibraryClassCheck.IgnoreLibraryClass -> {0} not found. Library Class not found".format(r))
+
+
+ # If XML object exists, add result
+ if overall_status != 0:
+ tc.SetFailed("LibraryClassCheck {0} Failed. Errors {1}".format(wsr_dec_path, overall_status), "CHECK_FAILED")
+ else:
+ tc.SetSuccess()
+ return overall_status
diff --git a/src/VBox/Devices/EFI/Firmware/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck_plug_in.yaml b/src/VBox/Devices/EFI/Firmware/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck_plug_in.yaml
new file mode 100644
index 00000000..db35f22e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck_plug_in.yaml
@@ -0,0 +1,11 @@
+## @file
+# CiBuildPlugin used to check that all library classes are declared correctly in dec file
+#
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+{
+ "scope": "cibuild",
+ "name": "Library Class Check Test",
+ "module": "LibraryClassCheck"
+}
diff --git a/src/VBox/Devices/EFI/Firmware/.pytool/Plugin/LibraryClassCheck/Readme.md b/src/VBox/Devices/EFI/Firmware/.pytool/Plugin/LibraryClassCheck/Readme.md
new file mode 100644
index 00000000..95f22e7b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/.pytool/Plugin/LibraryClassCheck/Readme.md
@@ -0,0 +1,25 @@
+# Library Class Check Plugin
+
+This CiBuildPlugin scans at all library header files found in the `Library`
+folders in all of the package's declared include directories and ensures that
+all files have a matching LibraryClass declaration in the DEC file for the
+package. Any missing declarations will cause a failure.
+
+## Configuration
+
+The plugin has a few configuration options to support the UEFI codebase.
+
+``` yaml
+"LibraryClassCheck": {
+ IgnoreHeaderFile: [], # Ignore a file found on disk
+ IgnoreLibraryClass: [] # Ignore a declaration found in dec file
+}
+```
+
+### IgnoreHeaderFile
+
+Ignore a file found on disk
+
+### IgnoreLibraryClass
+
+Ignore a declaration found in dec file