2 # This file is for installed package information database operations
4 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
16 from os
.path
import dirname
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)
35 # This class represents the dependency rule check mechanism
37 # @param object: Inherited from object class
39 class DependencyRules(object):
40 def __init__(self
, Datab
, ToBeInstalledPkgList
=None):
42 self
.WsPkgList
= GetWorkspacePackage()
43 self
.WsModuleList
= GetWorkspaceModule()
45 self
.PkgsToBeDepend
= [(PkgInfo
[1], PkgInfo
[2]) for PkgInfo
in self
.WsPkgList
]
47 # Add package info from the DIST to be installed.
48 self
.PkgsToBeDepend
.extend(self
.GenToBeInstalledPkgList(ToBeInstalledPkgList
))
50 def GenToBeInstalledPkgList(self
, ToBeInstalledPkgList
):
51 if not ToBeInstalledPkgList
:
54 for Dist
in ToBeInstalledPkgList
:
55 for Package
in Dist
.PackageSurfaceArea
:
56 RtnList
.append((Package
[0], Package
[1]))
60 ## Check whether a module exists by checking the Guid+Version+Name+Path combination
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
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:
78 ## Check whether a module depex satisfied.
80 # @param ModuleObj: A module object
81 # @param DpObj: A distribution object
82 # @return: True if module depex satisfied
85 def CheckModuleDepexSatisfied(self
, ModuleObj
, DpObj
=None):
86 Logger
.Verbose(ST
.MSG_CHECK_MODULE_DEPEX_START
)
89 if ModuleObj
.GetPackageDependencyList():
90 Dep
= ModuleObj
.GetPackageDependencyList()[0]
91 for Dep
in ModuleObj
.GetPackageDependencyList():
93 # first check whether the dependency satisfied by current workspace
95 Exist
= self
.CheckPackageExists(Dep
.GetGuid(), Dep
.GetVersion())
97 # check whether satisfied by current distribution
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:
109 if Dep
.GetVersion() == GuidVerPair
[1]:
117 Logger
.Error("CheckModuleDepex", UNKNOWN_ERROR
, \
118 ST
.ERR_DEPENDENCY_NOT_MATCH
% (ModuleObj
.GetName(), \
119 Dep
.GetPackageFilePath(), \
124 ## Check whether a package exists in a package list specified by PkgsToBeDepend.
126 # @param Guid: Guid of a package
127 # @param Version: Version of a package
128 # @return: True if package exist
131 def CheckPackageExists(self
, Guid
, Version
):
132 Logger
.Verbose(ST
.MSG_CHECK_PACKAGE_START
)
134 for (PkgGuid
, PkgVer
) in self
.PkgsToBeDepend
:
135 if (PkgGuid
== Guid
):
137 # if version is not empty and not equal, then not match
139 if Version
and (PkgVer
!= Version
):
148 Logger
.Verbose(ST
.MSG_CHECK_PACKAGE_FINISH
)
151 ## Check whether a package depex satisfied.
153 # @param PkgObj: A package object
154 # @param DpObj: A distribution object
155 # @return: True if package depex satisfied
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
):
168 ## Check whether a DP exists.
170 # @param Guid: Guid of a Distribution
171 # @param Version: Version of a Distribution
172 # @return: True if Distribution exist
174 def CheckDpExists(self
, Guid
, Version
):
175 Logger
.Verbose(ST
.MSG_CHECK_DP_START
)
176 DpList
= self
.IpiDb
.GetDp(Guid
, Version
)
182 Logger
.Verbose(ST
.MSG_CHECK_DP_FINISH
)
185 ## Check whether a DP depex satisfied by current workspace for Install
187 # @param DpObj: A distribution object
188 # @return: True if distribution depex satisfied
191 def CheckInstallDpDepexSatisfied(self
, DpObj
):
192 return self
.CheckDpDepexSatisfied(DpObj
)
194 # # Check whether multiple DP depex satisfied by current workspace for Install
196 # @param DpObjList: A distribution object list
197 # @return: True if distribution depex satisfied
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
))
212 ## Check whether a DP depex satisfied by current workspace
213 # (excluding the original distribution's packages to be replaced) for Replace
215 # @param DpObj: A distribution object
216 # @param OrigDpGuid: The original distribution's Guid
217 # @param OrigDpVersion: The original distribution's Version
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
)
228 ## Check whether a DP depex satisfied by current workspace.
230 # @param DpObj: A distribution object
232 def CheckDpDepexSatisfied(self
, DpObj
):
233 for PkgKey
in DpObj
.PackageSurfaceArea
.keys():
234 PkgObj
= DpObj
.PackageSurfaceArea
[PkgKey
]
235 if self
.CheckPackageDepexSatisfied(PkgObj
, DpObj
):
240 for ModKey
in DpObj
.ModuleSurfaceArea
.keys():
241 ModObj
= DpObj
.ModuleSurfaceArea
[ModKey
]
242 if self
.CheckModuleDepexSatisfied(ModObj
, DpObj
):
249 ## Check whether a DP could be removed from current workspace.
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
256 def CheckDpDepexForRemove(self
, DpGuid
, DpVersion
):
258 DependModuleList
= []
259 WsModuleList
= self
.WsModuleList
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
)
269 ST
.ERR_MODULE_NOT_INSTALLED
% Module
)
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
:
279 DecPath
= dirname(DecFile
)
280 if DecPath
.find(WorkSP
) > -1:
281 InstallPath
= GetRelativePath(DecPath
, WorkSP
)
282 DecFileRelaPath
= GetRelativePath(DecFile
, WorkSP
)
284 InstallPath
= DecPath
285 DecFileRelaPath
= DecFile
287 if (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
288 DpPackagePathList
.append(DecFileRelaPath
)
289 DpPackageList
.remove((PkgGuid
, PkgVersion
, InstallPath
))
292 # the left items in DpPackageList are the packages that installed but not found anymore
294 for (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
296 ST
.WARN_INSTALLED_PACKAGE_NOT_FOUND
%(PkgGuid
, PkgVersion
, InstallPath
))
299 # check modules to see if has dependency on package of current DP
301 for Module
in WsModuleList
:
302 if (not VerifyRemoveModuleDep(Module
, DpPackagePathList
)):
304 DependModuleList
.append(Module
)
305 return (Removable
, DependModuleList
)
308 ## Check whether a DP could be replaced by a distribution containing NewDpPkgList
309 # from current workspace.
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
317 def CheckDpDepexForReplace(self
, OrigDpGuid
, OrigDpVersion
, NewDpPkgList
):
319 DependModuleList
= []
320 WsModuleList
= self
.WsModuleList
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
)
330 ST
.ERR_MODULE_NOT_INSTALLED
% Module
)
332 OtherPkgList
= NewDpPkgList
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
:
342 DecPath
= dirname(DecFile
)
343 if DecPath
.find(WorkSP
) > -1:
344 InstallPath
= GetRelativePath(DecPath
, WorkSP
)
345 DecFileRelaPath
= GetRelativePath(DecFile
, WorkSP
)
347 InstallPath
= DecPath
348 DecFileRelaPath
= DecFile
350 if (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
351 DpPackagePathList
.append(DecFileRelaPath
)
352 DpPackageList
.remove((PkgGuid
, PkgVersion
, InstallPath
))
354 OtherPkgList
.append((PkgGuid
, PkgVersion
))
357 # the left items in DpPackageList are the packages that installed but not found anymore
359 for (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
361 ST
.WARN_INSTALLED_PACKAGE_NOT_FOUND
%(PkgGuid
, PkgVersion
, InstallPath
))
364 # check modules to see if it can be satisfied by package not belong to removed DP
366 for Module
in WsModuleList
:
367 if (not VerifyReplaceModuleDep(Module
, DpPackagePathList
, OtherPkgList
)):
369 DependModuleList
.append(Module
)
370 return (Replaceable
, DependModuleList
)
373 ## check whether module depends on packages in DpPackagePathList, return True
374 # if found, False else
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
381 def VerifyRemoveModuleDep(Path
, DpPackagePathList
):
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
))
390 except FatalError
as ErrCode
:
391 if ErrCode
.message
== EDK1_INF_ERROR
:
393 ST
.WRN_EDK1_INF_FOUND
%Path
)
400 # Get Dependency package path from an Inf file path
402 def GetPackagePath(InfPath
):
404 if os
.path
.exists(InfPath
):
406 for Line
in open(InfPath
).readlines():
410 if Line
.startswith('#'):
412 if Line
.startswith('[Packages') and Line
.endswith(']'):
415 if Line
.startswith('[') and Line
.endswith(']') and FindSection
:
418 PackagePath
.append(os
.path
.normpath(Line
))
422 ## check whether module depends on packages in DpPackagePathList and can not be satisfied by OtherPkgList
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
431 def VerifyReplaceModuleDep(Path
, DpPackagePathList
, OtherPkgList
):
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
))
442 except FatalError
as ErrCode
:
443 if ErrCode
.message
== EDK1_INF_ERROR
:
445 ST
.WRN_EDK1_INF_FOUND
%Path
)