]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/PackagingTool/InstallPkg.py
Sync EDKII BaseTools to BaseTools project r1971
[mirror_edk2.git] / BaseTools / Source / Python / PackagingTool / InstallPkg.py
1 ## @file
2 # Install distribution package.
3 #
4 # Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
9 #
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 #
13
14 ##
15 # Import Modules
16 #
17 import os
18 import sys
19 import glob
20 import shutil
21 import traceback
22 import platform
23 from optparse import OptionParser
24
25 import Common.EdkLogger as EdkLogger
26 from Common.BuildToolError import *
27 from Common.Misc import *
28 from Common.XmlParser import *
29 from Common.InfClassObjectLight import Inf
30 from Common.DecClassObjectLight import Dec
31
32 from PackageFile import *
33 from IpiDb import *
34 from DependencyRules import *
35 import md5
36
37 # Version and Copyright
38 VersionNumber = "0.1"
39 __version__ = "%prog Version " + VersionNumber
40 __copyright__ = "Copyright (c) 2008, Intel Corporation All rights reserved."
41
42 ## Check environment variables
43 #
44 # Check environment variables that must be set for build. Currently they are
45 #
46 # WORKSPACE The directory all packages/platforms start from
47 # EDK_TOOLS_PATH The directory contains all tools needed by the build
48 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
49 #
50 # If any of above environment variable is not set or has error, the build
51 # will be broken.
52 #
53 def CheckEnvVariable():
54 # check WORKSPACE
55 if "WORKSPACE" not in os.environ:
56 EdkLogger.error("InstallPkg", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
57 ExtraData="WORKSPACE")
58
59 WorkspaceDir = os.path.normpath(os.environ["WORKSPACE"])
60 if not os.path.exists(WorkspaceDir):
61 EdkLogger.error("InstallPkg", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData="%s" % WorkspaceDir)
62 elif ' ' in WorkspaceDir:
63 EdkLogger.error("InstallPkg", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",
64 ExtraData=WorkspaceDir)
65 os.environ["WORKSPACE"] = WorkspaceDir
66
67 ## Parse command line options
68 #
69 # Using standard Python module optparse to parse command line option of this tool.
70 #
71 # @retval Opt A optparse.Values object containing the parsed options
72 # @retval Args Target of build command
73 #
74 def MyOptionParser():
75 UsageString = "%prog -i <distribution_package> [-t] [-f] [-q | -v] [-h]"
76
77 Parser = OptionParser(description=__copyright__,version=__version__,prog="InstallPkg",usage=UsageString)
78
79 Parser.add_option("-?", action="help", help="show this help message and exit")
80
81 Parser.add_option("-i", "--distribution-package", action="store", type="string", dest="PackageFile",
82 help="The distribution package to be installed")
83
84 Parser.add_option("-t", "--install-tools", action="store_true", type=None, dest="Tools",
85 help="Specify it to install tools or ignore the tools of the distribution package.")
86
87 Parser.add_option("-f", "--misc-files", action="store_true", type=None, dest="MiscFiles",
88 help="Specify it to install misc file or ignore the misc files of the distribution package.")
89
90 Parser.add_option("-q", "--quiet", action="store_const", dest="LogLevel", const=EdkLogger.QUIET,
91 help="Disable all messages except FATAL ERRORS.")
92
93 Parser.add_option("-v", "--verbose", action="store_const", dest="LogLevel", const=EdkLogger.VERBOSE,
94 help="Turn on verbose output")
95
96 Parser.add_option("-d", "--debug", action="store", type="int", dest="LogLevel",
97 help="Enable debug messages at specified level.")
98
99 Parser.set_defaults(LogLevel=EdkLogger.INFO)
100
101 (Opt, Args)=Parser.parse_args()
102
103 return Opt
104
105 def InstallNewPackage(WorkspaceDir, Path):
106 FullPath = os.path.normpath(os.path.join(WorkspaceDir, Path))
107 if os.path.exists(FullPath):
108 print "Directory [%s] already exists, please select another location, press [Enter] with no input to quit:" %Path
109 Input = sys.stdin.readline()
110 Input = Input.replace('\r', '').replace('\n', '')
111 if Input == '':
112 EdkLogger.error("InstallPkg", UNKNOWN_ERROR, "User interrupt")
113 Input = Input.replace('\r', '').replace('\n', '')
114 return InstallNewPackage(WorkspaceDir, Input)
115 else:
116 return Path
117
118 def InstallNewFile(WorkspaceDir, File):
119 FullPath = os.path.normpath(os.path.join(WorkspaceDir, File))
120 if os.path.exists(FullPath):
121 print "File [%s] already exists, please select another path, press [Enter] with no input to quit:" %File
122 Input = sys.stdin.readline()
123 Input = Input.replace('\r', '').replace('\n', '')
124 if Input == '':
125 EdkLogger.error("InstallPkg", UNKNOWN_ERROR, "User interrupt")
126 Input = Input.replace('\r', '').replace('\n', '')
127 return InstallNewFile(WorkspaceDir, Input)
128 else:
129 return File
130
131 ## Tool entrance method
132 #
133 # This method mainly dispatch specific methods per the command line options.
134 # If no error found, return zero value so the caller of this tool can know
135 # if it's executed successfully or not.
136 #
137 # @retval 0 Tool was successful
138 # @retval 1 Tool failed
139 #
140 def Main():
141 EdkLogger.Initialize()
142 Options = None
143 DistFileName = 'dist.pkg'
144 ContentFileName = 'content.zip'
145 DistFile, ContentZipFile, UnpackDir = None, None, None
146
147 Options = MyOptionParser()
148 try:
149 if Options.LogLevel < EdkLogger.DEBUG_9:
150 EdkLogger.SetLevel(Options.LogLevel + 1)
151 else:
152 EdkLogger.SetLevel(Options.LogLevel)
153
154 CheckEnvVariable()
155 WorkspaceDir = os.environ["WORKSPACE"]
156 if not Options.PackageFile:
157 EdkLogger.error("InstallPkg", OPTION_NOT_SUPPORTED, ExtraData="Must specify one distribution package")
158
159 # unzip dist.pkg file
160 EdkLogger.quiet("Unzipping and parsing distribution package XML file ... ")
161 DistFile = PackageFile(Options.PackageFile)
162 UnpackDir = os.path.normpath(os.path.join(WorkspaceDir, ".tmp"))
163 DistPkgFile = DistFile.UnpackFile(DistFileName, os.path.normpath(os.path.join(UnpackDir, DistFileName)))
164 if not DistPkgFile:
165 EdkLogger.error("InstallPkg", FILE_NOT_FOUND, "File [%s] is broken in distribution package" %DistFileName)
166
167 # Generate distpkg
168 DistPkgObj = DistributionPackageXml()
169 DistPkg = DistPkgObj.FromXml(DistPkgFile)
170
171 # prepare check dependency
172 Db = IpiDatabase(os.path.normpath(os.path.join(WorkspaceDir, "Conf/DistributionPackageDatabase.db")))
173 Db.InitDatabase()
174 Dep = DependencyRules(Db)
175
176 # Check distribution package exist
177 if Dep.CheckDpExists(DistPkg.Header.Guid, DistPkg.Header.Version):
178 EdkLogger.error("InstallPkg", UNKNOWN_ERROR, "This distribution package has been installed", ExtraData=DistPkg.Header.Name)
179
180 # unzip contents.zip file
181 ContentFile = DistFile.UnpackFile(ContentFileName, os.path.normpath(os.path.join(UnpackDir, ContentFileName)))
182 ContentZipFile = PackageFile(ContentFile)
183 if not ContentFile:
184 EdkLogger.error("InstallPkg", FILE_NOT_FOUND, "File [%s] is broken in distribution package" %ContentFileName)
185
186 # verify MD5 signature
187 Md5Sigature = md5.new(open(ContentFile).read())
188 if DistPkg.Header.Signature != Md5Sigature.hexdigest():
189 EdkLogger.error("InstallPkg", FILE_CHECKSUM_FAILURE, ExtraData=ContentFile)
190
191 # Check package exist and install
192 for Guid,Version,Path in DistPkg.PackageSurfaceArea:
193 PackagePath = os.path.dirname(Path)
194 NewPackagePath = PackagePath
195 Package = DistPkg.PackageSurfaceArea[Guid,Version,Path]
196 EdkLogger.info("Installing package ... %s" % Package.PackageHeader.Name)
197 if Dep.CheckPackageExists(Guid, Version):
198 EdkLogger.quiet("Package [%s] has been installed" %Path)
199 NewPackagePath = InstallNewPackage(WorkspaceDir, PackagePath)
200 Package.FileList = []
201 for Item in Package.MiscFiles.Files:
202 FromFile = os.path.join(PackagePath, Item.Filename)
203 ToFile = os.path.normpath(os.path.join(WorkspaceDir, NewPackagePath, Item.Filename))
204 ContentZipFile.UnpackFile(FromFile, ToFile)
205 Package.FileList.append(ToFile)
206
207 # Update package
208 Package.PackageHeader.CombinePath = Package.PackageHeader.CombinePath.replace(PackagePath, NewPackagePath, 1)
209 # Update modules of package
210 Module = None
211 for ModuleGuid, ModuleVersion, ModulePath in Package.Modules:
212 Module = Package.Modules[ModuleGuid, ModuleVersion, ModulePath]
213 NewModulePath = ModulePath.replace(PackagePath, NewPackagePath, 1)
214 del Package.Modules[ModuleGuid, ModuleVersion, ModulePath]
215 Package.Modules[ModuleGuid, ModuleVersion, NewModulePath] = Module
216 del DistPkg.PackageSurfaceArea[Guid,Version,Path]
217 DistPkg.PackageSurfaceArea[Guid,Version,Package.PackageHeader.CombinePath] = Package
218
219 # SaveFileOnChange(os.path.join(Options.InstallDir, ModulePath, Module.Header.Name, ".inf"), Inf.ModuleToInf(Module), False)
220 # EdkLogger.info("Installing package ... %s" % Package.Header.Name)
221 # shutil.copytree(os.path.join(ContentFileDir, Path), Options.InstallDir)
222 # SaveFileOnChange(os.path.join(Options.InstallDir, Path, Package.Header.Name, ".dec"), Dec.PackageToDec(Package), False)
223
224 # Check module exist and install
225 Module = None
226 for Guid,Version,Path in DistPkg.ModuleSurfaceArea:
227 ModulePath = os.path.dirname(Path)
228 NewModulePath = ModulePath
229 Module = DistPkg.ModuleSurfaceArea[Guid,Version,Path]
230 EdkLogger.info("Installing module ... %s" % Module.ModuleHeader.Name)
231 if Dep.CheckModuleExists(Guid, Version):
232 EdkLogger.quiet("Module [%s] has been installed" %Path)
233 NewModulePath = InstallNewPackage(WorkspaceDir, ModulePath)
234 Module.FileList = []
235 for Item in Module.MiscFiles.Files:
236 ModulePath = ModulePath[os.path.normpath(ModulePath).rfind(os.path.normpath('/'))+1:]
237 FromFile = os.path.join(ModulePath, Item.Filename)
238 ToFile = os.path.normpath(os.path.join(WorkspaceDir, NewModulePath, Item.Filename))
239 ContentZipFile.UnpackFile(FromFile, ToFile)
240 Module.FileList.append(ToFile)
241
242 # EdkLogger.info("Installing module ... %s" % Module.Header.Name)
243 # shutil.copytree(os.path.join(ContentFileDir, Path), Options.InstallDir)
244 # SaveFileOnChange(os.path.join(Options.InstallDir, Path, Module.Header.Name, ".inf"), Inf.ModuleToInf(Module), False)
245
246 # Update module
247 Module.ModuleHeader.CombinePath = Module.ModuleHeader.CombinePath.replace(os.path.dirname(Path), NewModulePath, 1)
248 del DistPkg.ModuleSurfaceArea[Guid,Version,Path]
249 DistPkg.ModuleSurfaceArea[Guid,Version,Module.ModuleHeader.CombinePath] = Module
250 #
251 #
252 # for Guid,Version,Path in DistPkg.PackageSurfaceArea:
253 # print Guid,Version,Path
254 # for item in DistPkg.PackageSurfaceArea[Guid,Version,Path].FileList:
255 # print item
256 # for Guid,Version,Path in DistPkg.ModuleSurfaceArea:
257 # print Guid,Version,Path
258 # for item in DistPkg.ModuleSurfaceArea[Guid,Version,Path].FileList:
259 # print item
260
261 if Options.Tools:
262 EdkLogger.info("Installing tools ... ")
263 for File in DistPkg.Tools.Files:
264 FromFile = File.Filename
265 ToFile = InstallNewFile(WorkspaceDir, FromFile)
266 ContentZipFile.UnpackFile(FromFile, ToFile)
267 if Options.MiscFiles:
268 EdkLogger.info("Installing misc files ... ")
269 for File in DistPkg.MiscellaneousFiles.Files:
270 FromFile = File.Filename
271 ToFile = InstallNewFile(WorkspaceDir, FromFile)
272 ContentZipFile.UnpackFile(FromFile, ToFile)
273
274 # update database
275 EdkLogger.quiet("Update Distribution Package Database ...")
276 Db.AddDPObject(DistPkg)
277
278 except FatalError, X:
279 if Options and Options.LogLevel < EdkLogger.DEBUG_9:
280 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
281 ReturnCode = X.args[0]
282 except KeyboardInterrupt:
283 ReturnCode = ABORT_ERROR
284 if Options and Options.LogLevel < EdkLogger.DEBUG_9:
285 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
286 except:
287 EdkLogger.error(
288 "\nInstallPkg",
289 CODE_ERROR,
290 "Unknown fatal error when installing [%s]" % Options.PackageFile,
291 ExtraData="\n(Please send email to edk2-buildtools-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n",
292 RaiseError=False
293 )
294 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
295 ReturnCode = CODE_ERROR
296 finally:
297 EdkLogger.quiet("Removing temp files ... ")
298 if DistFile:
299 DistFile.Close()
300 if ContentZipFile:
301 ContentZipFile.Close()
302 if UnpackDir:
303 shutil.rmtree(UnpackDir)
304
305 EdkLogger.quiet("DONE")
306 Progressor.Abort()
307
308 if __name__ == '__main__':
309 sys.exit(Main())