| ## @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 glob | |
| import shutil | |
| 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 Common.InfClassObjectLight import Inf | |
| from Common.DecClassObjectLight import Dec | |
| from PackageFile import * | |
| from IpiDb import * | |
| from DependencyRules import * | |
| import md5 | |
| # 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/<sys> 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("InstallPkg", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found", | |
| ExtraData="WORKSPACE") | |
| WorkspaceDir = os.path.normpath(os.environ["WORKSPACE"]) | |
| if not os.path.exists(WorkspaceDir): | |
| EdkLogger.error("InstallPkg", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData="%s" % WorkspaceDir) | |
| elif ' ' in WorkspaceDir: | |
| EdkLogger.error("InstallPkg", 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 -i <distribution_package> [-t] [-f] [-q | -v] [-h]" | |
| Parser = OptionParser(description=__copyright__,version=__version__,prog="InstallPkg",usage=UsageString) | |
| Parser.add_option("-?", action="help", help="show this help message and exit") | |
| Parser.add_option("-i", "--distribution-package", action="store", type="string", dest="PackageFile", | |
| help="The distribution package to be installed") | |
| Parser.add_option("-t", "--install-tools", action="store_true", type=None, dest="Tools", | |
| help="Specify it to install tools or ignore the tools of the distribution package.") | |
| Parser.add_option("-f", "--misc-files", action="store_true", type=None, dest="MiscFiles", | |
| help="Specify it to install misc file or ignore the misc files of the distribution package.") | |
| 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 | |
| def InstallNewPackage(WorkspaceDir, Path): | |
| FullPath = os.path.normpath(os.path.join(WorkspaceDir, Path)) | |
| if os.path.exists(FullPath): | |
| print "Directory [%s] already exists, please select another location, press [Enter] with no input to quit:" %Path | |
| Input = sys.stdin.readline() | |
| Input = Input.replace('\r', '').replace('\n', '') | |
| if Input == '': | |
| EdkLogger.error("InstallPkg", UNKNOWN_ERROR, "User interrupt") | |
| Input = Input.replace('\r', '').replace('\n', '') | |
| return InstallNewPackage(WorkspaceDir, Input) | |
| else: | |
| return Path | |
| def InstallNewFile(WorkspaceDir, File): | |
| FullPath = os.path.normpath(os.path.join(WorkspaceDir, File)) | |
| if os.path.exists(FullPath): | |
| print "File [%s] already exists, please select another path, press [Enter] with no input to quit:" %File | |
| Input = sys.stdin.readline() | |
| Input = Input.replace('\r', '').replace('\n', '') | |
| if Input == '': | |
| EdkLogger.error("InstallPkg", UNKNOWN_ERROR, "User interrupt") | |
| Input = Input.replace('\r', '').replace('\n', '') | |
| return InstallNewFile(WorkspaceDir, Input) | |
| else: | |
| return File | |
| ## 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 = None | |
| DistFileName = 'dist.pkg' | |
| ContentFileName = 'content.zip' | |
| DistFile, ContentZipFile, UnpackDir = None, None, None | |
| Options = MyOptionParser() | |
| try: | |
| if Options.LogLevel < EdkLogger.DEBUG_9: | |
| EdkLogger.SetLevel(Options.LogLevel + 1) | |
| else: | |
| EdkLogger.SetLevel(Options.LogLevel) | |
| CheckEnvVariable() | |
| WorkspaceDir = os.environ["WORKSPACE"] | |
| if not Options.PackageFile: | |
| EdkLogger.error("InstallPkg", OPTION_NOT_SUPPORTED, ExtraData="Must specify one distribution package") | |
| # unzip dist.pkg file | |
| EdkLogger.quiet("Unzipping and parsing distribution package XML file ... ") | |
| DistFile = PackageFile(Options.PackageFile) | |
| UnpackDir = os.path.normpath(os.path.join(WorkspaceDir, ".tmp")) | |
| DistPkgFile = DistFile.UnpackFile(DistFileName, os.path.normpath(os.path.join(UnpackDir, DistFileName))) | |
| if not DistPkgFile: | |
| EdkLogger.error("InstallPkg", FILE_NOT_FOUND, "File [%s] is broken in distribution package" %DistFileName) | |
| # Generate distpkg | |
| DistPkgObj = DistributionPackageXml() | |
| DistPkg = DistPkgObj.FromXml(DistPkgFile) | |
| # prepare check dependency | |
| Db = IpiDatabase(os.path.normpath(os.path.join(WorkspaceDir, "Conf/DistributionPackageDatabase.db"))) | |
| Db.InitDatabase() | |
| Dep = DependencyRules(Db) | |
| # Check distribution package exist | |
| if Dep.CheckDpExists(DistPkg.Header.Guid, DistPkg.Header.Version): | |
| EdkLogger.error("InstallPkg", UNKNOWN_ERROR, "This distribution package has been installed", ExtraData=DistPkg.Header.Name) | |
| # unzip contents.zip file | |
| ContentFile = DistFile.UnpackFile(ContentFileName, os.path.normpath(os.path.join(UnpackDir, ContentFileName))) | |
| ContentZipFile = PackageFile(ContentFile) | |
| if not ContentFile: | |
| EdkLogger.error("InstallPkg", FILE_NOT_FOUND, "File [%s] is broken in distribution package" %ContentFileName) | |
| # verify MD5 signature | |
| Md5Sigature = md5.new(open(ContentFile).read()) | |
| if DistPkg.Header.Signature != Md5Sigature.hexdigest(): | |
| EdkLogger.error("InstallPkg", FILE_CHECKSUM_FAILURE, ExtraData=ContentFile) | |
| # Check package exist and install | |
| for Guid,Version,Path in DistPkg.PackageSurfaceArea: | |
| PackagePath = os.path.dirname(Path) | |
| NewPackagePath = PackagePath | |
| Package = DistPkg.PackageSurfaceArea[Guid,Version,Path] | |
| EdkLogger.info("Installing package ... %s" % Package.PackageHeader.Name) | |
| if Dep.CheckPackageExists(Guid, Version): | |
| EdkLogger.quiet("Package [%s] has been installed" %Path) | |
| NewPackagePath = InstallNewPackage(WorkspaceDir, PackagePath) | |
| Package.FileList = [] | |
| for Item in Package.MiscFiles.Files: | |
| FromFile = os.path.join(PackagePath, Item.Filename) | |
| ToFile = os.path.normpath(os.path.join(WorkspaceDir, NewPackagePath, Item.Filename)) | |
| ContentZipFile.UnpackFile(FromFile, ToFile) | |
| Package.FileList.append(ToFile) | |
| # Update package | |
| Package.PackageHeader.CombinePath = Package.PackageHeader.CombinePath.replace(PackagePath, NewPackagePath, 1) | |
| # Update modules of package | |
| Module = None | |
| for ModuleGuid, ModuleVersion, ModulePath in Package.Modules: | |
| Module = Package.Modules[ModuleGuid, ModuleVersion, ModulePath] | |
| NewModulePath = ModulePath.replace(PackagePath, NewPackagePath, 1) | |
| del Package.Modules[ModuleGuid, ModuleVersion, ModulePath] | |
| Package.Modules[ModuleGuid, ModuleVersion, NewModulePath] = Module | |
| del DistPkg.PackageSurfaceArea[Guid,Version,Path] | |
| DistPkg.PackageSurfaceArea[Guid,Version,Package.PackageHeader.CombinePath] = Package | |
| # SaveFileOnChange(os.path.join(Options.InstallDir, ModulePath, Module.Header.Name, ".inf"), Inf.ModuleToInf(Module), False) | |
| # EdkLogger.info("Installing package ... %s" % Package.Header.Name) | |
| # shutil.copytree(os.path.join(ContentFileDir, Path), Options.InstallDir) | |
| # SaveFileOnChange(os.path.join(Options.InstallDir, Path, Package.Header.Name, ".dec"), Dec.PackageToDec(Package), False) | |
| # Check module exist and install | |
| Module = None | |
| for Guid,Version,Path in DistPkg.ModuleSurfaceArea: | |
| ModulePath = os.path.dirname(Path) | |
| NewModulePath = ModulePath | |
| Module = DistPkg.ModuleSurfaceArea[Guid,Version,Path] | |
| EdkLogger.info("Installing module ... %s" % Module.ModuleHeader.Name) | |
| if Dep.CheckModuleExists(Guid, Version): | |
| EdkLogger.quiet("Module [%s] has been installed" %Path) | |
| NewModulePath = InstallNewPackage(WorkspaceDir, ModulePath) | |
| Module.FileList = [] | |
| for Item in Module.MiscFiles.Files: | |
| ModulePath = ModulePath[os.path.normpath(ModulePath).rfind(os.path.normpath('/'))+1:] | |
| FromFile = os.path.join(ModulePath, Item.Filename) | |
| ToFile = os.path.normpath(os.path.join(WorkspaceDir, NewModulePath, Item.Filename)) | |
| ContentZipFile.UnpackFile(FromFile, ToFile) | |
| Module.FileList.append(ToFile) | |
| # EdkLogger.info("Installing module ... %s" % Module.Header.Name) | |
| # shutil.copytree(os.path.join(ContentFileDir, Path), Options.InstallDir) | |
| # SaveFileOnChange(os.path.join(Options.InstallDir, Path, Module.Header.Name, ".inf"), Inf.ModuleToInf(Module), False) | |
| # Update module | |
| Module.ModuleHeader.CombinePath = Module.ModuleHeader.CombinePath.replace(os.path.dirname(Path), NewModulePath, 1) | |
| del DistPkg.ModuleSurfaceArea[Guid,Version,Path] | |
| DistPkg.ModuleSurfaceArea[Guid,Version,Module.ModuleHeader.CombinePath] = Module | |
| # | |
| # | |
| # for Guid,Version,Path in DistPkg.PackageSurfaceArea: | |
| # print Guid,Version,Path | |
| # for item in DistPkg.PackageSurfaceArea[Guid,Version,Path].FileList: | |
| # print item | |
| # for Guid,Version,Path in DistPkg.ModuleSurfaceArea: | |
| # print Guid,Version,Path | |
| # for item in DistPkg.ModuleSurfaceArea[Guid,Version,Path].FileList: | |
| # print item | |
| if Options.Tools: | |
| EdkLogger.info("Installing tools ... ") | |
| for File in DistPkg.Tools.Files: | |
| FromFile = File.Filename | |
| ToFile = InstallNewFile(WorkspaceDir, FromFile) | |
| ContentZipFile.UnpackFile(FromFile, ToFile) | |
| if Options.MiscFiles: | |
| EdkLogger.info("Installing misc files ... ") | |
| for File in DistPkg.MiscellaneousFiles.Files: | |
| FromFile = File.Filename | |
| ToFile = InstallNewFile(WorkspaceDir, FromFile) | |
| ContentZipFile.UnpackFile(FromFile, ToFile) | |
| # update database | |
| EdkLogger.quiet("Update Distribution Package Database ...") | |
| Db.AddDPObject(DistPkg) | |
| 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( | |
| "\nInstallPkg", | |
| CODE_ERROR, | |
| "Unknown fatal error when installing [%s]" % Options.PackageFile, | |
| ExtraData="\n(Please send email to dev@buildtools.tianocore.org 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: | |
| EdkLogger.quiet("Removing temp files ... ") | |
| if DistFile: | |
| DistFile.Close() | |
| if ContentZipFile: | |
| ContentZipFile.Close() | |
| if UnpackDir: | |
| shutil.rmtree(UnpackDir) | |
| EdkLogger.quiet("DONE") | |
| Progressor.Abort() | |
| if __name__ == '__main__': | |
| sys.exit(Main()) |