| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # | 2 # |
| 3 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 import sys | 7 import sys |
| 8 | 8 |
| 9 from idl_log import ErrOut, InfoOut, WarnOut | 9 from idl_log import ErrOut, InfoOut, WarnOut |
| 10 from idl_option import GetOption, Option, ParseOptions | 10 from idl_option import GetOption, Option, ParseOptions |
| 11 from idl_parser import ParseFiles |
| 11 | 12 |
| 12 GeneratorList = [] | 13 GeneratorList = [] |
| 13 | 14 |
| 14 Option('release', 'Which release to generate.', default='') | 15 Option('release', 'Which release to generate.', default='') |
| 15 Option('range', 'Which ranges in the form of MIN,MAX.', default='start,end') | 16 Option('range', 'Which ranges in the form of MIN,MAX.', default='start,end') |
| 16 | 17 |
| 17 | 18 |
| 18 # | 19 # |
| 19 # Generator | 20 # Generator |
| 20 # | 21 # |
| (...skipping 11 matching lines...) Expand all Loading... |
| 32 # NOTE: Generators still have access to global options | 33 # NOTE: Generators still have access to global options |
| 33 | 34 |
| 34 class Generator(object): | 35 class Generator(object): |
| 35 def __init__(self, name, sname, desc): | 36 def __init__(self, name, sname, desc): |
| 36 self.name = name | 37 self.name = name |
| 37 self.run_switch = Option(sname, desc) | 38 self.run_switch = Option(sname, desc) |
| 38 self.opt_switch = Option(sname + '_opt', 'Options for %s.' % sname, | 39 self.opt_switch = Option(sname + '_opt', 'Options for %s.' % sname, |
| 39 default='') | 40 default='') |
| 40 GeneratorList.append(self) | 41 GeneratorList.append(self) |
| 41 self.errors = 0 | 42 self.errors = 0 |
| 43 self.skip_list = [] |
| 42 | 44 |
| 43 def Error(self, msg): | 45 def Error(self, msg): |
| 44 ErrOut.Log('Error %s : %s' % (self.name, msg)) | 46 ErrOut.Log('Error %s : %s' % (self.name, msg)) |
| 45 self.errors += 1 | 47 self.errors += 1 |
| 46 | 48 |
| 47 def GetRunOptions(self): | 49 def GetRunOptions(self): |
| 48 options = {} | 50 options = {} |
| 49 option_list = self.opt_switch.Get() | 51 option_list = self.opt_switch.Get() |
| 50 if option_list: | 52 if option_list: |
| 51 option_list = option_list.split(',') | 53 option_list = option_list.split(',') |
| 52 for opt in option_list: | 54 for opt in option_list: |
| 53 offs = opt.find('=') | 55 offs = opt.find('=') |
| 54 if offs > 0: | 56 if offs > 0: |
| 55 options[opt[:offs]] = opt[offs+1:] | 57 options[opt[:offs]] = opt[offs+1:] |
| 56 else: | 58 else: |
| 57 options[opt] = True | 59 options[opt] = True |
| 58 return options | 60 return options |
| 59 if self.run_switch.Get(): | 61 if self.run_switch.Get(): |
| 60 return options | 62 return options |
| 61 return None | 63 return None |
| 62 | 64 |
| 63 def Generate(self, ast, options): | 65 def Generate(self, ast, options): |
| 64 self.errors = 0 | 66 self.errors = 0 |
| 65 | 67 |
| 66 rangestr = GetOption('range') | 68 rangestr = GetOption('range') |
| 67 releasestr = GetOption('release') | 69 releasestr = GetOption('release') |
| 68 | 70 |
| 69 print "Found releases: %s" % ast.releases | 71 print "Found releases: %s" % ast.releases |
| 70 | 72 |
| 73 # Generate list of files to ignore due to errors |
| 74 for filenode in ast.GetListOf('File'): |
| 75 # If this file has errors, skip it |
| 76 if filenode.GetProperty('ERRORS') > 0: |
| 77 self.skip_list.append(filenode) |
| 78 continue |
| 79 |
| 71 # Check for a range option which over-rides a release option | 80 # Check for a range option which over-rides a release option |
| 72 if not releasestr and rangestr: | 81 if not releasestr and rangestr: |
| 73 range_list = rangestr.split(',') | 82 range_list = rangestr.split(',') |
| 74 if len(range_list) != 2: | 83 if len(range_list) != 2: |
| 75 self.Error('Failed to generate for %s, incorrect range: "%s"' % | 84 self.Error('Failed to generate for %s, incorrect range: "%s"' % |
| 76 (self.name, rangestr)) | 85 (self.name, rangestr)) |
| 77 else: | 86 else: |
| 78 vmin = range_list[0] | 87 vmin = range_list[0] |
| 79 vmax = range_list[1] | 88 vmax = range_list[1] |
| 80 | 89 |
| 81 # Generate 'start' and 'end' represent first and last found. | 90 # Generate 'start' and 'end' represent first and last found. |
| 82 if vmin == 'start': | 91 if vmin == 'start': |
| 83 vmin = ast.releases[0] | 92 vmin = ast.releases[0] |
| 84 if vmax == 'end': | 93 if vmax == 'end': |
| 85 vmax = ast.releases[-1] | 94 vmax = ast.releases[-1] |
| 86 | 95 |
| 87 vmin = ast.releases.index(vmin) | 96 vmin = ast.releases.index(vmin) |
| 88 vmax = ast.releases.index(vmax) + 1 | 97 vmax = ast.releases.index(vmax) + 1 |
| 89 range = ast.releases[vmin:vmax] | 98 releases = ast.releases[vmin:vmax] |
| 90 InfoOut.Log('Generate range %s of %s.' % (range, self.name)) | 99 InfoOut.Log('Generate range %s of %s.' % (range, self.name)) |
| 91 ret = self.GenerateRange(ast, range, options) | 100 ret = self.GenerateRange(ast, releases, options) |
| 92 if ret < 0: | 101 if ret < 0: |
| 93 self.Error('Failed to generate range %s : %s.' %(vmin, vmax)) | 102 self.Error('Failed to generate range %s : %s.' %(vmin, vmax)) |
| 94 else: | 103 else: |
| 95 InfoOut.Log('%s wrote %d files.' % (self.name, ret)) | 104 InfoOut.Log('%s wrote %d files.' % (self.name, ret)) |
| 96 # Otherwise this should be a single release generation | 105 # Otherwise this should be a single release generation |
| 97 else: | 106 else: |
| 98 if releasestr: | 107 if releasestr: |
| 99 InfoOut.Log('Generate release %s of %s.' % (releasestr, self.name)) | 108 InfoOut.Log('Generate release %s of %s.' % (releasestr, self.name)) |
| 100 ret = self.GenerateRelease(ast, releasestr, options) | 109 ret = self.GenerateRelease(ast, releasestr, options) |
| 101 if ret < 0: | 110 if ret < 0: |
| 102 self.Error('Failed to generate release %s.' % releasestr) | 111 self.Error('Failed to generate release %s.' % releasestr) |
| 103 else: | 112 else: |
| 104 InfoOut.Log('%s wrote %d files.' % (self.name, ret)) | 113 InfoOut.Log('%s wrote %d files.' % (self.name, ret)) |
| 105 | 114 |
| 106 else: | 115 else: |
| 107 self.Error('No range or release specified for %s.' % releasestr) | 116 self.Error('No range or release specified for %s.' % releasestr) |
| 108 return self.errors | 117 return self.errors |
| 109 | 118 |
| 110 def GenerateRelease(self, ast, release, options): | 119 def GenerateRelease(self, ast, release, options): |
| 111 __pychecker__ = 'unusednames=ast,release,options' | 120 __pychecker__ = 'unusednames=ast,release,options' |
| 112 self.Error("Undefined release generator.") | 121 self.Error("Undefined release generator.") |
| 113 return 0 | 122 return 0 |
| 114 | 123 |
| 115 def GenerateRange(self, ast, vmin, vmax, options): | 124 def GenerateRange(self, ast, releases, options): |
| 116 __pychecker__ = 'unusednames=ast,vmin,vmax,options' | 125 __pychecker__ = 'unusednames=ast,releases,options' |
| 117 self.Error("Undefined range generator.") | 126 self.Error("Undefined range generator.") |
| 118 return 0 | 127 return 0 |
| 119 | 128 |
| 120 @staticmethod | 129 @staticmethod |
| 121 def Run(ast): | 130 def Run(ast): |
| 122 fail_count = 0 | 131 fail_count = 0 |
| 123 | 132 |
| 124 # Check all registered generators if they should run. | 133 # Check all registered generators if they should run. |
| 125 for gen in GeneratorList: | 134 for gen in GeneratorList: |
| 126 options = gen.GetRunOptions() | 135 options = gen.GetRunOptions() |
| 127 if options is not None: | 136 if options is not None: |
| 128 if gen.Generate(ast, options): | 137 if gen.Generate(ast, options): |
| 129 fail_count += 1 | 138 fail_count += 1 |
| 130 return fail_count | 139 return fail_count |
| 131 | 140 |
| 132 | 141 |
| 133 # | 142 # |
| 134 # GeneratorByFile | 143 # GeneratorByFile |
| 135 # | 144 # |
| 136 # A subclass of Generator for use of generators which have a one to one | 145 # A subclass of Generator for use of generators which have a one to one |
| 137 # mapping between IDL sources and output files. To use, derive a new class | 146 # mapping between IDL sources and output files. To use, derive a new class |
| 138 # which defines: | 147 # which defines: |
| 139 # | 148 # |
| 140 # GetOutFile - Returns an IDLOutFile based on filenode (name) and options | 149 # GetOutFile - Returns an IDLOutFile based on filenode (name) and options |
| 141 # GenerateHead - Writes the first part of the file (includes, etc...) | 150 # GenerateHead - Writes the first part of the file (includes, etc...) |
| 142 # GenerateBody - Writes the body of the file (definitions) | 151 # GenerateBody - Writes the body of the file (definitions) |
| 143 # GenerateTail - Writes the end of the file (closing include guard, etc...) | 152 # GenerateTail - Writes the end of the file (closing include guard, etc...) |
| 144 # | 153 # |
| 145 class GeneratorByFile(Generator): | 154 class GeneratorByFile(Generator): |
| 155 def GenerateFile(self, filenode, releases, options): |
| 156 __pychecker__ = 'unusednames=filenode,releases,options' |
| 157 self.Error("Undefined release generator.") |
| 158 return 0 |
| 159 |
| 146 def GenerateRelease(self, ast, release, options): | 160 def GenerateRelease(self, ast, release, options): |
| 147 return self.GenerateRange(ast, [release], options) | 161 return self.GenerateRange(ast, [release], options) |
| 148 | 162 |
| 149 def GenerateRange(self, ast, releases, options): | 163 def GenerateRange(self, ast, releases, options): |
| 150 # Get list of out files | 164 # Get list of out files |
| 151 outlist = GetOption('out') | 165 outlist = GetOption('out') |
| 152 if outlist: outlist = outlist.split(',') | 166 if outlist: outlist = outlist.split(',') |
| 153 | 167 |
| 154 skipList = [] | 168 skipList = [] |
| 155 cnt = 0 | 169 cnt = 0 |
| 156 for filenode in ast.GetListOf('File'): | 170 for filenode in ast.GetListOf('File'): |
| 171 # Ignore files with errors |
| 172 if filenode in self.skip_list: |
| 173 continue |
| 174 |
| 157 # Skip this file if not required | 175 # Skip this file if not required |
| 158 if outlist and filenode.GetName() not in outlist: | 176 if outlist and filenode.GetName() not in outlist: |
| 159 continue | 177 continue |
| 160 | 178 |
| 161 # If this file has errors, skip it | 179 # Create the output file and increment out count if there was a delta |
| 162 if filenode.GetProperty('ERRORS') > 0: | 180 if self.GenerateFile(filenode, releases, options): |
| 163 skipList.append(filenode) | 181 cnt = cnt + 1 |
| 164 continue | |
| 165 | |
| 166 # Create output file | |
| 167 out = self.GetOutFile(filenode, options) | |
| 168 self.GenerateHead(out, filenode, releases, options) | |
| 169 self.GenerateBody(out, filenode, releases, options) | |
| 170 self.GenerateTail(out, filenode, releases, options) | |
| 171 | |
| 172 if out.Close(): cnt = cnt + 1 | |
| 173 | 182 |
| 174 for filenode in skipList: | 183 for filenode in skipList: |
| 175 errcnt = filenode.GetProperty('ERRORS') | 184 errcnt = filenode.GetProperty('ERRORS') |
| 176 ErrOut.Log('%s : Skipped because of %d errors.' % ( | 185 ErrOut.Log('%s : Skipped because of %d errors.' % ( |
| 177 filenode.GetName(), errcnt)) | 186 filenode.GetName(), errcnt)) |
| 178 | 187 |
| 179 if skipList: | 188 if skipList: |
| 180 return -len(skipList) | 189 return -len(skipList) |
| 181 | 190 |
| 182 if GetOption('diff'): | 191 if GetOption('diff'): |
| (...skipping 18 matching lines...) Expand all Loading... |
| 201 check_item = check_map[item] | 210 check_item = check_map[item] |
| 202 option_item = options.get(item, None) | 211 option_item = options.get(item, None) |
| 203 if check_item != option_item: | 212 if check_item != option_item: |
| 204 print 'Option %s is %s, expecting %s' % (item, option_item, check_item) | 213 print 'Option %s is %s, expecting %s' % (item, option_item, check_item) |
| 205 check_release = 0 | 214 check_release = 0 |
| 206 | 215 |
| 207 if release != 'M14': | 216 if release != 'M14': |
| 208 check_release = 0 | 217 check_release = 0 |
| 209 return check_release == 1 | 218 return check_release == 1 |
| 210 | 219 |
| 211 def GenerateRange(self, ast, vmin, vmax, options = {}): | 220 def GenerateRange(self, ast, releases, options): |
| 212 __pychecker__ = 'unusednames=ast,vmin,vmax,options' | 221 __pychecker__ = 'unusednames=ast,releases,options' |
| 213 global check_range | 222 global check_range |
| 214 check_range = 1 | 223 check_range = 1 |
| 215 return True | 224 return True |
| 216 | 225 |
| 217 def Test(): | 226 def Test(): |
| 218 __pychecker__ = 'unusednames=args' | 227 __pychecker__ = 'unusednames=args' |
| 219 global check_release | 228 global check_release |
| 220 global check_range | 229 global check_range |
| 221 | 230 |
| 222 ParseOptions(['--testgen_opt=so_long,MyOpt=XYZ,goodbye']) | 231 ParseOptions(['--testgen_opt=so_long,MyOpt=XYZ,goodbye']) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 237 if check_release != 0 or check_range != 1: | 246 if check_release != 0 or check_range != 1: |
| 238 print 'Gererate range: Failed to run.\n' | 247 print 'Gererate range: Failed to run.\n' |
| 239 return -1 | 248 return -1 |
| 240 | 249 |
| 241 print 'Generator test: Pass' | 250 print 'Generator test: Pass' |
| 242 return 0 | 251 return 0 |
| 243 | 252 |
| 244 | 253 |
| 245 def Main(args): | 254 def Main(args): |
| 246 if not args: return Test() | 255 if not args: return Test() |
| 247 | |
| 248 filenames = ParseOptions(args) | 256 filenames = ParseOptions(args) |
| 249 ast = ParseFiles(filenames) | 257 ast = ParseFiles(filenames) |
| 250 | 258 |
| 251 return Generator.Run(ast) | 259 return Generator.Run(ast) |
| 252 | 260 |
| 253 | 261 |
| 254 if __name__ == '__main__': | 262 if __name__ == '__main__': |
| 255 GeneratorReleaseTest('Test Gen', 'testgen', 'Generator Class Test.') | 263 GeneratorReleaseTest('Test Gen', 'testgen', 'Generator Class Test.') |
| 256 sys.exit(Main(sys.argv[1:])) | 264 sys.exit(Main(sys.argv[1:])) |
| 257 | 265 |
| OLD | NEW |