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
, ToBeInstalledPkgList
=None):
49 self
.WsPkgList
= GetWorkspacePackage()
50 self
.WsModuleList
= GetWorkspaceModule()
52 self
.PkgsToBeDepend
= [(PkgInfo
[1], PkgInfo
[2]) for PkgInfo
in self
.WsPkgList
]
54 # Add package info from the DIST to be installed.
55 self
.PkgsToBeDepend
.extend(self
.GenToBeInstalledPkgList(ToBeInstalledPkgList
))
57 def GenToBeInstalledPkgList(self
, ToBeInstalledPkgList
):
59 for Dist
in ToBeInstalledPkgList
:
60 for Package
in Dist
.PackageSurfaceArea
:
61 RtnList
.append((Package
[0], Package
[1]))
65 ## Check whether a module exists by checking the Guid+Version+Name+Path combination
67 # @param Guid: Guid of a module
68 # @param Version: Version of a module
69 # @param Name: Name of a module
70 # @param Path: Path of a module
71 # @return: True if module existed, else False
73 def CheckModuleExists(self
, Guid
, Version
, Name
, Path
):
74 Logger
.Verbose(ST
.MSG_CHECK_MODULE_EXIST
)
75 ModuleList
= self
.IpiDb
.GetModInPackage(Guid
, Version
, Name
, Path
)
76 ModuleList
.extend(self
.IpiDb
.GetStandaloneModule(Guid
, Version
, Name
, Path
))
77 Logger
.Verbose(ST
.MSG_CHECK_MODULE_EXIST_FINISH
)
78 if len(ModuleList
) > 0:
83 ## Check whether a module depex satisfied.
85 # @param ModuleObj: A module object
86 # @param DpObj: A distribution object
87 # @return: True if module depex satisfied
90 def CheckModuleDepexSatisfied(self
, ModuleObj
, DpObj
=None):
91 Logger
.Verbose(ST
.MSG_CHECK_MODULE_DEPEX_START
)
94 if ModuleObj
.GetPackageDependencyList():
95 Dep
= ModuleObj
.GetPackageDependencyList()[0]
96 for Dep
in ModuleObj
.GetPackageDependencyList():
98 # first check whether the dependency satisfied by current workspace
100 Exist
= self
.CheckPackageExists(Dep
.GetGuid(), Dep
.GetVersion())
102 # check whether satisfied by current distribution
108 for GuidVerPair
in DpObj
.PackageSurfaceArea
.keys():
109 if Dep
.GetGuid() == GuidVerPair
[0]:
110 if Dep
.GetVersion() == None or \
111 len(Dep
.GetVersion()) == 0:
114 if Dep
.GetVersion() == GuidVerPair
[1]:
122 Logger
.Error("CheckModuleDepex", UNKNOWN_ERROR
, \
123 ST
.ERR_DEPENDENCY_NOT_MATCH
% (ModuleObj
.GetName(), \
124 Dep
.GetPackageFilePath(), \
129 ## Check whether a package exists in a package list specified by PkgsToBeDepend.
131 # @param Guid: Guid of a package
132 # @param Version: Version of a package
133 # @return: True if package exist
136 def CheckPackageExists(self
, Guid
, Version
):
137 Logger
.Verbose(ST
.MSG_CHECK_PACKAGE_START
)
139 for (PkgGuid
, PkgVer
) in self
.PkgsToBeDepend
:
140 if (PkgGuid
== Guid
):
142 # if version is not empty and not equal, then not match
144 if Version
and (PkgVer
!= Version
):
153 Logger
.Verbose(ST
.MSG_CHECK_PACKAGE_FINISH
)
156 ## Check whether a package depex satisfied.
158 # @param PkgObj: A package object
159 # @param DpObj: A distribution object
160 # @return: True if package depex satisified
163 def CheckPackageDepexSatisfied(self
, PkgObj
, DpObj
=None):
164 ModuleDict
= PkgObj
.GetModuleDict()
165 for ModKey
in ModuleDict
.keys():
166 ModObj
= ModuleDict
[ModKey
]
167 if self
.CheckModuleDepexSatisfied(ModObj
, DpObj
):
173 ## Check whether a DP exists.
175 # @param Guid: Guid of a Distribution
176 # @param Version: Version of a Distribution
177 # @return: True if Distribution exist
179 def CheckDpExists(self
, Guid
, Version
):
180 Logger
.Verbose(ST
.MSG_CHECK_DP_START
)
181 DpList
= self
.IpiDb
.GetDp(Guid
, Version
)
187 Logger
.Verbose(ST
.MSG_CHECK_DP_FINISH
)
190 ## Check whether a DP depex satisfied by current workspace for Install
192 # @param DpObj: A distribution object
193 # @return: True if distribution depex satisfied
196 def CheckInstallDpDepexSatisfied(self
, DpObj
):
197 return self
.CheckDpDepexSatisfied(DpObj
)
199 # # Check whether multiple DP depex satisfied by current workspace for Install
201 # @param DpObjList: A distribution object list
202 # @return: True if distribution depex satisfied
205 def CheckTestInstallPdDepexSatisfied(self
, DpObjList
):
206 for DpObj
in DpObjList
:
207 if self
.CheckDpDepexSatisfied(DpObj
):
208 for PkgKey
in DpObj
.PackageSurfaceArea
.keys():
209 PkgObj
= DpObj
.PackageSurfaceArea
[PkgKey
]
210 self
.PkgsToBeDepend
.append((PkgObj
.Guid
, PkgObj
.Version
))
217 ## Check whether a DP depex satisfied by current workspace
218 # (excluding the original distribution's packages to be replaced) for Replace
220 # @param DpObj: A distribution object
221 # @param OrigDpGuid: The original distribution's Guid
222 # @param OrigDpVersion: The original distribution's Version
224 def ReplaceCheckNewDpDepex(self
, DpObj
, OrigDpGuid
, OrigDpVersion
):
225 self
.PkgsToBeDepend
= [(PkgInfo
[1], PkgInfo
[2]) for PkgInfo
in self
.WsPkgList
]
226 OrigDpPackageList
= self
.IpiDb
.GetPackageListFromDp(OrigDpGuid
, OrigDpVersion
)
227 for OrigPkgInfo
in OrigDpPackageList
:
228 Guid
, Version
= OrigPkgInfo
[0], OrigPkgInfo
[1]
229 if (Guid
, Version
) in self
.PkgsToBeDepend
:
230 self
.PkgsToBeDepend
.remove((Guid
, Version
))
231 return self
.CheckDpDepexSatisfied(DpObj
)
233 ## Check whether a DP depex satisfied by current workspace.
235 # @param DpObj: A distribution object
237 def CheckDpDepexSatisfied(self
, DpObj
):
238 for PkgKey
in DpObj
.PackageSurfaceArea
.keys():
239 PkgObj
= DpObj
.PackageSurfaceArea
[PkgKey
]
240 if self
.CheckPackageDepexSatisfied(PkgObj
, DpObj
):
245 for ModKey
in DpObj
.ModuleSurfaceArea
.keys():
246 ModObj
= DpObj
.ModuleSurfaceArea
[ModKey
]
247 if self
.CheckModuleDepexSatisfied(ModObj
, DpObj
):
254 ## Check whether a DP could be removed from current workspace.
256 # @param DpGuid: File's guid
257 # @param DpVersion: File's version
258 # @retval Removable: True if distribution could be removed, False Else
259 # @retval DependModuleList: the list of modules that make distribution can not be removed
261 def CheckDpDepexForRemove(self
, DpGuid
, DpVersion
):
263 DependModuleList
= []
264 WsModuleList
= self
.WsModuleList
266 # remove modules that included in current DP
267 # List of item (FilePath)
268 DpModuleList
= self
.IpiDb
.GetDpModuleList(DpGuid
, DpVersion
)
269 for Module
in DpModuleList
:
270 if Module
in WsModuleList
:
271 WsModuleList
.remove(Module
)
274 ST
.ERR_MODULE_NOT_INSTALLED
% Module
)
276 # get packages in current Dp and find the install path
277 # List of item (PkgGuid, PkgVersion, InstallPath)
278 DpPackageList
= self
.IpiDb
.GetPackageListFromDp(DpGuid
, DpVersion
)
279 DpPackagePathList
= []
280 WorkSP
= GlobalData
.gWORKSPACE
281 for (PkgName
, PkgGuid
, PkgVersion
, DecFile
) in self
.WsPkgList
:
284 DecPath
= dirname(DecFile
)
285 if DecPath
.find(WorkSP
) > -1:
286 InstallPath
= GetRelativePath(DecPath
,WorkSP
)
287 DecFileRelaPath
= GetRelativePath(DecFile
,WorkSP
)
289 InstallPath
= DecPath
290 DecFileRelaPath
= DecFile
292 if (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
293 DpPackagePathList
.append(DecFileRelaPath
)
294 DpPackageList
.remove((PkgGuid
, PkgVersion
, InstallPath
))
297 # the left items in DpPackageList are the packages that installed but not found anymore
299 for (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
301 ST
.WARN_INSTALLED_PACKAGE_NOT_FOUND
%(PkgGuid
, PkgVersion
, InstallPath
))
304 # check modules to see if has dependency on package of current DP
306 for Module
in WsModuleList
:
307 if (not VerifyRemoveModuleDep(Module
, DpPackagePathList
)):
309 DependModuleList
.append(Module
)
310 return (Removable
, DependModuleList
)
313 ## Check whether a DP could be replaced by a distribution containing NewDpPkgList
314 # from current workspace.
316 # @param OrigDpGuid: original Dp's Guid
317 # @param OrigDpVersion: original Dp's version
318 # @param NewDpPkgList: a list of package information (Guid, Version) in new Dp
319 # @retval Replaceable: True if distribution could be replaced, False Else
320 # @retval DependModuleList: the list of modules that make distribution can not be replaced
322 def CheckDpDepexForReplace(self
, OrigDpGuid
, OrigDpVersion
, NewDpPkgList
):
324 DependModuleList
= []
325 WsModuleList
= self
.WsModuleList
327 # remove modules that included in current DP
328 # List of item (FilePath)
329 DpModuleList
= self
.IpiDb
.GetDpModuleList(OrigDpGuid
, OrigDpVersion
)
330 for Module
in DpModuleList
:
331 if Module
in WsModuleList
:
332 WsModuleList
.remove(Module
)
335 ST
.ERR_MODULE_NOT_INSTALLED
% Module
)
337 OtherPkgList
= NewDpPkgList
339 # get packages in current Dp and find the install path
340 # List of item (PkgGuid, PkgVersion, InstallPath)
341 DpPackageList
= self
.IpiDb
.GetPackageListFromDp(OrigDpGuid
, OrigDpVersion
)
342 DpPackagePathList
= []
343 WorkSP
= GlobalData
.gWORKSPACE
344 for (PkgName
, PkgGuid
, PkgVersion
, DecFile
) in self
.WsPkgList
:
347 DecPath
= dirname(DecFile
)
348 if DecPath
.find(WorkSP
) > -1:
349 InstallPath
= GetRelativePath(DecPath
,WorkSP
)
350 DecFileRelaPath
= GetRelativePath(DecFile
,WorkSP
)
352 InstallPath
= DecPath
353 DecFileRelaPath
= DecFile
355 if (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
356 DpPackagePathList
.append(DecFileRelaPath
)
357 DpPackageList
.remove((PkgGuid
, PkgVersion
, InstallPath
))
359 OtherPkgList
.append((PkgGuid
, PkgVersion
))
362 # the left items in DpPackageList are the packages that installed but not found anymore
364 for (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
366 ST
.WARN_INSTALLED_PACKAGE_NOT_FOUND
%(PkgGuid
, PkgVersion
, InstallPath
))
369 # check modules to see if it can be satisfied by package not belong to removed DP
371 for Module
in WsModuleList
:
372 if (not VerifyReplaceModuleDep(Module
, DpPackagePathList
, OtherPkgList
)):
374 DependModuleList
.append(Module
)
375 return (Replaceable
, DependModuleList
)
378 ## check whether module depends on packages in DpPackagePathList, return True
379 # if found, False else
381 # @param Path: a module path
382 # @param DpPackagePathList: a list of Package Paths
383 # @retval: False: module depends on package in DpPackagePathList
384 # True: module doesn't depend on package in DpPackagePathList
386 def VerifyRemoveModuleDep(Path
, DpPackagePathList
):
388 for Item
in GetPackagePath(Path
):
389 if Item
in DpPackagePathList
:
390 DecPath
= os
.path
.normpath(os
.path
.join(GlobalData
.gWORKSPACE
, Item
))
391 Logger
.Info(ST
.MSG_MODULE_DEPEND_ON
% (Path
, DecPath
))
395 except FatalError
, ErrCode
:
396 if ErrCode
.message
== EDK1_INF_ERROR
:
398 ST
.WRN_EDK1_INF_FOUND
%Path
)
405 # Get Dependency package path from an Inf file path
407 def GetPackagePath(InfPath
):
409 if os
.path
.exists(InfPath
):
411 for Line
in open(InfPath
).readlines():
415 if Line
.startswith('#'):
417 if Line
.startswith('[Packages') and Line
.endswith(']'):
420 if Line
.startswith('[') and Line
.endswith(']') and FindSection
:
423 PackagePath
.append(os
.path
.normpath(Line
))
427 ## check whether module depends on packages in DpPackagePathList and can not be satisfied by OtherPkgList
429 # @param Path: a module path
430 # @param DpPackagePathList: a list of Package Paths
431 # @param OtherPkgList: a list of Package Information (Guid, Version)
432 # @retval: False: module depends on package in DpPackagePathList and can not be satisfied by OtherPkgList
433 # True: either module doesn't depend on DpPackagePathList or module depends on DpPackagePathList
434 # but can be satisfied by OtherPkgList
436 def VerifyReplaceModuleDep(Path
, DpPackagePathList
, OtherPkgList
):
438 for Item
in GetPackagePath(Path
):
439 if Item
in DpPackagePathList
:
440 DecPath
= os
.path
.normpath(os
.path
.join(GlobalData
.gWORKSPACE
, Item
))
441 Name
, Guid
, Version
= GetPkgInfoFromDec(DecPath
)
442 if (Guid
, Version
) not in OtherPkgList
:
443 Logger
.Info(ST
.MSG_MODULE_DEPEND_ON
% (Path
, DecPath
))
447 except FatalError
, ErrCode
:
448 if ErrCode
.message
== EDK1_INF_ERROR
:
450 ST
.WRN_EDK1_INF_FOUND
%Path
)