| ## @file | |
| # Install distribution package. | |
| # | |
| # Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR> | |
| # | |
| # This program and the accompanying materials are licensed and made available | |
| # under the terms and conditions of the BSD License which accompanies this | |
| # distribution. The full text of the license may be found at | |
| # http://opensource.org/licenses/bsd-license.php | |
| # | |
| # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| # | |
| ''' | |
| RmPkg | |
| ''' | |
| ## | |
| # Import Modules | |
| # | |
| import os.path | |
| from stat import S_IWUSR | |
| from traceback import format_exc | |
| from platform import python_version | |
| import md5 | |
| 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: | |
| # | |
| # report list of modules that are not valid due to force | |
| # 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: | |
| Logger.Warn("\nRmPkg", ST.ERR_FILE_WRITE_FAILURE, | |
| File=LogFilePath) | |
| except IOError: | |
| Logger.Warn("\nRmPkg", ST.ERR_FILE_OPEN_FAILURE, | |
| File=LogFilePath) | |
| finally: | |
| LogFile.close() | |
| ## Remove Path | |
| # | |
| # removing readonly file on windows will get "Access is denied" | |
| # error, so before removing, change the mode to be writeable | |
| # | |
| # @param Path: The Path to be removed | |
| # | |
| 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. | |
| # | |
| # @param Options: command option | |
| # | |
| def Main(Options = None): | |
| try: | |
| DataBase = GlobalData.gDB | |
| if not Options.DistributionFile: | |
| Logger.Error("RmPkg", | |
| OPTION_MISSING, | |
| ExtraData=ST.ERR_SPECIFY_PACKAGE) | |
| WorkspaceDir = GlobalData.gWORKSPACE | |
| # | |
| # Prepare check dependency | |
| # | |
| Dep = DependencyRules(DataBase) | |
| # | |
| # Get the Dp information | |
| # | |
| StoredDistFile, Guid, Version = GetInstalledDpInfo(Options.DistributionFile, Dep, DataBase, WorkspaceDir) | |
| # | |
| # Check Dp depex | |
| # | |
| CheckDpDepex(Dep, Guid, Version, WorkspaceDir) | |
| # | |
| # remove distribution | |
| # | |
| RemoveDist(Guid, Version, StoredDistFile, DataBase, WorkspaceDir, Options.Yes) | |
| Logger.Quiet(ST.MSG_FINISH) | |
| ReturnCode = 0 | |
| except FatalError, XExcept: | |
| ReturnCode = XExcept.args[0] | |
| 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, | |
| ExtraData=ST.MSG_SEARCH_FOR_HELP, | |
| RaiseError=False | |
| ) | |
| Logger.Quiet(ST.MSG_PYTHON_ON % (python_version(), platform) + \ | |
| format_exc()) | |
| ReturnCode = CODE_ERROR | |
| return ReturnCode | |
| ## 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) | |
| # | |
| # Check for Distribution files existence in /conf/upt, if not exist, | |
| # 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 | |
| # | |
| Md5Sigature = md5.new(open(str(Path), 'rb').read()) | |
| if Md5Sum != Md5Sigature.hexdigest(): | |
| 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) | |
| 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) |