2 # Install distribution package.
4 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
17 from stat
import S_IWUSR
18 from traceback
import format_exc
19 from platform
import python_version
20 from hashlib
import md5
22 from sys
import platform
24 from Core
.DependencyRules
import DependencyRules
25 from Library
import GlobalData
26 from Logger
import StringTable
as ST
27 import Logger
.Log
as Logger
28 from Logger
.ToolError
import OPTION_MISSING
29 from Logger
.ToolError
import UNKNOWN_ERROR
30 from Logger
.ToolError
import ABORT_ERROR
31 from Logger
.ToolError
import CODE_ERROR
32 from Logger
.ToolError
import FatalError
37 # Check if the Depex is satisfied
39 # @param Guid: Guid of Dp
40 # @param Version: Version of Dp
41 # @param WorkspaceDir: Workspace Dir
43 def CheckDpDepex(Dep
, Guid
, Version
, WorkspaceDir
):
44 (Removable
, DependModuleList
) = Dep
.CheckDpDepexForRemove(Guid
, Version
)
46 Logger
.Info(ST
.MSG_CONFIRM_REMOVE
)
47 Logger
.Info(ST
.MSG_USER_DELETE_OP
)
48 Input
= stdin
.readline()
49 Input
= Input
.replace('\r', '').replace('\n', '')
50 if Input
.upper() != 'Y':
51 Logger
.Error("RmPkg", UNKNOWN_ERROR
, ST
.ERR_USER_INTERRUPT
)
55 # report list of modules that are not valid due to force
57 # also generate a log file for reference
59 Logger
.Info(ST
.MSG_INVALID_MODULE_INTRODUCED
)
60 LogFilePath
= os
.path
.normpath(os
.path
.join(WorkspaceDir
, GlobalData
.gINVALID_MODULE_FILE
))
61 Logger
.Info(ST
.MSG_CHECK_LOG_FILE
% LogFilePath
)
63 LogFile
= open(LogFilePath
, 'w')
65 for ModulePath
in DependModuleList
:
66 LogFile
.write("%s\n"%ModulePath
)
67 Logger
.Info(ModulePath
)
69 Logger
.Warn("\nRmPkg", ST
.ERR_FILE_WRITE_FAILURE
,
72 Logger
.Warn("\nRmPkg", ST
.ERR_FILE_OPEN_FAILURE
,
79 # removing readonly file on windows will get "Access is denied"
80 # error, so before removing, change the mode to be writeable
82 # @param Path: The Path to be removed
85 Logger
.Info(ST
.MSG_REMOVE_FILE
% Path
)
86 if not os
.access(Path
, os
.W_OK
):
87 os
.chmod(Path
, S_IWUSR
)
90 os
.removedirs(os
.path
.split(Path
)[0])
95 # @param DataBase: DataBase of UPT
96 # @param Guid: Guid of Dp
97 # @param Version: Version of Dp
98 # @param WorkspaceDir: Workspace Dir
100 def GetCurrentFileList(DataBase
, Guid
, Version
, WorkspaceDir
):
102 for Dir
in DataBase
.GetDpInstallDirList(Guid
, Version
):
103 RootDir
= os
.path
.normpath(os
.path
.join(WorkspaceDir
, Dir
))
104 for Root
, Dirs
, Files
in os
.walk(RootDir
):
105 Logger
.Debug(0, Dirs
)
107 FilePath
= os
.path
.join(Root
, File
)
108 if FilePath
not in NewFileList
:
109 NewFileList
.append(FilePath
)
113 ## Tool entrance method
115 # This method mainly dispatch specific methods per the command line options.
116 # If no error found, return zero value so the caller of this tool can know
117 # if it's executed successfully or not.
119 # @param Options: command option
121 def Main(Options
= None):
124 DataBase
= GlobalData
.gDB
125 if not Options
.DistributionFile
:
126 Logger
.Error("RmPkg",
128 ExtraData
=ST
.ERR_SPECIFY_PACKAGE
)
129 WorkspaceDir
= GlobalData
.gWORKSPACE
131 # Prepare check dependency
133 Dep
= DependencyRules(DataBase
)
136 # Get the Dp information
138 StoredDistFile
, Guid
, Version
= GetInstalledDpInfo(Options
.DistributionFile
, Dep
, DataBase
, WorkspaceDir
)
143 CheckDpDepex(Dep
, Guid
, Version
, WorkspaceDir
)
146 # remove distribution
148 RemoveDist(Guid
, Version
, StoredDistFile
, DataBase
, WorkspaceDir
, Options
.Yes
)
150 Logger
.Quiet(ST
.MSG_FINISH
)
154 except FatalError
as XExcept
:
155 ReturnCode
= XExcept
.args
[0]
156 if Logger
.GetLevel() <= Logger
.DEBUG_9
:
157 Logger
.Quiet(ST
.MSG_PYTHON_ON
% (python_version(), platform
) + \
159 except KeyboardInterrupt:
160 ReturnCode
= ABORT_ERROR
161 if Logger
.GetLevel() <= Logger
.DEBUG_9
:
162 Logger
.Quiet(ST
.MSG_PYTHON_ON
% (python_version(), platform
) + \
168 ST
.ERR_UNKNOWN_FATAL_REMOVING_ERR
,
169 ExtraData
=ST
.MSG_SEARCH_FOR_HELP
% ST
.MSG_EDKII_MAIL_ADDR
,
172 Logger
.Quiet(ST
.MSG_PYTHON_ON
% (python_version(), platform
) + \
174 ReturnCode
= CODE_ERROR
177 ## GetInstalledDpInfo method
179 # Get the installed distribution information
181 # @param DistributionFile: the name of the distribution
182 # @param Dep: the instance of DependencyRules
183 # @param DataBase: the internal database
184 # @param WorkspaceDir: work space directory
185 # @retval StoredDistFile: the distribution file that backed up
186 # @retval Guid: the Guid of the distribution
187 # @retval Version: the Version of distribution
189 def GetInstalledDpInfo(DistributionFile
, Dep
, DataBase
, WorkspaceDir
):
190 (Guid
, Version
, NewDpFileName
) = DataBase
.GetDpByName(os
.path
.split(DistributionFile
)[1])
192 Logger
.Error("RmPkg", UNKNOWN_ERROR
, ST
.ERR_PACKAGE_NOT_INSTALLED
% DistributionFile
)
197 if not Dep
.CheckDpExists(Guid
, Version
):
198 Logger
.Error("RmPkg", UNKNOWN_ERROR
, ST
.ERR_DISTRIBUTION_NOT_INSTALLED
)
200 # Check for Distribution files existence in /conf/upt, if not exist,
201 # Warn user and go on.
203 StoredDistFile
= os
.path
.normpath(os
.path
.join(WorkspaceDir
, GlobalData
.gUPT_DIR
, NewDpFileName
))
204 if not os
.path
.isfile(StoredDistFile
):
205 Logger
.Warn("RmPkg", ST
.WRN_DIST_NOT_FOUND
%StoredDistFile
)
206 StoredDistFile
= None
208 return StoredDistFile
, Guid
, Version
212 # remove a distribution
214 # @param Guid: the Guid of the distribution
215 # @param Version: the Version of distribution
216 # @param StoredDistFile: the distribution file that backed up
217 # @param DataBase: the internal database
218 # @param WorkspaceDir: work space directory
219 # @param ForceRemove: whether user want to remove file even it is modified
221 def RemoveDist(Guid
, Version
, StoredDistFile
, DataBase
, WorkspaceDir
, ForceRemove
):
223 # Get Current File List
225 NewFileList
= GetCurrentFileList(DataBase
, Guid
, Version
, WorkspaceDir
)
231 for (Path
, Md5Sum
) in DataBase
.GetDpFileList(Guid
, Version
):
232 if os
.path
.isfile(Path
):
233 if Path
in NewFileList
:
234 NewFileList
.remove(Path
)
237 # check whether modified by users
239 Md5Signature
= md5(open(str(Path
), 'rb').read())
240 if Md5Sum
!= Md5Signature
.hexdigest():
241 Logger
.Info(ST
.MSG_CONFIRM_REMOVE2
% Path
)
242 Input
= stdin
.readline()
243 Input
= Input
.replace('\r', '').replace('\n', '')
244 if Input
.upper() != 'Y':
248 MissingFileList
.append(Path
)
250 for Path
in NewFileList
:
251 if os
.path
.isfile(Path
):
252 if (not ForceRemove
) and (not os
.path
.split(Path
)[1].startswith('.')):
253 Logger
.Info(ST
.MSG_CONFIRM_REMOVE3
% Path
)
254 Input
= stdin
.readline()
255 Input
= Input
.replace('\r', '').replace('\n', '')
256 if Input
.upper() != 'Y':
261 # Remove distribution files in /Conf/.upt
263 if StoredDistFile
is not None:
264 os
.remove(StoredDistFile
)
269 Logger
.Quiet(ST
.MSG_UPDATE_PACKAGE_DATABASE
)
270 DataBase
.RemoveDpObj(Guid
, Version
)