summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Core/DependencyRules.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Core/DependencyRules.py
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Core/DependencyRules.py')
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Core/DependencyRules.py448
1 files changed, 448 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Core/DependencyRules.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Core/DependencyRules.py
new file mode 100755
index 00000000..2742db84
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Core/DependencyRules.py
@@ -0,0 +1,448 @@
+## @file
+# This file is for installed package information database operations
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+'''
+Dependency
+'''
+
+##
+# Import Modules
+#
+from os.path import dirname
+import os
+
+import Logger.Log as Logger
+from Logger import StringTable as ST
+from Library.Parsing import GetWorkspacePackage
+from Library.Parsing import GetWorkspaceModule
+from Library.Parsing import GetPkgInfoFromDec
+from Library.Misc import GetRelativePath
+from Library import GlobalData
+from Logger.ToolError import FatalError
+from Logger.ToolError import EDK1_INF_ERROR
+from Logger.ToolError import UNKNOWN_ERROR
+(DEPEX_CHECK_SUCCESS, DEPEX_CHECK_MODULE_NOT_FOUND, \
+DEPEX_CHECK_PACKAGE_NOT_FOUND, DEPEX_CHECK_DP_NOT_FOUND) = (0, 1, 2, 3)
+
+
+## DependencyRules
+#
+# This class represents the dependency rule check mechanism
+#
+# @param object: Inherited from object class
+#
+class DependencyRules(object):
+ def __init__(self, Datab, ToBeInstalledPkgList=None):
+ self.IpiDb = Datab
+ self.WsPkgList = GetWorkspacePackage()
+ self.WsModuleList = GetWorkspaceModule()
+
+ self.PkgsToBeDepend = [(PkgInfo[1], PkgInfo[2]) for PkgInfo in self.WsPkgList]
+
+ # Add package info from the DIST to be installed.
+ self.PkgsToBeDepend.extend(self.GenToBeInstalledPkgList(ToBeInstalledPkgList))
+
+ def GenToBeInstalledPkgList(self, ToBeInstalledPkgList):
+ if not ToBeInstalledPkgList:
+ return []
+ RtnList = []
+ for Dist in ToBeInstalledPkgList:
+ for Package in Dist.PackageSurfaceArea:
+ RtnList.append((Package[0], Package[1]))
+
+ return RtnList
+
+ ## Check whether a module exists by checking the Guid+Version+Name+Path combination
+ #
+ # @param Guid: Guid of a module
+ # @param Version: Version of a module
+ # @param Name: Name of a module
+ # @param Path: Path of a module
+ # @return: True if module existed, else False
+ #
+ def CheckModuleExists(self, Guid, Version, Name, Path):
+ Logger.Verbose(ST.MSG_CHECK_MODULE_EXIST)
+ ModuleList = self.IpiDb.GetModInPackage(Guid, Version, Name, Path)
+ ModuleList.extend(self.IpiDb.GetStandaloneModule(Guid, Version, Name, Path))
+ Logger.Verbose(ST.MSG_CHECK_MODULE_EXIST_FINISH)
+ if len(ModuleList) > 0:
+ return True
+ else:
+ return False
+
+ ## Check whether a module depex satisfied.
+ #
+ # @param ModuleObj: A module object
+ # @param DpObj: A distribution object
+ # @return: True if module depex satisfied
+ # False else
+ #
+ def CheckModuleDepexSatisfied(self, ModuleObj, DpObj=None):
+ Logger.Verbose(ST.MSG_CHECK_MODULE_DEPEX_START)
+ Result = True
+ Dep = None
+ if ModuleObj.GetPackageDependencyList():
+ Dep = ModuleObj.GetPackageDependencyList()[0]
+ for Dep in ModuleObj.GetPackageDependencyList():
+ #
+ # first check whether the dependency satisfied by current workspace
+ #
+ Exist = self.CheckPackageExists(Dep.GetGuid(), Dep.GetVersion())
+ #
+ # check whether satisfied by current distribution
+ #
+ if not Exist:
+ if DpObj is None:
+ Result = False
+ break
+ for GuidVerPair in DpObj.PackageSurfaceArea.keys():
+ if Dep.GetGuid() == GuidVerPair[0]:
+ if Dep.GetVersion() is None or \
+ len(Dep.GetVersion()) == 0:
+ Result = True
+ break
+ if Dep.GetVersion() == GuidVerPair[1]:
+ Result = True
+ break
+ else:
+ Result = False
+ break
+
+ if not Result:
+ Logger.Error("CheckModuleDepex", UNKNOWN_ERROR, \
+ ST.ERR_DEPENDENCY_NOT_MATCH % (ModuleObj.GetName(), \
+ Dep.GetPackageFilePath(), \
+ Dep.GetGuid(), \
+ Dep.GetVersion()))
+ return Result
+
+ ## Check whether a package exists in a package list specified by PkgsToBeDepend.
+ #
+ # @param Guid: Guid of a package
+ # @param Version: Version of a package
+ # @return: True if package exist
+ # False else
+ #
+ def CheckPackageExists(self, Guid, Version):
+ Logger.Verbose(ST.MSG_CHECK_PACKAGE_START)
+ Found = False
+ for (PkgGuid, PkgVer) in self.PkgsToBeDepend:
+ if (PkgGuid == Guid):
+ #
+ # if version is not empty and not equal, then not match
+ #
+ if Version and (PkgVer != Version):
+ Found = False
+ break
+ else:
+ Found = True
+ break
+ else:
+ Found = False
+
+ Logger.Verbose(ST.MSG_CHECK_PACKAGE_FINISH)
+ return Found
+
+ ## Check whether a package depex satisfied.
+ #
+ # @param PkgObj: A package object
+ # @param DpObj: A distribution object
+ # @return: True if package depex satisfied
+ # False else
+ #
+ def CheckPackageDepexSatisfied(self, PkgObj, DpObj=None):
+ ModuleDict = PkgObj.GetModuleDict()
+ for ModKey in ModuleDict.keys():
+ ModObj = ModuleDict[ModKey]
+ if self.CheckModuleDepexSatisfied(ModObj, DpObj):
+ continue
+ else:
+ return False
+ return True
+
+ ## Check whether a DP exists.
+ #
+ # @param Guid: Guid of a Distribution
+ # @param Version: Version of a Distribution
+ # @return: True if Distribution exist
+ # False else
+ def CheckDpExists(self, Guid, Version):
+ Logger.Verbose(ST.MSG_CHECK_DP_START)
+ DpList = self.IpiDb.GetDp(Guid, Version)
+ if len(DpList) > 0:
+ Found = True
+ else:
+ Found = False
+
+ Logger.Verbose(ST.MSG_CHECK_DP_FINISH)
+ return Found
+
+ ## Check whether a DP depex satisfied by current workspace for Install
+ #
+ # @param DpObj: A distribution object
+ # @return: True if distribution depex satisfied
+ # False else
+ #
+ def CheckInstallDpDepexSatisfied(self, DpObj):
+ return self.CheckDpDepexSatisfied(DpObj)
+
+ # # Check whether multiple DP depex satisfied by current workspace for Install
+ #
+ # @param DpObjList: A distribution object list
+ # @return: True if distribution depex satisfied
+ # False else
+ #
+ def CheckTestInstallPdDepexSatisfied(self, DpObjList):
+ for DpObj in DpObjList:
+ if self.CheckDpDepexSatisfied(DpObj):
+ for PkgKey in DpObj.PackageSurfaceArea.keys():
+ PkgObj = DpObj.PackageSurfaceArea[PkgKey]
+ self.PkgsToBeDepend.append((PkgObj.Guid, PkgObj.Version))
+ else:
+ return False, DpObj
+
+ return True, DpObj
+
+
+ ## Check whether a DP depex satisfied by current workspace
+ # (excluding the original distribution's packages to be replaced) for Replace
+ #
+ # @param DpObj: A distribution object
+ # @param OrigDpGuid: The original distribution's Guid
+ # @param OrigDpVersion: The original distribution's Version
+ #
+ def ReplaceCheckNewDpDepex(self, DpObj, OrigDpGuid, OrigDpVersion):
+ self.PkgsToBeDepend = [(PkgInfo[1], PkgInfo[2]) for PkgInfo in self.WsPkgList]
+ OrigDpPackageList = self.IpiDb.GetPackageListFromDp(OrigDpGuid, OrigDpVersion)
+ for OrigPkgInfo in OrigDpPackageList:
+ Guid, Version = OrigPkgInfo[0], OrigPkgInfo[1]
+ if (Guid, Version) in self.PkgsToBeDepend:
+ self.PkgsToBeDepend.remove((Guid, Version))
+ return self.CheckDpDepexSatisfied(DpObj)
+
+ ## Check whether a DP depex satisfied by current workspace.
+ #
+ # @param DpObj: A distribution object
+ #
+ def CheckDpDepexSatisfied(self, DpObj):
+ for PkgKey in DpObj.PackageSurfaceArea.keys():
+ PkgObj = DpObj.PackageSurfaceArea[PkgKey]
+ if self.CheckPackageDepexSatisfied(PkgObj, DpObj):
+ continue
+ else:
+ return False
+
+ for ModKey in DpObj.ModuleSurfaceArea.keys():
+ ModObj = DpObj.ModuleSurfaceArea[ModKey]
+ if self.CheckModuleDepexSatisfied(ModObj, DpObj):
+ continue
+ else:
+ return False
+
+ return True
+
+ ## Check whether a DP could be removed from current workspace.
+ #
+ # @param DpGuid: File's guid
+ # @param DpVersion: File's version
+ # @retval Removable: True if distribution could be removed, False Else
+ # @retval DependModuleList: the list of modules that make distribution can not be removed
+ #
+ def CheckDpDepexForRemove(self, DpGuid, DpVersion):
+ Removable = True
+ DependModuleList = []
+ WsModuleList = self.WsModuleList
+ #
+ # remove modules that included in current DP
+ # List of item (FilePath)
+ DpModuleList = self.IpiDb.GetDpModuleList(DpGuid, DpVersion)
+ for Module in DpModuleList:
+ if Module in WsModuleList:
+ WsModuleList.remove(Module)
+ else:
+ Logger.Warn("UPT\n",
+ ST.ERR_MODULE_NOT_INSTALLED % Module)
+ #
+ # get packages in current Dp and find the install path
+ # List of item (PkgGuid, PkgVersion, InstallPath)
+ DpPackageList = self.IpiDb.GetPackageListFromDp(DpGuid, DpVersion)
+ DpPackagePathList = []
+ WorkSP = GlobalData.gWORKSPACE
+ for (PkgName, PkgGuid, PkgVersion, DecFile) in self.WsPkgList:
+ if PkgName:
+ pass
+ DecPath = dirname(DecFile)
+ if DecPath.find(WorkSP) > -1:
+ InstallPath = GetRelativePath(DecPath, WorkSP)
+ DecFileRelaPath = GetRelativePath(DecFile, WorkSP)
+ else:
+ InstallPath = DecPath
+ DecFileRelaPath = DecFile
+
+ if (PkgGuid, PkgVersion, InstallPath) in DpPackageList:
+ DpPackagePathList.append(DecFileRelaPath)
+ DpPackageList.remove((PkgGuid, PkgVersion, InstallPath))
+
+ #
+ # the left items in DpPackageList are the packages that installed but not found anymore
+ #
+ for (PkgGuid, PkgVersion, InstallPath) in DpPackageList:
+ Logger.Warn("UPT",
+ ST.WARN_INSTALLED_PACKAGE_NOT_FOUND%(PkgGuid, PkgVersion, InstallPath))
+
+ #
+ # check modules to see if has dependency on package of current DP
+ #
+ for Module in WsModuleList:
+ if (not VerifyRemoveModuleDep(Module, DpPackagePathList)):
+ Removable = False
+ DependModuleList.append(Module)
+ return (Removable, DependModuleList)
+
+
+ ## Check whether a DP could be replaced by a distribution containing NewDpPkgList
+ # from current workspace.
+ #
+ # @param OrigDpGuid: original Dp's Guid
+ # @param OrigDpVersion: original Dp's version
+ # @param NewDpPkgList: a list of package information (Guid, Version) in new Dp
+ # @retval Replaceable: True if distribution could be replaced, False Else
+ # @retval DependModuleList: the list of modules that make distribution can not be replaced
+ #
+ def CheckDpDepexForReplace(self, OrigDpGuid, OrigDpVersion, NewDpPkgList):
+ Replaceable = True
+ DependModuleList = []
+ WsModuleList = self.WsModuleList
+ #
+ # remove modules that included in current DP
+ # List of item (FilePath)
+ DpModuleList = self.IpiDb.GetDpModuleList(OrigDpGuid, OrigDpVersion)
+ for Module in DpModuleList:
+ if Module in WsModuleList:
+ WsModuleList.remove(Module)
+ else:
+ Logger.Warn("UPT\n",
+ ST.ERR_MODULE_NOT_INSTALLED % Module)
+
+ OtherPkgList = NewDpPkgList
+ #
+ # get packages in current Dp and find the install path
+ # List of item (PkgGuid, PkgVersion, InstallPath)
+ DpPackageList = self.IpiDb.GetPackageListFromDp(OrigDpGuid, OrigDpVersion)
+ DpPackagePathList = []
+ WorkSP = GlobalData.gWORKSPACE
+ for (PkgName, PkgGuid, PkgVersion, DecFile) in self.WsPkgList:
+ if PkgName:
+ pass
+ DecPath = dirname(DecFile)
+ if DecPath.find(WorkSP) > -1:
+ InstallPath = GetRelativePath(DecPath, WorkSP)
+ DecFileRelaPath = GetRelativePath(DecFile, WorkSP)
+ else:
+ InstallPath = DecPath
+ DecFileRelaPath = DecFile
+
+ if (PkgGuid, PkgVersion, InstallPath) in DpPackageList:
+ DpPackagePathList.append(DecFileRelaPath)
+ DpPackageList.remove((PkgGuid, PkgVersion, InstallPath))
+ else:
+ OtherPkgList.append((PkgGuid, PkgVersion))
+
+ #
+ # the left items in DpPackageList are the packages that installed but not found anymore
+ #
+ for (PkgGuid, PkgVersion, InstallPath) in DpPackageList:
+ Logger.Warn("UPT",
+ ST.WARN_INSTALLED_PACKAGE_NOT_FOUND%(PkgGuid, PkgVersion, InstallPath))
+
+ #
+ # check modules to see if it can be satisfied by package not belong to removed DP
+ #
+ for Module in WsModuleList:
+ if (not VerifyReplaceModuleDep(Module, DpPackagePathList, OtherPkgList)):
+ Replaceable = False
+ DependModuleList.append(Module)
+ return (Replaceable, DependModuleList)
+
+
+## check whether module depends on packages in DpPackagePathList, return True
+# if found, False else
+#
+# @param Path: a module path
+# @param DpPackagePathList: a list of Package Paths
+# @retval: False: module depends on package in DpPackagePathList
+# True: module doesn't depend on package in DpPackagePathList
+#
+def VerifyRemoveModuleDep(Path, DpPackagePathList):
+ try:
+ for Item in GetPackagePath(Path):
+ if Item in DpPackagePathList:
+ DecPath = os.path.normpath(os.path.join(GlobalData.gWORKSPACE, Item))
+ Logger.Info(ST.MSG_MODULE_DEPEND_ON % (Path, DecPath))
+ return False
+ else:
+ return True
+ except FatalError as ErrCode:
+ if ErrCode.message == EDK1_INF_ERROR:
+ Logger.Warn("UPT",
+ ST.WRN_EDK1_INF_FOUND%Path)
+ return True
+ else:
+ return True
+
+# # GetPackagePath
+#
+# Get Dependency package path from an Inf file path
+#
+def GetPackagePath(InfPath):
+ PackagePath = []
+ if os.path.exists(InfPath):
+ FindSection = False
+ for Line in open(InfPath).readlines():
+ Line = Line.strip()
+ if not Line:
+ continue
+ if Line.startswith('#'):
+ continue
+ if Line.startswith('[Packages') and Line.endswith(']'):
+ FindSection = True
+ continue
+ if Line.startswith('[') and Line.endswith(']') and FindSection:
+ break
+ if FindSection:
+ PackagePath.append(os.path.normpath(Line))
+
+ return PackagePath
+
+## check whether module depends on packages in DpPackagePathList and can not be satisfied by OtherPkgList
+#
+# @param Path: a module path
+# @param DpPackagePathList: a list of Package Paths
+# @param OtherPkgList: a list of Package Information (Guid, Version)
+# @retval: False: module depends on package in DpPackagePathList and can not be satisfied by OtherPkgList
+# True: either module doesn't depend on DpPackagePathList or module depends on DpPackagePathList
+# but can be satisfied by OtherPkgList
+#
+def VerifyReplaceModuleDep(Path, DpPackagePathList, OtherPkgList):
+ try:
+ for Item in GetPackagePath(Path):
+ if Item in DpPackagePathList:
+ DecPath = os.path.normpath(os.path.join(GlobalData.gWORKSPACE, Item))
+ Name, Guid, Version = GetPkgInfoFromDec(DecPath)
+ if (Guid, Version) not in OtherPkgList:
+ Logger.Info(ST.MSG_MODULE_DEPEND_ON % (Path, DecPath))
+ return False
+ else:
+ return True
+ except FatalError as ErrCode:
+ if ErrCode.message == EDK1_INF_ERROR:
+ Logger.Warn("UPT",
+ ST.WRN_EDK1_INF_FOUND%Path)
+ return True
+ else:
+ return True