1## @file
2# Install distribution package.
3#
4# Copyright (c) 2011 - 2014, 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
15'''
16MkPkg
17'''
18
19##
20# Import Modules
21#
22from os import remove
23from os import getcwd
24from os import chdir
25import os.path
26from sys import stdin
27from sys import platform
28from traceback import format_exc
29from platform import python_version
30import md5
31from time import strftime
32from time import localtime
33from uuid import uuid4
34
35from Logger import StringTable as ST
36from Logger.ToolError import OPTION_UNKNOWN_ERROR
37from Logger.ToolError import OPTION_VALUE_INVALID
38from Logger.ToolError import ABORT_ERROR
39from Logger.ToolError import UPT_REPKG_ERROR
40from Logger.ToolError import CODE_ERROR
41from Logger.ToolError import FatalError
42from Logger.ToolError import FILE_NOT_FOUND
43import Logger.Log as Logger
44
45from Xml.XmlParser import DistributionPackageXml
46from Xml.IniToXml import IniToXml
47
48from Library import GlobalData
49from Library.ParserValidate import IsValidPath
50
51from Core.DistributionPackageClass import DistributionPackageClass
52from Core.PackageFile import PackageFile
53from Common.MultipleWorkspace import MultipleWorkspace as mws
54
55## CheckForExistingDp
56#
57# Check if there is a same name DP file existing
58# @param Path: The path to be checked
59#
60def CheckForExistingDp(Path):
61    if os.path.exists(Path):
62        Logger.Info(ST.MSG_DISTRIBUTION_PACKAGE_FILE_EXISTS % Path)
63        Input = stdin.readline()
64        Input = Input.replace('\r', '').replace('\n', '')
65        if Input.upper() != "Y":
66            Logger.Error("\nMkPkg", ABORT_ERROR, ST.ERR_USER_ABORT, RaiseError=True)
67
68## Tool entrance method
69#
70# This method mainly dispatch specific methods per the command line options.
71# If no error found, return zero value so the caller of this tool can know
72# if it's executed successfully or not.
73#
74#
75def Main(Options = None):
76    if Options == None:
77        Logger.Error("\nMkPkg", OPTION_UNKNOWN_ERROR, ST.ERR_OPTION_NOT_FOUND)
78    try:
79        DataBase = GlobalData.gDB
80        ContentFileClosed = True
81        WorkspaceDir = GlobalData.gWORKSPACE
82
83        #
84        # Init PackFileToCreate
85        #
86        if not Options.PackFileToCreate:
87            Logger.Error("\nMkPkg", OPTION_UNKNOWN_ERROR, ST.ERR_OPTION_NOT_FOUND)
88
89        #
90        # Handle if the distribution package file already exists
91        #
92        CheckForExistingDp(Options.PackFileToCreate)
93
94        #
95        # Check package file existing and valid
96        #
97        CheckFileList('.DEC', Options.PackageFileList, ST.ERR_INVALID_PACKAGE_NAME, ST.ERR_INVALID_PACKAGE_PATH)
98        #
99        # Check module file existing and valid
100        #
101        CheckFileList('.INF', Options.ModuleFileList, ST.ERR_INVALID_MODULE_NAME, ST.ERR_INVALID_MODULE_PATH)
102
103        #
104        # Get list of files that installed with RePackage attribute available
105        #
106        RePkgDict = DataBase.GetRePkgDict()
107
108        ContentFile = PackageFile(GlobalData.gCONTENT_FILE, "w")
109        ContentFileClosed = False
110
111        #
112        # Add temp distribution header
113        #
114        if Options.PackageInformationDataFile:
115            XmlFile = IniToXml(Options.PackageInformationDataFile)
116            DistPkg = DistributionPackageXml().FromXml(XmlFile)
117            remove(XmlFile)
118
119            #
120            # add distribution level tool/misc files
121            # before pack, current dir should be workspace dir, else the full
122            # path will be in the pack file
123            #
124            Cwd = getcwd()
125            chdir(WorkspaceDir)
126            ToolObject = DistPkg.Tools
127            MiscObject = DistPkg.MiscellaneousFiles
128            FileList = []
129            if ToolObject:
130                FileList += ToolObject.GetFileList()
131            if MiscObject:
132                FileList += MiscObject.GetFileList()
133            for FileObject in FileList:
134                #
135                # If you have unicode file names, please convert them to byte
136                # strings in your desired encoding before passing them to
137                # write().
138                #
139                FromFile = os.path.normpath(FileObject.GetURI()).encode('utf_8')
140                FileFullPath = mws.join(WorkspaceDir, FromFile)
141                if FileFullPath in RePkgDict:
142                    (DpGuid, DpVersion, DpName, Repackage) = RePkgDict[FileFullPath]
143                    if not Repackage:
144                        Logger.Error("\nMkPkg",
145                                     UPT_REPKG_ERROR,
146                                     ST.ERR_UPT_REPKG_ERROR,
147                                     ExtraData=ST.MSG_REPKG_CONFLICT %\
148                                     (FileFullPath, DpGuid, DpVersion, DpName)
149                                     )
150                    else:
151                        DistPkg.Header.RePackage = True
152                ContentFile.PackFile(FromFile)
153            chdir(Cwd)
154
155        #
156        # Add init dp information
157        #
158        else:
159            DistPkg = DistributionPackageClass()
160            DistPkg.Header.Name = 'Distribution Package'
161            DistPkg.Header.Guid = str(uuid4())
162            DistPkg.Header.Version = '1.0'
163
164        DistPkg.GetDistributionPackage(WorkspaceDir, Options.PackageFileList, \
165                                       Options.ModuleFileList)
166        FileList, MetaDataFileList = DistPkg.GetDistributionFileList()
167        for File in FileList + MetaDataFileList:
168            FileFullPath = os.path.normpath(os.path.join(WorkspaceDir, File))
169            #
170            # check whether file was included in a distribution that can not
171            # be repackaged
172            #
173            if FileFullPath in RePkgDict:
174                (DpGuid, DpVersion, DpName, Repackage) = RePkgDict[FileFullPath]
175                if not Repackage:
176                    Logger.Error("\nMkPkg",
177                                 UPT_REPKG_ERROR,
178                                 ST.ERR_UPT_REPKG_ERROR,
179                                 ExtraData = \
180                                 ST.MSG_REPKG_CONFLICT %(FileFullPath, DpName, \
181                                                         DpGuid, DpVersion)
182                                 )
183                else:
184                    DistPkg.Header.RePackage = True
185
186        Cwd = getcwd()
187        chdir(WorkspaceDir)
188        ContentFile.PackFiles(FileList)
189        chdir(Cwd)
190
191        Logger.Verbose(ST.MSG_COMPRESS_DISTRIBUTION_PKG)
192
193        ContentFile.Close()
194        ContentFileClosed = True
195
196        #
197        # Add Md5Sigature
198        #
199        DistPkg.Header.Signature = md5.new(open(str(ContentFile), 'rb').read()).hexdigest()
200        #
201        # Add current Date
202        #
203        DistPkg.Header.Date = str(strftime("%Y-%m-%dT%H:%M:%S", localtime()))
204
205        #
206        # Finish final dp file
207        #
208        DistPkgFile = PackageFile(Options.PackFileToCreate, "w")
209        DistPkgFile.PackFile(str(ContentFile))
210        DistPkgXml = DistributionPackageXml()
211        DistPkgFile.PackData(DistPkgXml.ToXml(DistPkg), GlobalData.gDESC_FILE)
212        DistPkgFile.Close()
213        Logger.Quiet(ST.MSG_FINISH)
214        ReturnCode = 0
215
216    except FatalError, XExcept:
217        ReturnCode = XExcept.args[0]
218        if Logger.GetLevel() <= Logger.DEBUG_9:
219            Logger.Quiet(ST.MSG_PYTHON_ON % \
220                         (python_version(), platform) + format_exc())
221    except KeyboardInterrupt:
222        ReturnCode = ABORT_ERROR
223        if Logger.GetLevel() <= Logger.DEBUG_9:
224            Logger.Quiet(ST.MSG_PYTHON_ON % \
225                         (python_version(), platform) + format_exc())
226    except OSError:
227        pass
228    except:
229        Logger.Error(
230                    "\nMkPkg",
231                    CODE_ERROR,
232                    ST.ERR_UNKNOWN_FATAL_CREATING_ERR % \
233                    Options.PackFileToCreate,
234                    ExtraData=ST.MSG_SEARCH_FOR_HELP,
235                    RaiseError=False
236                    )
237        Logger.Quiet(ST.MSG_PYTHON_ON % \
238                     (python_version(), platform) + format_exc())
239        ReturnCode = CODE_ERROR
240    finally:
241        if os.path.exists(GlobalData.gCONTENT_FILE):
242            if not ContentFileClosed:
243                ContentFile.Close()
244            os.remove(GlobalData.gCONTENT_FILE)
245
246    return ReturnCode
247
248
249## CheckFileList
250#
251# @param QualifiedExt:             QualifiedExt
252# @param FileList:                 FileList
253# @param ErrorStringExt:           ErrorStringExt
254# @param ErrorStringFullPath:      ErrorStringFullPath
255#
256def CheckFileList(QualifiedExt, FileList, ErrorStringExt, ErrorStringFullPath):
257    if not FileList:
258        return
259    WorkspaceDir = GlobalData.gWORKSPACE
260    WorkspaceDir = os.path.normpath(WorkspaceDir)
261    for Item in FileList:
262        Ext = os.path.splitext(Item)[1]
263        if Ext.upper() != QualifiedExt.upper():
264            Logger.Error("\nMkPkg", OPTION_VALUE_INVALID, \
265                         ErrorStringExt % Item)
266
267        Item = os.path.normpath(Item)
268        Path = mws.join(WorkspaceDir, Item)
269        if not os.path.exists(Path):
270            Logger.Error("\nMkPkg", FILE_NOT_FOUND, ST.ERR_NOT_FOUND % Item)
271        elif Item == Path:
272            Logger.Error("\nMkPkg", OPTION_VALUE_INVALID,
273                         ErrorStringFullPath % Item)
274        elif not IsValidPath(Item, WorkspaceDir):
275            Logger.Error("\nMkPkg", OPTION_VALUE_INVALID, \
276                         ErrorStringExt % Item)
277
278        if not os.path.split(Item)[0]:
279            Logger.Error("\nMkPkg", OPTION_VALUE_INVALID, \
280                         ST.ERR_INVALID_METAFILE_PATH % Item)
281