2 # This file is for installed package information database operations
4 # Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
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
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.
23 from os
.path
import dirname
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)
42 # This class represents the dependency rule check mechanism
44 # @param object: Inherited from object class
46 class DependencyRules(object):
47 def __init__(self
, Datab
):
49 self
.WsPkgList
= GetWorkspacePackage()
50 self
.WsModuleList
= GetWorkspaceModule()
51 self
.PkgsToBeDepend
= []
53 ## Check whether a module exists by checking the Guid+Version+Name+Path combination
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
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:
71 ## Check whether a module depex satisfied.
73 # @param ModuleObj: A module object
74 # @param DpObj: A distribution object
75 # @return: True if module depex satisfied
78 def CheckModuleDepexSatisfied(self
, ModuleObj
, DpObj
=None):
79 Logger
.Verbose(ST
.MSG_CHECK_MODULE_DEPEX_START
)
82 if ModuleObj
.GetPackageDependencyList():
83 Dep
= ModuleObj
.GetPackageDependencyList()[0]
84 for Dep
in ModuleObj
.GetPackageDependencyList():
86 # first check whether the dependency satisfied by current workspace
88 Exist
= self
.CheckPackageExists(Dep
.GetGuid(), Dep
.GetVersion())
90 # check whether satisfied by current distribution
96 for GuidVerPair
in DpObj
.PackageSurfaceArea
.keys():
97 if Dep
.GetGuid() == GuidVerPair
[0]:
98 if Dep
.GetVersion() == None or \
99 len(Dep
.GetVersion()) == 0:
102 if Dep
.GetVersion() == GuidVerPair
[1]:
110 Logger
.Error("CheckModuleDepex", UNKNOWN_ERROR
, \
111 ST
.ERR_DEPENDENCY_NOT_MATCH
% (ModuleObj
.GetName(), \
112 Dep
.GetPackageFilePath(), \
117 ## Check whether a package exists in a package list specified by PkgsToBeDepend.
119 # @param Guid: Guid of a package
120 # @param Version: Version of a package
121 # @return: True if package exist
124 def CheckPackageExists(self
, Guid
, Version
):
125 Logger
.Verbose(ST
.MSG_CHECK_PACKAGE_START
)
127 for (PkgGuid
, PkgVer
) in self
.PkgsToBeDepend
:
128 if (PkgGuid
== Guid
):
130 # if version is not empty and not equal, then not match
132 if Version
and (PkgVer
!= Version
):
141 Logger
.Verbose(ST
.MSG_CHECK_PACKAGE_FINISH
)
144 ## Check whether a package depex satisfied.
146 # @param PkgObj: A package object
147 # @param DpObj: A distribution object
148 # @return: True if package depex satisified
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
):
161 ## Check whether a DP exists.
163 # @param Guid: Guid of a Distribution
164 # @param Version: Version of a Distribution
165 # @return: True if Distribution exist
167 def CheckDpExists(self
, Guid
, Version
):
168 Logger
.Verbose(ST
.MSG_CHECK_DP_START
)
169 DpList
= self
.IpiDb
.GetDp(Guid
, Version
)
175 Logger
.Verbose(ST
.MSG_CHECK_DP_FINISH
)
178 ## Check whether a DP depex satisfied by current workspace for Install
180 # @param DpObj: A distribution object
181 # @return: True if distribution depex satisfied
184 def CheckInstallDpDepexSatisfied(self
, DpObj
):
185 self
.PkgsToBeDepend
= [(PkgInfo
[1], PkgInfo
[2]) for PkgInfo
in self
.WsPkgList
]
186 return self
.CheckDpDepexSatisfied(DpObj
)
188 # # Check whether multiple DP depex satisfied by current workspace for Install
190 # @param DpObjList: A distribution object list
191 # @return: True if distribution depex satisfied
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
))
207 ## Check whether a DP depex satisfied by current workspace
208 # (excluding the original distribution's packages to be replaced) for Replace
210 # @param DpObj: A distribution object
211 # @param OrigDpGuid: The original distribution's Guid
212 # @param OrigDpVersion: The original distribution's Version
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
)
223 ## Check whether a DP depex satisfied by current workspace.
225 # @param DpObj: A distribution object
227 def CheckDpDepexSatisfied(self
, DpObj
):
228 for PkgKey
in DpObj
.PackageSurfaceArea
.keys():
229 PkgObj
= DpObj
.PackageSurfaceArea
[PkgKey
]
230 if self
.CheckPackageDepexSatisfied(PkgObj
, DpObj
):
235 for ModKey
in DpObj
.ModuleSurfaceArea
.keys():
236 ModObj
= DpObj
.ModuleSurfaceArea
[ModKey
]
237 if self
.CheckModuleDepexSatisfied(ModObj
, DpObj
):
244 ## Check whether a DP could be removed from current workspace.
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
251 def CheckDpDepexForRemove(self
, DpGuid
, DpVersion
):
253 DependModuleList
= []
254 WsModuleList
= self
.WsModuleList
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
)
264 ST
.ERR_MODULE_NOT_INSTALLED
% Module
)
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
:
274 DecPath
= dirname(DecFile
)
275 if DecPath
.find(WorkSP
) > -1:
276 InstallPath
= GetRelativePath(DecPath
,WorkSP
)
277 DecFileRelaPath
= GetRelativePath(DecFile
,WorkSP
)
279 InstallPath
= DecPath
280 DecFileRelaPath
= DecFile
282 if (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
283 DpPackagePathList
.append(DecFileRelaPath
)
284 DpPackageList
.remove((PkgGuid
, PkgVersion
, InstallPath
))
287 # the left items in DpPackageList are the packages that installed but not found anymore
289 for (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
291 ST
.WARN_INSTALLED_PACKAGE_NOT_FOUND
%(PkgGuid
, PkgVersion
, InstallPath
))
294 # check modules to see if has dependency on package of current DP
296 for Module
in WsModuleList
:
297 if (not VerifyRemoveModuleDep(Module
, DpPackagePathList
)):
299 DependModuleList
.append(Module
)
300 return (Removable
, DependModuleList
)
303 ## Check whether a DP could be replaced by a distribution containing NewDpPkgList
304 # from current workspace.
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
312 def CheckDpDepexForReplace(self
, OrigDpGuid
, OrigDpVersion
, NewDpPkgList
):
314 DependModuleList
= []
315 WsModuleList
= self
.WsModuleList
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
)
325 ST
.ERR_MODULE_NOT_INSTALLED
% Module
)
327 OtherPkgList
= NewDpPkgList
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
:
337 DecPath
= dirname(DecFile
)
338 if DecPath
.find(WorkSP
) > -1:
339 InstallPath
= GetRelativePath(DecPath
,WorkSP
)
340 DecFileRelaPath
= GetRelativePath(DecFile
,WorkSP
)
342 InstallPath
= DecPath
343 DecFileRelaPath
= DecFile
345 if (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
346 DpPackagePathList
.append(DecFileRelaPath
)
347 DpPackageList
.remove((PkgGuid
, PkgVersion
, InstallPath
))
349 OtherPkgList
.append((PkgGuid
, PkgVersion
))
352 # the left items in DpPackageList are the packages that installed but not found anymore
354 for (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
356 ST
.WARN_INSTALLED_PACKAGE_NOT_FOUND
%(PkgGuid
, PkgVersion
, InstallPath
))
359 # check modules to see if it can be satisfied by package not belong to removed DP
361 for Module
in WsModuleList
:
362 if (not VerifyReplaceModuleDep(Module
, DpPackagePathList
, OtherPkgList
)):
364 DependModuleList
.append(Module
)
365 return (Replaceable
, DependModuleList
)
368 ## check whether module depends on packages in DpPackagePathList, return True
369 # if found, False else
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
376 def VerifyRemoveModuleDep(Path
, DpPackagePathList
):
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
))
385 except FatalError
, ErrCode
:
386 if ErrCode
.message
== EDK1_INF_ERROR
:
388 ST
.WRN_EDK1_INF_FOUND
%Path
)
395 # Get Dependency package path from an Inf file path
397 def GetPackagePath(InfPath
):
399 if os
.path
.exists(InfPath
):
401 for Line
in open(InfPath
).readlines():
405 if Line
.startswith('#'):
407 if Line
.startswith('[Packages') and Line
.endswith(']'):
410 if Line
.startswith('[') and Line
.endswith(']') and FindSection
:
413 PackagePath
.append(os
.path
.normpath(Line
))
417 ## check whether module depends on packages in DpPackagePathList and can not be satisfied by OtherPkgList
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
426 def VerifyReplaceModuleDep(Path
, DpPackagePathList
, OtherPkgList
):
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
))
437 except FatalError
, ErrCode
:
438 if ErrCode
.message
== EDK1_INF_ERROR
:
440 ST
.WRN_EDK1_INF_FOUND
%Path
)