1## @file
2# Install distribution package.
3#
4# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
5#
6# This program and the accompanying materials are licensed and made available
7# under the terms and conditions of the BSD License which accompanies this
8# distribution. The full text of the license may be found at
9# http://opensource.org/licenses/bsd-license.php
10#
11# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13#
14"""
15Install a distribution package
16"""
17##
18# Import Modules
19#
20from Core.FileHook import __FileHookOpen__
21import os.path
22from os import chmod
23from os import SEEK_SET
24from os import SEEK_END
25import stat
26import md5
27import copy
28from sys import stdin
29from sys import platform
30from shutil import rmtree
31from shutil import copyfile
32from traceback import format_exc
33from platform import python_version
34
35from Logger import StringTable as ST
36from Logger.ToolError import UNKNOWN_ERROR
37from Logger.ToolError import FILE_UNKNOWN_ERROR
38from Logger.ToolError import OPTION_MISSING
39from Logger.ToolError import UPT_ALREADY_INSTALLED_ERROR
40from Logger.ToolError import FatalError
41from Logger.ToolError import ABORT_ERROR
42from Logger.ToolError import CODE_ERROR
43from Logger.ToolError import FORMAT_INVALID
44from Logger.ToolError import FILE_TYPE_MISMATCH
45import Logger.Log as Logger
46
47from Library.Misc import Sdict
48from Library.Misc import ConvertPath
49from Library.ParserValidate import IsValidInstallPath
50from Xml.XmlParser import DistributionPackageXml
51from GenMetaFile.GenDecFile import PackageToDec
52from GenMetaFile.GenInfFile import ModuleToInf
53from Core.PackageFile import PackageFile
54from Core.PackageFile import FILE_NOT_FOUND
55from Core.PackageFile import FILE_CHECKSUM_FAILURE
56from Core.PackageFile import CreateDirectory
57from Core.DependencyRules import DependencyRules
58from Library import GlobalData
59
60## InstallNewPackage
61#
62# @param WorkspaceDir:   Workspace Directory
63# @param Path:           Package Path
64# @param CustomPath:     whether need to customize path at first
65#
66def InstallNewPackage(WorkspaceDir, Path, CustomPath = False):
67    if os.path.isabs(Path):
68        Logger.Info(ST.MSG_RELATIVE_PATH_ONLY%Path)
69    elif CustomPath:
70        Logger.Info(ST.MSG_NEW_PKG_PATH)
71    else:
72        Path = ConvertPath(Path)
73        Path = os.path.normpath(Path)
74        FullPath = os.path.normpath(os.path.join(WorkspaceDir, Path))
75        if os.path.exists(FullPath):
76            Logger.Info(ST.ERR_DIR_ALREADY_EXIST%FullPath)
77        else:
78            return Path
79
80    Input = stdin.readline()
81    Input = Input.replace('\r', '').replace('\n', '')
82    if Input == '':
83        Logger.Error("InstallPkg", UNKNOWN_ERROR, ST.ERR_USER_INTERRUPT)
84    Input = Input.replace('\r', '').replace('\n', '')
85    return InstallNewPackage(WorkspaceDir, Input, False)
86
87## InstallNewModule
88#
89# @param WorkspaceDir:   Workspace Directory
90# @param Path:           Standalone Module Path
91# @param PathList:       The already installed standalone module Path list
92#
93def InstallNewModule(WorkspaceDir, Path, PathList = None):
94    if PathList == None:
95        PathList = []
96    Path = ConvertPath(Path)
97    Path = os.path.normpath(Path)
98    FullPath = os.path.normpath(os.path.join(WorkspaceDir, Path))
99    if os.path.exists(FullPath) and FullPath not in PathList:
100        Logger.Info(ST.ERR_DIR_ALREADY_EXIST%Path)
101    elif Path == FullPath:
102        Logger.Info(ST.MSG_RELATIVE_PATH_ONLY%FullPath)
103    else:
104        return Path
105
106    Input = stdin.readline()
107    Input = Input.replace('\r', '').replace('\n', '')
108    if Input == '':
109        Logger.Error("InstallPkg", UNKNOWN_ERROR, ST.ERR_USER_INTERRUPT)
110    Input = Input.replace('\r', '').replace('\n', '')
111    return InstallNewModule(WorkspaceDir, Input, PathList)
112
113
114## InstallNewFile
115#
116# @param WorkspaceDir:   Workspace Direction
117# @param File:      File
118#
119def InstallNewFile(WorkspaceDir, File):
120    FullPath = os.path.normpath(os.path.join(WorkspaceDir, File))
121    if os.path.exists(FullPath):
122        Logger.Info(ST.ERR_FILE_ALREADY_EXIST %File)
123        Input = stdin.readline()
124        Input = Input.replace('\r', '').replace('\n', '')
125        if Input == '':
126            Logger.Error("InstallPkg", UNKNOWN_ERROR, ST.ERR_USER_INTERRUPT)
127        Input = Input.replace('\r', '').replace('\n', '')
128        return InstallNewFile(WorkspaceDir, Input)
129    else:
130        return File
131
132## UnZipDp
133#
134# UnZipDp
135#
136def UnZipDp(WorkspaceDir, DpPkgFileName):
137    ContentZipFile = None
138    Logger.Quiet(ST.MSG_UZIP_PARSE_XML)
139    DistFile = PackageFile(DpPkgFileName)
140
141    DpDescFileName, ContentFileName = GetDPFile(DistFile.GetZipFile())
142
143    GlobalData.gUNPACK_DIR = os.path.normpath(os.path.join(WorkspaceDir, ".tmp"))
144    DistPkgFile = DistFile.UnpackFile(DpDescFileName,
145        os.path.normpath(os.path.join(GlobalData.gUNPACK_DIR, DpDescFileName)))
146    if not DistPkgFile:
147        Logger.Error("InstallPkg", FILE_NOT_FOUND, ST.ERR_FILE_BROKEN %DpDescFileName)
148
149    #
150    # Generate distpkg
151    #
152    DistPkgObj = DistributionPackageXml()
153    DistPkg = DistPkgObj.FromXml(DistPkgFile)
154    if DistPkg.Header.RePackage == '':
155        DistPkg.Header.RePackage = False
156    if DistPkg.Header.ReadOnly == '':
157        DistPkg.Header.ReadOnly = False
158
159    #
160    # unzip contents.zip file
161    #
162    ContentFile = DistFile.UnpackFile(ContentFileName,
163        os.path.normpath(os.path.join(GlobalData.gUNPACK_DIR, ContentFileName)))
164    if not ContentFile:
165        Logger.Error("InstallPkg", FILE_NOT_FOUND,
166            ST.ERR_FILE_BROKEN % ContentFileName)
167
168    FilePointer = __FileHookOpen__(ContentFile, "rb")
169    #
170    # Assume no archive comment.
171    #
172    FilePointer.seek(0, SEEK_SET)
173    FilePointer.seek(0, SEEK_END)
174    #
175    # Get file size
176    #
177    FileSize = FilePointer.tell()
178    FilePointer.close()
179
180    if FileSize != 0:
181        ContentZipFile = PackageFile(ContentFile)
182
183    #
184    # verify MD5 signature when existed
185    #
186    if DistPkg.Header.Signature != '':
187        Md5Sigature = md5.new(__FileHookOpen__(ContentFile, 'rb').read())
188        if DistPkg.Header.Signature != Md5Sigature.hexdigest():
189            ContentZipFile.Close()
190            Logger.Error("InstallPkg", FILE_CHECKSUM_FAILURE,
191                ExtraData=ContentFile)
192
193    return DistPkg, ContentZipFile, DpPkgFileName, DistFile
194
195## GetPackageList
196#
197# GetPackageList
198#
199def GetPackageList(DistPkg, Dep, WorkspaceDir, Options, ContentZipFile, ModuleList, PackageList):
200    NewDict = Sdict()
201    for Guid, Version, Path in DistPkg.PackageSurfaceArea:
202        PackagePath = Path
203        Package = DistPkg.PackageSurfaceArea[Guid, Version, Path]
204        Logger.Info(ST.MSG_INSTALL_PACKAGE % Package.GetName())
205        if Dep.CheckPackageExists(Guid, Version):
206            Logger.Info(ST.WRN_PACKAGE_EXISTED %(Guid, Version))
207        if Options.UseGuidedPkgPath:
208            GuidedPkgPath = "%s_%s_%s" % (Package.GetName(), Guid, Version)
209            NewPackagePath = InstallNewPackage(WorkspaceDir, GuidedPkgPath, Options.CustomPath)
210        else:
211            NewPackagePath = InstallNewPackage(WorkspaceDir, PackagePath, Options.CustomPath)
212        InstallPackageContent(PackagePath, NewPackagePath, Package, ContentZipFile, Dep, WorkspaceDir, ModuleList,
213                              DistPkg.Header.ReadOnly)
214        PackageList.append(Package)
215
216        NewDict[Guid, Version, Package.GetPackagePath()] = Package
217
218    #
219    # Now generate meta-data files, first generate all dec for package
220    # dec should be generated before inf, and inf should be generated after
221    # all packages installed, else hard to resolve modules' package
222    # dependency (Hard to get the location of the newly installed package)
223    #
224    for Package in PackageList:
225        FilePath = PackageToDec(Package, DistPkg.Header)
226        Md5Sigature = md5.new(__FileHookOpen__(str(FilePath), 'rb').read())
227        Md5Sum = Md5Sigature.hexdigest()
228        if (FilePath, Md5Sum) not in Package.FileList:
229            Package.FileList.append((FilePath, Md5Sum))
230
231    return NewDict
232
233## GetModuleList
234#
235# GetModuleList
236#
237def GetModuleList(DistPkg, Dep, WorkspaceDir, ContentZipFile, ModuleList):
238    #
239    # ModulePathList will keep track of the standalone module path that
240    # we just installed. If a new module's path in that list
241    # (only multiple INF in one directory will be so), we will
242    # install them directly. If not, we will try to create a new directory
243    # for it.
244    #
245    ModulePathList = []
246
247    #
248    # Check module exist and install
249    #
250    Module = None
251    NewDict = Sdict()
252    for Guid, Version, Name, Path in DistPkg.ModuleSurfaceArea:
253        ModulePath = Path
254        Module = DistPkg.ModuleSurfaceArea[Guid, Version, Name, Path]
255        Logger.Info(ST.MSG_INSTALL_MODULE % Module.GetName())
256        if Dep.CheckModuleExists(Guid, Version, Name, Path):
257            Logger.Quiet(ST.WRN_MODULE_EXISTED %Path)
258        #
259        # here check for the multiple inf share the same module path cases:
260        # they should be installed into the same directory
261        #
262        ModuleFullPath = \
263        os.path.normpath(os.path.join(WorkspaceDir, ModulePath))
264        if ModuleFullPath not in ModulePathList:
265            NewModulePath = InstallNewModule(WorkspaceDir, ModulePath, ModulePathList)
266            NewModuleFullPath = os.path.normpath(os.path.join(WorkspaceDir, NewModulePath))
267            ModulePathList.append(NewModuleFullPath)
268        else:
269            NewModulePath = ModulePath
270
271        InstallModuleContent(ModulePath, NewModulePath, '', Module, ContentZipFile, WorkspaceDir, ModuleList, None,
272                             DistPkg.Header.ReadOnly)
273        #
274        # Update module
275        #
276        Module.SetModulePath(Module.GetModulePath().replace(Path, NewModulePath, 1))
277
278        NewDict[Guid, Version, Name, Module.GetModulePath()] = Module
279
280    #
281    # generate all inf for modules
282    #
283    for (Module, Package) in ModuleList:
284        CheckCNameInModuleRedefined(Module, DistPkg)
285        FilePath = ModuleToInf(Module, Package, DistPkg.Header)
286        Md5Sigature = md5.new(__FileHookOpen__(str(FilePath), 'rb').read())
287        Md5Sum = Md5Sigature.hexdigest()
288        if Package:
289            if (FilePath, Md5Sum) not in Package.FileList:
290                Package.FileList.append((FilePath, Md5Sum))
291        else:
292            if (FilePath, Md5Sum) not in Module.FileList:
293                Module.FileList.append((FilePath, Md5Sum))
294        #
295        # append the module unicode files to Package FileList
296        #
297        for (FilePath, Md5Sum) in Module.FileList:
298            if str(FilePath).endswith('.uni') and Package and (FilePath, Md5Sum) not in Package.FileList:
299                Package.FileList.append((FilePath, Md5Sum))
300
301    return NewDict
302
303##
304# Get all protocol/ppi/guid CNames and pcd name from all dependent DEC file
305#
306def GetDepProtocolPpiGuidPcdNames(DePackageObjList):
307    #
308    # [[Dec1Protocol1, Dec1Protocol2...], [Dec2Protocols...],...]
309    #
310    DependentProtocolCNames = []
311    DependentPpiCNames = []
312    DependentGuidCNames = []
313    DependentPcdNames = []
314
315    for PackageObj in DePackageObjList:
316        #
317        # Get protocol CName list from all dependent DEC file
318        #
319        ProtocolCNames = []
320        for Protocol in PackageObj.GetProtocolList():
321            if Protocol.GetCName() not in ProtocolCNames:
322                ProtocolCNames.append(Protocol.GetCName())
323
324        DependentProtocolCNames.append(ProtocolCNames)
325
326        #
327        # Get Ppi CName list from all dependent DEC file
328        #
329        PpiCNames = []
330        for Ppi in PackageObj.GetPpiList():
331            if Ppi.GetCName() not in PpiCNames:
332                PpiCNames.append(Ppi.GetCName())
333
334        DependentPpiCNames.append(PpiCNames)
335
336        #
337        # Get Guid CName list from all dependent DEC file
338        #
339        GuidCNames = []
340        for Guid in PackageObj.GetGuidList():
341            if Guid.GetCName() not in GuidCNames:
342                GuidCNames.append(Guid.GetCName())
343
344        DependentGuidCNames.append(GuidCNames)
345
346        #
347        # Get PcdName list from all dependent DEC file
348        #
349        PcdNames = []
350        for Pcd in PackageObj.GetPcdList():
351            PcdName = '.'.join([Pcd.GetTokenSpaceGuidCName(), Pcd.GetCName()])
352            if PcdName not in PcdNames:
353                PcdNames.append(PcdName)
354
355        DependentPcdNames.append(PcdNames)
356
357
358    return DependentProtocolCNames, DependentPpiCNames, DependentGuidCNames, DependentPcdNames
359
360##
361# Check if protocol CName is redefined
362#
363def CheckProtoclCNameRedefined(Module, DependentProtocolCNames):
364    for ProtocolInModule in Module.GetProtocolList():
365        IsCNameDefined = False
366        for PackageProtocolCNames in DependentProtocolCNames:
367            if ProtocolInModule.GetCName() in PackageProtocolCNames:
368                if IsCNameDefined:
369                    Logger.Error("\nUPT", FORMAT_INVALID,
370                                 File = Module.GetFullPath(),
371                                 ExtraData = \
372                                 ST.ERR_INF_PARSER_ITEM_DUPLICATE_IN_DEC % ProtocolInModule.GetCName())
373                else:
374                    IsCNameDefined = True
375
376##
377# Check if Ppi CName is redefined
378#
379def CheckPpiCNameRedefined(Module, DependentPpiCNames):
380    for PpiInModule in Module.GetPpiList():
381        IsCNameDefined = False
382        for PackagePpiCNames in DependentPpiCNames:
383            if PpiInModule.GetCName() in PackagePpiCNames:
384                if IsCNameDefined:
385                    Logger.Error("\nUPT", FORMAT_INVALID,
386                                 File = Module.GetFullPath(),
387                                 ExtraData = ST.ERR_INF_PARSER_ITEM_DUPLICATE_IN_DEC % PpiInModule.GetCName())
388                else:
389                    IsCNameDefined = True
390
391##
392# Check if Guid CName is redefined
393#
394def CheckGuidCNameRedefined(Module, DependentGuidCNames):
395    for GuidInModule in Module.GetGuidList():
396        IsCNameDefined = False
397        for PackageGuidCNames in DependentGuidCNames:
398            if GuidInModule.GetCName() in PackageGuidCNames:
399                if IsCNameDefined:
400                    Logger.Error("\nUPT", FORMAT_INVALID,
401                                 File = Module.GetFullPath(),
402                                 ExtraData = \
403                                 ST.ERR_INF_PARSER_ITEM_DUPLICATE_IN_DEC % GuidInModule.GetCName())
404                else:
405                    IsCNameDefined = True
406
407##
408# Check if PcdName is redefined
409#
410def CheckPcdNameRedefined(Module, DependentPcdNames):
411    PcdObjs = []
412    if not Module.GetBinaryFileList():
413        PcdObjs += Module.GetPcdList()
414    else:
415        Binary = Module.GetBinaryFileList()[0]
416        for AsBuild in Binary.GetAsBuiltList():
417            PcdObjs += AsBuild.GetPatchPcdList() + AsBuild.GetPcdExList()
418
419    for PcdObj in PcdObjs:
420        PcdName = '.'.join([PcdObj.GetTokenSpaceGuidCName(), PcdObj.GetCName()])
421        IsPcdNameDefined = False
422        for PcdNames in DependentPcdNames:
423            if PcdName in PcdNames:
424                if IsPcdNameDefined:
425                    Logger.Error("\nUPT", FORMAT_INVALID,
426                                 File = Module.GetFullPath(),
427                                 ExtraData = ST.ERR_INF_PARSER_ITEM_DUPLICATE_IN_DEC % PcdName)
428                else:
429                    IsPcdNameDefined = True
430
431##
432# Check if any Protocol/Ppi/Guid and Pcd name is redefined in its dependent DEC files
433#
434def CheckCNameInModuleRedefined(Module, DistPkg):
435    DePackageObjList = []
436    #
437    # Get all dependent package objects
438    #
439    for Obj in Module.GetPackageDependencyList():
440        Guid = Obj.GetGuid()
441        Version = Obj.GetVersion()
442        for Key in DistPkg.PackageSurfaceArea:
443            if Key[0] == Guid and Key[1] == Version:
444                if DistPkg.PackageSurfaceArea[Key] not in DePackageObjList:
445                    DePackageObjList.append(DistPkg.PackageSurfaceArea[Key])
446
447    DependentProtocolCNames, DependentPpiCNames, DependentGuidCNames, DependentPcdNames = \
448    GetDepProtocolPpiGuidPcdNames(DePackageObjList)
449
450    CheckProtoclCNameRedefined(Module, DependentProtocolCNames)
451    CheckPpiCNameRedefined(Module, DependentPpiCNames)
452    CheckGuidCNameRedefined(Module, DependentGuidCNames)
453    CheckPcdNameRedefined(Module, DependentPcdNames)
454
455## GenToolMisc
456#
457# GenToolMisc
458#
459#
460def GenToolMisc(DistPkg, WorkspaceDir, ContentZipFile):
461    ToolObject = DistPkg.Tools
462    MiscObject = DistPkg.MiscellaneousFiles
463    DistPkg.FileList = []
464    FileList = []
465    ToolFileNum = 0
466    FileNum = 0
467    RootDir = WorkspaceDir
468
469    #
470    # FileList stores both tools files and misc files
471    # Misc file list must be appended to FileList *AFTER* Tools file list
472    #
473    if ToolObject:
474        FileList += ToolObject.GetFileList()
475        ToolFileNum = len(ToolObject.GetFileList())
476        if 'EDK_TOOLS_PATH' in os.environ:
477            RootDir = os.environ['EDK_TOOLS_PATH']
478    if MiscObject:
479        FileList += MiscObject.GetFileList()
480    for FileObject in FileList:
481        FileNum += 1
482        if FileNum > ToolFileNum:
483            #
484            # Misc files, root should be changed to WORKSPACE
485            #
486            RootDir = WorkspaceDir
487        File = ConvertPath(FileObject.GetURI())
488        ToFile = os.path.normpath(os.path.join(RootDir, File))
489        if os.path.exists(ToFile):
490            Logger.Info( ST.WRN_FILE_EXISTED % ToFile )
491            #
492            # ask for user input the new file name
493            #
494            Logger.Info( ST.MSG_NEW_FILE_NAME)
495            Input = stdin.readline()
496            Input = Input.replace('\r', '').replace('\n', '')
497            OrigPath = os.path.split(ToFile)[0]
498            ToFile = os.path.normpath(os.path.join(OrigPath, Input))
499        FromFile = os.path.join(FileObject.GetURI())
500        Md5Sum = InstallFile(ContentZipFile, FromFile, ToFile, DistPkg.Header.ReadOnly, FileObject.GetExecutable())
501        DistPkg.FileList.append((ToFile, Md5Sum))
502
503## Tool entrance method
504#
505# This method mainly dispatch specific methods per the command line options.
506# If no error found, return zero value so the caller of this tool can know
507# if it's executed successfully or not.
508#
509# @param  Options: command Options
510#
511def Main(Options = None):
512    ContentZipFile, DistFile = None, None
513
514    try:
515        DataBase = GlobalData.gDB
516        WorkspaceDir = GlobalData.gWORKSPACE
517        if not Options.PackageFile:
518            Logger.Error("InstallPkg", OPTION_MISSING, ExtraData=ST.ERR_SPECIFY_PACKAGE)
519
520        #
521        # unzip dist.pkg file
522        #
523        DistPkg, ContentZipFile, DpPkgFileName, DistFile = UnZipDp(WorkspaceDir, Options.PackageFile)
524
525        #
526        # check dependency
527        #
528        Dep = DependencyRules(DataBase)
529        CheckInstallDpx(Dep, DistPkg)
530
531        #
532        # Install distribution
533        #
534        InstallDp(DistPkg, DpPkgFileName, ContentZipFile, Options, Dep, WorkspaceDir, DataBase)
535        ReturnCode = 0
536
537    except FatalError, XExcept:
538        ReturnCode = XExcept.args[0]
539        if Logger.GetLevel() <= Logger.DEBUG_9:
540            Logger.Quiet(ST.MSG_PYTHON_ON % (python_version(), platform) + format_exc())
541
542    except KeyboardInterrupt:
543        ReturnCode = ABORT_ERROR
544        if Logger.GetLevel() <= Logger.DEBUG_9:
545            Logger.Quiet(ST.MSG_PYTHON_ON % (python_version(), platform) + format_exc())
546
547    except:
548        ReturnCode = CODE_ERROR
549        Logger.Error(
550                    "\nInstallPkg",
551                    CODE_ERROR,
552                    ST.ERR_UNKNOWN_FATAL_INSTALL_ERR % Options.PackageFile,
553                    ExtraData=ST.MSG_SEARCH_FOR_HELP,
554                    RaiseError=False
555                    )
556        Logger.Quiet(ST.MSG_PYTHON_ON % (python_version(),
557            platform) + format_exc())
558    finally:
559        if ReturnCode != UPT_ALREADY_INSTALLED_ERROR:
560            Logger.Quiet(ST.MSG_REMOVE_TEMP_FILE_STARTED)
561            if DistFile:
562                DistFile.Close()
563            if ContentZipFile:
564                ContentZipFile.Close()
565            if GlobalData.gUNPACK_DIR:
566                rmtree(GlobalData.gUNPACK_DIR)
567                GlobalData.gUNPACK_DIR = None
568            Logger.Quiet(ST.MSG_REMOVE_TEMP_FILE_DONE)
569    if ReturnCode == 0:
570        Logger.Quiet(ST.MSG_FINISH)
571    return ReturnCode
572
573# BackupDist method
574#
575# This method will backup the Distribution file into the $(WORKSPACE)/conf/upt, and rename it
576# if there is already a same-named distribution existed.
577#
578# @param DpPkgFileName: The distribution path
579# @param Guid:          The distribution Guid
580# @param Version:       The distribution Version
581# @param WorkspaceDir:  The workspace directory
582# @retval NewDpPkgFileName: The exact backup file name
583#
584def BackupDist(DpPkgFileName, Guid, Version, WorkspaceDir):
585    DistFileName = os.path.split(DpPkgFileName)[1]
586    DestDir = os.path.normpath(os.path.join(WorkspaceDir, GlobalData.gUPT_DIR))
587    CreateDirectory(DestDir)
588    DestFile = os.path.normpath(os.path.join(DestDir, DistFileName))
589    if os.path.exists(DestFile):
590        FileName, Ext = os.path.splitext(DistFileName)
591        NewFileName = FileName + '_' + Guid + '_' + Version + Ext
592        DestFile = os.path.normpath(os.path.join(DestDir, NewFileName))
593        if os.path.exists(DestFile):
594            #
595            # ask for user input the new file name
596            #
597            Logger.Info( ST.MSG_NEW_FILE_NAME_FOR_DIST)
598            Input = stdin.readline()
599            Input = Input.replace('\r', '').replace('\n', '')
600            DestFile = os.path.normpath(os.path.join(DestDir, Input))
601    copyfile(DpPkgFileName, DestFile)
602    NewDpPkgFileName = DestFile[DestFile.find(DestDir) + len(DestDir) + 1:]
603    return NewDpPkgFileName
604
605## CheckInstallDpx method
606#
607#  check whether distribution could be installed
608#
609#   @param  Dep: the DependencyRules instance that used to check dependency
610#   @param  DistPkg: the distribution object
611#
612def CheckInstallDpx(Dep, DistPkg):
613    #
614    # Check distribution package installed or not
615    #
616    if Dep.CheckDpExists(DistPkg.Header.GetGuid(),
617        DistPkg.Header.GetVersion()):
618        Logger.Error("InstallPkg", UPT_ALREADY_INSTALLED_ERROR,
619            ST.WRN_DIST_PKG_INSTALLED)
620    #
621    # Check distribution dependency (all module dependency should be
622    # satisfied)
623    #
624    if not Dep.CheckInstallDpDepexSatisfied(DistPkg):
625        Logger.Error("InstallPkg", UNKNOWN_ERROR,
626            ST.ERR_PACKAGE_NOT_MATCH_DEPENDENCY,
627            ExtraData=DistPkg.Header.Name)
628
629## InstallModuleContent method
630#
631# If this is standalone module, then Package should be none,
632# ModulePath should be ''
633#   @param  FromPath: FromPath
634#   @param  NewPath: NewPath
635#   @param  ModulePath: ModulePath
636#   @param  Module: Module
637#   @param  ContentZipFile: ContentZipFile
638#   @param  WorkspaceDir: WorkspaceDir
639#   @param  ModuleList: ModuleList
640#   @param  Package: Package
641#
642def InstallModuleContent(FromPath, NewPath, ModulePath, Module, ContentZipFile,
643    WorkspaceDir, ModuleList, Package = None, ReadOnly = False):
644
645    if NewPath.startswith("\\") or NewPath.startswith("/"):
646        NewPath = NewPath[1:]
647
648    if not IsValidInstallPath(NewPath):
649        Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%NewPath)
650
651    NewModuleFullPath = os.path.normpath(os.path.join(WorkspaceDir, NewPath,
652        ConvertPath(ModulePath)))
653    Module.SetFullPath(os.path.normpath(os.path.join(NewModuleFullPath,
654        ConvertPath(Module.GetName()) + '.inf')))
655    Module.FileList = []
656
657    for MiscFile in Module.GetMiscFileList():
658        if not MiscFile:
659            continue
660        for Item in MiscFile.GetFileList():
661            File = Item.GetURI()
662            if File.startswith("\\") or File.startswith("/"):
663                File = File[1:]
664
665            if not IsValidInstallPath(File):
666                Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%File)
667
668            FromFile = os.path.join(FromPath, ModulePath, File)
669            Executable = Item.GetExecutable()
670            ToFile = os.path.normpath(os.path.join(NewModuleFullPath, ConvertPath(File)))
671            Md5Sum = InstallFile(ContentZipFile, FromFile, ToFile, ReadOnly, Executable)
672            if Package and ((ToFile, Md5Sum) not in Package.FileList):
673                Package.FileList.append((ToFile, Md5Sum))
674            elif Package:
675                continue
676            elif (ToFile, Md5Sum) not in Module.FileList:
677                Module.FileList.append((ToFile, Md5Sum))
678    for Item in Module.GetSourceFileList():
679        File = Item.GetSourceFile()
680        if File.startswith("\\") or File.startswith("/"):
681            File = File[1:]
682
683        if not IsValidInstallPath(File):
684            Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%File)
685
686        FromFile = os.path.join(FromPath, ModulePath, File)
687        ToFile = os.path.normpath(os.path.join(NewModuleFullPath, ConvertPath(File)))
688        Md5Sum = InstallFile(ContentZipFile, FromFile, ToFile, ReadOnly)
689        if Package and ((ToFile, Md5Sum) not in Package.FileList):
690            Package.FileList.append((ToFile, Md5Sum))
691        elif Package:
692            continue
693        elif (ToFile, Md5Sum) not in Module.FileList:
694            Module.FileList.append((ToFile, Md5Sum))
695    for Item in Module.GetBinaryFileList():
696        FileNameList = Item.GetFileNameList()
697        for FileName in FileNameList:
698            File = FileName.GetFilename()
699            if File.startswith("\\") or File.startswith("/"):
700                File = File[1:]
701
702            if not IsValidInstallPath(File):
703                Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%File)
704
705            FromFile = os.path.join(FromPath, ModulePath, File)
706            ToFile = os.path.normpath(os.path.join(NewModuleFullPath, ConvertPath(File)))
707            Md5Sum = InstallFile(ContentZipFile, FromFile, ToFile, ReadOnly)
708            if Package and ((ToFile, Md5Sum) not in Package.FileList):
709                Package.FileList.append((ToFile, Md5Sum))
710            elif Package:
711                continue
712            elif (ToFile, Md5Sum) not in Module.FileList:
713                Module.FileList.append((ToFile, Md5Sum))
714
715    InstallModuleContentZipFile(ContentZipFile, FromPath, ModulePath, WorkspaceDir, NewPath, Module, Package, ReadOnly,
716                                ModuleList)
717
718## InstallModuleContentZipFile
719#
720# InstallModuleContentZipFile
721#
722def InstallModuleContentZipFile(ContentZipFile, FromPath, ModulePath, WorkspaceDir, NewPath, Module, Package, ReadOnly,
723                                ModuleList):
724    #
725    # Extract other files under current module path in content Zip file but not listed in the description
726    #
727    if ContentZipFile:
728        for FileName in ContentZipFile.GetZipFile().namelist():
729            FileName = os.path.normpath(FileName)
730            CheckPath = os.path.normpath(os.path.join(FromPath, ModulePath))
731            if FileUnderPath(FileName, CheckPath):
732                if FileName.startswith("\\") or FileName.startswith("/"):
733                    FileName = FileName[1:]
734
735                if not IsValidInstallPath(FileName):
736                    Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%FileName)
737
738                FromFile = FileName
739                ToFile = os.path.normpath(os.path.join(WorkspaceDir,
740                        ConvertPath(FileName.replace(FromPath, NewPath, 1))))
741                CheckList = copy.copy(Module.FileList)
742                if Package:
743                    CheckList += Package.FileList
744                for Item in CheckList:
745                    if Item[0] == ToFile:
746                        break
747                else:
748                    Md5Sum = InstallFile(ContentZipFile, FromFile, ToFile, ReadOnly)
749                    if Package and ((ToFile, Md5Sum) not in Package.FileList):
750                        Package.FileList.append((ToFile, Md5Sum))
751                    elif Package:
752                        continue
753                    elif (ToFile, Md5Sum) not in Module.FileList:
754                        Module.FileList.append((ToFile, Md5Sum))
755
756    ModuleList.append((Module, Package))
757
758## FileUnderPath
759#  Check whether FileName started with directory specified by CheckPath
760#
761# @param FileName: the FileName need to be checked
762# @param CheckPath: the path need to be checked against
763# @return:  True or False
764#
765def FileUnderPath(FileName, CheckPath):
766    FileName = FileName.replace('\\', '/')
767    FileName = os.path.normpath(FileName)
768    CheckPath = CheckPath.replace('\\', '/')
769    CheckPath = os.path.normpath(CheckPath)
770    if FileName.startswith(CheckPath):
771        RemainingPath = os.path.normpath(FileName.replace(CheckPath, '', 1))
772        while RemainingPath.startswith('\\') or RemainingPath.startswith('/'):
773            RemainingPath = RemainingPath[1:]
774        if FileName == os.path.normpath(os.path.join(CheckPath, RemainingPath)):
775            return True
776
777    return False
778
779## InstallFile
780#  Extract File from Zipfile, set file attribute, and return the Md5Sum
781#
782# @return:  True or False
783#
784def InstallFile(ContentZipFile, FromFile, ToFile, ReadOnly, Executable=False):
785    if os.path.exists(os.path.normpath(ToFile)):
786        pass
787    else:
788        if not ContentZipFile or not ContentZipFile.UnpackFile(FromFile, ToFile):
789            Logger.Error("UPT", FILE_NOT_FOUND, ST.ERR_INSTALL_FILE_FROM_EMPTY_CONTENT % FromFile)
790
791        if ReadOnly:
792            if not Executable:
793                chmod(ToFile, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
794            else:
795                chmod(ToFile, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
796        elif Executable:
797            chmod(ToFile, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IWUSR | stat.S_IWGRP |
798                  stat.S_IWOTH | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
799        else:
800            chmod(ToFile, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH)
801
802    Md5Sigature = md5.new(__FileHookOpen__(str(ToFile), 'rb').read())
803    Md5Sum = Md5Sigature.hexdigest()
804
805    return Md5Sum
806
807## InstallPackageContent method
808#
809#   @param  FromPath: FromPath
810#   @param  ToPath: ToPath
811#   @param  Package: Package
812#   @param  ContentZipFile: ContentZipFile
813#   @param  Dep: Dep
814#   @param  WorkspaceDir: WorkspaceDir
815#   @param  ModuleList: ModuleList
816#
817def InstallPackageContent(FromPath, ToPath, Package, ContentZipFile, Dep,
818    WorkspaceDir, ModuleList, ReadOnly = False):
819    if Dep:
820        pass
821    Package.FileList = []
822
823    if ToPath.startswith("\\") or ToPath.startswith("/"):
824        ToPath = ToPath[1:]
825
826    if not IsValidInstallPath(ToPath):
827        Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%ToPath)
828
829    if FromPath.startswith("\\") or FromPath.startswith("/"):
830        FromPath = FromPath[1:]
831
832    if not IsValidInstallPath(FromPath):
833        Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%FromPath)
834
835    PackageFullPath = os.path.normpath(os.path.join(WorkspaceDir, ToPath))
836    for MiscFile in Package.GetMiscFileList():
837        for Item in MiscFile.GetFileList():
838            FileName = Item.GetURI()
839            if FileName.startswith("\\") or FileName.startswith("/"):
840                FileName = FileName[1:]
841
842            if not IsValidInstallPath(FileName):
843                Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%FileName)
844
845            FromFile = os.path.join(FromPath, FileName)
846            Executable = Item.GetExecutable()
847            ToFile =  (os.path.join(PackageFullPath, ConvertPath(FileName)))
848            Md5Sum = InstallFile(ContentZipFile, FromFile, ToFile, ReadOnly, Executable)
849            if (ToFile, Md5Sum) not in Package.FileList:
850                Package.FileList.append((ToFile, Md5Sum))
851    PackageIncludeArchList = []
852    for Item in Package.GetPackageIncludeFileList():
853        FileName = Item.GetFilePath()
854        if FileName.startswith("\\") or FileName.startswith("/"):
855            FileName = FileName[1:]
856
857        if not IsValidInstallPath(FileName):
858            Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%FileName)
859
860        FromFile = os.path.join(FromPath, FileName)
861        ToFile = os.path.normpath(os.path.join(PackageFullPath, ConvertPath(FileName)))
862        RetFile = ContentZipFile.UnpackFile(FromFile, ToFile)
863        if RetFile == '':
864            #
865            # a non-exist path in Zipfile will return '', which means an include directory in our case
866            # save the information for later DEC creation usage and also create the directory
867            #
868            PackageIncludeArchList.append([Item.GetFilePath(), Item.GetSupArchList()])
869            CreateDirectory(ToFile)
870            continue
871        if ReadOnly:
872            chmod(ToFile, stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH)
873        else:
874            chmod(ToFile, stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH|stat.S_IWUSR|stat.S_IWGRP|stat.S_IWOTH)
875        Md5Sigature = md5.new(__FileHookOpen__(str(ToFile), 'rb').read())
876        Md5Sum = Md5Sigature.hexdigest()
877        if (ToFile, Md5Sum) not in Package.FileList:
878            Package.FileList.append((ToFile, Md5Sum))
879    Package.SetIncludeArchList(PackageIncludeArchList)
880
881    for Item in Package.GetStandardIncludeFileList():
882        FileName = Item.GetFilePath()
883        if FileName.startswith("\\") or FileName.startswith("/"):
884            FileName = FileName[1:]
885
886        if not IsValidInstallPath(FileName):
887            Logger.Error("UPT", FORMAT_INVALID, ST.ERR_FILE_NAME_INVALIDE%FileName)
888
889        FromFile = os.path.join(FromPath, FileName)
890        ToFile = os.path.normpath(os.path.join(PackageFullPath, ConvertPath(FileName)))
891        Md5Sum = InstallFile(ContentZipFile, FromFile, ToFile, ReadOnly)
892        if (ToFile, Md5Sum) not in Package.FileList:
893            Package.FileList.append((ToFile, Md5Sum))
894
895    #
896    # Update package
897    #
898    Package.SetPackagePath(Package.GetPackagePath().replace(FromPath,
899        ToPath, 1))
900    Package.SetFullPath(os.path.normpath(os.path.join(PackageFullPath,
901        ConvertPath(Package.GetName()) + '.dec')))
902
903    #
904    # Install files in module
905    #
906    Module = None
907    ModuleDict = Package.GetModuleDict()
908    for ModuleGuid, ModuleVersion, ModuleName, ModulePath in ModuleDict:
909        Module = ModuleDict[ModuleGuid, ModuleVersion, ModuleName, ModulePath]
910        InstallModuleContent(FromPath, ToPath, ModulePath, Module,
911            ContentZipFile, WorkspaceDir, ModuleList, Package, ReadOnly)
912
913## GetDPFile method
914#
915#   @param  ZipFile: A ZipFile
916#
917def GetDPFile(ZipFile):
918    ContentFile = ''
919    DescFile = ''
920    for FileName in ZipFile.namelist():
921        if FileName.endswith('.content'):
922            if not ContentFile:
923                ContentFile = FileName
924                continue
925        elif FileName.endswith('.pkg'):
926            if not DescFile:
927                DescFile = FileName
928                continue
929        else:
930            continue
931
932        Logger.Error("PackagingTool", FILE_TYPE_MISMATCH,
933            ExtraData=ST.ERR_DIST_FILE_TOOMANY)
934    if not DescFile or not ContentFile:
935        Logger.Error("PackagingTool", FILE_UNKNOWN_ERROR,
936            ExtraData=ST.ERR_DIST_FILE_TOOFEW)
937    return DescFile, ContentFile
938
939## InstallDp method
940#
941#   Install the distribution to current workspace
942#
943def InstallDp(DistPkg, DpPkgFileName, ContentZipFile, Options, Dep, WorkspaceDir, DataBase):
944    #
945    # PackageList, ModuleList record the information for the meta-data
946    # files that need to be generated later
947    #
948    PackageList = []
949    ModuleList = []
950    DistPkg.PackageSurfaceArea = GetPackageList(DistPkg, Dep, WorkspaceDir, Options,
951                                                ContentZipFile, ModuleList, PackageList)
952
953    DistPkg.ModuleSurfaceArea = GetModuleList(DistPkg, Dep, WorkspaceDir, ContentZipFile, ModuleList)
954
955    GenToolMisc(DistPkg, WorkspaceDir, ContentZipFile)
956
957    #
958    # copy "Distribution File" to directory $(WORKSPACE)/conf/upt
959    #
960    DistFileName = os.path.split(DpPkgFileName)[1]
961    NewDpPkgFileName = BackupDist(DpPkgFileName, DistPkg.Header.GetGuid(), DistPkg.Header.GetVersion(), WorkspaceDir)
962
963    #
964    # update database
965    #
966    Logger.Quiet(ST.MSG_UPDATE_PACKAGE_DATABASE)
967    DataBase.AddDPObject(DistPkg, NewDpPkgFileName, DistFileName,
968                   DistPkg.Header.RePackage)
969
970