2011-08-26 09:46:26 +02:00
|
|
|
## @file
|
|
|
|
# Install distribution package.
|
|
|
|
#
|
2018-07-05 11:40:04 +02:00
|
|
|
# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
|
2011-08-26 09:46:26 +02:00
|
|
|
#
|
2019-04-04 01:03:11 +02:00
|
|
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
2011-08-26 09:46:26 +02:00
|
|
|
#
|
|
|
|
|
|
|
|
'''
|
|
|
|
RmPkg
|
|
|
|
'''
|
|
|
|
|
|
|
|
##
|
|
|
|
# Import Modules
|
|
|
|
#
|
|
|
|
import os.path
|
|
|
|
from stat import S_IWUSR
|
|
|
|
from traceback import format_exc
|
|
|
|
from platform import python_version
|
2018-08-08 08:56:55 +02:00
|
|
|
from hashlib import md5
|
2011-08-26 09:46:26 +02:00
|
|
|
from sys import stdin
|
|
|
|
from sys import platform
|
|
|
|
|
|
|
|
from Core.DependencyRules import DependencyRules
|
|
|
|
from Library import GlobalData
|
|
|
|
from Logger import StringTable as ST
|
|
|
|
import Logger.Log as Logger
|
|
|
|
from Logger.ToolError import OPTION_MISSING
|
|
|
|
from Logger.ToolError import UNKNOWN_ERROR
|
|
|
|
from Logger.ToolError import ABORT_ERROR
|
|
|
|
from Logger.ToolError import CODE_ERROR
|
|
|
|
from Logger.ToolError import FatalError
|
|
|
|
|
|
|
|
|
|
|
|
## CheckDpDepex
|
|
|
|
#
|
|
|
|
# Check if the Depex is satisfied
|
|
|
|
# @param Dep: Dep
|
|
|
|
# @param Guid: Guid of Dp
|
|
|
|
# @param Version: Version of Dp
|
|
|
|
# @param WorkspaceDir: Workspace Dir
|
|
|
|
#
|
|
|
|
def CheckDpDepex(Dep, Guid, Version, WorkspaceDir):
|
|
|
|
(Removable, DependModuleList) = Dep.CheckDpDepexForRemove(Guid, Version)
|
|
|
|
if not Removable:
|
|
|
|
Logger.Info(ST.MSG_CONFIRM_REMOVE)
|
|
|
|
Logger.Info(ST.MSG_USER_DELETE_OP)
|
|
|
|
Input = stdin.readline()
|
|
|
|
Input = Input.replace('\r', '').replace('\n', '')
|
|
|
|
if Input.upper() != 'Y':
|
|
|
|
Logger.Error("RmPkg", UNKNOWN_ERROR, ST.ERR_USER_INTERRUPT)
|
|
|
|
return 1
|
|
|
|
else:
|
|
|
|
#
|
2018-07-05 11:40:04 +02:00
|
|
|
# report list of modules that are not valid due to force
|
2011-08-26 09:46:26 +02:00
|
|
|
# remove,
|
|
|
|
# also generate a log file for reference
|
|
|
|
#
|
|
|
|
Logger.Info(ST.MSG_INVALID_MODULE_INTRODUCED)
|
|
|
|
LogFilePath = os.path.normpath(os.path.join(WorkspaceDir, GlobalData.gINVALID_MODULE_FILE))
|
|
|
|
Logger.Info(ST.MSG_CHECK_LOG_FILE % LogFilePath)
|
|
|
|
try:
|
|
|
|
LogFile = open(LogFilePath, 'w')
|
|
|
|
try:
|
|
|
|
for ModulePath in DependModuleList:
|
|
|
|
LogFile.write("%s\n"%ModulePath)
|
|
|
|
Logger.Info(ModulePath)
|
|
|
|
except IOError:
|
2018-07-05 11:40:04 +02:00
|
|
|
Logger.Warn("\nRmPkg", ST.ERR_FILE_WRITE_FAILURE,
|
2011-08-26 09:46:26 +02:00
|
|
|
File=LogFilePath)
|
|
|
|
except IOError:
|
2018-07-05 11:40:04 +02:00
|
|
|
Logger.Warn("\nRmPkg", ST.ERR_FILE_OPEN_FAILURE,
|
2011-08-26 09:46:26 +02:00
|
|
|
File=LogFilePath)
|
2018-07-05 11:40:04 +02:00
|
|
|
finally:
|
2011-08-26 09:46:26 +02:00
|
|
|
LogFile.close()
|
|
|
|
|
|
|
|
## Remove Path
|
|
|
|
#
|
|
|
|
# removing readonly file on windows will get "Access is denied"
|
|
|
|
# error, so before removing, change the mode to be writeable
|
|
|
|
#
|
2018-07-05 11:40:04 +02:00
|
|
|
# @param Path: The Path to be removed
|
2011-08-26 09:46:26 +02:00
|
|
|
#
|
|
|
|
def RemovePath(Path):
|
|
|
|
Logger.Info(ST.MSG_REMOVE_FILE % Path)
|
|
|
|
if not os.access(Path, os.W_OK):
|
|
|
|
os.chmod(Path, S_IWUSR)
|
|
|
|
os.remove(Path)
|
|
|
|
try:
|
|
|
|
os.removedirs(os.path.split(Path)[0])
|
|
|
|
except OSError:
|
|
|
|
pass
|
|
|
|
## GetCurrentFileList
|
|
|
|
#
|
|
|
|
# @param DataBase: DataBase of UPT
|
|
|
|
# @param Guid: Guid of Dp
|
|
|
|
# @param Version: Version of Dp
|
|
|
|
# @param WorkspaceDir: Workspace Dir
|
|
|
|
#
|
|
|
|
def GetCurrentFileList(DataBase, Guid, Version, WorkspaceDir):
|
|
|
|
NewFileList = []
|
|
|
|
for Dir in DataBase.GetDpInstallDirList(Guid, Version):
|
|
|
|
RootDir = os.path.normpath(os.path.join(WorkspaceDir, Dir))
|
|
|
|
for Root, Dirs, Files in os.walk(RootDir):
|
|
|
|
Logger.Debug(0, Dirs)
|
|
|
|
for File in Files:
|
|
|
|
FilePath = os.path.join(Root, File)
|
|
|
|
if FilePath not in NewFileList:
|
|
|
|
NewFileList.append(FilePath)
|
|
|
|
return NewFileList
|
|
|
|
|
|
|
|
|
|
|
|
## Tool entrance method
|
|
|
|
#
|
|
|
|
# This method mainly dispatch specific methods per the command line options.
|
|
|
|
# If no error found, return zero value so the caller of this tool can know
|
|
|
|
# if it's executed successfully or not.
|
|
|
|
#
|
2018-07-05 11:40:04 +02:00
|
|
|
# @param Options: command option
|
2011-08-26 09:46:26 +02:00
|
|
|
#
|
|
|
|
def Main(Options = None):
|
|
|
|
|
|
|
|
try:
|
2018-07-05 11:40:04 +02:00
|
|
|
DataBase = GlobalData.gDB
|
2011-08-26 09:46:26 +02:00
|
|
|
if not Options.DistributionFile:
|
2018-07-05 11:40:04 +02:00
|
|
|
Logger.Error("RmPkg",
|
|
|
|
OPTION_MISSING,
|
2011-08-26 09:46:26 +02:00
|
|
|
ExtraData=ST.ERR_SPECIFY_PACKAGE)
|
|
|
|
WorkspaceDir = GlobalData.gWORKSPACE
|
|
|
|
#
|
|
|
|
# Prepare check dependency
|
|
|
|
#
|
|
|
|
Dep = DependencyRules(DataBase)
|
2018-07-05 11:40:04 +02:00
|
|
|
|
2011-08-26 09:46:26 +02:00
|
|
|
#
|
2014-08-26 07:58:02 +02:00
|
|
|
# Get the Dp information
|
2011-08-26 09:46:26 +02:00
|
|
|
#
|
2014-08-26 07:58:02 +02:00
|
|
|
StoredDistFile, Guid, Version = GetInstalledDpInfo(Options.DistributionFile, Dep, DataBase, WorkspaceDir)
|
|
|
|
|
2018-07-05 11:40:04 +02:00
|
|
|
#
|
2011-08-26 09:46:26 +02:00
|
|
|
# Check Dp depex
|
|
|
|
#
|
|
|
|
CheckDpDepex(Dep, Guid, Version, WorkspaceDir)
|
|
|
|
|
2018-07-05 11:40:04 +02:00
|
|
|
#
|
2014-08-26 07:58:02 +02:00
|
|
|
# remove distribution
|
2011-08-26 09:46:26 +02:00
|
|
|
#
|
2014-08-26 07:58:02 +02:00
|
|
|
RemoveDist(Guid, Version, StoredDistFile, DataBase, WorkspaceDir, Options.Yes)
|
2011-08-26 09:46:26 +02:00
|
|
|
|
|
|
|
Logger.Quiet(ST.MSG_FINISH)
|
2018-07-05 11:40:04 +02:00
|
|
|
|
2011-08-26 09:46:26 +02:00
|
|
|
ReturnCode = 0
|
2018-07-05 11:40:04 +02:00
|
|
|
|
2018-06-25 12:31:25 +02:00
|
|
|
except FatalError as XExcept:
|
2018-07-05 11:40:04 +02:00
|
|
|
ReturnCode = XExcept.args[0]
|
2011-08-26 09:46:26 +02:00
|
|
|
if Logger.GetLevel() <= Logger.DEBUG_9:
|
|
|
|
Logger.Quiet(ST.MSG_PYTHON_ON % (python_version(), platform) + \
|
|
|
|
format_exc())
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
ReturnCode = ABORT_ERROR
|
|
|
|
if Logger.GetLevel() <= Logger.DEBUG_9:
|
|
|
|
Logger.Quiet(ST.MSG_PYTHON_ON % (python_version(), platform) + \
|
|
|
|
format_exc())
|
|
|
|
except:
|
|
|
|
Logger.Error(
|
|
|
|
"\nRmPkg",
|
|
|
|
CODE_ERROR,
|
|
|
|
ST.ERR_UNKNOWN_FATAL_REMOVING_ERR,
|
2019-05-21 04:06:52 +02:00
|
|
|
ExtraData=ST.MSG_SEARCH_FOR_HELP % ST.MSG_EDKII_MAIL_ADDR,
|
2011-08-26 09:46:26 +02:00
|
|
|
RaiseError=False
|
|
|
|
)
|
|
|
|
Logger.Quiet(ST.MSG_PYTHON_ON % (python_version(), platform) + \
|
|
|
|
format_exc())
|
|
|
|
ReturnCode = CODE_ERROR
|
|
|
|
return ReturnCode
|
|
|
|
|
2014-08-26 07:58:02 +02:00
|
|
|
## GetInstalledDpInfo method
|
|
|
|
#
|
|
|
|
# Get the installed distribution information
|
|
|
|
#
|
|
|
|
# @param DistributionFile: the name of the distribution
|
|
|
|
# @param Dep: the instance of DependencyRules
|
|
|
|
# @param DataBase: the internal database
|
|
|
|
# @param WorkspaceDir: work space directory
|
|
|
|
# @retval StoredDistFile: the distribution file that backed up
|
|
|
|
# @retval Guid: the Guid of the distribution
|
|
|
|
# @retval Version: the Version of distribution
|
|
|
|
#
|
|
|
|
def GetInstalledDpInfo(DistributionFile, Dep, DataBase, WorkspaceDir):
|
|
|
|
(Guid, Version, NewDpFileName) = DataBase.GetDpByName(os.path.split(DistributionFile)[1])
|
|
|
|
if not Guid:
|
|
|
|
Logger.Error("RmPkg", UNKNOWN_ERROR, ST.ERR_PACKAGE_NOT_INSTALLED % DistributionFile)
|
|
|
|
|
|
|
|
#
|
|
|
|
# Check Dp existing
|
|
|
|
#
|
|
|
|
if not Dep.CheckDpExists(Guid, Version):
|
|
|
|
Logger.Error("RmPkg", UNKNOWN_ERROR, ST.ERR_DISTRIBUTION_NOT_INSTALLED)
|
|
|
|
#
|
2018-07-05 11:40:04 +02:00
|
|
|
# Check for Distribution files existence in /conf/upt, if not exist,
|
2014-08-26 07:58:02 +02:00
|
|
|
# Warn user and go on.
|
|
|
|
#
|
|
|
|
StoredDistFile = os.path.normpath(os.path.join(WorkspaceDir, GlobalData.gUPT_DIR, NewDpFileName))
|
|
|
|
if not os.path.isfile(StoredDistFile):
|
|
|
|
Logger.Warn("RmPkg", ST.WRN_DIST_NOT_FOUND%StoredDistFile)
|
|
|
|
StoredDistFile = None
|
|
|
|
|
|
|
|
return StoredDistFile, Guid, Version
|
|
|
|
|
|
|
|
## RemoveDist method
|
|
|
|
#
|
|
|
|
# remove a distribution
|
|
|
|
#
|
|
|
|
# @param Guid: the Guid of the distribution
|
|
|
|
# @param Version: the Version of distribution
|
|
|
|
# @param StoredDistFile: the distribution file that backed up
|
|
|
|
# @param DataBase: the internal database
|
|
|
|
# @param WorkspaceDir: work space directory
|
|
|
|
# @param ForceRemove: whether user want to remove file even it is modified
|
|
|
|
#
|
|
|
|
def RemoveDist(Guid, Version, StoredDistFile, DataBase, WorkspaceDir, ForceRemove):
|
|
|
|
#
|
|
|
|
# Get Current File List
|
|
|
|
#
|
|
|
|
NewFileList = GetCurrentFileList(DataBase, Guid, Version, WorkspaceDir)
|
|
|
|
|
|
|
|
#
|
|
|
|
# Remove all files
|
|
|
|
#
|
|
|
|
MissingFileList = []
|
|
|
|
for (Path, Md5Sum) in DataBase.GetDpFileList(Guid, Version):
|
|
|
|
if os.path.isfile(Path):
|
|
|
|
if Path in NewFileList:
|
|
|
|
NewFileList.remove(Path)
|
|
|
|
if not ForceRemove:
|
|
|
|
#
|
|
|
|
# check whether modified by users
|
|
|
|
#
|
2019-02-06 08:44:39 +01:00
|
|
|
Md5Signature = md5(open(str(Path), 'rb').read())
|
|
|
|
if Md5Sum != Md5Signature.hexdigest():
|
2014-08-26 07:58:02 +02:00
|
|
|
Logger.Info(ST.MSG_CONFIRM_REMOVE2 % Path)
|
|
|
|
Input = stdin.readline()
|
|
|
|
Input = Input.replace('\r', '').replace('\n', '')
|
|
|
|
if Input.upper() != 'Y':
|
|
|
|
continue
|
|
|
|
RemovePath(Path)
|
|
|
|
else:
|
|
|
|
MissingFileList.append(Path)
|
2018-07-05 11:40:04 +02:00
|
|
|
|
2014-08-26 07:58:02 +02:00
|
|
|
for Path in NewFileList:
|
|
|
|
if os.path.isfile(Path):
|
|
|
|
if (not ForceRemove) and (not os.path.split(Path)[1].startswith('.')):
|
|
|
|
Logger.Info(ST.MSG_CONFIRM_REMOVE3 % Path)
|
|
|
|
Input = stdin.readline()
|
|
|
|
Input = Input.replace('\r', '').replace('\n', '')
|
|
|
|
if Input.upper() != 'Y':
|
|
|
|
continue
|
|
|
|
RemovePath(Path)
|
|
|
|
|
|
|
|
#
|
|
|
|
# Remove distribution files in /Conf/.upt
|
|
|
|
#
|
|
|
|
if StoredDistFile is not None:
|
|
|
|
os.remove(StoredDistFile)
|
|
|
|
|
|
|
|
#
|
|
|
|
# update database
|
|
|
|
#
|
|
|
|
Logger.Quiet(ST.MSG_UPDATE_PACKAGE_DATABASE)
|
|
|
|
DataBase.RemoveDpObj(Guid, Version)
|