1## @file
2#
3# This file is the main entry for UPT
4#
5# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
6#
7# This program and the accompanying materials are licensed and made available
8# under the terms and conditions of the BSD License which accompanies this
9# distribution. The full text of the license may be found at
10# http://opensource.org/licenses/bsd-license.php
11#
12# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14#
15
16'''
17UPT
18'''
19
20## import modules
21#
22from Core import FileHook
23import sys
24import os.path
25from sys import platform
26import platform as pf
27from optparse import OptionParser
28from traceback import format_exc
29from platform import python_version
30
31from Logger import StringTable as ST
32import Logger.Log as Logger
33from Logger.StringTable import MSG_VERSION
34from Logger.StringTable import MSG_DESCRIPTION
35from Logger.StringTable import MSG_USAGE
36from Logger.ToolError import FILE_NOT_FOUND
37from Logger.ToolError import OPTION_MISSING
38from Logger.ToolError import FILE_TYPE_MISMATCH
39from Logger.ToolError import OPTION_CONFLICT
40from Logger.ToolError import FatalError
41from Logger.ToolError import UPT_ALREADY_INSTALLED_ERROR
42from Common.MultipleWorkspace import MultipleWorkspace as mws
43
44import MkPkg
45import InstallPkg
46import RmPkg
47import InventoryWs
48import ReplacePkg
49from Library.Misc import GetWorkspace
50from Library import GlobalData
51from Core.IpiDb import IpiDatabase
52from BuildVersion import gBUILD_VERSION
53
54## CheckConflictOption
55#
56# CheckConflictOption
57#
58def CheckConflictOption(Opt):
59    if (Opt.PackFileToCreate or Opt.PackFileToInstall or Opt.PackFileToRemove or Opt.PackFileToReplace) \
60    and Opt.InventoryWs:
61        Logger.Error("UPT", OPTION_CONFLICT, ExtraData=ST.ERR_L_OA_EXCLUSIVE)
62    elif Opt.PackFileToReplace and (Opt.PackFileToCreate or Opt.PackFileToInstall or Opt.PackFileToRemove):
63        Logger.Error("UPT", OPTION_CONFLICT, ExtraData=ST.ERR_U_ICR_EXCLUSIVE)
64    elif (Opt.PackFileToCreate and Opt.PackFileToInstall and Opt.PackFileToRemove):
65        Logger.Error("UPT", OPTION_CONFLICT, ExtraData=ST.ERR_REQUIRE_I_C_R_OPTION)
66    elif Opt.PackFileToCreate and Opt.PackFileToInstall:
67        Logger.Error("UPT", OPTION_CONFLICT, ExtraData=ST.ERR_I_C_EXCLUSIVE)
68    elif Opt.PackFileToInstall and Opt.PackFileToRemove:
69        Logger.Error("UPT", OPTION_CONFLICT, ExtraData=ST.ERR_I_R_EXCLUSIVE)
70    elif Opt.PackFileToCreate and  Opt.PackFileToRemove:
71        Logger.Error("UPT", OPTION_CONFLICT, ExtraData=ST.ERR_C_R_EXCLUSIVE)
72
73    if Opt.CustomPath and Opt.UseGuidedPkgPath:
74        Logger.Warn("UPT", ST.WARN_CUSTOMPATH_OVERRIDE_USEGUIDEDPATH)
75        Opt.UseGuidedPkgPath = False
76
77## SetLogLevel
78#
79def SetLogLevel(Opt):
80    if Opt.opt_verbose:
81        Logger.SetLevel(Logger.VERBOSE)
82    elif Opt.opt_quiet:
83        Logger.SetLevel(Logger.QUIET + 1)
84    elif Opt.debug_level != None:
85        if Opt.debug_level < 0 or Opt.debug_level > 9:
86            Logger.Warn("UPT", ST.ERR_DEBUG_LEVEL)
87            Logger.SetLevel(Logger.INFO)
88        else:
89            Logger.SetLevel(Opt.debug_level + 1)
90    elif Opt.opt_slient:
91        Logger.SetLevel(Logger.SILENT)
92    else:
93        Logger.SetLevel(Logger.INFO)
94
95## Main
96#
97# Main
98#
99def Main():
100    Logger.Initialize()
101
102    Parser = OptionParser(version=(MSG_VERSION + ' ' + gBUILD_VERSION), description=MSG_DESCRIPTION,
103                          prog="UPT.exe", usage=MSG_USAGE)
104
105    Parser.add_option("-d", "--debug", action="store", type="int", dest="debug_level", help=ST.HLP_PRINT_DEBUG_INFO)
106
107    Parser.add_option("-v", "--verbose", action="store_true", dest="opt_verbose",
108                      help=ST.HLP_PRINT_INFORMATIONAL_STATEMENT)
109
110    Parser.add_option("-s", "--silent", action="store_true", dest="opt_slient", help=ST.HLP_RETURN_NO_DISPLAY)
111
112    Parser.add_option("-q", "--quiet", action="store_true", dest="opt_quiet", help=ST.HLP_RETURN_AND_DISPLAY)
113
114    Parser.add_option("-i", "--install", action="store", type="string", dest="Install_Distribution_Package_File",
115                      help=ST.HLP_SPECIFY_PACKAGE_NAME_INSTALL)
116
117    Parser.add_option("-c", "--create", action="store", type="string", dest="Create_Distribution_Package_File",
118                      help=ST.HLP_SPECIFY_PACKAGE_NAME_CREATE)
119
120    Parser.add_option("-r", "--remove", action="store", type="string", dest="Remove_Distribution_Package_File",
121                      help=ST.HLP_SPECIFY_PACKAGE_NAME_REMOVE)
122
123    Parser.add_option("-t", "--template", action="store", type="string", dest="Package_Information_Data_File",
124                      help=ST.HLP_SPECIFY_TEMPLATE_NAME_CREATE)
125
126    Parser.add_option("-p", "--dec-filename", action="append", type="string", dest="EDK2_DEC_Filename",
127                      help=ST.HLP_SPECIFY_DEC_NAME_CREATE)
128
129    Parser.add_option("-m", "--inf-filename", action="append", type="string", dest="EDK2_INF_Filename",
130                      help=ST.HLP_SPECIFY_INF_NAME_CREATE)
131
132    Parser.add_option("-l", "--list", action="store_true", dest="List_Dist_Installed",
133                      help=ST.HLP_LIST_DIST_INSTALLED)
134
135    Parser.add_option("-f", "--force", action="store_true", dest="Yes", help=ST.HLP_DISABLE_PROMPT)
136
137    Parser.add_option("-n", "--custom-path", action="store_true", dest="CustomPath", help=ST.HLP_CUSTOM_PATH_PROMPT)
138
139    Parser.add_option("-x", "--free-lock", action="store_true", dest="SkipLock", help=ST.HLP_SKIP_LOCK_CHECK)
140
141    Parser.add_option("-u", "--replace", action="store", type="string", dest="Replace_Distribution_Package_File",
142                      help=ST.HLP_SPECIFY_PACKAGE_NAME_REPLACE)
143
144    Parser.add_option("-o", "--original", action="store", type="string", dest="Original_Distribution_Package_File",
145                      help=ST.HLP_SPECIFY_PACKAGE_NAME_TO_BE_REPLACED)
146
147    Parser.add_option("--use-guided-paths", action="store_true", dest="Use_Guided_Paths", help=ST.HLP_USE_GUIDED_PATHS)
148
149    Opt = Parser.parse_args()[0]
150
151    Var2Var = [
152        ("PackageInformationDataFile", Opt.Package_Information_Data_File),
153        ("PackFileToInstall", Opt.Install_Distribution_Package_File),
154        ("PackFileToCreate", Opt.Create_Distribution_Package_File),
155        ("PackFileToRemove", Opt.Remove_Distribution_Package_File),
156        ("PackageFileList", Opt.EDK2_DEC_Filename),
157        ("ModuleFileList", Opt.EDK2_INF_Filename),
158        ("InventoryWs", Opt.List_Dist_Installed),
159        ("PackFileToReplace", Opt.Replace_Distribution_Package_File),
160        ("PackFileToBeReplaced", Opt.Original_Distribution_Package_File),
161        ("UseGuidedPkgPath", Opt.Use_Guided_Paths),
162    ]
163
164    for Var in Var2Var:
165        setattr(Opt, Var[0], Var[1])
166
167    try:
168        GlobalData.gWORKSPACE, GlobalData.gPACKAGE_PATH = GetWorkspace()
169    except FatalError, XExcept:
170        if Logger.GetLevel() <= Logger.DEBUG_9:
171            Logger.Quiet(ST.MSG_PYTHON_ON % (python_version(), platform) + format_exc())
172        return XExcept.args[0]
173
174    # Start *********************************************
175    # Support WORKSPACE is a long path
176    # Only work well on windows
177    # Linux Solution TBD
178    if pf.system() == 'Windows':
179        os.system('@echo off\nsubst b: /D')
180        os.system('subst b: "%s"' % GlobalData.gWORKSPACE)
181        GlobalData.gWORKSPACE = 'B:\\'
182    # End ***********************************************
183
184    WorkspaceDir = GlobalData.gWORKSPACE
185
186    SetLogLevel(Opt)
187
188    Mgr = FileHook.RecoverMgr(WorkspaceDir)
189    FileHook.SetRecoverMgr(Mgr)
190
191    GlobalData.gDB = IpiDatabase(os.path.normpath(os.path.join(WorkspaceDir, \
192                                                               "Conf/DistributionPackageDatabase.db")), WorkspaceDir)
193    GlobalData.gDB.InitDatabase(Opt.SkipLock)
194
195    #
196    # Make sure the Db will get closed correctly
197    #
198    try:
199        ReturnCode = 0
200        CheckConflictOption(Opt)
201
202        RunModule = None
203        if Opt.PackFileToCreate:
204            if Opt.PackageInformationDataFile:
205                if not os.path.exists(Opt.PackageInformationDataFile):
206                    if not os.path.exists(os.path.join(WorkspaceDir, Opt.PackageInformationDataFile)):
207                        Logger.Error("\nUPT", FILE_NOT_FOUND, ST.ERR_NO_TEMPLATE_FILE % Opt.PackageInformationDataFile)
208                    else:
209                        Opt.PackageInformationDataFile = os.path.join(WorkspaceDir, Opt.PackageInformationDataFile)
210            else:
211                Logger.Error("UPT", OPTION_MISSING, ExtraData=ST.ERR_REQUIRE_T_OPTION)
212            if not Opt.PackFileToCreate.endswith('.dist'):
213                Logger.Error("CreatePkg", FILE_TYPE_MISMATCH, ExtraData=ST.ERR_DIST_EXT_ERROR % Opt.PackFileToCreate)
214            RunModule = MkPkg.Main
215
216        elif Opt.PackFileToInstall:
217            if not Opt.PackFileToInstall.endswith('.dist'):
218                Logger.Error("InstallPkg", FILE_TYPE_MISMATCH, ExtraData=ST.ERR_DIST_EXT_ERROR % Opt.PackFileToInstall)
219
220            AbsPath = GetFullPathDist(Opt.PackFileToInstall, WorkspaceDir)
221            if not AbsPath:
222                Logger.Error("InstallPkg", FILE_NOT_FOUND, ST.ERR_INSTALL_DIST_NOT_FOUND % Opt.PackFileToInstall)
223
224            Opt.PackFileToInstall = AbsPath
225            setattr(Opt, 'PackageFile', Opt.PackFileToInstall)
226            RunModule = InstallPkg.Main
227
228        elif Opt.PackFileToRemove:
229            if not Opt.PackFileToRemove.endswith('.dist'):
230                Logger.Error("RemovePkg", FILE_TYPE_MISMATCH, ExtraData=ST.ERR_DIST_EXT_ERROR % Opt.PackFileToRemove)
231            head, tail = os.path.split(Opt.PackFileToRemove)
232            if head or not tail:
233                Logger.Error("RemovePkg",
234                             FILE_TYPE_MISMATCH,
235                             ExtraData=ST.ERR_DIST_FILENAME_ONLY_FOR_REMOVE % Opt.PackFileToRemove)
236
237            setattr(Opt, 'DistributionFile', Opt.PackFileToRemove)
238            RunModule = RmPkg.Main
239        elif Opt.InventoryWs:
240            RunModule = InventoryWs.Main
241
242        elif Opt.PackFileToBeReplaced and not Opt.PackFileToReplace:
243            Logger.Error("ReplacePkg", OPTION_MISSING, ExtraData=ST.ERR_REQUIRE_U_OPTION)
244
245        elif Opt.PackFileToReplace:
246            if not Opt.PackFileToReplace.endswith('.dist'):
247                Logger.Error("ReplacePkg", FILE_TYPE_MISMATCH, ExtraData=ST.ERR_DIST_EXT_ERROR % Opt.PackFileToReplace)
248            if not Opt.PackFileToBeReplaced:
249                Logger.Error("ReplacePkg", OPTION_MISSING, ExtraData=ST.ERR_REQUIRE_O_OPTION)
250            if not Opt.PackFileToBeReplaced.endswith('.dist'):
251                Logger.Error("ReplacePkg",
252                             FILE_TYPE_MISMATCH,
253                             ExtraData=ST.ERR_DIST_EXT_ERROR % Opt.PackFileToBeReplaced)
254
255            head, tail = os.path.split(Opt.PackFileToBeReplaced)
256            if head or not tail:
257                Logger.Error("ReplacePkg",
258                             FILE_TYPE_MISMATCH,
259                             ExtraData=ST.ERR_DIST_FILENAME_ONLY_FOR_REPLACE_ORIG % Opt.PackFileToBeReplaced)
260
261            AbsPath = GetFullPathDist(Opt.PackFileToReplace, WorkspaceDir)
262            if not AbsPath:
263                Logger.Error("ReplacePkg", FILE_NOT_FOUND, ST.ERR_REPLACE_DIST_NOT_FOUND % Opt.PackFileToReplace)
264
265            Opt.PackFileToReplace = AbsPath
266            RunModule = ReplacePkg.Main
267
268        else:
269            Parser.print_usage()
270            return OPTION_MISSING
271
272        ReturnCode = RunModule(Opt)
273    except FatalError, XExcept:
274        ReturnCode = XExcept.args[0]
275        if Logger.GetLevel() <= Logger.DEBUG_9:
276            Logger.Quiet(ST.MSG_PYTHON_ON % (python_version(), platform) + \
277                         format_exc())
278    finally:
279        try:
280            if ReturnCode != 0 and ReturnCode != UPT_ALREADY_INSTALLED_ERROR:
281                Logger.Quiet(ST.MSG_RECOVER_START)
282                GlobalData.gDB.RollBack()
283                Mgr.rollback()
284                Logger.Quiet(ST.MSG_RECOVER_DONE)
285            else:
286                GlobalData.gDB.Commit()
287                Mgr.commit()
288        except StandardError:
289            Logger.Quiet(ST.MSG_RECOVER_FAIL)
290        GlobalData.gDB.CloseDb()
291        if pf.system() == 'Windows':
292            os.system('subst b: /D')
293
294    return ReturnCode
295
296## GetFullPathDist
297#
298#  This function will check DistFile existence, if not absolute path, then try current working directory,
299#  then $(WORKSPACE),and return the AbsPath. If file doesn't find, then return None
300#
301# @param DistFile:       The distribution file in either relative path or absolute path
302# @param WorkspaceDir:   Workspace Directory
303# @return AbsPath:       The Absolute path of the distribution file if existed, None else
304#
305def GetFullPathDist(DistFile, WorkspaceDir):
306    if os.path.isabs(DistFile):
307        if not (os.path.exists(DistFile) and os.path.isfile(DistFile)):
308            return None
309        else:
310            return DistFile
311    else:
312        AbsPath = os.path.normpath(os.path.join(os.getcwd(), DistFile))
313        if not (os.path.exists(AbsPath) and os.path.isfile(AbsPath)):
314            AbsPath = os.path.normpath(os.path.join(WorkspaceDir, DistFile))
315            if not (os.path.exists(AbsPath) and os.path.isfile(AbsPath)):
316                return None
317
318        return AbsPath
319
320if __name__ == '__main__':
321    RETVAL = Main()
322    #
323    # 0-127 is a safe return range, and 1 is a standard default error
324    #
325    if RETVAL < 0 or RETVAL > 127:
326        RETVAL = 1
327    sys.exit(RETVAL)
328