159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn#!/usr/bin/python2
259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
33daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi#
43daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi# Copyright (C) 2015 The Android Open Source Project
53daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi#
63daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi# Licensed under the Apache License, Version 2.0 (the "License");
73daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi# you may not use this file except in compliance with the License.
83daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi# You may obtain a copy of the License at
93daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi#
103daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi#      http://www.apache.org/licenses/LICENSE-2.0
113daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi#
123daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi# Unless required by applicable law or agreed to in writing, software
133daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi# distributed under the License is distributed on an "AS IS" BASIS,
143daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
153daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi# See the License for the specific language governing permissions and
163daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi# limitations under the License.
173daa5a0d71ba8facd8be9370df54c20c23be6d8dUtkarsh Sanghi#
1859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
1959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn"""A C++ code generator for printing protobufs which use the LITE_RUNTIME.
2059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
2159ea81cf9e7b293ec3241e5d442092b0278a3643Darren KrahnNormally printing a protobuf would be done with Message::DebugString(). However,
2259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnthis is not available when using only MessageLite. This script generates code to
2359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnemulate Message::DebugString() without using reflection. The input must be a
2459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnvalid .proto file.
2559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
2659ea81cf9e7b293ec3241e5d442092b0278a3643Darren KrahnUsage: proto_print.py [--subdir=foo] <bar.proto>
2759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
2859ea81cf9e7b293ec3241e5d442092b0278a3643Darren KrahnFiles named print_bar_proto.h and print_bar_proto.cc will be created in the
2959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahncurrent working directory.
3059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn"""
3159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
3259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnfrom __future__ import print_function
3359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
3459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnimport argparse
3559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnimport collections
3659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnfrom datetime import date
3759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnimport os
3859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnimport re
3959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnimport subprocess
4059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
4159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
4259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn# Holds information about a protobuf message field.
4359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn#
4459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn# Attributes:
4559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn#   repeated: Whether the field is a repeated field.
4659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn#   type_: The type of the field. E.g. int32.
4759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn#   name: The name of the field.
4859ea81cf9e7b293ec3241e5d442092b0278a3643Darren KrahnField = collections.namedtuple('Field', 'repeated type_ name')
4959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
5059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
5159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnclass Message(object):
5259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  """Holds information about a protobuf message.
5359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
5459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  Attributes:
5559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    name: The name of the message.
5659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    fields: A list of Field tuples.
5759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  """
5859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
5959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  def __init__(self, name):
6059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    """Initializes a Message instance.
6159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
6259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    Args:
6359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      name: The protobuf message name.
6459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    """
6559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    self.name = name
6659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    self.fields = []
6759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
6859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  def AddField(self, attribute, field_type, field_name):
6959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    """Adds a new field to the message.
7059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
7159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    Args:
7259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      attribute: This should be 'optional', 'required', or 'repeated'.
7359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      field_type: The type of the field. E.g. int32.
7459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      field_name: The name of the field.
7559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    """
7659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    self.fields.append(Field(repeated=attribute == 'repeated',
7759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                             type_=field_type, name=field_name))
7859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
7959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
8059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnclass Enum(object):
8159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  """Holds information about a protobuf enum.
8259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
8359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  Attributes:
8459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    name: The name of the enum.
8559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    values: A list of enum value names.
8659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  """
8759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
8859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  def __init__(self, name):
8959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    """Initializes a Enum instance.
9059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
9159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    Args:
9259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      name: The protobuf enum name.
9359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    """
9459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    self.name = name
9559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    self.values = []
9659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
9759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  def AddValue(self, value_name):
9859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    """Adds a new value to the enum.
9959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
10059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    Args:
10159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      value_name: The name of the value.
10259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    """
10359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    self.values.append(value_name)
10459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
10559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
10659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahndef ParseProto(input_file):
10759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  """Parses a proto file and returns a tuple of parsed information.
10859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
10959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  Args:
11059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    input_file: The proto file to parse.
11159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
11259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  Returns:
11359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    A tuple in the form (package, imports, messages, enums) where
11459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      package: A string holding the proto package.
11559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      imports: A list of strings holding proto imports.
11659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      messages: A list of Message objects; one for each message in the proto.
11759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      enums: A list of Enum objects; one for each enum in the proto.
11859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  """
11959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  package = ''
12059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  imports = []
12159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  messages = []
12259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  enums = []
12359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  current_message_stack = []
12459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  current_enum = None
12559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  package_re = re.compile(r'package\s+(\w+);')
12659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  import_re = re.compile(r'import\s+"(\w+).proto";')
12759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  message_re = re.compile(r'message\s+(\w+)\s*{')
12859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  field_re = re.compile(r'(optional|required|repeated)\s+(\w+)\s+(\w+)\s*=')
12959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  enum_re = re.compile(r'enum\s+(\w+)\s*{')
13059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  enum_value_re = re.compile(r'(\w+)\s*=')
13159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  for line in input_file:
13259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    line = line.strip()
13359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    if not line or line.startswith('//'):
13459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      continue
13559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    # Close off the current scope. Enums first because they can't be nested.
13659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    if line == '}':
13759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      if current_enum:
13859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn        enums.append(current_enum)
13959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn        current_enum = None
14059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      if current_message_stack:
14159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn        messages.append(current_message_stack.pop())
14259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      continue
14359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    # Look for a message definition.
14459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    match = message_re.search(line)
14559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    if match:
14659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      prefix = ''
14759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      if current_message_stack:
14859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn        prefix = '::'.join([m.name for m in current_message_stack]) + '::'
14959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      current_message_stack.append(Message(prefix + match.group(1)))
15059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      continue
15159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    # Look for a message field definition.
15259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    if current_message_stack:
15359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      match = field_re.search(line)
15459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      if match:
15559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn        current_message_stack[-1].AddField(match.group(1),
15659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                                           match.group(2),
15759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                                           match.group(3))
15859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn        continue
15959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    # Look for an enum definition.
16059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    match = enum_re.search(line)
16159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    if match:
16259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      current_enum = Enum(match.group(1))
16359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      continue
16459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    # Look for an enum value.
16559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    if current_enum:
16659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      match = enum_value_re.search(line)
16759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      if match:
16859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn        current_enum.AddValue(match.group(1))
16959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn        continue
17059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    # Look for a package statement.
17159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    match = package_re.search(line)
17259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    if match:
17359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      package = match.group(1)
17459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    # Look for an import statement.
17559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    match = import_re.search(line)
17659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    if match:
17759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      imports.append(match.group(1))
17859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  return package, imports, messages, enums
17959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
18059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
18159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahndef GenerateFileHeaders(proto_name, package, imports, subdir, header_file_name,
18259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                        header_file, impl_file):
18359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  """Generates and prints file headers.
18459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
18559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  Args:
18659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    proto_name: The name of the proto file.
18759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    package: The protobuf package.
18859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    imports: A list of imported protos.
18959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    subdir: The --subdir arg.
19059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    header_file_name: The header file name.
19159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    header_file: The header file handle, open for writing.
19259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    impl_file: The implementation file handle, open for writing.
19359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  """
19459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  if subdir:
19559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    guard_name = '%s_%s_PRINT_%s_PROTO_H_' % (package.upper(),
19659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                                              subdir.upper(),
19759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                                              proto_name.upper())
19859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    package_with_subdir = '%s/%s' % (package, subdir)
19959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  else:
20059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    guard_name = '%s_PRINT_%s_PROTO_H_' % (package.upper(), proto_name.upper())
20159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    package_with_subdir = package
20259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  includes = '\n'.join(
20359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      ['#include "%(package_with_subdir)s/print_%(import)s_proto.h"' % {
20459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn          'package_with_subdir': package_with_subdir,
20559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn          'import': current_import} for current_import in imports])
20659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  header = """\
20759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn// Copyright %(year)s The Chromium OS Authors. All rights reserved.
20859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn// Use of this source code is governed by a BSD-style license that can be
20959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn// found in the LICENSE file.
21059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
21159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn// THIS CODE IS GENERATED.
21259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
21359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn#ifndef %(guard_name)s
21459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn#define %(guard_name)s
21559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
21659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn#include <string>
21759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
21859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn#include "%(package_with_subdir)s/%(proto)s.pb.h"
21959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
22059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnnamespace %(package)s {
22159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn""" % {'year': date.today().year,
22259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn       'guard_name': guard_name,
22359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn       'package': package,
22459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn       'proto': proto_name,
22559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn       'package_with_subdir': package_with_subdir}
22659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  impl = """\
22759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn// Copyright %(year)s The Chromium OS Authors. All rights reserved.
22859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn// Use of this source code is governed by a BSD-style license that can be
22959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn// found in the LICENSE file.
23059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
23159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn// THIS CODE IS GENERATED.
23259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
23359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn#include "%(package_with_subdir)s/%(header_file_name)s"
23459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
23559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn#include <string>
23659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
23759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn#include <base/strings/string_number_conversions.h>
23859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn#include <base/strings/stringprintf.h>
23959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
24059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn%(includes)s
24159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
24259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnnamespace %(package)s {
24359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn""" % {'year': date.today().year,
24459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn       'package': package,
24559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn       'package_with_subdir': package_with_subdir,
24659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn       'header_file_name': header_file_name,
24759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn       'includes': includes}
24859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
24959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  header_file.write(header)
25059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  impl_file.write(impl)
25159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
25259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
25359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahndef GenerateFileFooters(proto_name, package, subdir, header_file, impl_file):
25459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  """Generates and prints file footers.
25559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
25659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  Args:
25759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    proto_name: The name of the proto file.
25859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    package: The protobuf package.
25959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    subdir: The --subdir arg.
26059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    header_file: The header file handle, open for writing.
26159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    impl_file: The implementation file handle, open for writing.
26259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  """
26359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  if subdir:
26459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    guard_name = '%s_%s_PRINT_%s_PROTO_H_' % (package.upper(),
26559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                                              subdir.upper(),
26659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                                              proto_name.upper())
26759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  else:
26859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    guard_name = '%s_PRINT_%s_PROTO_H_' % (package.upper(), proto_name.upper())
26959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  header = """
27059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
27159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn}  // namespace %(package)s
27259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
27359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn#endif  // %(guard_name)s
27459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn""" % {'guard_name': guard_name, 'package': package}
27559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  impl = """
27659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn}  // namespace %(package)s
27759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn""" % {'package': package}
27859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
27959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  header_file.write(header)
28059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  impl_file.write(impl)
28159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
28259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
28359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahndef GenerateEnumPrinter(enum, header_file, impl_file):
28459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  """Generates and prints a function to print an enum value.
28559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
28659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  Args:
28759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    enum: An Enum instance.
28859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    header_file: The header file handle, open for writing.
28959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    impl_file: The implementation file handle, open for writing.
29059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  """
29159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  declare = """
29259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnstd::string GetProtoDebugStringWithIndent(%(name)s value, int indent_size);
29359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnstd::string GetProtoDebugString(%(name)s value);""" % {'name': enum.name}
29459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  define_begin = """
29559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnstd::string GetProtoDebugString(%(name)s value) {
29659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  return GetProtoDebugStringWithIndent(value, 0);
29759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn}
29859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
29959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnstd::string GetProtoDebugStringWithIndent(%(name)s value, int indent_size) {
30059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn""" % {'name': enum.name}
30159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  define_end = """
30259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  return "<unknown>";
30359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn}
30459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn"""
30559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  condition = """
30659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  if (value == %(value_name)s) {
30759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    return "%(value_name)s";
30859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  }"""
30959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
31059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  header_file.write(declare)
31159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  impl_file.write(define_begin)
31259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  for value_name in enum.values:
31359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    impl_file.write(condition % {'value_name': value_name})
31459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  impl_file.write(define_end)
31559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
31659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
31759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahndef GenerateMessagePrinter(message, header_file, impl_file):
31859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  """Generates and prints a function to print a message.
31959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
32059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  Args:
32159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    message: A Message instance.
32259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    header_file: The header file handle, open for writing.
32359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    impl_file: The implementation file handle, open for writing.
32459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  """
32559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  declare = """
32659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnstd::string GetProtoDebugStringWithIndent(const %(name)s& value,
32759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                                          int indent_size);
32859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnstd::string GetProtoDebugString(const %(name)s& value);""" % {'name':
32959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                                                              message.name}
33059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  define_begin = """
33159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnstd::string GetProtoDebugString(const %(name)s& value) {
33259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  return GetProtoDebugStringWithIndent(value, 0);
33359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn}
33459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
33559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnstd::string GetProtoDebugStringWithIndent(const %(name)s& value,
33659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                                          int indent_size) {
33759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  std::string indent(indent_size, ' ');
33859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  std::string output = base::StringPrintf("[%%s] {\\n",
33959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                                          value.GetTypeName().c_str());
34059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn""" % {'name': message.name}
34159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  define_end = """
34259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  output += indent + "}\\n";
34359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  return output;
34459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn}
34559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn"""
34659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  singular_field = """
34759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  if (value.has_%(name)s()) {
34859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    output += indent + "  %(name)s: ";
34959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    base::StringAppendF(&output, %(format)s);
35059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    output += "\\n";
35159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  }"""
35259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  repeated_field = """
35359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  output += indent + "  %(name)s: {";
35459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  for (int i = 0; i < value.%(name)s_size(); ++i) {
35559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    base::StringAppendF(&output, %(format)s);
35659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  }
35759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  output += "}\\n";"""
35859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  singular_field_get = 'value.%(name)s()'
35959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  repeated_field_get = 'value.%(name)s(i)'
36059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  formats = {'bool': '"%%s", %(value)s ? "true" : "false"',
36159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn             'int32': '"%%d", %(value)s',
36259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn             'int64': '"%%ld", %(value)s',
36359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn             'uint32': '"%%u", %(value)s',
36459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn             'uint64': '"%%lu", %(value)s',
36559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn             'string': '"%%s", %(value)s.c_str()',
36659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn             'bytes': """"%%s", base::HexEncode(%(value)s.data(),
36759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                                                %(value)s.size()).c_str()"""}
36859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  subtype_format = ('"%%s", GetProtoDebugStringWithIndent(%(value)s, '
36959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                    'indent_size + 2).c_str()')
37059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
37159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  header_file.write(declare)
37259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  impl_file.write(define_begin)
37359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  for field in message.fields:
37459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    if field.repeated:
37559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      value_get = repeated_field_get % {'name': field.name}
37659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      field_code = repeated_field
37759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    else:
37859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      value_get = singular_field_get % {'name': field.name}
37959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      field_code = singular_field
38059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    if field.type_ in formats:
38159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      value_format = formats[field.type_] % {'value': value_get}
38259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    else:
38359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      value_format = subtype_format % {'value': value_get}
38459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    impl_file.write(field_code % {'name': field.name,
38559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                                  'format': value_format})
38659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  impl_file.write(define_end)
38759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
38859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
38959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahndef FormatFile(filename):
39059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  subprocess.call(['clang-format', '-i', '-style=Chromium', filename])
39159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
39259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
39359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahndef main():
39459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  parser = argparse.ArgumentParser(description='print proto code generator')
39559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  parser.add_argument('input_file')
39659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  parser.add_argument('--subdir', default='')
39759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  args = parser.parse_args()
39859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  with open(args.input_file) as input_file:
39959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    package, imports, messages, enums = ParseProto(input_file)
40059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  proto_name = os.path.basename(args.input_file).rsplit('.', 1)[0]
40159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  header_file_name = 'print_%s_proto.h' % proto_name
40259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  impl_file_name = 'print_%s_proto.cc' % proto_name
40359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  with open(header_file_name, 'w') as header_file:
40459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn    with open(impl_file_name, 'w') as impl_file:
40559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      GenerateFileHeaders(proto_name, package, imports, args.subdir,
40659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                          header_file_name, header_file, impl_file)
40759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      for enum in enums:
40859ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn        GenerateEnumPrinter(enum, header_file, impl_file)
40959ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      for message in messages:
41059ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn        GenerateMessagePrinter(message, header_file, impl_file)
41159ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn      GenerateFileFooters(proto_name, package, args.subdir, header_file,
41259ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn                          impl_file)
41359ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  FormatFile(header_file_name)
41459ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  FormatFile(impl_file_name)
41559ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn
41659ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahnif __name__ == '__main__':
41759ea81cf9e7b293ec3241e5d442092b0278a3643Darren Krahn  main()
418