]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/Python/UPT/Core/DependencyRules.py
BaseTools: Refactor python except statements
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Core / DependencyRules.py
index ac656bb02aaa214b24925aeb37fbbc7118542021..34f56e7bb487b9e719f0a303c7af7e4ea89f0dc1 100644 (file)
@@ -1,7 +1,7 @@
 ## @file\r
 # This file is for installed package information database operations\r
 #\r
-# Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>\r
 #\r
 # This program and the accompanying materials are licensed and made available \r
 # under the terms and conditions of the BSD License which accompanies this \r
@@ -20,15 +20,16 @@ Dependency
 ##\r
 # Import Modules\r
 #\r
-from os import getenv\r
-from os import environ\r
 from os.path import dirname\r
+import os\r
 \r
 import Logger.Log as Logger\r
 from Logger import StringTable as ST\r
 from Library.Parsing import GetWorkspacePackage\r
 from Library.Parsing import GetWorkspaceModule\r
-from PomAdapter.InfPomAlignment import InfPomAlignment\r
+from Library.Parsing import GetPkgInfoFromDec\r
+from Library.Misc import GetRelativePath\r
+from Library import GlobalData\r
 from Logger.ToolError import FatalError\r
 from Logger.ToolError import EDK1_INF_ERROR\r
 from Logger.ToolError import UNKNOWN_ERROR\r
@@ -36,46 +37,59 @@ from Logger.ToolError import UNKNOWN_ERROR
 DEPEX_CHECK_PACKAGE_NOT_FOUND, DEPEX_CHECK_DP_NOT_FOUND) = (0, 1, 2, 3)\r
 \r
 \r
-## IpiDb\r
+## DependencyRules\r
 #\r
-# This class represents the installed package information database\r
-# Add/Remove/Get installed distribution package information here.\r
-# \r
+# This class represents the dependency rule check mechanism\r
 # \r
 # @param object:      Inherited from object class\r
 #\r
 class DependencyRules(object):\r
-    def __init__(self, Datab):\r
+    def __init__(self, Datab, ToBeInstalledPkgList=None):\r
         self.IpiDb = Datab\r
         self.WsPkgList = GetWorkspacePackage()\r
         self.WsModuleList = GetWorkspaceModule()\r
 \r
-    ## Check whether a module exists in current workspace.\r
+        self.PkgsToBeDepend = [(PkgInfo[1], PkgInfo[2]) for PkgInfo in self.WsPkgList]\r
+\r
+        # Add package info from the DIST to be installed.\r
+        self.PkgsToBeDepend.extend(self.GenToBeInstalledPkgList(ToBeInstalledPkgList))\r
+        \r
+    def GenToBeInstalledPkgList(self, ToBeInstalledPkgList):\r
+        if not ToBeInstalledPkgList:\r
+            return []\r
+        RtnList = []\r
+        for Dist in ToBeInstalledPkgList:\r
+            for Package in Dist.PackageSurfaceArea:\r
+                RtnList.append((Package[0], Package[1]))\r
+\r
+        return RtnList\r
+\r
+    ## Check whether a module exists by checking the Guid+Version+Name+Path combination\r
     #\r
     # @param Guid:  Guid of a module\r
     # @param Version: Version of a module\r
+    # @param Name: Name of a module\r
+    # @param Path: Path of a module\r
+    # @return:  True if module existed, else False\r
     #\r
-    def CheckModuleExists(self, Guid, Version, ReturnCode=DEPEX_CHECK_SUCCESS):\r
-        if ReturnCode:\r
-            pass\r
+    def CheckModuleExists(self, Guid, Version, Name, Path):\r
         Logger.Verbose(ST.MSG_CHECK_MODULE_EXIST)\r
-        ModuleList = self.IpiDb.GetModInPackage(Guid, Version)\r
-        ModuleList.extend(self.IpiDb.GetStandaloneModule(Guid, Version))\r
+        ModuleList = self.IpiDb.GetModInPackage(Guid, Version, Name, Path)\r
+        ModuleList.extend(self.IpiDb.GetStandaloneModule(Guid, Version, Name, Path))\r
         Logger.Verbose(ST.MSG_CHECK_MODULE_EXIST_FINISH)\r
         if len(ModuleList) > 0:\r
             return True\r
         else:\r
             return False\r
         \r
-    ## Check whether a module depex satisfied by current workspace or dist.\r
+    ## Check whether a module depex satisfied.\r
     #\r
     # @param ModuleObj: A module object\r
-    # @param DpObj: A depex object\r
+    # @param DpObj: A distribution object\r
+    # @return: True if module depex satisfied\r
+    #          False else\r
     #\r
-    def CheckModuleDepexSatisfied(self, ModuleObj, DpObj=None, \\r
-                                  ReturnCode=DEPEX_CHECK_SUCCESS):\r
-        if ReturnCode:\r
-            pass\r
+    def CheckModuleDepexSatisfied(self, ModuleObj, DpObj=None):\r
         Logger.Verbose(ST.MSG_CHECK_MODULE_DEPEX_START)\r
         Result = True\r
         Dep = None\r
@@ -90,12 +104,12 @@ class DependencyRules(object):
             # check whether satisfied by current distribution \r
             #\r
             if not Exist:\r
-                if DpObj == None:\r
+                if DpObj is None:\r
                     Result = False\r
                     break\r
                 for GuidVerPair in DpObj.PackageSurfaceArea.keys():\r
                     if Dep.GetGuid() == GuidVerPair[0]:\r
-                        if Dep.GetVersion() == None or \\r
+                        if Dep.GetVersion() is None or \\r
                         len(Dep.GetVersion()) == 0:\r
                             Result = True\r
                             break\r
@@ -114,97 +128,139 @@ class DependencyRules(object):
                                                         Dep.GetVersion()))\r
         return Result\r
             \r
-    ## Check whether a package exists in current workspace.\r
+    ## Check whether a package exists in a package list specified by PkgsToBeDepend.\r
     #\r
     # @param Guid: Guid of a package\r
     # @param Version: Version of a package\r
+    # @return: True if package exist\r
+    #          False else\r
     #\r
     def CheckPackageExists(self, Guid, Version):\r
         Logger.Verbose(ST.MSG_CHECK_PACKAGE_START)\r
-        for (PkgName, PkgGuid, PkgVer, PkgPath) in self.WsPkgList:\r
-            if PkgName or PkgPath:\r
-                pass\r
+        Found = False\r
+        for (PkgGuid, PkgVer) in self.PkgsToBeDepend:\r
             if (PkgGuid == Guid):\r
                 #\r
                 # if version is not empty and not equal, then not match\r
                 #\r
                 if Version and (PkgVer != Version):\r
-                    return False\r
+                    Found = False\r
+                    break\r
                 else:\r
-                    return True\r
+                    Found = True\r
+                    break\r
         else:\r
-            return False\r
-                        \r
+            Found = False\r
+\r
         Logger.Verbose(ST.MSG_CHECK_PACKAGE_FINISH)\r
+        return Found\r
          \r
-    ## Check whether a package depex satisfied by current workspace.\r
+    ## Check whether a package depex satisfied.\r
     #\r
     # @param PkgObj: A package object\r
-    # @param DpObj: A package depex object\r
+    # @param DpObj: A distribution object\r
+    # @return: True if package depex satisified\r
+    #          False else\r
     #\r
-    def CheckPackageDepexSatisfied(self, PkgObj, DpObj=None, \\r
-                                   ReturnCode=DEPEX_CHECK_SUCCESS):\r
-        \r
+    def CheckPackageDepexSatisfied(self, PkgObj, DpObj=None):\r
         ModuleDict = PkgObj.GetModuleDict()\r
         for ModKey in ModuleDict.keys():\r
             ModObj = ModuleDict[ModKey]\r
-            if self.CheckModuleDepexSatisfied(ModObj, DpObj, ReturnCode):\r
+            if self.CheckModuleDepexSatisfied(ModObj, DpObj):\r
                 continue\r
             else:\r
                 return False\r
         return True\r
         \r
-    ## Check whether a DP exists in current workspace.\r
-    #\r
-    # @param Guid: Guid of a module\r
-    # @param Version: Version of a module\r
+    ## Check whether a DP exists.\r
     #\r
-    def CheckDpExists(self, Guid, Version, ReturnCode=DEPEX_CHECK_SUCCESS):\r
-        if ReturnCode:\r
-            pass\r
+    # @param Guid: Guid of a Distribution\r
+    # @param Version: Version of a Distribution\r
+    # @return: True if Distribution exist\r
+    #          False else\r
+    def CheckDpExists(self, Guid, Version):\r
         Logger.Verbose(ST.MSG_CHECK_DP_START)\r
         DpList = self.IpiDb.GetDp(Guid, Version)\r
         if len(DpList) > 0:\r
-            return True\r
+            Found = True\r
         else:\r
-            return False\r
-            \r
-        Logger.Verbose(ST.MSG_CHECK_DP_FINISH) \r
-        \r
+            Found = False\r
+\r
+        Logger.Verbose(ST.MSG_CHECK_DP_FINISH)\r
+        return Found\r
+\r
+    ## Check whether a DP depex satisfied by current workspace for Install\r
+    #\r
+    # @param DpObj:  A distribution object\r
+    # @return: True if distribution depex satisfied\r
+    #          False else\r
+    #\r
+    def CheckInstallDpDepexSatisfied(self, DpObj):\r
+        return self.CheckDpDepexSatisfied(DpObj)\r
+\r
+    # # Check whether multiple DP depex satisfied by current workspace for Install\r
+    #\r
+    # @param DpObjList:  A distribution object list\r
+    # @return: True if distribution depex satisfied\r
+    #          False else\r
+    #\r
+    def CheckTestInstallPdDepexSatisfied(self, DpObjList):\r
+        for DpObj in DpObjList:\r
+            if self.CheckDpDepexSatisfied(DpObj):\r
+                for PkgKey in DpObj.PackageSurfaceArea.keys():\r
+                    PkgObj = DpObj.PackageSurfaceArea[PkgKey]\r
+                    self.PkgsToBeDepend.append((PkgObj.Guid, PkgObj.Version))\r
+            else:\r
+                return False, DpObj\r
+\r
+        return True, DpObj\r
+\r
+\r
+    ## Check whether a DP depex satisfied by current workspace \r
+    #  (excluding the original distribution's packages to be replaced) for Replace\r
+    #\r
+    # @param DpObj:  A distribution object\r
+    # @param OrigDpGuid: The original distribution's Guid\r
+    # @param OrigDpVersion: The original distribution's Version\r
+    #\r
+    def ReplaceCheckNewDpDepex(self, DpObj, OrigDpGuid, OrigDpVersion):\r
+        self.PkgsToBeDepend = [(PkgInfo[1], PkgInfo[2]) for PkgInfo in self.WsPkgList]\r
+        OrigDpPackageList = self.IpiDb.GetPackageListFromDp(OrigDpGuid, OrigDpVersion)\r
+        for OrigPkgInfo in OrigDpPackageList:\r
+            Guid, Version = OrigPkgInfo[0], OrigPkgInfo[1]\r
+            if (Guid, Version) in self.PkgsToBeDepend:\r
+                self.PkgsToBeDepend.remove((Guid, Version))\r
+        return self.CheckDpDepexSatisfied(DpObj)\r
+\r
     ## Check whether a DP depex satisfied by current workspace.\r
     #\r
-    # @param DpObj:  Depex object\r
-    # @param ReturnCode: ReturnCode\r
+    # @param DpObj:  A distribution object\r
     #\r
-    def CheckDpDepexSatisfied(self, DpObj, ReturnCode=DEPEX_CHECK_SUCCESS):\r
-        \r
+    def CheckDpDepexSatisfied(self, DpObj):\r
         for PkgKey in DpObj.PackageSurfaceArea.keys():\r
             PkgObj = DpObj.PackageSurfaceArea[PkgKey]\r
-            if self.CheckPackageDepexSatisfied(PkgObj, DpObj, ReturnCode):\r
+            if self.CheckPackageDepexSatisfied(PkgObj, DpObj):\r
                 continue\r
             else:\r
                 return False\r
             \r
         for ModKey in DpObj.ModuleSurfaceArea.keys():\r
             ModObj = DpObj.ModuleSurfaceArea[ModKey]\r
-            if self.CheckModuleDepexSatisfied(ModObj, DpObj, ReturnCode):\r
+            if self.CheckModuleDepexSatisfied(ModObj, DpObj):\r
                 continue\r
             else:\r
                 return False\r
         \r
         return True\r
     \r
-    ## Check whether a DP depex satisfied by current workspace. Return False \r
-    # if Can not remove (there is dependency), True else\r
+    ## Check whether a DP could be removed from current workspace. \r
     #\r
     # @param DpGuid:  File's guid\r
     # @param DpVersion: File's version\r
-    # @param ReturnCode: ReturnCode\r
-    # \r
-    def CheckDpDepexForRemove(self, DpGuid, DpVersion, \\r
-                              ReturnCode=DEPEX_CHECK_SUCCESS):\r
-        if ReturnCode:\r
-            pass\r
+    # @retval Removable: True if distribution could be removed, False Else\r
+    # @retval DependModuleList: the list of modules that make distribution can not be removed\r
+    #\r
+    def CheckDpDepexForRemove(self, DpGuid, DpVersion):\r
         Removable = True\r
         DependModuleList = []\r
         WsModuleList = self.WsModuleList\r
@@ -223,15 +279,14 @@ class DependencyRules(object):
         # List of item (PkgGuid, PkgVersion, InstallPath)\r
         DpPackageList = self.IpiDb.GetPackageListFromDp(DpGuid, DpVersion) \r
         DpPackagePathList = []\r
-        WorkSP = environ["WORKSPACE"]\r
+        WorkSP = GlobalData.gWORKSPACE\r
         for (PkgName, PkgGuid, PkgVersion, DecFile) in self.WsPkgList:\r
             if PkgName:\r
                 pass\r
             DecPath = dirname(DecFile)\r
             if DecPath.find(WorkSP) > -1:\r
-                InstallPath = DecPath[DecPath.find(WorkSP) + len(WorkSP) + 1:]\r
-                DecFileRelaPath = \\r
-                DecFile[DecFile.find(WorkSP) + len(WorkSP) + 1:]\r
+                InstallPath = GetRelativePath(DecPath,WorkSP)\r
+                DecFileRelaPath = GetRelativePath(DecFile,WorkSP)\r
             else:\r
                 InstallPath = DecPath\r
                 DecFileRelaPath = DecFile\r
@@ -251,43 +306,150 @@ class DependencyRules(object):
         # check modules to see if has dependency on package of current DP\r
         #\r
         for Module in WsModuleList:\r
-            if (CheckModuleDependFromInf(Module, DpPackagePathList)):\r
+            if (not VerifyRemoveModuleDep(Module, DpPackagePathList)):\r
                 Removable = False\r
                 DependModuleList.append(Module)\r
         return (Removable, DependModuleList)\r
 \r
 \r
+    ## Check whether a DP could be replaced by a distribution containing NewDpPkgList\r
+    # from current workspace.\r
+    #\r
+    # @param OrigDpGuid:  original Dp's Guid\r
+    # @param OrigDpVersion: original Dp's version\r
+    # @param NewDpPkgList: a list of package information (Guid, Version) in new Dp\r
+    # @retval Replaceable: True if distribution could be replaced, False Else\r
+    # @retval DependModuleList: the list of modules that make distribution can not be replaced\r
+    # \r
+    def CheckDpDepexForReplace(self, OrigDpGuid, OrigDpVersion, NewDpPkgList):\r
+        Replaceable = True\r
+        DependModuleList = []\r
+        WsModuleList = self.WsModuleList\r
+        #\r
+        # remove modules that included in current DP\r
+        # List of item (FilePath)\r
+        DpModuleList = self.IpiDb.GetDpModuleList(OrigDpGuid, OrigDpVersion) \r
+        for Module in DpModuleList:\r
+            if Module in WsModuleList:\r
+                WsModuleList.remove(Module)\r
+            else:\r
+                Logger.Warn("UPT\n",\r
+                            ST.ERR_MODULE_NOT_INSTALLED % Module)\r
+        \r
+        OtherPkgList = NewDpPkgList\r
+        #\r
+        # get packages in current Dp and find the install path\r
+        # List of item (PkgGuid, PkgVersion, InstallPath)\r
+        DpPackageList = self.IpiDb.GetPackageListFromDp(OrigDpGuid, OrigDpVersion) \r
+        DpPackagePathList = []\r
+        WorkSP = GlobalData.gWORKSPACE\r
+        for (PkgName, PkgGuid, PkgVersion, DecFile) in self.WsPkgList:\r
+            if PkgName:\r
+                pass\r
+            DecPath = dirname(DecFile)\r
+            if DecPath.find(WorkSP) > -1:\r
+                InstallPath = GetRelativePath(DecPath,WorkSP)\r
+                DecFileRelaPath = GetRelativePath(DecFile,WorkSP)\r
+            else:\r
+                InstallPath = DecPath\r
+                DecFileRelaPath = DecFile\r
+                \r
+            if (PkgGuid, PkgVersion, InstallPath) in DpPackageList:\r
+                DpPackagePathList.append(DecFileRelaPath)\r
+                DpPackageList.remove((PkgGuid, PkgVersion, InstallPath))\r
+            else:\r
+                OtherPkgList.append((PkgGuid, PkgVersion))\r
+\r
+        #\r
+        # the left items in DpPackageList are the packages that installed but not found anymore\r
+        #\r
+        for (PkgGuid, PkgVersion, InstallPath) in DpPackageList:\r
+            Logger.Warn("UPT",\r
+                        ST.WARN_INSTALLED_PACKAGE_NOT_FOUND%(PkgGuid, PkgVersion, InstallPath))\r
+        \r
+        #\r
+        # check modules to see if it can be satisfied by package not belong to removed DP\r
+        #\r
+        for Module in WsModuleList:\r
+            if (not VerifyReplaceModuleDep(Module, DpPackagePathList, OtherPkgList)):\r
+                Replaceable = False\r
+                DependModuleList.append(Module)\r
+        return (Replaceable, DependModuleList)\r
+\r
+    \r
 ## check whether module depends on packages in DpPackagePathList, return True \r
 # if found, False else\r
 #\r
 # @param Path: a module path\r
 # @param DpPackagePathList: a list of Package Paths\r
+# @retval:  False: module depends on package in DpPackagePathList\r
+#           True:  module doesn't depend on package in DpPackagePathList\r
 #\r
-def CheckModuleDependFromInf(Path, DpPackagePathList):\r
-    \r
-    #  \r
-    # use InfParser to parse inf, then get the information for now,\r
-    # later on, may consider only parse to get the package dependency info \r
-    # (Need to take care how to deal wit Macros)\r
-    #\r
-    WorkSP = getenv('WORKSPACE')\r
-    \r
+def VerifyRemoveModuleDep(Path, DpPackagePathList):\r
     try:\r
-        PomAli = InfPomAlignment(Path, WorkSP, Skip=True)\r
-\r
-        for Item in PomAli.GetPackageDependencyList():\r
-            if Item.GetPackageFilePath() in DpPackagePathList:\r
-                Logger.Info(ST.MSG_MODULE_DEPEND_ON % (Path, Item.GetPackageFilePath()))\r
-                return True\r
+        for Item in GetPackagePath(Path):\r
+            if Item in DpPackagePathList:\r
+                DecPath = os.path.normpath(os.path.join(GlobalData.gWORKSPACE, Item))\r
+                Logger.Info(ST.MSG_MODULE_DEPEND_ON % (Path, DecPath))\r
+                return False\r
         else:\r
-            return False\r
-    except FatalError, ErrCode:\r
+            return True\r
+    except FatalError as ErrCode:\r
         if ErrCode.message == EDK1_INF_ERROR:\r
             Logger.Warn("UPT",\r
                         ST.WRN_EDK1_INF_FOUND%Path)\r
-            return False\r
+            return True\r
         else:\r
-            return False\r
-        \r
+            return True\r
+\r
+# # GetPackagePath\r
+#\r
+# Get Dependency package path from an Inf file path\r
+#\r
+def GetPackagePath(InfPath):\r
+    PackagePath = []\r
+    if os.path.exists(InfPath):\r
+        FindSection = False\r
+        for Line in open(InfPath).readlines():\r
+            Line = Line.strip()\r
+            if not Line:\r
+                continue\r
+            if Line.startswith('#'):\r
+                continue\r
+            if Line.startswith('[Packages') and Line.endswith(']'):\r
+                FindSection = True\r
+                continue\r
+            if Line.startswith('[') and Line.endswith(']') and FindSection:\r
+                break\r
+            if FindSection:\r
+                PackagePath.append(os.path.normpath(Line))\r
 \r
+    return PackagePath\r
 \r
+## check whether module depends on packages in DpPackagePathList and can not be satisfied by OtherPkgList\r
+#\r
+# @param Path: a module path\r
+# @param DpPackagePathList:  a list of Package Paths\r
+# @param OtherPkgList:       a list of Package Information (Guid, Version)\r
+# @retval:  False: module depends on package in DpPackagePathList and can not be satisfied by OtherPkgList\r
+#           True:  either module doesn't depend on DpPackagePathList or module depends on DpPackagePathList \r
+#                 but can be satisfied by OtherPkgList\r
+#\r
+def VerifyReplaceModuleDep(Path, DpPackagePathList, OtherPkgList):\r
+    try:\r
+        for Item in GetPackagePath(Path):\r
+            if Item in DpPackagePathList:\r
+                DecPath = os.path.normpath(os.path.join(GlobalData.gWORKSPACE, Item))\r
+                Name, Guid, Version = GetPkgInfoFromDec(DecPath)\r
+                if (Guid, Version) not in OtherPkgList:\r
+                    Logger.Info(ST.MSG_MODULE_DEPEND_ON % (Path, DecPath))\r
+                    return False\r
+        else:\r
+            return True\r
+    except FatalError as ErrCode:\r
+        if ErrCode.message == EDK1_INF_ERROR:\r
+            Logger.Warn("UPT",\r
+                        ST.WRN_EDK1_INF_FOUND%Path)\r
+            return True\r
+        else:\r
+            return True\r