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