1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#!/usr/bin/env python
2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# found in the LICENSE file.
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)"""Generator for C++ features from json files.
6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Usage example:
8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  features_compiler.py --destdir gen --root /home/Work/src _permissions.json
9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)"""
10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import optparse
12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import os
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)from schema_loader import SchemaLoader
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)from features_cc_generator import CCGenerator
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)from features_h_generator import HGenerator
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)from model import CreateFeature
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)def _GenerateSchema(filename, root, destdir, namespace):
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  """Generates C++ features files from the json file |filename|.
22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  """
23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  # Load in the feature permissions from the JSON file.
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  schema = os.path.normpath(filename)
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  schema_loader = SchemaLoader(os.path.dirname(os.path.relpath(schema, root)),
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    os.path.dirname(schema))
27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  schema_filename = os.path.splitext(schema)[0]
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  feature_defs = schema_loader.LoadSchema(schema)
29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  # Generate a list of the features defined and a list of their models.
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  feature_list = []
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for feature_def, feature in feature_defs.iteritems():
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    feature_list.append(CreateFeature(feature_def, feature))
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  source_file_dir, _ = os.path.split(schema)
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  relpath = os.path.relpath(os.path.normpath(source_file_dir), root)
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  full_path = os.path.join(relpath, schema)
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  generators = [
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ('%s.cc' % schema_filename, CCGenerator()),
41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ('%s.h' % schema_filename, HGenerator())
42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ]
43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  # Generate and output the code for all features.
45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  output_code = []
46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for filename, generator in generators:
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    code = generator.Generate(feature_list, full_path, namespace).Render()
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if destdir:
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      with open(os.path.join(destdir, relpath, filename), 'w') as f:
50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        f.write(code)
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    output_code += [filename, '', code, '']
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return '\n'.join(output_code)
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)if __name__ == '__main__':
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  parser = optparse.OptionParser(
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      description='Generates a C++ features model from JSON schema',
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      usage='usage: %prog [option]... schema')
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  parser.add_option('-r', '--root', default='.',
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      help='logical include root directory. Path to schema files from '
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)           'specified dir will be the include path.')
63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  parser.add_option('-d', '--destdir',
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      help='root directory to output generated files.')
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  parser.add_option('-n', '--namespace', default='generated_features',
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      help='C++ namespace for generated files. e.g extensions::api.')
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  (opts, filenames) = parser.parse_args()
68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  # Only one file is currently specified.
70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if len(filenames) != 1:
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    raise ValueError('One (and only one) file is required (for now).')
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  result = _GenerateSchema(filenames[0], opts.root, opts.destdir,
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           opts.namespace)
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if not opts.destdir:
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    print result
77