1## @file 2# This file is for installed package information database operations 3# 4# Copyright (c) 2011 - 2014, 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 a DP depex satisfied by current workspace 188 # (excluding the original distribution's packages to be replaced) for Replace 189 # 190 # @param DpObj: A distribution object 191 # @param OrigDpGuid: The original distribution's Guid 192 # @param OrigDpVersion: The original distribution's Version 193 # 194 def ReplaceCheckNewDpDepex(self, DpObj, OrigDpGuid, OrigDpVersion): 195 self.PkgsToBeDepend = [(PkgInfo[1], PkgInfo[2]) for PkgInfo in self.WsPkgList] 196 OrigDpPackageList = self.IpiDb.GetPackageListFromDp(OrigDpGuid, OrigDpVersion) 197 for OrigPkgInfo in OrigDpPackageList: 198 Guid, Version = OrigPkgInfo[0], OrigPkgInfo[1] 199 if (Guid, Version) in self.PkgsToBeDepend: 200 self.PkgsToBeDepend.remove((Guid, Version)) 201 return self.CheckDpDepexSatisfied(DpObj) 202 203 ## Check whether a DP depex satisfied by current workspace. 204 # 205 # @param DpObj: A distribution object 206 # 207 def CheckDpDepexSatisfied(self, DpObj): 208 for PkgKey in DpObj.PackageSurfaceArea.keys(): 209 PkgObj = DpObj.PackageSurfaceArea[PkgKey] 210 if self.CheckPackageDepexSatisfied(PkgObj, DpObj): 211 continue 212 else: 213 return False 214 215 for ModKey in DpObj.ModuleSurfaceArea.keys(): 216 ModObj = DpObj.ModuleSurfaceArea[ModKey] 217 if self.CheckModuleDepexSatisfied(ModObj, DpObj): 218 continue 219 else: 220 return False 221 222 return True 223 224 ## Check whether a DP could be removed from current workspace. 225 # 226 # @param DpGuid: File's guid 227 # @param DpVersion: File's version 228 # @retval Removable: True if distribution could be removed, False Else 229 # @retval DependModuleList: the list of modules that make distribution can not be removed 230 # 231 def CheckDpDepexForRemove(self, DpGuid, DpVersion): 232 Removable = True 233 DependModuleList = [] 234 WsModuleList = self.WsModuleList 235 # 236 # remove modules that included in current DP 237 # List of item (FilePath) 238 DpModuleList = self.IpiDb.GetDpModuleList(DpGuid, DpVersion) 239 for Module in DpModuleList: 240 if Module in WsModuleList: 241 WsModuleList.remove(Module) 242 else: 243 Logger.Warn("UPT\n", 244 ST.ERR_MODULE_NOT_INSTALLED % Module) 245 # 246 # get packages in current Dp and find the install path 247 # List of item (PkgGuid, PkgVersion, InstallPath) 248 DpPackageList = self.IpiDb.GetPackageListFromDp(DpGuid, DpVersion) 249 DpPackagePathList = [] 250 WorkSP = GlobalData.gWORKSPACE 251 for (PkgName, PkgGuid, PkgVersion, DecFile) in self.WsPkgList: 252 if PkgName: 253 pass 254 DecPath = dirname(DecFile) 255 if DecPath.find(WorkSP) > -1: 256 InstallPath = GetRelativePath(DecPath,WorkSP) 257 DecFileRelaPath = GetRelativePath(DecFile,WorkSP) 258 else: 259 InstallPath = DecPath 260 DecFileRelaPath = DecFile 261 262 if (PkgGuid, PkgVersion, InstallPath) in DpPackageList: 263 DpPackagePathList.append(DecFileRelaPath) 264 DpPackageList.remove((PkgGuid, PkgVersion, InstallPath)) 265 266 # 267 # the left items in DpPackageList are the packages that installed but not found anymore 268 # 269 for (PkgGuid, PkgVersion, InstallPath) in DpPackageList: 270 Logger.Warn("UPT", 271 ST.WARN_INSTALLED_PACKAGE_NOT_FOUND%(PkgGuid, PkgVersion, InstallPath)) 272 273 # 274 # check modules to see if has dependency on package of current DP 275 # 276 for Module in WsModuleList: 277 if (not VerifyRemoveModuleDep(Module, DpPackagePathList)): 278 Removable = False 279 DependModuleList.append(Module) 280 return (Removable, DependModuleList) 281 282 283 ## Check whether a DP could be replaced by a distribution containing NewDpPkgList 284 # from current workspace. 285 # 286 # @param OrigDpGuid: original Dp's Guid 287 # @param OrigDpVersion: original Dp's version 288 # @param NewDpPkgList: a list of package information (Guid, Version) in new Dp 289 # @retval Replaceable: True if distribution could be replaced, False Else 290 # @retval DependModuleList: the list of modules that make distribution can not be replaced 291 # 292 def CheckDpDepexForReplace(self, OrigDpGuid, OrigDpVersion, NewDpPkgList): 293 Replaceable = True 294 DependModuleList = [] 295 WsModuleList = self.WsModuleList 296 # 297 # remove modules that included in current DP 298 # List of item (FilePath) 299 DpModuleList = self.IpiDb.GetDpModuleList(OrigDpGuid, OrigDpVersion) 300 for Module in DpModuleList: 301 if Module in WsModuleList: 302 WsModuleList.remove(Module) 303 else: 304 Logger.Warn("UPT\n", 305 ST.ERR_MODULE_NOT_INSTALLED % Module) 306 307 OtherPkgList = NewDpPkgList 308 # 309 # get packages in current Dp and find the install path 310 # List of item (PkgGuid, PkgVersion, InstallPath) 311 DpPackageList = self.IpiDb.GetPackageListFromDp(OrigDpGuid, OrigDpVersion) 312 DpPackagePathList = [] 313 WorkSP = GlobalData.gWORKSPACE 314 for (PkgName, PkgGuid, PkgVersion, DecFile) in self.WsPkgList: 315 if PkgName: 316 pass 317 DecPath = dirname(DecFile) 318 if DecPath.find(WorkSP) > -1: 319 InstallPath = GetRelativePath(DecPath,WorkSP) 320 DecFileRelaPath = GetRelativePath(DecFile,WorkSP) 321 else: 322 InstallPath = DecPath 323 DecFileRelaPath = DecFile 324 325 if (PkgGuid, PkgVersion, InstallPath) in DpPackageList: 326 DpPackagePathList.append(DecFileRelaPath) 327 DpPackageList.remove((PkgGuid, PkgVersion, InstallPath)) 328 else: 329 OtherPkgList.append((PkgGuid, PkgVersion)) 330 331 # 332 # the left items in DpPackageList are the packages that installed but not found anymore 333 # 334 for (PkgGuid, PkgVersion, InstallPath) in DpPackageList: 335 Logger.Warn("UPT", 336 ST.WARN_INSTALLED_PACKAGE_NOT_FOUND%(PkgGuid, PkgVersion, InstallPath)) 337 338 # 339 # check modules to see if it can be satisfied by package not belong to removed DP 340 # 341 for Module in WsModuleList: 342 if (not VerifyReplaceModuleDep(Module, DpPackagePathList, OtherPkgList)): 343 Replaceable = False 344 DependModuleList.append(Module) 345 return (Replaceable, DependModuleList) 346 347 348## check whether module depends on packages in DpPackagePathList, return True 349# if found, False else 350# 351# @param Path: a module path 352# @param DpPackagePathList: a list of Package Paths 353# @retval: False: module depends on package in DpPackagePathList 354# True: module doesn't depend on package in DpPackagePathList 355# 356def VerifyRemoveModuleDep(Path, DpPackagePathList): 357 WorkSP = GlobalData.gWORKSPACE 358 359 try: 360 PomAli = InfPomAlignment(Path, WorkSP, Skip=True) 361 362 for Item in PomAli.GetPackageDependencyList(): 363 if Item.GetPackageFilePath() in DpPackagePathList: 364 Logger.Info(ST.MSG_MODULE_DEPEND_ON % (Path, Item.GetPackageFilePath())) 365 return False 366 else: 367 return True 368 except FatalError, ErrCode: 369 if ErrCode.message == EDK1_INF_ERROR: 370 Logger.Warn("UPT", 371 ST.WRN_EDK1_INF_FOUND%Path) 372 return True 373 else: 374 return True 375 376## check whether module depends on packages in DpPackagePathList and can not be satisfied by OtherPkgList 377# 378# @param Path: a module path 379# @param DpPackagePathList: a list of Package Paths 380# @param OtherPkgList: a list of Package Information (Guid, Version) 381# @retval: False: module depends on package in DpPackagePathList and can not be satisfied by OtherPkgList 382# True: either module doesn't depend on DpPackagePathList or module depends on DpPackagePathList 383# but can be satisfied by OtherPkgList 384# 385def VerifyReplaceModuleDep(Path, DpPackagePathList, OtherPkgList): 386 WorkSP = GlobalData.gWORKSPACE 387 388 try: 389 PomAli = InfPomAlignment(Path, WorkSP, Skip=True) 390 391 for Item in PomAli.GetPackageDependencyList(): 392 if Item.GetPackageFilePath() in DpPackagePathList: 393 Guid, Version = Item.GetGuid(), Item.GetVersion() 394 if (Guid, Version) not in OtherPkgList: 395 Logger.Info(ST.MSG_MODULE_DEPEND_ON % (Path, Item.GetPackageFilePath())) 396 return False 397 else: 398 return True 399 except FatalError, ErrCode: 400 if ErrCode.message == EDK1_INF_ERROR: 401 Logger.Warn("UPT", 402 ST.WRN_EDK1_INF_FOUND%Path) 403 return True 404 else: 405 return True 406 407 408 409