VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/.pytool/Plugin/DependencyCheck/DependencyCheck.py@ 85805

Last change on this file since 85805 was 85718, checked in by vboxsync, 5 years ago

Devices/EFI: Merge edk-stable202005 and make it build, bugref:4643

  • Property svn:eol-style set to native
File size: 5.6 KB
Line 
1# @file dependency_check.py
2#
3# Copyright (c) Microsoft Corporation.
4# SPDX-License-Identifier: BSD-2-Clause-Patent
5##
6
7import logging
8import os
9from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin
10from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser
11from edk2toolext.environment.var_dict import VarDict
12
13
14class DependencyCheck(ICiBuildPlugin):
15 """
16 A CiBuildPlugin that finds all modules (inf files) in a package and reviews the packages used
17 to confirm they are acceptable. This is to help enforce layering and identify improper
18 dependencies between packages.
19
20 Configuration options:
21 "DependencyCheck": {
22 "AcceptableDependencies": [], # Package dec files that are allowed in all INFs. Example: MdePkg/MdePkg.dec
23 "AcceptableDependencies-<MODULE_TYPE>": [], # OPTIONAL Package dependencies for INFs that are HOST_APPLICATION
24 "AcceptableDependencies-HOST_APPLICATION": [], # EXAMPLE Package dependencies for INFs that are HOST_APPLICATION
25 "IgnoreInf": [] # Ignore INF if found in filesystem
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 ("Test Package Dependencies for modules in " + packagename, packagename + ".DependencyCheck")
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 # - EnvConfig Object
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 # Get current platform
58 abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagename)
59
60 # Get INF Files
61 INFFiles = self.WalkDirectoryForExtension([".inf"], abs_pkg_path)
62 INFFiles = [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(x) for x in INFFiles] # make edk2relative path so can compare with Ignore List
63
64 # Remove ignored INFs
65 if "IgnoreInf" in pkgconfig:
66 for a in pkgconfig["IgnoreInf"]:
67 a = a.replace(os.sep, "/") ## convert path sep in case ignore list is bad. Can't change case
68 try:
69 INFFiles.remove(a)
70 tc.LogStdOut("IgnoreInf {0}".format(a))
71 except:
72 logging.info("DependencyConfig.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a))
73 tc.LogStdError("DependencyConfig.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a))
74
75
76 # Get the AccpetableDependencies list
77 if "AcceptableDependencies" not in pkgconfig:
78 logging.info("DependencyCheck Skipped. No Acceptable Dependencies defined.")
79 tc.LogStdOut("DependencyCheck Skipped. No Acceptable Dependencies defined.")
80 tc.SetSkipped()
81 return -1
82
83 # Log dependencies
84 for k in pkgconfig.keys():
85 if k.startswith("AcceptableDependencies"):
86 pkgstring = "\n".join(pkgconfig[k])
87 if ("-" in k):
88 _, _, mod_type = k.partition("-")
89 tc.LogStdOut(f"Additional dependencies for MODULE_TYPE {mod_type}:\n {pkgstring}")
90 else:
91 tc.LogStdOut(f"Acceptable Dependencies:\n {pkgstring}")
92
93 # For each INF file
94 for file in INFFiles:
95 ip = InfParser()
96 logging.debug("Parsing " + file)
97 ip.SetBaseAbsPath(Edk2pathObj.WorkspacePath).SetPackagePaths(Edk2pathObj.PackagePathList).ParseFile(file)
98
99 if("MODULE_TYPE" not in ip.Dict):
100 tc.LogStdOut("Ignoring INF. Missing key for MODULE_TYPE {0}".format(file))
101 continue
102
103 mod_type = ip.Dict["MODULE_TYPE"].upper()
104 for p in ip.PackagesUsed:
105 if p not in pkgconfig["AcceptableDependencies"]:
106 # If not in the main acceptable dependencies list then check module specific
107 mod_specific_key = "AcceptableDependencies-" + mod_type
108 if mod_specific_key in pkgconfig and p in pkgconfig[mod_specific_key]:
109 continue
110
111 logging.error("Dependency Check: Invalid Dependency INF: {0} depends on pkg {1}".format(file, p))
112 tc.LogStdError("Dependency Check: Invalid Dependency INF: {0} depends on pkg {1}".format(file, p))
113 overall_status += 1
114
115 # If XML object exists, add results
116 if overall_status != 0:
117 tc.SetFailed("Failed with {0} errors".format(overall_status), "DEPENDENCYCHECK_FAILED")
118 else:
119 tc.SetSuccess()
120 return overall_status
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette