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
):
58 if not ToBeInstalledPkgList
:
61 for Dist
in ToBeInstalledPkgList
:
62 for Package
in Dist
.PackageSurfaceArea
:
63 RtnList
.append((Package
[0], Package
[1]))
67 ## Check whether a module exists by checking the Guid+Version+Name+Path combination
69 # @param Guid: Guid of a module
70 # @param Version: Version of a module
71 # @param Name: Name of a module
72 # @param Path: Path of a module
73 # @return: True if module existed, else False
75 def CheckModuleExists(self
, Guid
, Version
, Name
, Path
):
76 Logger
.Verbose(ST
.MSG_CHECK_MODULE_EXIST
)
77 ModuleList
= self
.IpiDb
.GetModInPackage(Guid
, Version
, Name
, Path
)
78 ModuleList
.extend(self
.IpiDb
.GetStandaloneModule(Guid
, Version
, Name
, Path
))
79 Logger
.Verbose(ST
.MSG_CHECK_MODULE_EXIST_FINISH
)
80 if len(ModuleList
) > 0:
85 ## Check whether a module depex satisfied.
87 # @param ModuleObj: A module object
88 # @param DpObj: A distribution object
89 # @return: True if module depex satisfied
92 def CheckModuleDepexSatisfied(self
, ModuleObj
, DpObj
=None):
93 Logger
.Verbose(ST
.MSG_CHECK_MODULE_DEPEX_START
)
96 if ModuleObj
.GetPackageDependencyList():
97 Dep
= ModuleObj
.GetPackageDependencyList()[0]
98 for Dep
in ModuleObj
.GetPackageDependencyList():
100 # first check whether the dependency satisfied by current workspace
102 Exist
= self
.CheckPackageExists(Dep
.GetGuid(), Dep
.GetVersion())
104 # check whether satisfied by current distribution
110 for GuidVerPair
in DpObj
.PackageSurfaceArea
.keys():
111 if Dep
.GetGuid() == GuidVerPair
[0]:
112 if Dep
.GetVersion() is None or \
113 len(Dep
.GetVersion()) == 0:
116 if Dep
.GetVersion() == GuidVerPair
[1]:
124 Logger
.Error("CheckModuleDepex", UNKNOWN_ERROR
, \
125 ST
.ERR_DEPENDENCY_NOT_MATCH
% (ModuleObj
.GetName(), \
126 Dep
.GetPackageFilePath(), \
131 ## Check whether a package exists in a package list specified by PkgsToBeDepend.
133 # @param Guid: Guid of a package
134 # @param Version: Version of a package
135 # @return: True if package exist
138 def CheckPackageExists(self
, Guid
, Version
):
139 Logger
.Verbose(ST
.MSG_CHECK_PACKAGE_START
)
141 for (PkgGuid
, PkgVer
) in self
.PkgsToBeDepend
:
142 if (PkgGuid
== Guid
):
144 # if version is not empty and not equal, then not match
146 if Version
and (PkgVer
!= Version
):
155 Logger
.Verbose(ST
.MSG_CHECK_PACKAGE_FINISH
)
158 ## Check whether a package depex satisfied.
160 # @param PkgObj: A package object
161 # @param DpObj: A distribution object
162 # @return: True if package depex satisified
165 def CheckPackageDepexSatisfied(self
, PkgObj
, DpObj
=None):
166 ModuleDict
= PkgObj
.GetModuleDict()
167 for ModKey
in ModuleDict
.keys():
168 ModObj
= ModuleDict
[ModKey
]
169 if self
.CheckModuleDepexSatisfied(ModObj
, DpObj
):
175 ## Check whether a DP exists.
177 # @param Guid: Guid of a Distribution
178 # @param Version: Version of a Distribution
179 # @return: True if Distribution exist
181 def CheckDpExists(self
, Guid
, Version
):
182 Logger
.Verbose(ST
.MSG_CHECK_DP_START
)
183 DpList
= self
.IpiDb
.GetDp(Guid
, Version
)
189 Logger
.Verbose(ST
.MSG_CHECK_DP_FINISH
)
192 ## Check whether a DP depex satisfied by current workspace for Install
194 # @param DpObj: A distribution object
195 # @return: True if distribution depex satisfied
198 def CheckInstallDpDepexSatisfied(self
, DpObj
):
199 return self
.CheckDpDepexSatisfied(DpObj
)
201 # # Check whether multiple DP depex satisfied by current workspace for Install
203 # @param DpObjList: A distribution object list
204 # @return: True if distribution depex satisfied
207 def CheckTestInstallPdDepexSatisfied(self
, DpObjList
):
208 for DpObj
in DpObjList
:
209 if self
.CheckDpDepexSatisfied(DpObj
):
210 for PkgKey
in DpObj
.PackageSurfaceArea
.keys():
211 PkgObj
= DpObj
.PackageSurfaceArea
[PkgKey
]
212 self
.PkgsToBeDepend
.append((PkgObj
.Guid
, PkgObj
.Version
))
219 ## Check whether a DP depex satisfied by current workspace
220 # (excluding the original distribution's packages to be replaced) for Replace
222 # @param DpObj: A distribution object
223 # @param OrigDpGuid: The original distribution's Guid
224 # @param OrigDpVersion: The original distribution's Version
226 def ReplaceCheckNewDpDepex(self
, DpObj
, OrigDpGuid
, OrigDpVersion
):
227 self
.PkgsToBeDepend
= [(PkgInfo
[1], PkgInfo
[2]) for PkgInfo
in self
.WsPkgList
]
228 OrigDpPackageList
= self
.IpiDb
.GetPackageListFromDp(OrigDpGuid
, OrigDpVersion
)
229 for OrigPkgInfo
in OrigDpPackageList
:
230 Guid
, Version
= OrigPkgInfo
[0], OrigPkgInfo
[1]
231 if (Guid
, Version
) in self
.PkgsToBeDepend
:
232 self
.PkgsToBeDepend
.remove((Guid
, Version
))
233 return self
.CheckDpDepexSatisfied(DpObj
)
235 ## Check whether a DP depex satisfied by current workspace.
237 # @param DpObj: A distribution object
239 def CheckDpDepexSatisfied(self
, DpObj
):
240 for PkgKey
in DpObj
.PackageSurfaceArea
.keys():
241 PkgObj
= DpObj
.PackageSurfaceArea
[PkgKey
]
242 if self
.CheckPackageDepexSatisfied(PkgObj
, DpObj
):
247 for ModKey
in DpObj
.ModuleSurfaceArea
.keys():
248 ModObj
= DpObj
.ModuleSurfaceArea
[ModKey
]
249 if self
.CheckModuleDepexSatisfied(ModObj
, DpObj
):
256 ## Check whether a DP could be removed from current workspace.
258 # @param DpGuid: File's guid
259 # @param DpVersion: File's version
260 # @retval Removable: True if distribution could be removed, False Else
261 # @retval DependModuleList: the list of modules that make distribution can not be removed
263 def CheckDpDepexForRemove(self
, DpGuid
, DpVersion
):
265 DependModuleList
= []
266 WsModuleList
= self
.WsModuleList
268 # remove modules that included in current DP
269 # List of item (FilePath)
270 DpModuleList
= self
.IpiDb
.GetDpModuleList(DpGuid
, DpVersion
)
271 for Module
in DpModuleList
:
272 if Module
in WsModuleList
:
273 WsModuleList
.remove(Module
)
276 ST
.ERR_MODULE_NOT_INSTALLED
% Module
)
278 # get packages in current Dp and find the install path
279 # List of item (PkgGuid, PkgVersion, InstallPath)
280 DpPackageList
= self
.IpiDb
.GetPackageListFromDp(DpGuid
, DpVersion
)
281 DpPackagePathList
= []
282 WorkSP
= GlobalData
.gWORKSPACE
283 for (PkgName
, PkgGuid
, PkgVersion
, DecFile
) in self
.WsPkgList
:
286 DecPath
= dirname(DecFile
)
287 if DecPath
.find(WorkSP
) > -1:
288 InstallPath
= GetRelativePath(DecPath
,WorkSP
)
289 DecFileRelaPath
= GetRelativePath(DecFile
,WorkSP
)
291 InstallPath
= DecPath
292 DecFileRelaPath
= DecFile
294 if (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
295 DpPackagePathList
.append(DecFileRelaPath
)
296 DpPackageList
.remove((PkgGuid
, PkgVersion
, InstallPath
))
299 # the left items in DpPackageList are the packages that installed but not found anymore
301 for (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
303 ST
.WARN_INSTALLED_PACKAGE_NOT_FOUND
%(PkgGuid
, PkgVersion
, InstallPath
))
306 # check modules to see if has dependency on package of current DP
308 for Module
in WsModuleList
:
309 if (not VerifyRemoveModuleDep(Module
, DpPackagePathList
)):
311 DependModuleList
.append(Module
)
312 return (Removable
, DependModuleList
)
315 ## Check whether a DP could be replaced by a distribution containing NewDpPkgList
316 # from current workspace.
318 # @param OrigDpGuid: original Dp's Guid
319 # @param OrigDpVersion: original Dp's version
320 # @param NewDpPkgList: a list of package information (Guid, Version) in new Dp
321 # @retval Replaceable: True if distribution could be replaced, False Else
322 # @retval DependModuleList: the list of modules that make distribution can not be replaced
324 def CheckDpDepexForReplace(self
, OrigDpGuid
, OrigDpVersion
, NewDpPkgList
):
326 DependModuleList
= []
327 WsModuleList
= self
.WsModuleList
329 # remove modules that included in current DP
330 # List of item (FilePath)
331 DpModuleList
= self
.IpiDb
.GetDpModuleList(OrigDpGuid
, OrigDpVersion
)
332 for Module
in DpModuleList
:
333 if Module
in WsModuleList
:
334 WsModuleList
.remove(Module
)
337 ST
.ERR_MODULE_NOT_INSTALLED
% Module
)
339 OtherPkgList
= NewDpPkgList
341 # get packages in current Dp and find the install path
342 # List of item (PkgGuid, PkgVersion, InstallPath)
343 DpPackageList
= self
.IpiDb
.GetPackageListFromDp(OrigDpGuid
, OrigDpVersion
)
344 DpPackagePathList
= []
345 WorkSP
= GlobalData
.gWORKSPACE
346 for (PkgName
, PkgGuid
, PkgVersion
, DecFile
) in self
.WsPkgList
:
349 DecPath
= dirname(DecFile
)
350 if DecPath
.find(WorkSP
) > -1:
351 InstallPath
= GetRelativePath(DecPath
,WorkSP
)
352 DecFileRelaPath
= GetRelativePath(DecFile
,WorkSP
)
354 InstallPath
= DecPath
355 DecFileRelaPath
= DecFile
357 if (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
358 DpPackagePathList
.append(DecFileRelaPath
)
359 DpPackageList
.remove((PkgGuid
, PkgVersion
, InstallPath
))
361 OtherPkgList
.append((PkgGuid
, PkgVersion
))
364 # the left items in DpPackageList are the packages that installed but not found anymore
366 for (PkgGuid
, PkgVersion
, InstallPath
) in DpPackageList
:
368 ST
.WARN_INSTALLED_PACKAGE_NOT_FOUND
%(PkgGuid
, PkgVersion
, InstallPath
))
371 # check modules to see if it can be satisfied by package not belong to removed DP
373 for Module
in WsModuleList
:
374 if (not VerifyReplaceModuleDep(Module
, DpPackagePathList
, OtherPkgList
)):
376 DependModuleList
.append(Module
)
377 return (Replaceable
, DependModuleList
)
380 ## check whether module depends on packages in DpPackagePathList, return True
381 # if found, False else
383 # @param Path: a module path
384 # @param DpPackagePathList: a list of Package Paths
385 # @retval: False: module depends on package in DpPackagePathList
386 # True: module doesn't depend on package in DpPackagePathList
388 def VerifyRemoveModuleDep(Path
, DpPackagePathList
):
390 for Item
in GetPackagePath(Path
):
391 if Item
in DpPackagePathList
:
392 DecPath
= os
.path
.normpath(os
.path
.join(GlobalData
.gWORKSPACE
, Item
))
393 Logger
.Info(ST
.MSG_MODULE_DEPEND_ON
% (Path
, DecPath
))
397 except FatalError
, ErrCode
:
398 if ErrCode
.message
== EDK1_INF_ERROR
:
400 ST
.WRN_EDK1_INF_FOUND
%Path
)
407 # Get Dependency package path from an Inf file path
409 def GetPackagePath(InfPath
):
411 if os
.path
.exists(InfPath
):
413 for Line
in open(InfPath
).readlines():
417 if Line
.startswith('#'):
419 if Line
.startswith('[Packages') and Line
.endswith(']'):
422 if Line
.startswith('[') and Line
.endswith(']') and FindSection
:
425 PackagePath
.append(os
.path
.normpath(Line
))
429 ## check whether module depends on packages in DpPackagePathList and can not be satisfied by OtherPkgList
431 # @param Path: a module path
432 # @param DpPackagePathList: a list of Package Paths
433 # @param OtherPkgList: a list of Package Information (Guid, Version)
434 # @retval: False: module depends on package in DpPackagePathList and can not be satisfied by OtherPkgList
435 # True: either module doesn't depend on DpPackagePathList or module depends on DpPackagePathList
436 # but can be satisfied by OtherPkgList
438 def VerifyReplaceModuleDep(Path
, DpPackagePathList
, OtherPkgList
):
440 for Item
in GetPackagePath(Path
):
441 if Item
in DpPackagePathList
:
442 DecPath
= os
.path
.normpath(os
.path
.join(GlobalData
.gWORKSPACE
, Item
))
443 Name
, Guid
, Version
= GetPkgInfoFromDec(DecPath
)
444 if (Guid
, Version
) not in OtherPkgList
:
445 Logger
.Info(ST
.MSG_MODULE_DEPEND_ON
% (Path
, DecPath
))
449 except FatalError
, ErrCode
:
450 if ErrCode
.message
== EDK1_INF_ERROR
:
452 ST
.WRN_EDK1_INF_FOUND
%Path
)