blob: e36761538b9173089aa5cdbeca49ac67552c5708 [file] [log] [blame]
[email protected]4a41db52012-01-13 00:02:561#!/usr/bin/env python
[email protected]2ec654a2012-01-10 17:47:002# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]acc3d8e2011-08-22 22:17:403# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import sys
7
8from idl_log import ErrOut, InfoOut, WarnOut
9from idl_option import GetOption, Option, ParseOptions
[email protected]406793d2011-11-14 22:26:5410from idl_parser import ParseFiles
[email protected]acc3d8e2011-08-22 22:17:4011
12GeneratorList = []
13
[email protected]14fa03b2011-08-26 21:10:3814Option('release', 'Which release to generate.', default='')
[email protected]a3aec322011-11-04 19:48:4815Option('range', 'Which ranges in the form of MIN,MAX.', default='start,end')
[email protected]acc3d8e2011-08-22 22:17:4016
17
18#
19# Generator
20#
21# Base class for generators. This class provides a mechanism for
22# adding new generator objects to the IDL driver. To use this class
[email protected]f7314732011-08-24 23:03:0623# override the GenerateRelease and GenerateRange members, and
[email protected]acc3d8e2011-08-22 22:17:4024# instantiate one copy of the class in the same module which defines it to
25# register the generator. After the AST is generated, call the static Run
26# member which will check every registered generator to see which ones have
27# been enabled through command-line options. To enable a generator use the
28# switches:
29# --<sname> : To enable with defaults
30# --<sname>_opt=<XXX,YYY=y> : To enable with generator specific options.
31#
32# NOTE: Generators still have access to global options
33
34class Generator(object):
35 def __init__(self, name, sname, desc):
36 self.name = name
37 self.run_switch = Option(sname, desc)
38 self.opt_switch = Option(sname + '_opt', 'Options for %s.' % sname,
39 default='')
40 GeneratorList.append(self)
41 self.errors = 0
[email protected]406793d2011-11-14 22:26:5442 self.skip_list = []
[email protected]acc3d8e2011-08-22 22:17:4043
44 def Error(self, msg):
45 ErrOut.Log('Error %s : %s' % (self.name, msg))
46 self.errors += 1
47
48 def GetRunOptions(self):
49 options = {}
50 option_list = self.opt_switch.Get()
51 if option_list:
52 option_list = option_list.split(',')
53 for opt in option_list:
54 offs = opt.find('=')
55 if offs > 0:
56 options[opt[:offs]] = opt[offs+1:]
57 else:
58 options[opt] = True
59 return options
60 if self.run_switch.Get():
61 return options
62 return None
63
64 def Generate(self, ast, options):
65 self.errors = 0
66
67 rangestr = GetOption('range')
68 releasestr = GetOption('release')
69
[email protected]a3aec322011-11-04 19:48:4870 print "Found releases: %s" % ast.releases
71
[email protected]406793d2011-11-14 22:26:5472 # Generate list of files to ignore due to errors
73 for filenode in ast.GetListOf('File'):
74 # If this file has errors, skip it
75 if filenode.GetProperty('ERRORS') > 0:
76 self.skip_list.append(filenode)
77 continue
78
[email protected]acc3d8e2011-08-22 22:17:4079 # Check for a range option which over-rides a release option
[email protected]14fa03b2011-08-26 21:10:3880 if not releasestr and rangestr:
[email protected]acc3d8e2011-08-22 22:17:4081 range_list = rangestr.split(',')
82 if len(range_list) != 2:
83 self.Error('Failed to generate for %s, incorrect range: "%s"' %
84 (self.name, rangestr))
85 else:
86 vmin = range_list[0]
87 vmax = range_list[1]
[email protected]a3aec322011-11-04 19:48:4888
89 # Generate 'start' and 'end' represent first and last found.
90 if vmin == 'start':
91 vmin = ast.releases[0]
92 if vmax == 'end':
93 vmax = ast.releases[-1]
94
[email protected]f7314732011-08-24 23:03:0695 vmin = ast.releases.index(vmin)
96 vmax = ast.releases.index(vmax) + 1
[email protected]406793d2011-11-14 22:26:5497 releases = ast.releases[vmin:vmax]
[email protected]55e1a702012-01-10 17:55:1798 InfoOut.Log('Generate range %s of %s.' % (rangestr, self.name))
[email protected]406793d2011-11-14 22:26:5499 ret = self.GenerateRange(ast, releases, options)
[email protected]f7314732011-08-24 23:03:06100 if ret < 0:
[email protected]acc3d8e2011-08-22 22:17:40101 self.Error('Failed to generate range %s : %s.' %(vmin, vmax))
[email protected]14fa03b2011-08-26 21:10:38102 else:
103 InfoOut.Log('%s wrote %d files.' % (self.name, ret))
[email protected]acc3d8e2011-08-22 22:17:40104 # Otherwise this should be a single release generation
105 else:
[email protected]55e1a702012-01-10 17:55:17106 if releasestr == 'start':
107 releasestr = ast.releases[0]
108 if releasestr == 'end':
109 releasestr = ast.releases[-1]
[email protected]acc3d8e2011-08-22 22:17:40110 if releasestr:
[email protected]14fa03b2011-08-26 21:10:38111 InfoOut.Log('Generate release %s of %s.' % (releasestr, self.name))
[email protected]f7314732011-08-24 23:03:06112 ret = self.GenerateRelease(ast, releasestr, options)
[email protected]acc3d8e2011-08-22 22:17:40113 if ret < 0:
114 self.Error('Failed to generate release %s.' % releasestr)
115 else:
116 InfoOut.Log('%s wrote %d files.' % (self.name, ret))
117
118 else:
119 self.Error('No range or release specified for %s.' % releasestr)
120 return self.errors
121
[email protected]f7314732011-08-24 23:03:06122 def GenerateRelease(self, ast, release, options):
[email protected]acc3d8e2011-08-22 22:17:40123 __pychecker__ = 'unusednames=ast,release,options'
124 self.Error("Undefined release generator.")
125 return 0
126
[email protected]406793d2011-11-14 22:26:54127 def GenerateRange(self, ast, releases, options):
128 __pychecker__ = 'unusednames=ast,releases,options'
[email protected]acc3d8e2011-08-22 22:17:40129 self.Error("Undefined range generator.")
130 return 0
131
132 @staticmethod
133 def Run(ast):
134 fail_count = 0
135
136 # Check all registered generators if they should run.
137 for gen in GeneratorList:
138 options = gen.GetRunOptions()
139 if options is not None:
140 if gen.Generate(ast, options):
141 fail_count += 1
142 return fail_count
143
144
[email protected]f7314732011-08-24 23:03:06145#
146# GeneratorByFile
147#
148# A subclass of Generator for use of generators which have a one to one
149# mapping between IDL sources and output files. To use, derive a new class
150# which defines:
151#
152# GetOutFile - Returns an IDLOutFile based on filenode (name) and options
153# GenerateHead - Writes the first part of the file (includes, etc...)
154# GenerateBody - Writes the body of the file (definitions)
155# GenerateTail - Writes the end of the file (closing include guard, etc...)
156#
157class GeneratorByFile(Generator):
[email protected]406793d2011-11-14 22:26:54158 def GenerateFile(self, filenode, releases, options):
159 __pychecker__ = 'unusednames=filenode,releases,options'
160 self.Error("Undefined release generator.")
161 return 0
162
[email protected]f7314732011-08-24 23:03:06163 def GenerateRelease(self, ast, release, options):
164 return self.GenerateRange(ast, [release], options)
165
166 def GenerateRange(self, ast, releases, options):
167 # Get list of out files
168 outlist = GetOption('out')
169 if outlist: outlist = outlist.split(',')
170
171 skipList = []
172 cnt = 0
173 for filenode in ast.GetListOf('File'):
[email protected]406793d2011-11-14 22:26:54174 # Ignore files with errors
175 if filenode in self.skip_list:
176 continue
177
[email protected]f7314732011-08-24 23:03:06178 # Skip this file if not required
[email protected]39375782011-09-14 16:55:09179 if outlist and filenode.GetName() not in outlist:
[email protected]f7314732011-08-24 23:03:06180 continue
181
[email protected]406793d2011-11-14 22:26:54182 # Create the output file and increment out count if there was a delta
183 if self.GenerateFile(filenode, releases, options):
184 cnt = cnt + 1
[email protected]f7314732011-08-24 23:03:06185
186 for filenode in skipList:
187 errcnt = filenode.GetProperty('ERRORS')
188 ErrOut.Log('%s : Skipped because of %d errors.' % (
189 filenode.GetName(), errcnt))
190
191 if skipList:
192 return -len(skipList)
193
194 if GetOption('diff'):
195 return -cnt
196 return cnt
197
198
[email protected]acc3d8e2011-08-22 22:17:40199check_release = 0
200check_range = 0
201
[email protected]f7314732011-08-24 23:03:06202class GeneratorReleaseTest(Generator):
203 def GenerateRelease(self, ast, release, options = {}):
[email protected]acc3d8e2011-08-22 22:17:40204 __pychecker__ = 'unusednames=ast,release,options'
205 global check_release
206 check_map = {
207 'so_long': True,
208 'MyOpt': 'XYZ',
209 'goodbye': True
210 }
211 check_release = 1
212 for item in check_map:
213 check_item = check_map[item]
214 option_item = options.get(item, None)
215 if check_item != option_item:
216 print 'Option %s is %s, expecting %s' % (item, option_item, check_item)
217 check_release = 0
218
219 if release != 'M14':
220 check_release = 0
221 return check_release == 1
222
[email protected]406793d2011-11-14 22:26:54223 def GenerateRange(self, ast, releases, options):
224 __pychecker__ = 'unusednames=ast,releases,options'
[email protected]acc3d8e2011-08-22 22:17:40225 global check_range
226 check_range = 1
227 return True
228
229def Test():
230 __pychecker__ = 'unusednames=args'
231 global check_release
232 global check_range
233
234 ParseOptions(['--testgen_opt=so_long,MyOpt=XYZ,goodbye'])
235 if Generator.Run('AST') != 0:
236 print 'Generate release: Failed.\n'
237 return -1
238
239 if check_release != 1 or check_range != 0:
240 print 'Gererate release: Failed to run.\n'
241 return -1
242
243 check_release = 0
244 ParseOptions(['--testgen_opt="HELLO"', '--range=M14,M16'])
245 if Generator.Run('AST') != 0:
246 print 'Generate range: Failed.\n'
247 return -1
248
249 if check_release != 0 or check_range != 1:
250 print 'Gererate range: Failed to run.\n'
251 return -1
252
253 print 'Generator test: Pass'
254 return 0
255
256
257def Main(args):
258 if not args: return Test()
[email protected]acc3d8e2011-08-22 22:17:40259 filenames = ParseOptions(args)
260 ast = ParseFiles(filenames)
261
262 return Generator.Run(ast)
263
264
265if __name__ == '__main__':
[email protected]f7314732011-08-24 23:03:06266 GeneratorReleaseTest('Test Gen', 'testgen', 'Generator Class Test.')
[email protected]acc3d8e2011-08-22 22:17:40267 sys.exit(Main(sys.argv[1:]))
[email protected]55e1a702012-01-10 17:55:17268