mirror of
https://github.com/acidanthera/audk.git
synced 2025-08-20 09:08:10 +02:00
Allows ignore lines in the CI YAML file to use git ignore syntax. This is especially useful for ignore files recursively in directories like those that may exist in an external dependency folder. Co-authored-by: Michael Kubacki <michael.kubacki@microsoft.com> Signed-off-by: Joey Vagedes <joey.vagedes@gmail.com>
157 lines
6.6 KiB
Python
157 lines
6.6 KiB
Python
# @file DscCompleteCheck.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.path_utilities import Edk2Path
|
|
from edk2toollib.uefi.edk2.parsers.dsc_parser import DscParser
|
|
from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser
|
|
from edk2toolext.environment.var_dict import VarDict
|
|
from edk2toollib.gitignore_parser import parse_gitignore_lines
|
|
from pathlib import Path
|
|
|
|
|
|
class DscCompleteCheck(ICiBuildPlugin):
|
|
"""
|
|
A CiBuildPlugin that scans the package dsc file and confirms all modules (inf files) are
|
|
listed in the components sections.
|
|
|
|
Configuration options:
|
|
"DscCompleteCheck": {
|
|
"DscPath": "<path to dsc from root of pkg>"
|
|
"IgnoreInf": [] # Ignore INF if found in filesystem by not dsc
|
|
}
|
|
"""
|
|
|
|
def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
|
|
""" Provide the testcase name and classname for use in reporting
|
|
|
|
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)
|
|
testclassname: a descriptive string for the testcase can include whitespace
|
|
classname: should be patterned <packagename>.<plugin>.<optionally any unique condition>
|
|
"""
|
|
return ("Check the " + packagename + " DSC for a being complete", packagename + ".DscCompleteCheck")
|
|
|
|
##
|
|
# 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
|
|
# - VarDict containing the shell environment Build Vars
|
|
# - 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
|
|
|
|
# Parse the config for required DscPath element
|
|
if "DscPath" not in pkgconfig:
|
|
tc.SetSkipped()
|
|
tc.LogStdError(
|
|
"DscPath not found in config file. Nothing to check.")
|
|
return -1
|
|
|
|
abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSystemFromEdk2RelativePath(
|
|
packagename)
|
|
abs_dsc_path = os.path.join(abs_pkg_path, pkgconfig["DscPath"].strip())
|
|
wsr_dsc_path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(
|
|
abs_dsc_path)
|
|
|
|
if abs_dsc_path is None or wsr_dsc_path == "" or not os.path.isfile(abs_dsc_path):
|
|
tc.SetSkipped()
|
|
tc.LogStdError("Package Dsc not found")
|
|
return 0
|
|
|
|
# Get INF Files
|
|
INFFiles = self.WalkDirectoryForExtension([".inf"], abs_pkg_path)
|
|
|
|
# remove ignores
|
|
ignored_paths = []
|
|
if "IgnoreInf" in pkgconfig:
|
|
ignore_filter = parse_gitignore_lines(
|
|
pkgconfig["IgnoreInf"],
|
|
"DSC Complete Check Config",
|
|
os.path.dirname(abs_pkg_path))
|
|
|
|
# INFFiles must be a list of absolute paths
|
|
ignored_paths = list(filter(ignore_filter, INFFiles))
|
|
for a in ignored_paths:
|
|
try:
|
|
tc.LogStdOut("Ignoring INF {0}".format(a))
|
|
INFFiles.remove(a)
|
|
except Exception:
|
|
tc.LogStdError(
|
|
"DscCompleteCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a))
|
|
logging.info(
|
|
"DscCompleteCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a))
|
|
|
|
# make edk2relative path so can compare with DSC
|
|
INFFiles = [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(x) for x in INFFiles]
|
|
|
|
# DSC Parser
|
|
dp = DscParser().SetEdk2Path(Edk2pathObj)
|
|
dp.SetInputVars(environment.GetAllBuildKeyValues())
|
|
dp.ParseFile(wsr_dsc_path)
|
|
|
|
# Check if INF in component section
|
|
for INF in INFFiles:
|
|
if not DscCompleteCheck._module_in_dsc(INF, dp, Edk2pathObj):
|
|
infp = InfParser().SetEdk2Path(Edk2pathObj)
|
|
infp.ParseFile(INF)
|
|
if("MODULE_TYPE" not in infp.Dict):
|
|
tc.LogStdOut(
|
|
"Ignoring INF. Missing key for MODULE_TYPE {0}".format(INF))
|
|
continue
|
|
|
|
if(infp.Dict["MODULE_TYPE"] == "HOST_APPLICATION"):
|
|
tc.LogStdOut(
|
|
"Ignoring INF. Module type is HOST_APPLICATION {0}".format(INF))
|
|
continue
|
|
|
|
if len(infp.SupportedPhases) == 1 and \
|
|
"HOST_APPLICATION" in infp.SupportedPhases:
|
|
tc.LogStdOut(
|
|
"Ignoring Library INF due to only supporting type HOST_APPLICATION {0}".format(INF))
|
|
continue
|
|
|
|
logging.critical(INF + " not in " + wsr_dsc_path)
|
|
tc.LogStdError("{0} not in {1}".format(INF, wsr_dsc_path))
|
|
overall_status = overall_status + 1
|
|
|
|
# If XML object exists, add result
|
|
if overall_status != 0:
|
|
tc.SetFailed("DscCompleteCheck {0} Failed. Errors {1}".format(
|
|
wsr_dsc_path, overall_status), "CHECK_FAILED")
|
|
else:
|
|
tc.SetSuccess()
|
|
return overall_status
|
|
|
|
@staticmethod
|
|
def _module_in_dsc(inf: str, dsc: DscParser, Edk2pathObj: Edk2Path) -> bool:
|
|
|
|
"""Checks if the given module (inf) is in the given dsc.
|
|
Args:
|
|
inf (str): The inf file to check for
|
|
dsc (DscParser): The parsed dsc file.
|
|
Edk2pathObj (Edk2Path): The path object capturing the workspace and package paths.
|
|
Returns:
|
|
bool: if the module is in the dsc.
|
|
"""
|
|
for module_type in (dsc.ThreeMods, dsc.SixMods, dsc.OtherMods):
|
|
for module in module_type:
|
|
if Path(module).is_absolute():
|
|
module = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(module)
|
|
if inf in module:
|
|
return True
|
|
return False
|