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