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