OLD | NEW |
1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import argparse | 5 import argparse |
6 import copy | 6 import copy |
7 from datetime import datetime | 7 from datetime import datetime |
8 import os | 8 import os |
9 | 9 |
10 from code import Code | 10 from code import Code |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
47 // Use of this source code is governed by a BSD-style license that can be | 47 // Use of this source code is governed by a BSD-style license that can be |
48 // found in the LICENSE file. | 48 // found in the LICENSE file. |
49 | 49 |
50 // GENERATED FROM THE FEATURES FILE: | 50 // GENERATED FROM THE FEATURES FILE: |
51 // %(source_files)s | 51 // %(source_files)s |
52 // DO NOT EDIT. | 52 // DO NOT EDIT. |
53 | 53 |
54 #include "%(header_file_path)s" | 54 #include "%(header_file_path)s" |
55 | 55 |
56 #include "extensions/common/features/api_feature.h" | 56 #include "extensions/common/features/api_feature.h" |
| 57 #include "extensions/common/features/behavior_feature.h" |
57 #include "extensions/common/features/complex_feature.h" | 58 #include "extensions/common/features/complex_feature.h" |
| 59 #include "extensions/common/features/manifest_feature.h" |
| 60 #include "extensions/common/features/permission_feature.h" |
58 | 61 |
59 namespace extensions { | 62 namespace extensions { |
60 | 63 |
61 """ | 64 """ |
62 | 65 |
63 # The end of the .cc file for the generated FeatureProvider. | 66 # The end of the .cc file for the generated FeatureProvider. |
64 CC_FILE_END = """ | 67 CC_FILE_END = """ |
65 %(provider_class)s::~%(provider_class)s() {} | 68 %(provider_class)s::~%(provider_class)s() {} |
66 | 69 |
67 } // namespace extensions | 70 } // namespace extensions |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 } | 188 } |
186 } | 189 } |
187 }, | 190 }, |
188 'whitelist': { | 191 'whitelist': { |
189 list: {'subtype': unicode} | 192 list: {'subtype': unicode} |
190 }, | 193 }, |
191 }) | 194 }) |
192 | 195 |
193 # These keys are used to find the parents of different features, but are not | 196 # These keys are used to find the parents of different features, but are not |
194 # compiled into the features themselves. | 197 # compiled into the features themselves. |
195 IGNORED_KEYS = ['noparent', 'default_parent'] | 198 IGNORED_KEYS = ['default_parent'] |
196 | 199 |
197 # By default, if an error is encountered, assert to stop the compilation. This | 200 # By default, if an error is encountered, assert to stop the compilation. This |
198 # can be disabled for testing. | 201 # can be disabled for testing. |
199 ENABLE_ASSERTIONS = True | 202 ENABLE_ASSERTIONS = True |
200 | 203 |
201 # JSON parsing returns all strings of characters as unicode types. For testing, | 204 # JSON parsing returns all strings of characters as unicode types. For testing, |
202 # we can enable converting all string types to unicode to avoid writing u'' | 205 # we can enable converting all string types to unicode to avoid writing u'' |
203 # everywhere. | 206 # everywhere. |
204 STRINGS_TO_UNICODE = False | 207 STRINGS_TO_UNICODE = False |
205 | 208 |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
323 if cpp_sub_value: | 326 if cpp_sub_value: |
324 cpp_value.append(cpp_sub_value) | 327 cpp_value.append(cpp_sub_value) |
325 if cpp_value: | 328 if cpp_value: |
326 cpp_value = '{' + ','.join(cpp_value) + '}' | 329 cpp_value = '{' + ','.join(cpp_value) + '}' |
327 else: | 330 else: |
328 cpp_value = self._GetCheckedValue(key, expected_type, expected_values, | 331 cpp_value = self._GetCheckedValue(key, expected_type, expected_values, |
329 enum_map, v) | 332 enum_map, v) |
330 | 333 |
331 if cpp_value: | 334 if cpp_value: |
332 self.feature_values[key] = cpp_value | 335 self.feature_values[key] = cpp_value |
| 336 elif key in self.feature_values: |
| 337 # If the key is empty and this feature inherited a value from its parent, |
| 338 # remove the inherited value. |
| 339 del self.feature_values[key] |
333 | 340 |
334 def SetParent(self, parent): | 341 def SetParent(self, parent): |
335 """Sets the parent of this feature, and inherits all properties from that | 342 """Sets the parent of this feature, and inherits all properties from that |
336 parent. | 343 parent. |
337 """ | 344 """ |
338 assert not self.feature_values, 'Parents must be set before parsing' | 345 assert not self.feature_values, 'Parents must be set before parsing' |
339 self.feature_values = copy.deepcopy(parent.feature_values) | 346 self.feature_values = copy.deepcopy(parent.feature_values) |
340 self.has_parent = True | 347 self.has_parent = True |
341 | 348 |
342 def Parse(self, parsed_json): | 349 def Parse(self, parsed_json): |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 print('FAILED: Exception encountered while loading "%s"' % | 396 print('FAILED: Exception encountered while loading "%s"' % |
390 abs_source_file) | 397 abs_source_file) |
391 raise | 398 raise |
392 dupes = set(f_json) & set(self._json) | 399 dupes = set(f_json) & set(self._json) |
393 assert not dupes, 'Duplicate keys found: %s' % list(dupes) | 400 assert not dupes, 'Duplicate keys found: %s' % list(dupes) |
394 self._json.update(f_json) | 401 self._json.update(f_json) |
395 | 402 |
396 def _FindParent(self, feature_name, feature_value): | 403 def _FindParent(self, feature_name, feature_value): |
397 """Checks to see if a feature has a parent. If it does, returns the | 404 """Checks to see if a feature has a parent. If it does, returns the |
398 parent.""" | 405 parent.""" |
| 406 no_parent = False |
| 407 if type(feature_value) is list: |
| 408 no_parent_values = ['noparent' in v for v in feature_value] |
| 409 no_parent = all(no_parent_values) |
| 410 assert no_parent or not any(no_parent_values), ( |
| 411 '"%s:" All child features must contain the same noparent value' % |
| 412 feature_name) |
| 413 else: |
| 414 no_parent = 'noparent' in feature_value |
399 sep = feature_name.rfind('.') | 415 sep = feature_name.rfind('.') |
400 if sep is -1 or 'noparent' in feature_value: | 416 if sep is -1 or no_parent: |
401 return None | 417 return None |
402 parent_name = feature_name[:sep] | 418 parent_name = feature_name[:sep] |
403 if parent_name not in self._features: | 419 if parent_name not in self._features: |
404 # TODO(devlin): It'd be kind of nice to be able to assert that the | 420 # TODO(devlin): It'd be kind of nice to be able to assert that the |
405 # deduced parent name is in our features, but some dotted features don't | 421 # deduced parent name is in our features, but some dotted features don't |
406 # have parents and also don't have noparent, e.g. system.cpu. We should | 422 # have parents and also don't have noparent, e.g. system.cpu. We should |
407 # probably just noparent them so that we can assert this. | 423 # probably just noparent them so that we can assert this. |
408 # raise KeyError('Could not find parent "%s" for feature "%s".' % | 424 # raise KeyError('Could not find parent "%s" for feature "%s".' % |
409 # (parent_name, feature_name)) | 425 # (parent_name, feature_name)) |
410 return None | 426 return None |
(...skipping 13 matching lines...) Expand all Loading... |
424 assert feature_value['nocompile'], ( | 440 assert feature_value['nocompile'], ( |
425 'nocompile should only be true; otherwise omit this key.') | 441 'nocompile should only be true; otherwise omit this key.') |
426 return | 442 return |
427 parent = self._FindParent(feature_name, feature_value) | 443 parent = self._FindParent(feature_name, feature_value) |
428 # Handle complex features, which are lists of simple features. | 444 # Handle complex features, which are lists of simple features. |
429 if type(feature_value) is list: | 445 if type(feature_value) is list: |
430 feature_list = [] | 446 feature_list = [] |
431 # This doesn't handle nested complex features. I think that's probably for | 447 # This doesn't handle nested complex features. I think that's probably for |
432 # the best. | 448 # the best. |
433 for v in feature_value: | 449 for v in feature_value: |
434 feature = Feature(feature_name) | 450 try: |
435 if parent: | 451 feature = Feature(feature_name) |
436 feature.SetParent(parent) | 452 if parent: |
437 feature.Parse(v) | 453 feature.SetParent(parent) |
438 feature_list.append(feature) | 454 feature.Parse(v) |
| 455 feature_list.append(feature) |
| 456 except: |
| 457 print('Failure to parse feature "%s"' % feature_name) |
| 458 raise |
439 self._features[feature_name] = feature_list | 459 self._features[feature_name] = feature_list |
440 return | 460 return |
441 | 461 |
442 feature = Feature(feature_name) | 462 try: |
443 if parent: | 463 feature = Feature(feature_name) |
444 feature.SetParent(parent) | 464 if parent: |
445 feature.Parse(feature_value) | 465 feature.SetParent(parent) |
446 self._features[feature_name] = feature | 466 feature.Parse(feature_value) |
| 467 self._features[feature_name] = feature |
| 468 except: |
| 469 print('Failure to parse feature "%s"' % feature_name) |
| 470 raise |
447 | 471 |
448 def Compile(self): | 472 def Compile(self): |
449 """Parses all features after loading the input files.""" | 473 """Parses all features after loading the input files.""" |
450 self._Load(); | 474 self._Load(); |
451 # Iterate over in sorted order so that parents come first. | 475 # Iterate over in sorted order so that parents come first. |
452 for k in sorted(self._json.keys()): | 476 for k in sorted(self._json.keys()): |
453 self._CompileFeature(k, self._json[k]) | 477 self._CompileFeature(k, self._json[k]) |
454 | 478 |
455 def Render(self): | 479 def Render(self): |
456 """Returns the Code object for the body of the .cc file, which handles the | 480 """Returns the Code object for the body of the .cc file, which handles the |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 'out_base_filename', type=str, | 551 'out_base_filename', type=str, |
528 help='The base filename for the C++ files (.h and .cc will be appended)') | 552 help='The base filename for the C++ files (.h and .cc will be appended)') |
529 parser.add_argument('source_files', type=str, nargs='+', | 553 parser.add_argument('source_files', type=str, nargs='+', |
530 help='The source features.json files') | 554 help='The source features.json files') |
531 args = parser.parse_args() | 555 args = parser.parse_args() |
532 c = FeatureCompiler(args.chrome_root, args.source_files, args.feature_class, | 556 c = FeatureCompiler(args.chrome_root, args.source_files, args.feature_class, |
533 args.provider_class, args.out_root, | 557 args.provider_class, args.out_root, |
534 args.out_base_filename) | 558 args.out_base_filename) |
535 c.Compile() | 559 c.Compile() |
536 c.Write() | 560 c.Write() |
OLD | NEW |