mirror of https://github.com/acidanthera/audk.git
968 lines
37 KiB
Python
968 lines
37 KiB
Python
## @file
|
|
# Install distribution package.
|
|
#
|
|
# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
#
|
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
#
|
|
"""
|
|
Install a distribution package
|
|
"""
|
|
##
|
|
# Import Modules
|
|
#
|
|
from Core.FileHook import __FileHookOpen__
|
|
import os.path
|
|
from os import chmod
|
|
from os import SEEK_SET
|
|
from os import SEEK_END
|
|
import stat
|
|
from hashlib import md5
|
|
import copy
|
|
from sys import stdin
|
|
from sys import platform
|
|
from shutil import rmtree
|
|
from shutil import copyfile
|
|
from traceback import format_exc
|
|
from platform import python_version
|
|
|
|
from Logger import StringTable as ST
|
|
from Logger.ToolError import UNKNOWN_ERROR
|
|
from Logger.ToolError import FILE_UNKNOWN_ERROR
|
|
from Logger.ToolError import OPTION_MISSING
|
|
from Logger.ToolError import UPT_ALREADY_INSTALLED_ERROR
|
|
from Logger.ToolError import FatalError
|
|
from Logger.ToolError import ABORT_ERROR
|
|
from Logger.ToolError import CODE_ERROR
|
|
from Logger.ToolError import FORMAT_INVALID
|
|
from Logger.ToolError import FILE_TYPE_MISMATCH
|
|
import Logger.Log as Logger
|
|
|
|
from Library.Misc import Sdict
|
|
from Library.Misc import ConvertPath
|
|
from Library.ParserValidate import IsValidInstallPath
|
|
from Xml.XmlParser import DistributionPackageXml
|
|
from GenMetaFile.GenDecFile import PackageToDec
|
|
from GenMetaFile.GenInfFile import ModuleToInf
|
|
from Core.PackageFile import PackageFile
|
|
from Core.PackageFile import FILE_NOT_FOUND
|
|
from Core.PackageFile import FILE_CHECKSUM_FAILURE
|
|
from Core.PackageFile import CreateDirectory
|
|
from Core.DependencyRules import DependencyRules
|
|
from Library import GlobalData
|
|
|
|
## InstallNewPackage
|
|
#
|
|
# @param WorkspaceDir: Workspace Directory
|
|
# @param Path: Package Path
|
|
# @param CustomPath: whether need to customize path at first
|
|
#
|
|
def InstallNewPackage(WorkspaceDir, Path, CustomPath = False):
|
|
if os.path.isabs(Path):
|
|
Logger.Info(ST.MSG_RELATIVE_PATH_ONLY%Path)
|
|
elif CustomPath:
|
|
Logger.Info(ST.MSG_NEW_PKG_PATH)
|
|
else:
|
|
Path = ConvertPath(Path)
|
|
Path = os.path.normpath(Path)
|
|
FullPath = os.path.normpath(os.path.join(WorkspaceDir, Path))
|
|
if os.path.exists(FullPath):
|
|
Logger.Info(ST.ERR_DIR_ALREADY_EXIST%FullPath)
|
|
else:
|
|
return Path
|
|
|
|
Input = stdin.readline()
|
|
Input = Input.replace('\r', '').replace('\n', '')
|
|
if Input == '':
|
|
Logger.Error("InstallPkg", UNKNOWN_ERROR, ST.ERR_USER_INTERRUPT)
|
|
Input = Input.replace('\r', '').replace('\n', '')
|
|
return InstallNewPackage(WorkspaceDir, Input, False)
|
|
|
|
## InstallNewModule
|
|
#
|
|
# @param WorkspaceDir: Workspace Directory
|
|
# @param Path: Standalone Module Path
|
|
# @param PathList: The already installed standalone module Path list
|
|
#
|
|
def InstallNewModule(WorkspaceDir, Path, PathList = None):
|
|
if PathList is None:
|
|
PathList = []
|
|
Path = ConvertPath(Path)
|
|
Path = os.path.normpath(Path)
|
|
FullPath = os.path.normpath(os.path.join(WorkspaceDir, Path))
|
|
if os.path.exists(FullPath) and FullPath not in PathList:
|
|
Logger.Info(ST.ERR_DIR_ALREADY_EXIST%Path)
|
|
elif Path == FullPath:
|
|
Logger.Info(ST.MSG_RELATIVE_PATH_ONLY%FullPath)
|
|
else:
|
|
return Path
|
|
|
|
Input = stdin.readline()
|
|
Input = Input.replace('\r', '').replace('\n', '')
|
|
if Input == '':
|
|
Logger.Error("InstallPkg", UNKNOWN_ERROR, ST.ERR_USER_INTERRUPT)
|
|
Input = Input.replace('\r', '').replace('\n', '')
|
|
return InstallNewModule(WorkspaceDir, Input, PathList)
|
|
|
|
|
|
## InstallNewFile
|
|
#
|
|
# @param WorkspaceDir: Workspace Direction
|
|
# @param File: File
|
|
#
|
|
def InstallNewFile(WorkspaceDir, File):
|
|
FullPath = os.path.normpath(os.path.join(WorkspaceDir, File))
|
|
if os.path.exists(FullPath):
|
|
Logger.Info(ST.ERR_FILE_ALREADY_EXIST %File)
|
|
Input = stdin.readline()
|
|
Input = Input.replace('\r', '').replace('\n', '')
|
|
if Input == '':
|
|
Logger.Error("InstallPkg", UNKNOWN_ERROR, ST.ERR_USER_INTERRUPT)
|
|
Input = Input.replace('\r', '').replace('\n', '')
|
|
return InstallNewFile(WorkspaceDir, Input)
|
|
else:
|
|
return File
|
|
|
|
## UnZipDp
|
|
#
|
|
# UnZipDp
|
|
#
|
|
def UnZipDp(WorkspaceDir, DpPkgFileName, Index=1):
|
|
ContentZipFile = None
|
|
Logger.Quiet(ST.MSG_UZIP_PARSE_XML)
|
|
DistFile = PackageFile(DpPkgFileName)
|
|
|
|
DpDescFileName, ContentFileName = GetDPFile(DistFile.GetZipFile())
|
|
|
|
TempDir = os.path.normpath(os.path.join(WorkspaceDir, "Conf/.tmp%s" % str(Index)))
|
|
GlobalData.gUNPACK_DIR.append(TempDir)
|
|
DistPkgFile = DistFile.UnpackFile(DpDescFileName, os.path.normpath(os.path.join(TempDir, DpDescFileName)))
|
|
if not DistPkgFile:
|
|
Logger.Error("InstallPkg", FILE_NOT_FOUND, ST.ERR_FILE_BROKEN %DpDescFileName)
|
|
|
|
#
|
|
# Generate distpkg
|
|
#
|
|
DistPkgObj = DistributionPackageXml()
|
|
DistPkg = DistPkgObj.FromXml(DistPkgFile)
|
|
if DistPkg.Header.RePackage == '':
|
|
DistPkg.Header.RePackage = False
|
|
if DistPkg.Header.ReadOnly == '':
|
|
DistPkg.Header.ReadOnly = False
|
|
|
|
#
|
|
# unzip contents.zip file
|
|
#
|
|
ContentFile = DistFile.UnpackFile(ContentFileName, os.path.normpath(os.path.join(TempDir, ContentFileName)))
|
|
if not ContentFile:
|
|
Logger.Error("InstallPkg", FILE_NOT_FOUND,
|
|
ST.ERR_FILE_BROKEN % ContentFileName)
|
|
|
|
#
|
|
# Get file size
|
|
#
|
|
FileSize = os.path.getsize(ContentFile)
|
|
|
|
if FileSize != 0:
|
|
ContentZipFile = PackageFile(ContentFile)
|
|
|
|
#
|
|
# verify MD5 signature when existed
|
|
#
|
|
if DistPkg.Header.Signature != '':
|
|
Md5Signature = md5(__FileHookOpen__(ContentFile, 'rb').read())
|
|
if DistPkg.Header.Signature != Md5Signature.hexdigest():
|
|
ContentZipFile.Close()
|
|
Logger.Error("InstallPkg", FILE_CHECKSUM_FAILURE,
|
|
ExtraData=ContentFile)
|
|
|
|
return DistPkg, ContentZipFile, DpPkgFileName, DistFile
|
|
|
|
## GetPackageList
|
|
#
|
|
# GetPackageList
|
|
#
|
|
def GetPackageList(DistPkg, Dep, WorkspaceDir, Options, ContentZipFile, ModuleList, PackageList):
|
|
NewDict = Sdict()
|
|
for Guid, Version, Path in DistPkg.PackageSurfaceArea:
|
|
PackagePath = Path
|
|
Package = DistPkg.PackageSurfaceArea[Guid, Version, Path]
|
|
Logger.Info(ST.MSG_INSTALL_PACKAGE % Package.GetName())
|
|
# if Dep.CheckPackageExists(Guid, Version):
|
|
# Logger.Info(ST.WRN_PACKAGE_EXISTED %(Guid, Version))
|
|
if Options.UseGuidedPkgPath:
|
|
GuidedPkgPath = "%s_%s_%s" % (Package.GetName(), Guid, Version)
|
|
NewPackagePath = InstallNewPackage(WorkspaceDir, GuidedPkgPath, Options.CustomPath)
|
|
else:
|
|
NewPackagePath = InstallNewPackage(WorkspaceDir, PackagePath, Options.CustomPath)
|
|
InstallPackageContent(PackagePath, NewPackagePath, Package, ContentZipFile, Dep, WorkspaceDir, ModuleList,
|
|
DistPkg.Header.ReadOnly)
|
|
PackageList.append(Package)
|
|
|
|
NewDict[Guid, Version, Package.GetPackagePath()] = Package
|
|
|
|
#
|
|
# Now generate meta-data files, first generate all dec for package
|
|
# dec should be generated before inf, and inf should be generated after
|
|
# all packages installed, else hard to resolve modules' package
|
|
# dependency (Hard to get the location of the newly installed package)
|
|
#
|
|
for Package in PackageList:
|
|
FilePath = PackageToDec(Package, DistPkg.Header)
|
|
Md5Signature = md5(__FileHookOpen__(str(FilePath), 'rb').read())
|
|
Md5Sum = Md5Signature.hexdigest()
|
|
if (FilePath, Md5Sum) not in Package.FileList:
|
|
Package.FileList.append((FilePath, Md5Sum))
|
|
|
|
return NewDict
|
|
|
|
## GetModuleList
|
|
#
|
|
# GetModuleList
|
|
#
|
|
def GetModuleList(DistPkg, Dep, WorkspaceDir, ContentZipFile, ModuleList):
|
|
#
|
|
# ModulePathList will keep track of the standalone module path that
|
|
# we just installed. If a new module's path in that list
|
|
# (only multiple INF in one directory will be so), we will
|
|
# install them directly. If not, we will try to create a new directory
|
|
# for it.
|
|
#
|
|
ModulePathList = []
|
|
|
|
#
|
|
# Check module exist and install
|
|
#
|
|
Module = None
|
|
NewDict = Sdict()
|
|
for Guid, Version, Name, Path in DistPkg.ModuleSurfaceArea:
|
|
ModulePath = Path
|
|
Module = DistPkg.ModuleSurfaceArea[Guid, Version, Name, Path]
|
|
Logger.Info(ST.MSG_INSTALL_MODULE % Module.GetName())
|
|
if Dep.CheckModuleExists(Guid, Version, Name, Path):
|
|
Logger.Quiet(ST.WRN_MODULE_EXISTED %Path)
|
|
#
|
|
# here check for the multiple inf share the same module path cases:
|
|
# they should be installed into the same directory
|
|
#
|
|
ModuleFullPath = \
|
|
os.path.normpath(os.path.join(WorkspaceDir, ModulePath))
|
|
if ModuleFullPath not in ModulePathList:
|
|
NewModulePath = InstallNewModule(WorkspaceDir, ModulePath, ModulePathList)
|
|
NewModuleFullPath = os.path.normpath(os.path.join(WorkspaceDir, NewModulePath))
|
|
ModulePathList.append(NewModuleFullPath)
|
|
else:
|
|
NewModulePath = ModulePath
|
|
|
|
InstallModuleContent(ModulePath, NewModulePath, '', Module, ContentZipFile, WorkspaceDir, ModuleList, None,
|
|
DistPkg.Header.ReadOnly)
|
|
#
|
|
# Update module
|
|
#
|
|
Module.SetModulePath(Module.GetModulePath().replace(Path, NewModulePath, 1))
|
|
|
|
NewDict[Guid, Version, Name, Module.GetModulePath()] = Module
|
|
|
|
#
|
|
# generate all inf for modules
|
|
#
|
|
for (Module, Package) in ModuleList:
|
|
CheckCNameInModuleRedefined(Module, DistPkg)
|
|
FilePath = ModuleToInf(Module, Package, DistPkg.Header)
|
|
Md5Signature = md5(__FileHookOpen__(str(FilePath), 'rb').read())
|
|
Md5Sum = Md5Signature.hexdigest()
|
|
if Package:
|
|
if (FilePath, Md5Sum) not in Package.FileList:
|
|
Package.FileList.append((FilePath, Md5Sum))
|
|
else:
|
|
if (FilePath, Md5Sum) not in Module.FileList:
|
|
Module.FileList.append((FilePath, Md5Sum))
|
|
#
|
|
# append the module unicode files to Package FileList
|
|
#
|
|
for (FilePath, Md5Sum) in Module.FileList:
|
|
if str(FilePath).endswith('.uni') and Package and (FilePath, Md5Sum) not in Package.FileList:
|
|
Package.FileList.append((FilePath, Md5Sum))
|
|
|
|
return NewDict
|
|
|
|
##
|
|
# Get all protocol/ppi/guid CNames and pcd name from all dependent DEC file
|
|
#
|
|
def GetDepProtocolPpiGuidPcdNames(DePackageObjList):
|
|
#
|
|
# [[Dec1Protocol1, Dec1Protocol2...], [Dec2Protocols...],...]
|
|
#
|
|
DependentProtocolCNames = []
|
|
DependentPpiCNames = []
|
|
DependentGuidCNames = []
|
|
DependentPcdNames = []
|
|
|
|
for PackageObj in DePackageObjList:
|
|
#
|
|
# Get protocol CName list from all dependent DEC file
|
|
#
|
|
ProtocolCNames = []
|
|
for Protocol in PackageObj.GetProtocolList():
|
|
if Protocol.GetCName() not in ProtocolCNames:
|
|
ProtocolCNames.append(Protocol.GetCName())
|
|
|
|
DependentProtocolCNames.append(ProtocolCNames)
|
|
|
|
#
|
|
# Get Ppi CName list from all dependent DEC file
|
|
#
|
|
PpiCNames = []
|
|
for Ppi in PackageObj.GetPpiList():
|
|
if Ppi.GetCName() not in PpiCNames:
|
|
PpiCNames.append(Ppi.GetCName())
|
|
|
|
DependentPpiCNames.append(PpiCNames)
|
|
|
|
#
|
|
# Get Guid CName list from all dependent DEC file
|
|
#
|
|
GuidCNames = []
|
|
for Guid in PackageObj.GetGuidList():
|
|
if Guid.GetCName() not in GuidCNames:
|
|
GuidCNames.append(Guid.GetCName())
|
|
|
|
DependentGuidCNames.append(GuidCNames)
|
|
|
|
#
|
|
# Get PcdName list from all dependent DEC file
|
|
#
|
|
PcdNames = []
|
|
for Pcd in PackageObj.GetPcdList():
|
|
PcdName = '.'.join([Pcd.GetTokenSpaceGuidCName(), Pcd.GetCName()])
|
|
if PcdName not in PcdNames:
|
|
PcdNames.append(PcdName)
|
|
|
|
DependentPcdNames.append(PcdNames)
|
|
|
|
|
|
return DependentProtocolCNames, DependentPpiCNames, DependentGuidCNames, DependentPcdNames
|
|
|
|
##
|
|
# Check if protocol CName is redefined
|
|
#
|
|
def CheckProtoclCNameRedefined(Module, DependentProtocolCNames):
|
|
for ProtocolInModule in Module.GetProtocolList():
|
|
IsCNameDefined = False
|
|
for PackageProtocolCNames in DependentProtocolCNames:
|
|
if ProtocolInModule.GetCName() in PackageProtocolCNames:
|
|
if IsCNameDefined:
|
|
Logger.Error("\nUPT", FORMAT_INVALID,
|
|
File = Module.GetFullPath(),
|
|
ExtraData = \
|
|
ST.ERR_INF_PARSER_ITEM_DUPLICATE_IN_DEC % ProtocolInModule.GetCName())
|
|
else:
|
|
IsCNameDefined = True
|
|
|
|
##
|
|
# Check if Ppi CName is redefined
|
|
#
|
|
def CheckPpiCNameRedefined(Module, DependentPpiCNames):
|
|
for PpiInModule in Module.GetPpiList():
|
|
IsCNameDefined = False
|
|
for PackagePpiCNames in DependentPpiCNames:
|
|
if PpiInModule.GetCName() in PackagePpiCNames:
|
|
if IsCNameDefined:
|
|
Logger.Error("\nUPT", FORMAT_INVALID,
|
|
File = Module.GetFullPath(),
|
|
ExtraData = ST.ERR_INF_PARSER_ITEM_DUPLICATE_IN_DEC % PpiInModule.GetCName())
|
|
else:
|
|
IsCNameDefined = True
|
|
|
|
##
|
|
# Check if Guid CName is redefined
|
|
#
|
|
def CheckGuidCNameRedefined(Module, DependentGuidCNames):
|
|
for GuidInModule in Module.GetGuidList():
|
|
IsCNameDefined = False
|
|
for PackageGuidCNames in DependentGuidCNames:
|
|
if GuidInModule.GetCName() in PackageGuidCNames:
|
|
if IsCNameDefined:
|
|
Logger.Error("\nUPT", FORMAT_INVALID,
|
|
File = Module.GetFullPath(),
|
|
ExtraData = \
|
|
ST.ERR_INF_PARSER_ITEM_DUPLICATE_IN_DEC % GuidInModule.GetCName())
|
|
else:
|
|
IsCNameDefined = True
|
|
|
|
##
|
|
# Check if PcdName is redefined
|
|
#
|
|
def CheckPcdNameRedefined(Module, DependentPcdNames):
|
|
PcdObjs = []
|
|
if not Module.GetBinaryFileList():
|
|
PcdObjs += Module.GetPcdList()
|
|
else:
|
|
Binary = Module.GetBinaryFileList()[0]
|
|
for AsBuild in Binary.GetAsBuiltList():
|
|
PcdObjs += AsBuild.GetPatchPcdList() + AsBuild.GetPcdExList()
|
|
|
|
for PcdObj in PcdObjs:
|
|
PcdName = '.'.join([PcdObj.GetTokenSpaceGuidCName(), PcdObj.GetCName()])
|
|
IsPcdNameDefined = False
|
|
for PcdNames in DependentPcdNames:
|
|
if PcdName in PcdNames:
|
|
if IsPcdNameDefined:
|
|
Logger.Error("\nUPT", FORMAT_INVALID,
|
|
File = Module.GetFullPath(),
|
|
ExtraData = ST.ERR_INF_PARSER_ITEM_DUPLICATE_IN_DEC % PcdName)
|
|
else:
|
|
IsPcdNameDefined = True
|
|
|
|
##
|
|
# Check if any Protocol/Ppi/Guid and Pcd name is redefined in its dependent DEC files
|
|
#
|
|
def CheckCNameInModuleRedefined(Module, DistPkg):
|
|
DePackageObjList = []
|
|
#
|
|
# Get all dependent package objects
|
|
#
|
|
for Obj in Module.GetPackageDependencyList():
|
|
Guid = Obj.GetGuid()
|
|
Version = Obj.GetVersion()
|
|
for Key in DistPkg.PackageSurfaceArea:
|
|
if Key[0] == Guid and Key[1] == Version:
|
|
if DistPkg.PackageSurfaceArea[Key] not in DePackageObjList:
|
|
DePackageObjList.append(DistPkg.PackageSurfaceArea[Key])
|
|
|
|
DependentProtocolCNames, DependentPpiCNames, DependentGuidCNames, DependentPcdNames = \
|
|
GetDepProtocolPpiGuidPcdNames(DePackageObjList)
|
|
|
|
CheckProtoclCNameRedefined(Module, DependentProtocolCNames)
|
|
CheckPpiCNameRedefined(Module, DependentPpiCNames)
|
|
CheckGuidCNameRedefined(Module, DependentGuidCNames)
|
|
CheckPcdNameRedefined(Module, DependentPcdNames)
|
|
|
|
## GenToolMisc
|
|
#
|
|
# GenToolMisc
|
|
#
|
|
#
|
|
def GenToolMisc(DistPkg, WorkspaceDir, ContentZipFile):
|
|
ToolObject = DistPkg.Tools
|
|
MiscObject = DistPkg.MiscellaneousFiles
|
|
DistPkg.FileList = []
|
|
FileList = []
|
|
ToolFileNum = 0
|
|
FileNum = 0
|
|
RootDir = WorkspaceDir
|
|
|
|
#
|
|
# FileList stores both tools files and misc files
|
|
# Misc file list must be appended to FileList *AFTER* Tools file list
|
|
#
|
|
if ToolObject:
|
|
FileList += ToolObject.GetFileList()
|
|
ToolFileNum = len(ToolObject.GetFileList())
|
|
if 'EDK_TOOLS_PATH' in os.environ:
|
|
RootDir = os.environ['EDK_TOOLS_PATH']
|
|
if MiscObject:
|
|
FileList += MiscObject.GetFileList()
|
|
for FileObject in FileList:
|
|
FileNum += 1
|
|
if FileNum > ToolFileNum:
|
|
#
|
|
# Misc files, root should be changed to WORKSPACE
|
|
#
|
|
RootDir = WorkspaceDir
|
|
File = ConvertPath(FileObject.GetURI())
|
|
ToFile = os.path.normpath(os.path.join(RootDir, File))
|
|
if os.path.exists(ToFile):
|
|
Logger.Info( ST.WRN_FILE_EXISTED % ToFile )
|
|
#
|
|
# ask for user input the new file name
|
|
#
|
|
Logger.Info( ST.MSG_NEW_FILE_NAME)
|
|
Input = stdin.readline()
|
|
Input = Input.replace('\r', '').replace('\n', '')
|
|
OrigPath = os.path.split(ToFile)[0]
|
|
ToFile = os.path.normpath(os.path.join(OrigPath, Input))
|
|
FromFile = os.path.join(FileObject.GetURI())
|
|
Md5Sum = InstallFile(ContentZipFile, FromFile, ToFile, DistPkg.Header.ReadOnly, FileObject.GetExecutable())
|
|
DistPkg.FileList.append((ToFile, Md5Sum))
|
|
|
|
## 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 Options
|
|
#
|
|
def Main(Options = None):
|
|
try:
|
|
DataBase = GlobalData.gDB
|
|
WorkspaceDir = GlobalData.gWORKSPACE
|
|
if not Options.PackageFile:
|
|
Logger.Error("InstallPkg", OPTION_MISSING, ExtraData=ST.ERR_SPECIFY_PACKAGE)
|
|
|
|
# Get all Dist Info
|
|
DistInfoList = []
|
|
DistPkgList = []
|
|
Index = 1
|
|
for ToBeInstalledDist in Options.PackageFile:
|
|
#
|
|
# unzip dist.pkg file
|
|
#
|
|
DistInfoList.append(UnZipDp(WorkspaceDir, ToBeInstalledDist, Index))
|
|
DistPkgList.append(DistInfoList[-1][0])
|
|
Index += 1
|
|
|
|
#
|
|
# Add dist
|
|
#
|
|
GlobalData.gTO_BE_INSTALLED_DIST_LIST.append(DistInfoList[-1][0])
|
|
|
|
# Check for dependency
|
|
Dep = DependencyRules(DataBase, DistPkgList)
|
|
|
|
for ToBeInstalledDist in DistInfoList:
|
|
CheckInstallDpx(Dep, ToBeInstalledDist[0], ToBeInstalledDist[2])
|
|
|
|
#
|
|
# Install distribution
|
|
#
|
|
InstallDp(ToBeInstalledDist[0], ToBeInstalledDist[2], ToBeInstalledDist[1],
|
|
Options, Dep, WorkspaceDir, DataBase)
|
|
ReturnCode = 0
|
|
|
|
except FatalError as 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:
|
|
ReturnCode = CODE_ERROR
|
|
Logger.Error(
|
|
"\nInstallPkg",
|
|
CODE_ERROR,
|
|
ST.ERR_UNKNOWN_FATAL_INSTALL_ERR % Options.PackageFile,
|
|
ExtraData=ST.MSG_SEARCH_FOR_HELP % ST.MSG_EDKII_MAIL_ADDR,
|
|
RaiseError=False
|
|
)
|
|
Logger.Quiet(ST.MSG_PYTHON_ON % (python_version(),
|
|
platform) + format_exc())
|
|
finally:
|
|
Logger.Quiet(ST.MSG_REMOVE_TEMP_FILE_STARTED)
|
|
for ToBeInstalledDist in DistInfoList:
|
|
if ToBeInstalledDist[3]:
|
|
ToBeInstalledDist[3].Close()
|
|
if ToBeInstalledDist[1]:
|
|
ToBeInstalledDist[1].Close()
|
|
for TempDir in GlobalData.gUNPACK_DIR:
|
|
rmtree(TempDir)
|
|
GlobalData.gUNPACK_DIR = []
|
|
Logger.Quiet(ST.MSG_REMOVE_TEMP_FILE_DONE)
|
|
if ReturnCode == 0:
|
|
Logger.Quiet(ST.MSG_FINISH)
|
|
return ReturnCode
|
|
|
|
# BackupDist method
|
|
#
|
|
# This method will backup the Distribution file into the $(WORKSPACE)/conf/upt, and rename it
|
|
# if there is already a same-named distribution existed.
|
|
#
|
|
# @param DpPkgFileName: The distribution path
|
|
# @param Guid: The distribution Guid
|
|
# @param Version: The distribution Version
|
|
# @param WorkspaceDir: The workspace directory
|
|
# @retval NewDpPkgFileName: The exact backup file name
|
|
#
|
|
def BackupDist(DpPkgFileName, Guid, Version, WorkspaceDir):
|
|
DistFileName = os.path.split(DpPkgFileName)[1]
|
|
DestDir = os.path.normpath(os.path.join(WorkspaceDir, GlobalData.gUPT_DIR))
|
|
CreateDirectory(DestDir)
|
|
DestFile = os.path.normpath(os.path.join(DestDir, DistFileName))
|
|
if os.path.exists(DestFile):
|
|
FileName, Ext = os.path.splitext(DistFileName)
|
|
NewFileName = FileName + '_' + Guid + '_' + Version + Ext
|
|
DestFile = os.path.normpath(os.path.join(DestDir, NewFileName))
|
|
if os.path.exists(DestFile):
|
|
#
|
|
# ask for user input the new file name
|
|
#
|
|
Logger.Info( ST.MSG_NEW_FILE_NAME_FOR_DIST)
|
|
Input = stdin.readline()
|
|
Input = Input.replace('\r', '').replace('\n', '')
|
|
DestFile = os.path.normpath(os.path.join(DestDir, Input))
|
|
copyfile(DpPkgFileName, DestFile)
|
|
NewDpPkgFileName = DestFile[DestFile.find(DestDir) + len(DestDir) + 1:]
|
|
return NewDpPkgFileName
|
|
|
|
## CheckInstallDpx method
|
|
#
|
|
# check whether distribution could be installed
|
|
#
|
|
# @param Dep: the DependencyRules instance that used to check dependency
|
|
# @param DistPkg: the distribution object
|
|
#
|
|
def CheckInstallDpx(Dep, DistPkg, DistPkgFileName):
|
|
#
|
|
# Check distribution package installed or not
|
|
#
|
|
if Dep.CheckDpExists(DistPkg.Header.GetGuid(),
|
|
DistPkg.Header.GetVersion()):
|
|
Logger.Error("InstallPkg",
|
|
UPT_ALREADY_INSTALLED_ERROR,
|
|
ST.WRN_DIST_PKG_INSTALLED % os.path.basename(DistPkgFileName))
|
|
#
|
|
# Check distribution dependency (all module dependency should be
|
|
# satisfied)
|
|
#
|
|
if not Dep.CheckInstallDpDepexSatisfied(DistPkg):
|
|
Logger.Error("InstallPkg", UNKNOWN_ERROR,
|
|
ST.ERR_PACKAGE_NOT_MATCH_DEPENDENCY,
|
|
ExtraData=DistPkg.Header.Name)
|
|
|
|
## InstallModuleContent method
|
|
#
|
|
# If this is standalone module, then Package should be none,
|
|
# ModulePath should be ''
|
|
# @param FromPath: FromPath
|
|
# @param NewPath: NewPath
|
|
# @param ModulePath: ModulePath
|
|
# @param Module: Module
|
|
# @param ContentZipFile: ContentZipFile
|
|
# @param WorkspaceDir: WorkspaceDir
|
|
# @param ModuleList: ModuleList
|
|
# @param Package: Package
|
|
#
|
|
def InstallModuleContent(FromPath, NewPath, ModulePath, Module, ContentZipFile,
|
|
WorkspaceDir, ModuleList, Package = None, ReadOnly = False):
|
|
|
|
if NewPath.startswith("\\") or NewPath.startswith("/"):
|
|
NewPath = NewPath[1:]
|
|
|
|
if not IsValidInstallPath(NewPath):
|
|
Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%NewPath)
|
|
|
|
NewModuleFullPath = os.path.normpath(os.path.join(WorkspaceDir, NewPath,
|
|
ConvertPath(ModulePath)))
|
|
Module.SetFullPath(os.path.normpath(os.path.join(NewModuleFullPath,
|
|
ConvertPath(Module.GetName()) + '.inf')))
|
|
Module.FileList = []
|
|
|
|
for MiscFile in Module.GetMiscFileList():
|
|
if not MiscFile:
|
|
continue
|
|
for Item in MiscFile.GetFileList():
|
|
File = Item.GetURI()
|
|
if File.startswith("\\") or File.startswith("/"):
|
|
File = File[1:]
|
|
|
|
if not IsValidInstallPath(File):
|
|
Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%File)
|
|
|
|
FromFile = os.path.join(FromPath, ModulePath, File)
|
|
Executable = Item.GetExecutable()
|
|
ToFile = os.path.normpath(os.path.join(NewModuleFullPath, ConvertPath(File)))
|
|
Md5Sum = InstallFile(ContentZipFile, FromFile, ToFile, ReadOnly, Executable)
|
|
if Package and ((ToFile, Md5Sum) not in Package.FileList):
|
|
Package.FileList.append((ToFile, Md5Sum))
|
|
elif Package:
|
|
continue
|
|
elif (ToFile, Md5Sum) not in Module.FileList:
|
|
Module.FileList.append((ToFile, Md5Sum))
|
|
for Item in Module.GetSourceFileList():
|
|
File = Item.GetSourceFile()
|
|
if File.startswith("\\") or File.startswith("/"):
|
|
File = File[1:]
|
|
|
|
if not IsValidInstallPath(File):
|
|
Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%File)
|
|
|
|
FromFile = os.path.join(FromPath, ModulePath, File)
|
|
ToFile = os.path.normpath(os.path.join(NewModuleFullPath, ConvertPath(File)))
|
|
Md5Sum = InstallFile(ContentZipFile, FromFile, ToFile, ReadOnly)
|
|
if Package and ((ToFile, Md5Sum) not in Package.FileList):
|
|
Package.FileList.append((ToFile, Md5Sum))
|
|
elif Package:
|
|
continue
|
|
elif (ToFile, Md5Sum) not in Module.FileList:
|
|
Module.FileList.append((ToFile, Md5Sum))
|
|
for Item in Module.GetBinaryFileList():
|
|
FileNameList = Item.GetFileNameList()
|
|
for FileName in FileNameList:
|
|
File = FileName.GetFilename()
|
|
if File.startswith("\\") or File.startswith("/"):
|
|
File = File[1:]
|
|
|
|
if not IsValidInstallPath(File):
|
|
Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%File)
|
|
|
|
FromFile = os.path.join(FromPath, ModulePath, File)
|
|
ToFile = os.path.normpath(os.path.join(NewModuleFullPath, ConvertPath(File)))
|
|
Md5Sum = InstallFile(ContentZipFile, FromFile, ToFile, ReadOnly)
|
|
if Package and ((ToFile, Md5Sum) not in Package.FileList):
|
|
Package.FileList.append((ToFile, Md5Sum))
|
|
elif Package:
|
|
continue
|
|
elif (ToFile, Md5Sum) not in Module.FileList:
|
|
Module.FileList.append((ToFile, Md5Sum))
|
|
|
|
InstallModuleContentZipFile(ContentZipFile, FromPath, ModulePath, WorkspaceDir, NewPath, Module, Package, ReadOnly,
|
|
ModuleList)
|
|
|
|
## InstallModuleContentZipFile
|
|
#
|
|
# InstallModuleContentZipFile
|
|
#
|
|
def InstallModuleContentZipFile(ContentZipFile, FromPath, ModulePath, WorkspaceDir, NewPath, Module, Package, ReadOnly,
|
|
ModuleList):
|
|
#
|
|
# Extract other files under current module path in content Zip file but not listed in the description
|
|
#
|
|
if ContentZipFile:
|
|
for FileName in ContentZipFile.GetZipFile().namelist():
|
|
FileName = os.path.normpath(FileName)
|
|
CheckPath = os.path.normpath(os.path.join(FromPath, ModulePath))
|
|
if FileUnderPath(FileName, CheckPath):
|
|
if FileName.startswith("\\") or FileName.startswith("/"):
|
|
FileName = FileName[1:]
|
|
|
|
if not IsValidInstallPath(FileName):
|
|
Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%FileName)
|
|
|
|
FromFile = FileName
|
|
ToFile = os.path.normpath(os.path.join(WorkspaceDir,
|
|
ConvertPath(FileName.replace(FromPath, NewPath, 1))))
|
|
CheckList = copy.copy(Module.FileList)
|
|
if Package:
|
|
CheckList += Package.FileList
|
|
for Item in CheckList:
|
|
if Item[0] == ToFile:
|
|
break
|
|
else:
|
|
Md5Sum = InstallFile(ContentZipFile, FromFile, ToFile, ReadOnly)
|
|
if Package and ((ToFile, Md5Sum) not in Package.FileList):
|
|
Package.FileList.append((ToFile, Md5Sum))
|
|
elif Package:
|
|
continue
|
|
elif (ToFile, Md5Sum) not in Module.FileList:
|
|
Module.FileList.append((ToFile, Md5Sum))
|
|
|
|
ModuleList.append((Module, Package))
|
|
|
|
## FileUnderPath
|
|
# Check whether FileName started with directory specified by CheckPath
|
|
#
|
|
# @param FileName: the FileName need to be checked
|
|
# @param CheckPath: the path need to be checked against
|
|
# @return: True or False
|
|
#
|
|
def FileUnderPath(FileName, CheckPath):
|
|
FileName = FileName.replace('\\', '/')
|
|
FileName = os.path.normpath(FileName)
|
|
CheckPath = CheckPath.replace('\\', '/')
|
|
CheckPath = os.path.normpath(CheckPath)
|
|
if FileName.startswith(CheckPath):
|
|
RemainingPath = os.path.normpath(FileName.replace(CheckPath, '', 1))
|
|
while RemainingPath.startswith('\\') or RemainingPath.startswith('/'):
|
|
RemainingPath = RemainingPath[1:]
|
|
if FileName == os.path.normpath(os.path.join(CheckPath, RemainingPath)):
|
|
return True
|
|
|
|
return False
|
|
|
|
## InstallFile
|
|
# Extract File from Zipfile, set file attribute, and return the Md5Sum
|
|
#
|
|
# @return: True or False
|
|
#
|
|
def InstallFile(ContentZipFile, FromFile, ToFile, ReadOnly, Executable=False):
|
|
if os.path.exists(os.path.normpath(ToFile)):
|
|
pass
|
|
else:
|
|
if not ContentZipFile or not ContentZipFile.UnpackFile(FromFile, ToFile):
|
|
Logger.Error("UPT", FILE_NOT_FOUND, ST.ERR_INSTALL_FILE_FROM_EMPTY_CONTENT % FromFile)
|
|
|
|
if ReadOnly:
|
|
if not Executable:
|
|
chmod(ToFile, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
|
|
else:
|
|
chmod(ToFile, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
|
|
elif Executable:
|
|
chmod(ToFile, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IWUSR | stat.S_IWGRP |
|
|
stat.S_IWOTH | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
|
|
else:
|
|
chmod(ToFile, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH)
|
|
|
|
Md5Signature = md5(__FileHookOpen__(str(ToFile), 'rb').read())
|
|
Md5Sum = Md5Signature.hexdigest()
|
|
|
|
return Md5Sum
|
|
|
|
## InstallPackageContent method
|
|
#
|
|
# @param FromPath: FromPath
|
|
# @param ToPath: ToPath
|
|
# @param Package: Package
|
|
# @param ContentZipFile: ContentZipFile
|
|
# @param Dep: Dep
|
|
# @param WorkspaceDir: WorkspaceDir
|
|
# @param ModuleList: ModuleList
|
|
#
|
|
def InstallPackageContent(FromPath, ToPath, Package, ContentZipFile, Dep,
|
|
WorkspaceDir, ModuleList, ReadOnly = False):
|
|
if Dep:
|
|
pass
|
|
Package.FileList = []
|
|
|
|
if ToPath.startswith("\\") or ToPath.startswith("/"):
|
|
ToPath = ToPath[1:]
|
|
|
|
if not IsValidInstallPath(ToPath):
|
|
Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%ToPath)
|
|
|
|
if FromPath.startswith("\\") or FromPath.startswith("/"):
|
|
FromPath = FromPath[1:]
|
|
|
|
if not IsValidInstallPath(FromPath):
|
|
Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%FromPath)
|
|
|
|
PackageFullPath = os.path.normpath(os.path.join(WorkspaceDir, ToPath))
|
|
for MiscFile in Package.GetMiscFileList():
|
|
for Item in MiscFile.GetFileList():
|
|
FileName = Item.GetURI()
|
|
if FileName.startswith("\\") or FileName.startswith("/"):
|
|
FileName = FileName[1:]
|
|
|
|
if not IsValidInstallPath(FileName):
|
|
Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%FileName)
|
|
|
|
FromFile = os.path.join(FromPath, FileName)
|
|
Executable = Item.GetExecutable()
|
|
ToFile = (os.path.join(PackageFullPath, ConvertPath(FileName)))
|
|
Md5Sum = InstallFile(ContentZipFile, FromFile, ToFile, ReadOnly, Executable)
|
|
if (ToFile, Md5Sum) not in Package.FileList:
|
|
Package.FileList.append((ToFile, Md5Sum))
|
|
PackageIncludeArchList = []
|
|
for Item in Package.GetPackageIncludeFileList():
|
|
FileName = Item.GetFilePath()
|
|
if FileName.startswith("\\") or FileName.startswith("/"):
|
|
FileName = FileName[1:]
|
|
|
|
if not IsValidInstallPath(FileName):
|
|
Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%FileName)
|
|
|
|
FromFile = os.path.join(FromPath, FileName)
|
|
ToFile = os.path.normpath(os.path.join(PackageFullPath, ConvertPath(FileName)))
|
|
RetFile = ContentZipFile.UnpackFile(FromFile, ToFile)
|
|
if RetFile == '':
|
|
#
|
|
# a non-exist path in Zipfile will return '', which means an include directory in our case
|
|
# save the information for later DEC creation usage and also create the directory
|
|
#
|
|
PackageIncludeArchList.append([Item.GetFilePath(), Item.GetSupArchList()])
|
|
CreateDirectory(ToFile)
|
|
continue
|
|
if ReadOnly:
|
|
chmod(ToFile, stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH)
|
|
else:
|
|
chmod(ToFile, stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH|stat.S_IWUSR|stat.S_IWGRP|stat.S_IWOTH)
|
|
Md5Signature = md5(__FileHookOpen__(str(ToFile), 'rb').read())
|
|
Md5Sum = Md5Signature.hexdigest()
|
|
if (ToFile, Md5Sum) not in Package.FileList:
|
|
Package.FileList.append((ToFile, Md5Sum))
|
|
Package.SetIncludeArchList(PackageIncludeArchList)
|
|
|
|
for Item in Package.GetStandardIncludeFileList():
|
|
FileName = Item.GetFilePath()
|
|
if FileName.startswith("\\") or FileName.startswith("/"):
|
|
FileName = FileName[1:]
|
|
|
|
if not IsValidInstallPath(FileName):
|
|
Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%FileName)
|
|
|
|
FromFile = os.path.join(FromPath, FileName)
|
|
ToFile = os.path.normpath(os.path.join(PackageFullPath, ConvertPath(FileName)))
|
|
Md5Sum = InstallFile(ContentZipFile, FromFile, ToFile, ReadOnly)
|
|
if (ToFile, Md5Sum) not in Package.FileList:
|
|
Package.FileList.append((ToFile, Md5Sum))
|
|
|
|
#
|
|
# Update package
|
|
#
|
|
Package.SetPackagePath(Package.GetPackagePath().replace(FromPath,
|
|
ToPath, 1))
|
|
Package.SetFullPath(os.path.normpath(os.path.join(PackageFullPath,
|
|
ConvertPath(Package.GetName()) + '.dec')))
|
|
|
|
#
|
|
# Install files in module
|
|
#
|
|
Module = None
|
|
ModuleDict = Package.GetModuleDict()
|
|
for ModuleGuid, ModuleVersion, ModuleName, ModulePath in ModuleDict:
|
|
Module = ModuleDict[ModuleGuid, ModuleVersion, ModuleName, ModulePath]
|
|
InstallModuleContent(FromPath, ToPath, ModulePath, Module,
|
|
ContentZipFile, WorkspaceDir, ModuleList, Package, ReadOnly)
|
|
|
|
## GetDPFile method
|
|
#
|
|
# @param ZipFile: A ZipFile
|
|
#
|
|
def GetDPFile(ZipFile):
|
|
ContentFile = ''
|
|
DescFile = ''
|
|
for FileName in ZipFile.namelist():
|
|
if FileName.endswith('.content'):
|
|
if not ContentFile:
|
|
ContentFile = FileName
|
|
continue
|
|
elif FileName.endswith('.pkg'):
|
|
if not DescFile:
|
|
DescFile = FileName
|
|
continue
|
|
else:
|
|
continue
|
|
|
|
Logger.Error("PackagingTool", FILE_TYPE_MISMATCH,
|
|
ExtraData=ST.ERR_DIST_FILE_TOOMANY)
|
|
if not DescFile or not ContentFile:
|
|
Logger.Error("PackagingTool", FILE_UNKNOWN_ERROR,
|
|
ExtraData=ST.ERR_DIST_FILE_TOOFEW)
|
|
return DescFile, ContentFile
|
|
|
|
## InstallDp method
|
|
#
|
|
# Install the distribution to current workspace
|
|
#
|
|
def InstallDp(DistPkg, DpPkgFileName, ContentZipFile, Options, Dep, WorkspaceDir, DataBase):
|
|
#
|
|
# PackageList, ModuleList record the information for the meta-data
|
|
# files that need to be generated later
|
|
#
|
|
PackageList = []
|
|
ModuleList = []
|
|
DistPkg.PackageSurfaceArea = GetPackageList(DistPkg, Dep, WorkspaceDir, Options,
|
|
ContentZipFile, ModuleList, PackageList)
|
|
|
|
DistPkg.ModuleSurfaceArea = GetModuleList(DistPkg, Dep, WorkspaceDir, ContentZipFile, ModuleList)
|
|
|
|
GenToolMisc(DistPkg, WorkspaceDir, ContentZipFile)
|
|
|
|
#
|
|
# copy "Distribution File" to directory $(WORKSPACE)/conf/upt
|
|
#
|
|
DistFileName = os.path.split(DpPkgFileName)[1]
|
|
NewDpPkgFileName = BackupDist(DpPkgFileName, DistPkg.Header.GetGuid(), DistPkg.Header.GetVersion(), WorkspaceDir)
|
|
|
|
#
|
|
# update database
|
|
#
|
|
Logger.Quiet(ST.MSG_UPDATE_PACKAGE_DATABASE)
|
|
DataBase.AddDPObject(DistPkg, NewDpPkgFileName, DistFileName,
|
|
DistPkg.Header.RePackage)
|
|
|