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