1## @file 2# This file is for installed package information database operations 3# 4# Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR> 5# 6# This program and the accompanying materials are licensed and made available 7# under the terms and conditions of the BSD License which accompanies this 8# distribution. The full text of the license may be found at 9# http://opensource.org/licenses/bsd-license.php 10# 11# 12# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14# 15 16''' 17Dependency 18''' 19 20## 21# Import Modules 22# 23from os.path import dirname 24 25import Logger.Log as Logger 26from Logger import StringTable as ST 27from Library.Parsing import GetWorkspacePackage 28from Library.Parsing import GetWorkspaceModule 29from Library.Misc import GetRelativePath 30from Library import GlobalData 31from PomAdapter.InfPomAlignment import InfPomAlignment 32from Logger.ToolError import FatalError 33from Logger.ToolError import EDK1_INF_ERROR 34from Logger.ToolError import UNKNOWN_ERROR 35(DEPEX_CHECK_SUCCESS, DEPEX_CHECK_MODULE_NOT_FOUND, \ 36DEPEX_CHECK_PACKAGE_NOT_FOUND, DEPEX_CHECK_DP_NOT_FOUND) = (0, 1, 2, 3) 37 38 39## DependencyRules 40# 41# This class represents the dependency rule check mechanism 42# 43# @param object: Inherited from object class 44# 45class DependencyRules(object): 46 def __init__(self, Datab): 47 self.IpiDb = Datab 48 self.WsPkgList = GetWorkspacePackage() 49 self.WsModuleList = GetWorkspaceModule() 50 self.PkgsToBeDepend = [] 51 52 ## Check whether a module exists by checking the Guid+Version+Name+Path combination 53 # 54 # @param Guid: Guid of a module 55 # @param Version: Version of a module 56 # @param Name: Name of a module 57 # @param Path: Path of a module 58 # @return: True if module existed, else False 59 # 60 def CheckModuleExists(self, Guid, Version, Name, Path): 61 Logger.Verbose(ST.MSG_CHECK_MODULE_EXIST) 62 ModuleList = self.IpiDb.GetModInPackage(Guid, Version, Name, Path) 63 ModuleList.extend(self.IpiDb.GetStandaloneModule(Guid, Version, Name, Path)) 64 Logger.Verbose(ST.MSG_CHECK_MODULE_EXIST_FINISH) 65 if len(ModuleList) > 0: 66 return True 67 else: 68 return False 69 70 ## Check whether a module depex satisfied. 71 # 72 # @param ModuleObj: A module object 73 # @param DpObj: A distribution object 74 # @return: True if module depex satisfied 75 # False else 76 # 77 def CheckModuleDepexSatisfied(self, ModuleObj, DpObj=None): 78 Logger.Verbose(ST.MSG_CHECK_MODULE_DEPEX_START) 79 Result = True 80 Dep = None 81 if ModuleObj.GetPackageDependencyList(): 82 Dep = ModuleObj.GetPackageDependencyList()[0] 83 for Dep in ModuleObj.GetPackageDependencyList(): 84 # 85 # first check whether the dependency satisfied by current workspace 86 # 87 Exist = self.CheckPackageExists(Dep.GetGuid(), Dep.GetVersion()) 88 # 89 # check whether satisfied by current distribution 90 # 91 if not Exist: 92 if DpObj == None: 93 Result = False 94 break 95 for GuidVerPair in DpObj.PackageSurfaceArea.keys(): 96 if Dep.GetGuid() == GuidVerPair[0]: 97 if Dep.GetVersion() == None or \ 98 len(Dep.GetVersion()) == 0: 99 Result = True 100 break 101 if Dep.GetVersion() == GuidVerPair[1]: 102 Result = True 103 break 104 else: 105 Result = False 106 break 107 108 if not Result: 109 Logger.Error("CheckModuleDepex", UNKNOWN_ERROR, \ 110 ST.ERR_DEPENDENCY_NOT_MATCH % (ModuleObj.GetName(), \ 111 Dep.GetPackageFilePath(), \ 112 Dep.GetGuid(), \ 113 Dep.GetVersion())) 114 return Result 115 116 ## Check whether a package exists in a package list specified by PkgsToBeDepend. 117 # 118 # @param Guid: Guid of a package 119 # @param Version: Version of a package 120 # @return: True if package exist 121 # False else 122 # 123 def CheckPackageExists(self, Guid, Version): 124 Logger.Verbose(ST.MSG_CHECK_PACKAGE_START) 125 Found = False 126 for (PkgGuid, PkgVer) in self.PkgsToBeDepend: 127 if (PkgGuid == Guid): 128 # 129 # if version is not empty and not equal, then not match 130 # 131 if Version and (PkgVer != Version): 132 Found = False 133 break 134 else: 135 Found = True 136 break 137 else: 138 Found = False 139 140 Logger.Verbose(ST.MSG_CHECK_PACKAGE_FINISH) 141 return Found 142 143 ## Check whether a package depex satisfied. 144 # 145 # @param PkgObj: A package object 146 # @param DpObj: A distribution object 147 # @return: True if package depex satisified 148 # False else 149 # 150 def CheckPackageDepexSatisfied(self, PkgObj, DpObj=None): 151 ModuleDict = PkgObj.GetModuleDict() 152 for ModKey in ModuleDict.keys(): 153 ModObj = ModuleDict[ModKey] 154 if self.CheckModuleDepexSatisfied(ModObj, DpObj): 155 continue 156 else: 157 return False 158 return True 159 160 ## Check whether a DP exists. 161 # 162 # @param Guid: Guid of a Distribution 163 # @param Version: Version of a Distribution 164 # @return: True if Distribution exist 165 # False else 166 def CheckDpExists(self, Guid, Version): 167 Logger.Verbose(ST.MSG_CHECK_DP_START) 168 DpList = self.IpiDb.GetDp(Guid, Version) 169 if len(DpList) > 0: 170 Found = True 171 else: 172 Found = False 173 174 Logger.Verbose(ST.MSG_CHECK_DP_FINISH) 175 return Found 176 177 ## Check whether a DP depex satisfied by current workspace for Install 178 # 179 # @param DpObj: A distribution object 180 # @return: True if distribution depex satisfied 181 # False else 182 # 183 def CheckInstallDpDepexSatisfied(self, DpObj): 184 self.PkgsToBeDepend = [(PkgInfo[1], PkgInfo[2]) for PkgInfo in self.WsPkgList] 185 return self.CheckDpDepexSatisfied(DpObj) 186 187 # # Check whether multiple DP depex satisfied by current workspace for Install 188 # 189 # @param DpObjList: A distribution object list 190 # @return: True if distribution depex satisfied 191 # False else 192 # 193 def CheckTestInstallPdDepexSatisfied(self, DpObjList): 194 self.PkgsToBeDepend = [(PkgInfo[1], PkgInfo[2]) for PkgInfo in self.WsPkgList] 195 for DpObj in DpObjList: 196 if self.CheckDpDepexSatisfied(DpObj): 197 for PkgKey in DpObj.PackageSurfaceArea.keys(): 198 PkgObj = DpObj.PackageSurfaceArea[PkgKey] 199 self.PkgsToBeDepend.append((PkgObj.Guid, PkgObj.Version)) 200 else: 201 return False, DpObj 202 203 return True, DpObj 204 205 206 ## Check whether a DP depex satisfied by current workspace 207 # (excluding the original distribution's packages to be replaced) for Replace 208 # 209 # @param DpObj: A distribution object 210 # @param OrigDpGuid: The original distribution's Guid 211 # @param OrigDpVersion: The original distribution's Version 212 # 213 def ReplaceCheckNewDpDepex(self, DpObj, OrigDpGuid, OrigDpVersion): 214 self.PkgsToBeDepend = [(PkgInfo[1], PkgInfo[2]) for PkgInfo in self.WsPkgList] 215 OrigDpPackageList = self.IpiDb.GetPackageListFromDp(OrigDpGuid, OrigDpVersion) 216 for OrigPkgInfo in OrigDpPackageList: 217 Guid, Version = OrigPkgInfo[0], OrigPkgInfo[1] 218 if (Guid, Version) in self.PkgsToBeDepend: 219 self.PkgsToBeDepend.remove((Guid, Version)) 220 return self.CheckDpDepexSatisfied(DpObj) 221 222 ## Check whether a DP depex satisfied by current workspace. 223 # 224 # @param DpObj: A distribution object 225 # 226 def CheckDpDepexSatisfied(self, DpObj): 227 for PkgKey in DpObj.PackageSurfaceArea.keys(): 228 PkgObj = DpObj.PackageSurfaceArea[PkgKey] 229 if self.CheckPackageDepexSatisfied(PkgObj, DpObj): 230 continue 231 else: 232 return False 233 234 for ModKey in DpObj.ModuleSurfaceArea.keys(): 235 ModObj = DpObj.ModuleSurfaceArea[ModKey] 236 if self.CheckModuleDepexSatisfied(ModObj, DpObj): 237 continue 238 else: 239 return False 240 241 return True 242 243 ## Check whether a DP could be removed from current workspace. 244 # 245 # @param DpGuid: File's guid 246 # @param DpVersion: File's version 247 # @retval Removable: True if distribution could be removed, False Else 248 # @retval DependModuleList: the list of modules that make distribution can not be removed 249 # 250 def CheckDpDepexForRemove(self, DpGuid, DpVersion): 251 Removable = True 252 DependModuleList = [] 253 WsModuleList = self.WsModuleList 254 # 255 # remove modules that included in current DP 256 # List of item (FilePath) 257 DpModuleList = self.IpiDb.GetDpModuleList(DpGuid, DpVersion) 258 for Module in DpModuleList: 259 if Module in WsModuleList: 260 WsModuleList.remove(Module) 261 else: 262 Logger.Warn("UPT\n", 263 ST.ERR_MODULE_NOT_INSTALLED % Module) 264 # 265 # get packages in current Dp and find the install path 266 # List of item (PkgGuid, PkgVersion, InstallPath) 267 DpPackageList = self.IpiDb.GetPackageListFromDp(DpGuid, DpVersion) 268 DpPackagePathList = [] 269 WorkSP = GlobalData.gWORKSPACE 270 for (PkgName, PkgGuid, PkgVersion, DecFile) in self.WsPkgList: 271 if PkgName: 272 pass 273 DecPath = dirname(DecFile) 274 if DecPath.find(WorkSP) > -1: 275 InstallPath = GetRelativePath(DecPath,WorkSP) 276 DecFileRelaPath = GetRelativePath(DecFile,WorkSP) 277 else: 278 InstallPath = DecPath 279 DecFileRelaPath = DecFile 280 281 if (PkgGuid, PkgVersion, InstallPath) in DpPackageList: 282 DpPackagePathList.append(DecFileRelaPath) 283 DpPackageList.remove((PkgGuid, PkgVersion, InstallPath)) 284 285 # 286 # the left items in DpPackageList are the packages that installed but not found anymore 287 # 288 for (PkgGuid, PkgVersion, InstallPath) in DpPackageList: 289 Logger.Warn("UPT", 290 ST.WARN_INSTALLED_PACKAGE_NOT_FOUND%(PkgGuid, PkgVersion, InstallPath)) 291 292 # 293 # check modules to see if has dependency on package of current DP 294 # 295 for Module in WsModuleList: 296 if (not VerifyRemoveModuleDep(Module, DpPackagePathList)): 297 Removable = False 298 DependModuleList.append(Module) 299 return (Removable, DependModuleList) 300 301 302 ## Check whether a DP could be replaced by a distribution containing NewDpPkgList 303 # from current workspace. 304 # 305 # @param OrigDpGuid: original Dp's Guid 306 # @param OrigDpVersion: original Dp's version 307 # @param NewDpPkgList: a list of package information (Guid, Version) in new Dp 308 # @retval Replaceable: True if distribution could be replaced, False Else 309 # @retval DependModuleList: the list of modules that make distribution can not be replaced 310 # 311 def CheckDpDepexForReplace(self, OrigDpGuid, OrigDpVersion, NewDpPkgList): 312 Replaceable = True 313 DependModuleList = [] 314 WsModuleList = self.WsModuleList 315 # 316 # remove modules that included in current DP 317 # List of item (FilePath) 318 DpModuleList = self.IpiDb.GetDpModuleList(OrigDpGuid, OrigDpVersion) 319 for Module in DpModuleList: 320 if Module in WsModuleList: 321 WsModuleList.remove(Module) 322 else: 323 Logger.Warn("UPT\n", 324 ST.ERR_MODULE_NOT_INSTALLED % Module) 325 326 OtherPkgList = NewDpPkgList 327 # 328 # get packages in current Dp and find the install path 329 # List of item (PkgGuid, PkgVersion, InstallPath) 330 DpPackageList = self.IpiDb.GetPackageListFromDp(OrigDpGuid, OrigDpVersion) 331 DpPackagePathList = [] 332 WorkSP = GlobalData.gWORKSPACE 333 for (PkgName, PkgGuid, PkgVersion, DecFile) in self.WsPkgList: 334 if PkgName: 335 pass 336 DecPath = dirname(DecFile) 337 if DecPath.find(WorkSP) > -1: 338 InstallPath = GetRelativePath(DecPath,WorkSP) 339 DecFileRelaPath = GetRelativePath(DecFile,WorkSP) 340 else: 341 InstallPath = DecPath 342 DecFileRelaPath = DecFile 343 344 if (PkgGuid, PkgVersion, InstallPath) in DpPackageList: 345 DpPackagePathList.append(DecFileRelaPath) 346 DpPackageList.remove((PkgGuid, PkgVersion, InstallPath)) 347 else: 348 OtherPkgList.append((PkgGuid, PkgVersion)) 349 350 # 351 # the left items in DpPackageList are the packages that installed but not found anymore 352 # 353 for (PkgGuid, PkgVersion, InstallPath) in DpPackageList: 354 Logger.Warn("UPT", 355 ST.WARN_INSTALLED_PACKAGE_NOT_FOUND%(PkgGuid, PkgVersion, InstallPath)) 356 357 # 358 # check modules to see if it can be satisfied by package not belong to removed DP 359 # 360 for Module in WsModuleList: 361 if (not VerifyReplaceModuleDep(Module, DpPackagePathList, OtherPkgList)): 362 Replaceable = False 363 DependModuleList.append(Module) 364 return (Replaceable, DependModuleList) 365 366 367## check whether module depends on packages in DpPackagePathList, return True 368# if found, False else 369# 370# @param Path: a module path 371# @param DpPackagePathList: a list of Package Paths 372# @retval: False: module depends on package in DpPackagePathList 373# True: module doesn't depend on package in DpPackagePathList 374# 375def VerifyRemoveModuleDep(Path, DpPackagePathList): 376 WorkSP = GlobalData.gWORKSPACE 377 378 try: 379 PomAli = InfPomAlignment(Path, WorkSP, Skip=True) 380 381 for Item in PomAli.GetPackageDependencyList(): 382 if Item.GetPackageFilePath() in DpPackagePathList: 383 Logger.Info(ST.MSG_MODULE_DEPEND_ON % (Path, Item.GetPackageFilePath())) 384 return False 385 else: 386 return True 387 except FatalError, ErrCode: 388 if ErrCode.message == EDK1_INF_ERROR: 389 Logger.Warn("UPT", 390 ST.WRN_EDK1_INF_FOUND%Path) 391 return True 392 else: 393 return True 394 395## check whether module depends on packages in DpPackagePathList and can not be satisfied by OtherPkgList 396# 397# @param Path: a module path 398# @param DpPackagePathList: a list of Package Paths 399# @param OtherPkgList: a list of Package Information (Guid, Version) 400# @retval: False: module depends on package in DpPackagePathList and can not be satisfied by OtherPkgList 401# True: either module doesn't depend on DpPackagePathList or module depends on DpPackagePathList 402# but can be satisfied by OtherPkgList 403# 404def VerifyReplaceModuleDep(Path, DpPackagePathList, OtherPkgList): 405 WorkSP = GlobalData.gWORKSPACE 406 407 try: 408 PomAli = InfPomAlignment(Path, WorkSP, Skip=True) 409 410 for Item in PomAli.GetPackageDependencyList(): 411 if Item.GetPackageFilePath() in DpPackagePathList: 412 Guid, Version = Item.GetGuid(), Item.GetVersion() 413 if (Guid, Version) not in OtherPkgList: 414 Logger.Info(ST.MSG_MODULE_DEPEND_ON % (Path, Item.GetPackageFilePath())) 415 return False 416 else: 417 return True 418 except FatalError, ErrCode: 419 if ErrCode.message == EDK1_INF_ERROR: 420 Logger.Warn("UPT", 421 ST.WRN_EDK1_INF_FOUND%Path) 422 return True 423 else: 424 return True 425 426 427 428