## @file
# Install distribution package.
#
# Copyright (c) 2007, Intel Corporation. All rights reserved.
# 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.
#
##
# Import Modules
#
import os
import sys
import traceback
import platform
from optparse import OptionParser
import Common.EdkLogger as EdkLogger
from Common.BuildToolError import *
from Common.Misc import *
from Common.XmlParser import *
from IpiDb import *
from DependencyRules import *
# Version and Copyright
VersionNumber = "0.1"
__version__ = "%prog Version " + VersionNumber
__copyright__ = "Copyright (c) 2008, Intel Corporation All rights reserved."
## Check environment variables
#
# Check environment variables that must be set for build. Currently they are
#
# WORKSPACE The directory all packages/platforms start from
# EDK_TOOLS_PATH The directory contains all tools needed by the build
# PATH $(EDK_TOOLS_PATH)/Bin/ must be set in PATH
#
# If any of above environment variable is not set or has error, the build
# will be broken.
#
def CheckEnvVariable():
# check WORKSPACE
if "WORKSPACE" not in os.environ:
EdkLogger.error("RmPkg", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
ExtraData="WORKSPACE")
WorkspaceDir = os.path.normpath(os.environ["WORKSPACE"])
if not os.path.exists(WorkspaceDir):
EdkLogger.error("RmPkg", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData="%s" % WorkspaceDir)
elif ' ' in WorkspaceDir:
EdkLogger.error("RmPkg", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",
ExtraData=WorkspaceDir)
os.environ["WORKSPACE"] = WorkspaceDir
## Parse command line options
#
# Using standard Python module optparse to parse command line option of this tool.
#
# @retval Opt A optparse.Values object containing the parsed options
# @retval Args Target of build command
#
def MyOptionParser():
UsageString = "%prog -g -n [-y] [-q | -v] [-h]"
Parser = OptionParser(description=__copyright__,version=__version__,prog="RmPkg",usage=UsageString)
Parser.add_option("-?", action="help", help="show this help message and exit")
# Parser.add_option("-f", "--force", action="store_true", type=None, dest="ForceRemove",
# help="Force creation - overwrite existing one.")
Parser.add_option("-y", "--yes", action="store_true", dest="Yes",
help="Not asking for confirmation when deleting files.")
Parser.add_option("-n", "--package-version", action="store", type="string", dest="PackageVersion",
help="The version of distribution package to be removed.")
Parser.add_option("-g", "--package-guid", action="store", type="string", dest="PackageGuid",
help="The GUID of distribution package to be removed.")
Parser.add_option("-q", "--quiet", action="store_const", dest="LogLevel", const=EdkLogger.QUIET,
help="Disable all messages except FATAL ERRORS.")
Parser.add_option("-v", "--verbose", action="store_const", dest="LogLevel", const=EdkLogger.VERBOSE,
help="Turn on verbose output")
Parser.add_option("-d", "--debug", action="store", type="int", dest="LogLevel",
help="Enable debug messages at specified level.")
Parser.set_defaults(LogLevel=EdkLogger.INFO)
(Opt, Args)=Parser.parse_args()
return Opt
## Remove all empty dirs under the path
def RemoveEmptyDirs(Path):
# Remove all sub dirs
for Root, Dirs, Files in os.walk(Path):
for Dir in Dirs:
FullPath = os.path.normpath(os.path.join(Root, Dir))
if os.path.isdir(FullPath):
if os.listdir(FullPath) == []:
os.rmdir(FullPath)
else:
RemoveEmptyDirs(FullPath)
# Remove itself
if os.path.isdir(Path) and os.listdir(Path) == []:
os.rmdir(Path)
## 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.
#
# @retval 0 Tool was successful
# @retval 1 Tool failed
#
def Main():
EdkLogger.Initialize()
Options = MyOptionParser()
try:
if not Options.PackageGuid and not Options.PackageVersion:
EdkLogger.error("RmPkg", OPTION_MISSING, ExtraData="The GUID and Version of distribution package must be specified")
if Options.LogLevel < EdkLogger.DEBUG_9:
EdkLogger.SetLevel(Options.LogLevel + 1)
else:
EdkLogger.SetLevel(Options.LogLevel)
CheckEnvVariable()
WorkspaceDir = os.environ["WORKSPACE"]
# Prepare check dependency
Db = IpiDatabase(os.path.normpath(os.path.join(WorkspaceDir, "Conf/DistributionPackageDatabase.db")))
Db.InitDatabase()
Dep = DependencyRules(Db)
Guid = Options.PackageGuid
Version = Options.PackageVersion
# Check Dp existing
if not Dep.CheckDpExists(Guid, Version):
EdkLogger.error("RmPkg", UNKNOWN_ERROR, "This distribution package are not installed!")
# Check Dp depex
if not Dep.CheckDpDepexForRemove(Guid, Version):
print "Some packages/modules are depending on this distribution package, do you really want to remove it?"
print "Press Y to delete all files or press other keys to quit:"
Input = Input = sys.stdin.readline()
Input = Input.replace('\r', '').replace('\n', '')
if Input.upper() != 'Y':
EdkLogger.error("RmPkg", UNKNOWN_ERROR, "User interrupt")
# Remove all files
if not Options.Yes:
print "All files of the distribution package will be removed, do you want to continue?"
print "Press Y to remove all files or press other keys to quit:"
Input = Input = sys.stdin.readline()
Input = Input.replace('\r', '').replace('\n', '')
if Input.upper() != 'Y':
EdkLogger.error("RmPkg", UNKNOWN_ERROR, "User interrupt")
# Remove all files
MissingFileList = []
for Item in Db.GetDpFileList(Guid, Version):
if os.path.isfile(Item):
print "Removing file [%s] ..." % Item
os.remove(Item)
else:
MissingFileList.append(Item)
# Remove all empty dirs of package
for Item in Db.GetPackageListFromDp(Guid, Version):
Dir = os.path.dirname(Item[2])
RemoveEmptyDirs(Dir)
# Remove all empty dirs of module
for Item in Db.GetStandaloneModuleInstallPathListFromDp(Guid, Version):
Dir = os.path.dirname(Item)
RemoveEmptyDirs(Dir)
# update database
EdkLogger.quiet("Update Distribution Package Database ...")
Db.RemoveDpObj(Guid, Version)
EdkLogger.quiet("DONE")
except FatalError, X:
if Options and Options.LogLevel < EdkLogger.DEBUG_9:
EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
ReturnCode = X.args[0]
except KeyboardInterrupt:
ReturnCode = ABORT_ERROR
if Options and Options.LogLevel < EdkLogger.DEBUG_9:
EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
except:
EdkLogger.error(
"\nRmPkg",
CODE_ERROR,
"Unknown fatal error when removing package",
ExtraData="\n(Please send email to edk2-buildtools-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n",
RaiseError=False
)
EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
ReturnCode = CODE_ERROR
finally:
Progressor.Abort()
if __name__ == '__main__':
sys.exit(Main())