1## @file
2# Target Tool Parser
3#
4#  Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
5#
6#  This program and the accompanying materials
7#  are licensed and made available under the terms and conditions of the BSD License
8#  which accompanies this 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
15import Common.LongFilePathOs as os
16import sys
17import traceback
18from optparse import OptionParser
19
20import Common.EdkLogger as EdkLogger
21import Common.BuildToolError as BuildToolError
22from Common.DataType import *
23from Common.BuildVersion import gBUILD_VERSION
24from Common.LongFilePathSupport import OpenLongFilePath as open
25
26# To Do 1.set clean, 2. add item, if the line is disabled.
27
28class TargetTool():
29    def __init__(self, opt, args):
30        self.WorkSpace = os.path.normpath(os.getenv('WORKSPACE'))
31        self.Opt       = opt
32        self.Arg       = args[0]
33        self.FileName  = os.path.normpath(os.path.join(self.WorkSpace, 'Conf', 'target.txt'))
34        if os.path.isfile(self.FileName) == False:
35            print "%s does not exist." % self.FileName
36            sys.exit(1)
37        self.TargetTxtDictionary = {
38            TAB_TAT_DEFINES_ACTIVE_PLATFORM                            : None,
39            TAB_TAT_DEFINES_TOOL_CHAIN_CONF                            : None,
40            TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER               : None,
41            TAB_TAT_DEFINES_TARGET                                     : None,
42            TAB_TAT_DEFINES_TOOL_CHAIN_TAG                             : None,
43            TAB_TAT_DEFINES_TARGET_ARCH                                : None,
44            TAB_TAT_DEFINES_BUILD_RULE_CONF                            : None,
45        }
46        self.LoadTargetTxtFile(self.FileName)
47
48    def LoadTargetTxtFile(self, filename):
49        if os.path.exists(filename) and os.path.isfile(filename):
50            return self.ConvertTextFileToDict(filename, '#', '=')
51        else:
52            raise ParseError('LoadTargetTxtFile() : No Target.txt file exists.')
53            return 1
54
55#
56# Convert a text file to a dictionary
57#
58    def ConvertTextFileToDict(self, FileName, CommentCharacter, KeySplitCharacter):
59        """Convert a text file to a dictionary of (name:value) pairs."""
60        try:
61            f = open(FileName,'r')
62            for Line in f:
63                if Line.startswith(CommentCharacter) or Line.strip() == '':
64                    continue
65                LineList = Line.split(KeySplitCharacter,1)
66                if len(LineList) >= 2:
67                    Key = LineList[0].strip()
68                    if Key.startswith(CommentCharacter) == False and Key in self.TargetTxtDictionary.keys():
69                        if Key == TAB_TAT_DEFINES_ACTIVE_PLATFORM or Key == TAB_TAT_DEFINES_TOOL_CHAIN_CONF \
70                          or Key == TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER \
71                          or Key == TAB_TAT_DEFINES_ACTIVE_MODULE:
72                            self.TargetTxtDictionary[Key] = LineList[1].replace('\\', '/').strip()
73                        elif Key == TAB_TAT_DEFINES_TARGET or Key == TAB_TAT_DEFINES_TARGET_ARCH \
74                          or Key == TAB_TAT_DEFINES_TOOL_CHAIN_TAG or Key == TAB_TAT_DEFINES_BUILD_RULE_CONF:
75                            self.TargetTxtDictionary[Key] = LineList[1].split()
76            f.close()
77            return 0
78        except:
79            last_type, last_value, last_tb = sys.exc_info()
80            traceback.print_exception(last_type, last_value, last_tb)
81
82    def Print(self):
83        KeyList = self.TargetTxtDictionary.keys()
84        errMsg  = ''
85        for Key in KeyList:
86            if type(self.TargetTxtDictionary[Key]) == type([]):
87                print "%-30s = %s" % (Key, ''.join(elem + ' ' for elem in self.TargetTxtDictionary[Key]))
88            elif self.TargetTxtDictionary[Key] == None:
89                errMsg += "  Missing %s configuration information, please use TargetTool to set value!" % Key + os.linesep
90            else:
91                print "%-30s = %s" % (Key, self.TargetTxtDictionary[Key])
92
93        if errMsg != '':
94            print os.linesep + 'Warning:' + os.linesep + errMsg
95
96    def RWFile(self, CommentCharacter, KeySplitCharacter, Num):
97        try:
98            fr = open(self.FileName, 'r')
99            fw = open(os.path.normpath(os.path.join(self.WorkSpace, 'Conf\\targetnew.txt')), 'w')
100
101            existKeys = []
102            for Line in fr:
103                if Line.startswith(CommentCharacter) or Line.strip() == '':
104                    fw.write(Line)
105                else:
106                    LineList = Line.split(KeySplitCharacter,1)
107                    if len(LineList) >= 2:
108                        Key = LineList[0].strip()
109                        if Key.startswith(CommentCharacter) == False and Key in self.TargetTxtDictionary.keys():
110                            if Key not in existKeys:
111                                existKeys.append(Key)
112                            else:
113                                print "Warning: Found duplicate key item in original configuration files!"
114
115                            if Num == 0:
116                                Line = "%-30s = \n" % Key
117                            else:
118                                ret = GetConfigureKeyValue(self, Key)
119                                if ret != None:
120                                    Line = ret
121                            fw.write(Line)
122            for key in self.TargetTxtDictionary.keys():
123                if key not in existKeys:
124                    print "Warning: %s does not exist in original configuration file" % key
125                    Line = GetConfigureKeyValue(self, key)
126                    if Line == None:
127                        Line = "%-30s = " % key
128                    fw.write(Line)
129
130            fr.close()
131            fw.close()
132            os.remove(self.FileName)
133            os.rename(os.path.normpath(os.path.join(self.WorkSpace, 'Conf\\targetnew.txt')), self.FileName)
134
135        except:
136            last_type, last_value, last_tb = sys.exc_info()
137            traceback.print_exception(last_type, last_value, last_tb)
138
139def GetConfigureKeyValue(self, Key):
140    Line = None
141    if Key == TAB_TAT_DEFINES_ACTIVE_PLATFORM and self.Opt.DSCFILE != None:
142        dscFullPath = os.path.join(self.WorkSpace, self.Opt.DSCFILE)
143        if os.path.exists(dscFullPath):
144            Line = "%-30s = %s\n" % (Key, self.Opt.DSCFILE)
145        else:
146            EdkLogger.error("TagetTool", BuildToolError.FILE_NOT_FOUND,
147                            "DSC file %s does not exist!" % self.Opt.DSCFILE, RaiseError=False)
148    elif Key == TAB_TAT_DEFINES_TOOL_CHAIN_CONF and self.Opt.TOOL_DEFINITION_FILE != None:
149        tooldefFullPath = os.path.join(self.WorkSpace, self.Opt.TOOL_DEFINITION_FILE)
150        if os.path.exists(tooldefFullPath):
151            Line = "%-30s = %s\n" % (Key, self.Opt.TOOL_DEFINITION_FILE)
152        else:
153            EdkLogger.error("TagetTool", BuildToolError.FILE_NOT_FOUND,
154                            "Tooldef file %s does not exist!" % self.Opt.TOOL_DEFINITION_FILE, RaiseError=False)
155
156    elif self.Opt.NUM >= 2:
157        Line = "%-30s = %s\n" % (Key, 'Enable')
158    elif self.Opt.NUM <= 1:
159        Line = "%-30s = %s\n" % (Key, 'Disable')
160    elif Key == TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER and self.Opt.NUM != None:
161        Line = "%-30s = %s\n" % (Key, str(self.Opt.NUM))
162    elif Key == TAB_TAT_DEFINES_TARGET and self.Opt.TARGET != None:
163        Line = "%-30s = %s\n" % (Key, ''.join(elem + ' ' for elem in self.Opt.TARGET))
164    elif Key == TAB_TAT_DEFINES_TARGET_ARCH and self.Opt.TARGET_ARCH != None:
165        Line = "%-30s = %s\n" % (Key, ''.join(elem + ' ' for elem in self.Opt.TARGET_ARCH))
166    elif Key == TAB_TAT_DEFINES_TOOL_CHAIN_TAG and self.Opt.TOOL_CHAIN_TAG != None:
167        Line = "%-30s = %s\n" % (Key, self.Opt.TOOL_CHAIN_TAG)
168    elif Key == TAB_TAT_DEFINES_BUILD_RULE_CONF and self.Opt.BUILD_RULE_FILE != None:
169        buildruleFullPath = os.path.join(self.WorkSpace, self.Opt.BUILD_RULE_FILE)
170        if os.path.exists(buildruleFullPath):
171            Line = "%-30s = %s\n" % (Key, self.Opt.BUILD_RULE_FILE)
172        else:
173            EdkLogger.error("TagetTool", BuildToolError.FILE_NOT_FOUND,
174                            "Build rule file %s does not exist!" % self.Opt.BUILD_RULE_FILE, RaiseError=False)
175    return Line
176
177VersionNumber = ("0.01" + " " + gBUILD_VERSION)
178__version__ = "%prog Version " + VersionNumber
179__copyright__ = "Copyright (c) 2007 - 2010, Intel Corporation  All rights reserved."
180__usage__ = "%prog [options] {args} \
181\nArgs:                                                  \
182\n Clean  clean the all default configuration of target.txt. \
183\n Print  print the all default configuration of target.txt. \
184\n Set    replace the default configuration with expected value specified by option."
185
186gParamCheck = []
187def SingleCheckCallback(option, opt_str, value, parser):
188    if option not in gParamCheck:
189        setattr(parser.values, option.dest, value)
190        gParamCheck.append(option)
191    else:
192        parser.error("Option %s only allows one instance in command line!" % option)
193
194def RangeCheckCallback(option, opt_str, value, parser):
195    if option not in gParamCheck:
196        gParamCheck.append(option)
197        if value < 1 or value > 8:
198            parser.error("The count of multi-thread is not in valid range of 1 ~ 8.")
199        else:
200            setattr(parser.values, option.dest, value)
201    else:
202        parser.error("Option %s only allows one instance in command line!" % option)
203
204def MyOptionParser():
205    parser = OptionParser(version=__version__,prog="TargetTool.exe",usage=__usage__,description=__copyright__)
206    parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC', 'ARM', 'AARCH64','0'], dest="TARGET_ARCH",
207        help="ARCHS is one of list: IA32, X64, IPF, ARM, AARCH64 or EBC, which replaces target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option. 0 will clear this setting in target.txt and can't combine with other value.")
208    parser.add_option("-p", "--platform", action="callback", type="string", dest="DSCFILE", callback=SingleCheckCallback,
209        help="Specify a DSC file, which replace target.txt's ACTIVE_PLATFORM definition. 0 will clear this setting in target.txt and can't combine with other value.")
210    parser.add_option("-c", "--tooldef", action="callback", type="string", dest="TOOL_DEFINITION_FILE", callback=SingleCheckCallback,
211        help="Specify the WORKSPACE relative path of tool_def.txt file, which replace target.txt's TOOL_CHAIN_CONF definition. 0 will clear this setting in target.txt and can't combine with other value.")
212    parser.add_option("-t", "--target", action="append", type="choice", choices=['DEBUG','RELEASE','0'], dest="TARGET",
213        help="TARGET is one of list: DEBUG, RELEASE, which replaces target.txt's TARGET definition. To specify more TARGET, please repeat this option. 0 will clear this setting in target.txt and can't combine with other value.")
214    parser.add_option("-n", "--tagname", action="callback", type="string", dest="TOOL_CHAIN_TAG", callback=SingleCheckCallback,
215        help="Specify the Tool Chain Tagname, which replaces target.txt's TOOL_CHAIN_TAG definition. 0 will clear this setting in target.txt and can't combine with other value.")
216    parser.add_option("-r", "--buildrule", action="callback", type="string", dest="BUILD_RULE_FILE", callback=SingleCheckCallback,
217        help="Specify the build rule configure file, which replaces target.txt's BUILD_RULE_CONF definition. If not specified, the default value Conf/build_rule.txt will be set.")
218    parser.add_option("-m", "--multithreadnum", action="callback", type="int", dest="NUM", callback=RangeCheckCallback,
219        help="Specify the multi-thread number which replace target.txt's MAX_CONCURRENT_THREAD_NUMBER. If the value is less than 2, MULTIPLE_THREAD will be disabled. If the value is larger than 1, MULTIPLE_THREAD will be enabled.")
220    (opt, args)=parser.parse_args()
221    return (opt, args)
222
223if __name__ == '__main__':
224    EdkLogger.Initialize()
225    EdkLogger.SetLevel(EdkLogger.QUIET)
226    if os.getenv('WORKSPACE') == None:
227        print "ERROR: WORKSPACE should be specified or edksetup script should be executed before run TargetTool"
228        sys.exit(1)
229
230    (opt, args) = MyOptionParser()
231    if len(args) != 1 or (args[0].lower() != 'print' and args[0].lower() != 'clean' and args[0].lower() != 'set'):
232        print "The number of args isn't 1 or the value of args is invalid."
233        sys.exit(1)
234    if opt.NUM != None and opt.NUM < 1:
235        print "The MAX_CONCURRENT_THREAD_NUMBER must be larger than 0."
236        sys.exit(1)
237    if opt.TARGET != None and len(opt.TARGET) > 1:
238        for elem in opt.TARGET:
239            if elem == '0':
240                print "0 will clear the TARGET setting in target.txt and can't combine with other value."
241                sys.exit(1)
242    if opt.TARGET_ARCH != None and len(opt.TARGET_ARCH) > 1:
243        for elem in opt.TARGET_ARCH:
244            if elem == '0':
245                print "0 will clear the TARGET_ARCH setting in target.txt and can't combine with other value."
246                sys.exit(1)
247
248    try:
249        FileHandle = TargetTool(opt, args)
250        if FileHandle.Arg.lower() == 'print':
251            FileHandle.Print()
252            sys.exit(0)
253        elif FileHandle.Arg.lower() == 'clean':
254            FileHandle.RWFile('#', '=', 0)
255        else:
256            FileHandle.RWFile('#', '=', 1)
257    except Exception, e:
258        last_type, last_value, last_tb = sys.exc_info()
259        traceback.print_exception(last_type, last_value, last_tb)
260
261