devtools_protocol_constants_generator.py revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1#!/usr/bin/python
2# Copyright 2014 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import sys
7import string
8import json
9
10package = sys.argv[1]
11output_cc_path = sys.argv[2]
12output_h_path = sys.argv[3]
13blink_protocol_path = sys.argv[4]
14browser_protocol_path = sys.argv[5] if len(sys.argv) > 5 else None
15
16template_h = string.Template("""\
17// Copyright 2013 The Chromium Authors. All rights reserved.
18// Use of this source code is governed by a BSD-style license that can be
19// found in the LICENSE file.
20
21#ifndef ${PACKAGE}_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTS_H_
22#define ${PACKAGE}_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTS_H_
23
24// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
25// Generated by
26//  content/public/browser/devtools_protocol_constants_generator.py from
27//  third_party/WebKit/Source/devtools/protocol.json and
28//  content/browser/devtools/browser_protocol.json
29
30#include <string>
31
32namespace $package {
33namespace devtools {
34
35extern const char kProtocolVersion[];
36
37bool IsSupportedProtocolVersion(const std::string& version);
38
39extern const char kResult[];
40$contents
41
42}  // devtools
43}  // $package
44
45#endif  // ${PACKAGE}_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTS_H_
46""")
47
48template_cc = string.Template("""\
49// Copyright 2013 The Chromium Authors. All rights reserved.
50// Use of this source code is governed by a BSD-style license that can be
51// found in the LICENSE file.
52
53// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
54// Generated by
55//  content/public/browser/devtools_protocol_constants_generator.py from
56//  third_party/WebKit/Source/devtools/protocol.json and
57//  content/browser/devtools/browser_protocol.json
58
59#include "base/strings/string_number_conversions.h"
60#include "base/strings/string_util.h"
61#include "$package/browser/devtools/devtools_protocol_constants.h"
62
63namespace $package {
64namespace devtools {
65
66const char kProtocolVersion[] = "$major.$minor";
67
68bool IsSupportedProtocolVersion(const std::string& version) {
69  std::vector<std::string> tokens;
70  Tokenize(version, ".", &tokens);
71  int major, minor;
72  return tokens.size() == 2 &&
73      base::StringToInt(tokens[0], &major) && major == $major &&
74      base::StringToInt(tokens[1], &minor) && minor <= $minor;
75}
76
77const char kResult[] = "result";
78$contents
79
80}  // devtools
81}  // $package
82""")
83
84def Capitalize(s):
85  return s[:1].capitalize() + s[1:]
86
87references = []
88
89def CreateNamespace(domain_name, data, keys, prefixes, name = None):
90  result = {}
91  if name:
92    result["kName"] = name
93  for i, key in enumerate(keys):
94    if key in data:
95      for parameter in data[key]:
96        parameter_name = parameter["name"];
97        result[prefixes[i] + Capitalize(parameter_name)] = parameter_name
98        if "enum" in parameter:
99          enum_name = Capitalize(parameter_name)
100          result[enum_name] = {}
101          for enum in parameter["enum"]:
102            result[enum_name]["kEnum" + Capitalize(enum)] = enum
103        reference = ""
104        if "$ref" in parameter:
105          reference = parameter["$ref"]
106        if "items" in parameter and "$ref" in parameter["items"]:
107          reference = parameter["items"]["$ref"]
108        if reference:
109          if not "." in reference:
110            reference = domain_name + "." + reference
111          references.append(reference)
112  return result
113
114def IsHandledInBrowser(item):
115  return "handlers" in item and "browser" in item["handlers"]
116
117def FormatContents(tree, indent, format_string):
118  outer = dict((key, value) for key, value in tree.iteritems()
119                if not isinstance(value, dict))
120  inner = dict((key, value) for key, value in tree.iteritems()
121              if isinstance(value, dict))
122  body = ""
123  body += "".join(indent + format_string.format(key, value)
124                 for (key, value) in sorted(outer.items()))
125  body += "".join(FormatNamespace(key, value, indent, format_string)
126                 for (key, value) in sorted(inner.items()))
127  return body
128
129def FormatNamespace(title, tree, indent, format_string):
130  if (not tree):
131    return ""
132  body = '\n' + indent + "namespace " + title + " {\n"
133  body += FormatContents(tree, indent + "  ", format_string)
134  body += indent + "} // " + title + "\n"
135  return body
136
137def CreateHeader(tree, output_file):
138  contents = FormatContents(tree, "", "extern const char {0}[];\n")
139  output_file.write(template_h.substitute({
140      "contents": contents,
141      "package": package,
142      "PACKAGE": package.upper()
143  }))
144
145def CreateBody(tree, version, output_file):
146  contents = FormatContents(tree, "", "const char {0}[] = \"{1}\";\n")
147  output_file.write(template_cc.substitute({
148      "major": version["major"],
149      "minor": version["minor"],
150      "contents": contents,
151      "package": package
152  }))
153
154blink_protocol_data = open(blink_protocol_path).read()
155blink_protocol = json.loads(blink_protocol_data)
156blink_version = blink_protocol["version"]
157
158domains = blink_protocol["domains"]
159
160if browser_protocol_path:
161  browser_protocol_data = open(browser_protocol_path).read()
162  browser_protocol = json.loads(browser_protocol_data)
163  domains = domains + browser_protocol["domains"]
164
165namespace_tree = {}
166
167for domain in domains:
168  domain_value = {}
169  domain_namespace_name = Capitalize(domain["domain"])
170  if "commands" in domain:
171    for command in domain["commands"]:
172      if (IsHandledInBrowser(command)):
173        domain_value[command["name"]] = CreateNamespace(domain["domain"],
174            command, ["parameters", "returns"], ["kParam", "kResponse"],
175            domain_namespace_name + "." + command["name"])
176
177  if "events" in domain:
178    for event in domain["events"]:
179      if IsHandledInBrowser(event):
180        domain_value[event["name"]] = CreateNamespace(domain["domain"],
181            event, ["parameters"], ["kParam"],
182            domain_namespace_name + "." + event["name"])
183  if domain_value:
184    namespace_tree[domain_namespace_name] = domain_value
185
186while (references):
187  reference = references.pop();
188  path = reference.split(".");
189  parent_namespace = namespace_tree;
190  for path_segment in path[0:-1]:
191    if path_segment not in parent_namespace:
192      parent_namespace[path_segment] = {}
193    parent_namespace = parent_namespace[path_segment]
194  if (path[-1] not in parent_namespace):
195    try:
196      domain = [d for d in domains if d["domain"] == path[0]][0]
197      ref_type = [t for t in domain["types"] if t["id"] == path[1]][0]
198      parent_namespace[ref_type["id"]] = CreateNamespace(path[0],
199          ref_type, ["properties"], ["kParam"])
200    except IndexError:
201      sys.stderr.write("Failed to resolve type [{0}].\n".format(reference))
202      sys.exit(1)
203
204for (namespace_name, namespace) in namespace_tree.items():
205  namespace["kName"] = namespace_name
206
207with open(output_cc_path, "w") as f:
208  CreateBody(namespace_tree, blink_version, f)
209
210with open(output_h_path, "w") as f:
211  CreateHeader(namespace_tree, f)
212