1## @file
2# Replace distribution package.
3#
4# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
5#
6# SPDX-License-Identifier: BSD-2-Clause-Patent
7#
8"""
9Replace a distribution package
10"""
11##
12# Import Modules
13#
14from shutil import rmtree
15from traceback import format_exc
16from platform import python_version
17from sys import platform
18from Logger import StringTable as ST
19from Logger.ToolError import UNKNOWN_ERROR
20from Logger.ToolError import FatalError
21from Logger.ToolError import ABORT_ERROR
22from Logger.ToolError import CODE_ERROR
23from Logger.ToolError import UPT_ALREADY_INSTALLED_ERROR
24import Logger.Log as Logger
25
26from Core.DependencyRules import DependencyRules
27from Library import GlobalData
28from InstallPkg import UnZipDp
29from InstallPkg import InstallDp
30from RmPkg import GetInstalledDpInfo
31from RmPkg import RemoveDist
32
33## Tool entrance method
34#
35# This method mainly dispatch specific methods per the command line options.
36# If no error found, return zero value so the caller of this tool can know
37# if it's executed successfully or not.
38#
39# @param  Options: command Options
40#
41def Main(Options = None):
42    ContentZipFile, DistFile = None, None
43    try:
44        DataBase = GlobalData.gDB
45        WorkspaceDir = GlobalData.gWORKSPACE
46        Dep = DependencyRules(DataBase)
47        DistPkg, ContentZipFile, DpPkgFileName, DistFile = UnZipDp(WorkspaceDir, Options.PackFileToReplace)
48
49        StoredDistFile, OrigDpGuid, OrigDpVersion = GetInstalledDpInfo(Options.PackFileToBeReplaced, \
50                                                                       Dep, DataBase, WorkspaceDir)
51
52        #
53        # check dependency
54        #
55        CheckReplaceDpx(Dep, DistPkg, OrigDpGuid, OrigDpVersion)
56
57        #
58        # Remove the old distribution
59        #
60        RemoveDist(OrigDpGuid, OrigDpVersion, StoredDistFile, DataBase, WorkspaceDir, Options.Yes)
61
62        #
63        # Install the new distribution
64        #
65        InstallDp(DistPkg, DpPkgFileName, ContentZipFile, Options, Dep, WorkspaceDir, DataBase)
66        ReturnCode = 0
67
68    except FatalError as XExcept:
69        ReturnCode = XExcept.args[0]
70        if Logger.GetLevel() <= Logger.DEBUG_9:
71            Logger.Quiet(ST.MSG_PYTHON_ON % (python_version(),
72                platform) + format_exc())
73    except KeyboardInterrupt:
74        ReturnCode = ABORT_ERROR
75        if Logger.GetLevel() <= Logger.DEBUG_9:
76            Logger.Quiet(ST.MSG_PYTHON_ON % (python_version(),
77                platform) + format_exc())
78    except:
79        ReturnCode = CODE_ERROR
80        Logger.Error(
81                    "\nReplacePkg",
82                    CODE_ERROR,
83                    ST.ERR_UNKNOWN_FATAL_REPLACE_ERR % (Options.PackFileToReplace, Options.PackFileToBeReplaced),
84                    ExtraData=ST.MSG_SEARCH_FOR_HELP % ST.MSG_EDKII_MAIL_ADDR,
85                    RaiseError=False
86                    )
87        Logger.Quiet(ST.MSG_PYTHON_ON % (python_version(),
88            platform) + format_exc())
89
90    finally:
91        Logger.Quiet(ST.MSG_REMOVE_TEMP_FILE_STARTED)
92        if DistFile:
93            DistFile.Close()
94        if ContentZipFile:
95            ContentZipFile.Close()
96        for TempDir in GlobalData.gUNPACK_DIR:
97            rmtree(TempDir)
98        GlobalData.gUNPACK_DIR = []
99        Logger.Quiet(ST.MSG_REMOVE_TEMP_FILE_DONE)
100
101    if ReturnCode == 0:
102        Logger.Quiet(ST.MSG_FINISH)
103
104    return ReturnCode
105
106def CheckReplaceDpx(Dep, DistPkg, OrigDpGuid, OrigDpVersion):
107    NewDpPkgList = []
108    for PkgInfo in DistPkg.PackageSurfaceArea:
109        Guid, Version = PkgInfo[0], PkgInfo[1]
110        NewDpPkgList.append((Guid, Version))
111
112    NewDpInfo = "%s %s" % (DistPkg.Header.GetGuid(), DistPkg.Header.GetVersion())
113    OrigDpInfo = "%s %s" % (OrigDpGuid, OrigDpVersion)
114
115    #
116    # check whether new distribution is already installed and not replacing itself
117    #
118    if (NewDpInfo != OrigDpInfo):
119        if Dep.CheckDpExists(DistPkg.Header.GetGuid(), DistPkg.Header.GetVersion()):
120            Logger.Error("\nReplacePkg", UPT_ALREADY_INSTALLED_ERROR,
121                ST.WRN_DIST_PKG_INSTALLED,
122                ExtraData=ST.MSG_REPLACE_ALREADY_INSTALLED_DP)
123
124    #
125    # check whether the original distribution could be replaced by new distribution
126    #
127    Logger.Verbose(ST.MSG_CHECK_DP_FOR_REPLACE%(NewDpInfo, OrigDpInfo))
128    DepInfoResult = Dep.CheckDpDepexForReplace(OrigDpGuid, OrigDpVersion, NewDpPkgList)
129    Replaceable = DepInfoResult[0]
130    if not Replaceable:
131        Logger.Error("\nReplacePkg", UNKNOWN_ERROR,
132            ST.ERR_PACKAGE_NOT_MATCH_DEPENDENCY)
133
134    #
135    # check whether new distribution could be installed by dependency rule
136    #
137    Logger.Verbose(ST.MSG_CHECK_DP_FOR_INSTALL%str(NewDpInfo))
138    if not Dep.ReplaceCheckNewDpDepex(DistPkg, OrigDpGuid, OrigDpVersion):
139        Logger.Error("\nReplacePkg", UNKNOWN_ERROR,
140            ST.ERR_PACKAGE_NOT_MATCH_DEPENDENCY,
141            ExtraData=DistPkg.Header.Name)
142
143