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