[DevTools] Various tweaks to inspector_protocol.

- allow importing all domains in single header;
- support for <includes.h>;
- separate export macro/header for lib, protocol and exported;
- improved code for defaults.

BUG=637032

Review-Url: https://codereview.chromium.org/2296043004
Cr-Original-Commit-Position: refs/heads/master@{#415753}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 9f0f2b6fa647284df16706073cd7b916ab9f6af3
diff --git a/CodeGenerator.py b/CodeGenerator.py
index 48c422a..97eda50 100644
--- a/CodeGenerator.py
+++ b/CodeGenerator.py
@@ -32,6 +32,21 @@
             return collections.namedtuple('X', keys)(*values)
         return json.loads(data, object_hook=json_object_hook)
 
+    def init_defaults(config_tuple, path, defaults):
+        keys = list(config_tuple._fields)  # pylint: disable=E1101
+        values = [getattr(config_tuple, k) for k in keys]
+        for i in xrange(len(keys)):
+            if hasattr(values[i], "_fields"):
+                values[i] = init_defaults(values[i], path + "." + keys[i], defaults)
+        for optional in defaults:
+            if optional.find(path + ".") != 0:
+                continue
+            optional_key = optional[len(path) + 1:]
+            if optional_key.find(".") == -1 and optional_key not in keys:
+                keys.append(optional_key)
+                values.append(defaults[optional])
+        return collections.namedtuple('X', keys)(*values)
+
     try:
         cmdline_parser = optparse.OptionParser()
         cmdline_parser.add_option("--output_base")
@@ -58,14 +73,23 @@
         config_json_file = open(config_file, "r")
         config_json_string = config_json_file.read()
         config_partial = json_to_object(config_json_string, output_base, config_base)
-        keys = list(config_partial._fields)  # pylint: disable=E1101
-        values = [getattr(config_partial, k) for k in keys]
-        for optional in ["imported", "exported", "lib"]:
-            if optional not in keys:
-                keys.append(optional)
-                values.append(False)
         config_json_file.close()
-        return (jinja_dir, config_file, collections.namedtuple('X', keys)(*values))
+        defaults = {
+            ".imported": False,
+            ".imported.export_macro": "",
+            ".imported.export_header": False,
+            ".imported.header": False,
+            ".imported.package": False,
+            ".protocol.export_macro": "",
+            ".protocol.export_header": False,
+            ".exported": False,
+            ".exported.export_macro": "",
+            ".exported.export_header": False,
+            ".lib": False,
+            ".lib.export_macro": "",
+            ".lib.export_header": False,
+        }
+        return (jinja_dir, config_file, init_defaults(config_partial, "", defaults))
     except Exception:
         # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html
         exc = sys.exc_info()[1]
@@ -320,6 +344,10 @@
     return False
 
 
+def format_include(header):
+    return "\"" + header + "\"" if header[0] not in "<\"" else header
+
+
 def read_protocol_file(file_name, json_api):
     input_file = open(file_name, "r")
     json_string = input_file.read()
@@ -391,7 +419,8 @@
             "join_arrays": join_arrays,
             "resolve_type": functools.partial(resolve_type, protocol),
             "type_definition": functools.partial(type_definition, protocol),
-            "has_disable": has_disable
+            "has_disable": has_disable,
+            "format_include": format_include,
         }
 
         if domain["domain"] in protocol.generate_domains:
@@ -404,7 +433,8 @@
 
     if config.lib:
         template_context = {
-            "config": config
+            "config": config,
+            "format_include": format_include,
         }
 
         lib_templates_dir = os.path.join(module_path, "lib")
diff --git a/lib/BackendCallback_h.template b/lib/BackendCallback_h.template
index ca1f118..3c8fc15 100644
--- a/lib/BackendCallback_h.template
+++ b/lib/BackendCallback_h.template
@@ -11,7 +11,7 @@
 namespace {{namespace}} {
 {% endfor %}
 
-class {{config.class_export.macro}} BackendCallback {
+class {{config.lib.export_macro}} BackendCallback {
 public:
     virtual ~BackendCallback() { }
     virtual void sendFailure(const ErrorString&) = 0;
diff --git a/lib/DispatcherBase_h.template b/lib/DispatcherBase_h.template
index 0c76933..17fd870 100644
--- a/lib/DispatcherBase_h.template
+++ b/lib/DispatcherBase_h.template
@@ -17,11 +17,11 @@
 
 class WeakPtr;
 
-class {{config.class_export.macro}} DispatcherBase {
+class {{config.lib.export_macro}} DispatcherBase {
     PROTOCOL_DISALLOW_COPY(DispatcherBase);
 public:
     static const char kInvalidRequest[];
-    class {{config.class_export.macro}} WeakPtr {
+    class {{config.lib.export_macro}} WeakPtr {
     public:
         explicit WeakPtr(DispatcherBase*);
         ~WeakPtr();
@@ -32,7 +32,7 @@
         DispatcherBase* m_dispatcher;
     };
 
-    class {{config.class_export.macro}} Callback : public protocol::BackendCallback {
+    class {{config.lib.export_macro}} Callback : public protocol::BackendCallback {
     public:
         Callback(std::unique_ptr<WeakPtr> backendImpl, int callId);
         virtual ~Callback();
@@ -76,7 +76,7 @@
     protocol::HashSet<WeakPtr*> m_weakPtrs;
 };
 
-class {{config.class_export.macro}} UberDispatcher {
+class {{config.lib.export_macro}} UberDispatcher {
     PROTOCOL_DISALLOW_COPY(UberDispatcher);
 public:
     explicit UberDispatcher(FrontendChannel*);
diff --git a/lib/ErrorSupport_h.template b/lib/ErrorSupport_h.template
index ac4783e..9d2a192 100644
--- a/lib/ErrorSupport_h.template
+++ b/lib/ErrorSupport_h.template
@@ -11,7 +11,7 @@
 namespace {{namespace}} {
 {% endfor %}
 
-class {{config.class_export.macro}} ErrorSupport {
+class {{config.lib.export_macro}} ErrorSupport {
 public:
     ErrorSupport();
     ErrorSupport(String* errorString);
diff --git a/lib/Forward_h.template b/lib/Forward_h.template
index b1b1f8b..2ad3897 100644
--- a/lib/Forward_h.template
+++ b/lib/Forward_h.template
@@ -5,9 +5,11 @@
 #ifndef {{"_".join(config.protocol.namespace)}}_Forward_h
 #define {{"_".join(config.protocol.namespace)}}_Forward_h
 
-#include "{{config.class_export.header}}"
-#include "{{config.lib.platform_header}}"
-#include "{{config.lib.string_header}}"
+{% if config.lib.export_header %}
+#include {{format_include(config.lib.export_header)}}
+{% endif %}
+#include {{format_include(config.lib.platform_header)}}
+#include {{format_include(config.lib.string_header)}}
 
 #include <vector>
 
diff --git a/lib/FrontendChannel_h.template b/lib/FrontendChannel_h.template
index 64701e6..8b653b5 100644
--- a/lib/FrontendChannel_h.template
+++ b/lib/FrontendChannel_h.template
@@ -9,7 +9,7 @@
 namespace {{namespace}} {
 {% endfor %}
 
-class {{config.class_export.macro}} FrontendChannel {
+class {{config.lib.export_macro}} FrontendChannel {
 public:
     virtual ~FrontendChannel() { }
     virtual void sendProtocolResponse(int callId, const String& message) = 0;
diff --git a/lib/Object_h.template b/lib/Object_h.template
index 611b794..4ccd88b 100644
--- a/lib/Object_h.template
+++ b/lib/Object_h.template
@@ -13,7 +13,7 @@
 namespace {{namespace}} {
 {% endfor %}
 
-class {{config.class_export.macro}} Object {
+class {{config.lib.export_macro}} Object {
 public:
     static std::unique_ptr<Object> parse(protocol::Value*, ErrorSupport*);
     ~Object();
diff --git a/lib/Parser_h.template b/lib/Parser_h.template
index 5172438..7b2a29b 100644
--- a/lib/Parser_h.template
+++ b/lib/Parser_h.template
@@ -12,8 +12,8 @@
 namespace {{namespace}} {
 {% endfor %}
 
-{{config.class_export.macro}} std::unique_ptr<Value> parseJSON(const uint8_t*, unsigned);
-{{config.class_export.macro}} std::unique_ptr<Value> parseJSON(const uint16_t*, unsigned);
+{{config.lib.export_macro}} std::unique_ptr<Value> parseJSON(const uint8_t*, unsigned);
+{{config.lib.export_macro}} std::unique_ptr<Value> parseJSON(const uint16_t*, unsigned);
 
 {% for namespace in config.protocol.namespace %}
 } // namespace {{namespace}}
diff --git a/lib/Values_h.template b/lib/Values_h.template
index 9199ab2..8f75ef2 100644
--- a/lib/Values_h.template
+++ b/lib/Values_h.template
@@ -17,7 +17,7 @@
 class DictionaryValue;
 class Value;
 
-class {{config.class_export.macro}} Value {
+class {{config.lib.export_macro}} Value {
     PROTOCOL_DISALLOW_COPY(Value);
 public:
     virtual ~Value() { }
@@ -63,7 +63,7 @@
     ValueType m_type;
 };
 
-class {{config.class_export.macro}} FundamentalValue : public Value {
+class {{config.lib.export_macro}} FundamentalValue : public Value {
 public:
     static std::unique_ptr<FundamentalValue> create(bool value)
     {
@@ -98,7 +98,7 @@
     };
 };
 
-class {{config.class_export.macro}} StringValue : public Value {
+class {{config.lib.export_macro}} StringValue : public Value {
 public:
     static std::unique_ptr<StringValue> create(const String& value)
     {
@@ -121,7 +121,7 @@
     String m_stringValue;
 };
 
-class {{config.class_export.macro}} SerializedValue : public Value {
+class {{config.lib.export_macro}} SerializedValue : public Value {
 public:
     static std::unique_ptr<SerializedValue> create(const String& value)
     {
@@ -138,7 +138,7 @@
     String m_serializedValue;
 };
 
-class {{config.class_export.macro}} DictionaryValue : public Value {
+class {{config.lib.export_macro}} DictionaryValue : public Value {
 public:
     using Entry = std::pair<String, Value*>;
     static std::unique_ptr<DictionaryValue> create()
@@ -205,7 +205,7 @@
     std::vector<String> m_order;
 };
 
-class {{config.class_export.macro}} ListValue : public Value {
+class {{config.lib.export_macro}} ListValue : public Value {
 public:
     static std::unique_ptr<ListValue> create()
     {
diff --git a/sample_config.json b/sample_config.json
index f21398d..82d7845 100644
--- a/sample_config.json
+++ b/sample_config.json
@@ -3,7 +3,9 @@
         "path": "./relative/path/protocol/sample_protocol.json",
         "package": "include/generated/files/like/this",
         "output": "place/generated/files/here",
-        "namespace": ["sample_project", "protocol"]
+        "namespace": ["sample_project", "protocol"],
+        "export_macro": "LIB_EXPORT",
+        "export_header": "lib/lib_export.h"
     },
 
     "exported": {
@@ -12,12 +14,15 @@
         "string_header": "include/exported/string.h",
         "string_in": "String",
         "string_out": "String",
-        "to_string_out": "toString(%s)"
+        "to_string_out": "toString(%s)",
+        "export_macro": "LIB_EXPORT",
+        "export_header": "lib/lib_export.h"
     },
 
     "imported": {
         "path": "../relative/path/imported_protocol.json",
-        "package": "include/imported/files/like/this",
+        "package": "either/include/imported/files/from/here",
+        "header": "or/include/them/all/together/like/this/imported_protocol.h",
         "to_imported_string": "toImportedString(%s)",
         "from_imported_string": "fromImportedString(%s)",
         "namespace": ["imported_project", "protocol"]
@@ -27,11 +32,8 @@
         "package": "include/lib/files/like/this",
         "output": "place/generated/lib/files/here",
         "string_header": "string/implementation.h",
-        "platform_header": "platform/implementation.h"
-    },
-
-    "class_export": {
-        "macro": "LIB_EXPORT",
-        "header": "lib/lib_export.h"
+        "platform_header": "platform/implementation.h",
+        "export_macro": "LIB_EXPORT",
+        "export_header": "lib/lib_export.h"
     }
 }
diff --git a/templates/Exported_h.template b/templates/Exported_h.template
index d0c76d8..3357f95 100644
--- a/templates/Exported_h.template
+++ b/templates/Exported_h.template
@@ -7,8 +7,10 @@
 #ifndef {{"_".join(config.protocol.namespace)}}_{{domain.domain}}_api_h
 #define {{"_".join(config.protocol.namespace)}}_{{domain.domain}}_api_h
 
-#include "{{config.class_export.header}}"
-#include "{{config.exported.string_header}}"
+{% if config.exported.export_header %}
+#include {{format_include(config.exported.export_header)}}
+{% endif %}
+#include {{format_include(config.exported.string_header)}}
 
 {% for namespace in config.protocol.namespace %}
 namespace {{namespace}} {
@@ -22,7 +24,7 @@
 
 namespace {{type.id}}Enum {
       {% for literal in type.enum %}
-{{config.class_export.macro}} extern const char* {{ literal | dash_to_camelcase}};
+{{config.exported.export_macro}} extern const char* {{ literal | dash_to_camelcase}};
       {% endfor %}
 } // {{type.id}}Enum
     {% endif %}
@@ -34,7 +36,7 @@
 namespace {{command.name | to_title_case}} {
 namespace {{param.name | to_title_case}}Enum {
         {% for literal in param.enum %}
-{{config.class_export.macro}} extern const char* {{ literal | dash_to_camelcase}};
+{{config.exported.export_macro}} extern const char* {{ literal | dash_to_camelcase}};
         {% endfor %}
 } // {{param.name | to_title_case}}Enum
 } // {{command.name | to_title_case }}
@@ -46,7 +48,7 @@
   {% for type in domain.types %}
     {% if not (type.type == "object") or not ("properties" in type) or not (type.exported) %}{% continue %}{% endif %}
 
-class {{config.class_export.macro}} {{type.id}} {
+class {{config.exported.export_macro}} {{type.id}} {
 public:
     virtual {{config.exported.string_out}} toJSONString() const = 0;
     virtual ~{{type.id}}() { }
diff --git a/templates/Imported_h.template b/templates/Imported_h.template
index afd9ce7..c23b8fe 100644
--- a/templates/Imported_h.template
+++ b/templates/Imported_h.template
@@ -8,7 +8,7 @@
 #define {{"_".join(config.protocol.namespace)}}_{{domain.domain}}_imported_h
 
 #include "{{config.protocol.package}}/Protocol.h"
-#include "{{config.imported.package}}/{{domain.domain}}.h"
+#include {{format_include(config.imported.header if config.imported.header else "\"%s/%s.h\"" % (config.imported.package, domain.domain))}}
 
 {% for namespace in config.protocol.namespace %}
 namespace {{namespace}} {
diff --git a/templates/TypeBuilder_h.template b/templates/TypeBuilder_h.template
index e0d782d..b72cdf2 100644
--- a/templates/TypeBuilder_h.template
+++ b/templates/TypeBuilder_h.template
@@ -7,7 +7,9 @@
 #ifndef {{"_".join(config.protocol.namespace)}}_{{domain.domain}}_h
 #define {{"_".join(config.protocol.namespace)}}_{{domain.domain}}_h
 
-#include "{{config.class_export.header}}"
+{% if config.protocol.export_header %}
+#include {{format_include(config.protocol.export_header)}}
+{% endif %}
 #include "{{config.protocol.package}}/Protocol.h"
 // For each imported domain we generate a ValueConversions struct instead of a full domain definition
 // and include Domain::API version from there.
@@ -43,7 +45,7 @@
 
 namespace {{type.id}}Enum {
       {% for literal in type.enum %}
-{{config.class_export.macro}} extern const char* {{ literal | dash_to_camelcase}};
+{{config.protocol.export_macro}} extern const char* {{ literal | dash_to_camelcase}};
       {% endfor %}
 } // namespace {{type.id}}Enum
     {% endif %}
@@ -55,7 +57,7 @@
 namespace {{command.name | to_title_case}} {
 namespace {{param.name | to_title_case}}Enum {
         {% for literal in param.enum %}
-{{config.class_export.macro}} extern const char* {{literal | dash_to_camelcase}};
+{{config.protocol.export_macro}} extern const char* {{literal | dash_to_camelcase}};
         {% endfor %}
 } // {{param.name | to_title_case}}Enum
 } // {{command.name | to_title_case }}
@@ -69,7 +71,7 @@
     {% set type_def = type_definition(domain.domain + "." + type.id)%}
 
 // {{type.description}}
-class {{config.class_export.macro}} {{type.id}} {% if type.exported %}: public API::{{type.id}} {% endif %}{
+class {{config.protocol.export_macro}} {{type.id}} {% if type.exported %}: public API::{{type.id}} {% endif %}{
     PROTOCOL_DISALLOW_COPY({{type.id}});
 public:
     static std::unique_ptr<{{type.id}}> parse(protocol::Value* value, ErrorSupport* errors);
@@ -78,7 +80,7 @@
     {% for property in type.properties %}
       {% if "enum" in property %}
 
-    struct {{config.class_export.macro}} {{property.name | to_title_case}}Enum {
+    struct {{config.protocol.export_macro}} {{property.name | to_title_case}}Enum {
         {% for literal in property.enum %}
         static const char* {{literal | dash_to_camelcase}};
         {% endfor %}
@@ -181,13 +183,13 @@
 
 // ------------- Backend interface.
 
-class {{config.class_export.macro}} Backend {
+class {{config.protocol.export_macro}} Backend {
 public:
   {% for command in domain.commands %}
     {% if "redirect" in command %}{% continue %}{% endif %}
     {% if ("handlers" in command) and not ("renderer" in command["handlers"]) %}{% continue %}{% endif %}
     {% if "async" in command %}
-    class {{config.class_export.macro}} {{command.name | to_title_case}}Callback : public BackendCallback {
+    class {{config.protocol.export_macro}} {{command.name | to_title_case}}Callback : public BackendCallback {
     public:
         virtual void sendSuccess(
             {%- for parameter in command.returns -%}
@@ -238,7 +240,7 @@
 
 // ------------- Frontend interface.
 
-class {{config.class_export.macro}} Frontend {
+class {{config.protocol.export_macro}} Frontend {
 public:
     Frontend(FrontendChannel* frontendChannel) : m_frontendChannel(frontendChannel) { }
   {% for event in domain.events %}
@@ -261,7 +263,7 @@
 
 // ------------- Dispatcher.
 
-class {{config.class_export.macro}} Dispatcher {
+class {{config.protocol.export_macro}} Dispatcher {
 public:
     static void wire(UberDispatcher*, Backend*);
 
@@ -271,7 +273,7 @@
 
 // ------------- Metainfo.
 
-class {{config.class_export.macro}} Metainfo {
+class {{config.protocol.export_macro}} Metainfo {
 public:
     using BackendClass = Backend;
     using FrontendClass = Frontend;