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