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