| #!/usr/bin/env python | 
 | # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | # Use of this source code is governed by a BSD-style license that can be | 
 | # found in the LICENSE file. | 
 | """ | 
 | A simple wrapper for protoc. | 
 |  | 
 | - Adds includes in generated headers. | 
 | - Handles building with system protobuf as an option. | 
 | """ | 
 |  | 
 | import optparse  #pylint: disable=deprecated-module | 
 | import os.path | 
 | import shutil | 
 | import subprocess | 
 | import sys | 
 | import tempfile | 
 |  | 
 | PROTOC_INCLUDE_POINT = '// @@protoc_insertion_point(includes)\n' | 
 |  | 
 |  | 
 | def ModifyHeader(header_file, extra_header): | 
 |   """Adds |extra_header| to |header_file|. Returns 0 on success. | 
 |  | 
 |   |extra_header| is the name of the header file to include. | 
 |   |header_file| is a generated protobuf cpp header. | 
 |   """ | 
 |   include_point_found = False | 
 |   header_contents = [] | 
 |   with open(header_file, encoding='utf=8') as f: | 
 |     for line in f: | 
 |       header_contents.append(line) | 
 |       if line == PROTOC_INCLUDE_POINT: | 
 |         extra_header_msg = f'#include "{extra_header}"\n' | 
 |         header_contents.append(extra_header_msg) | 
 |         include_point_found = True | 
 |   if not include_point_found: | 
 |     return 1 | 
 |  | 
 |   with open(header_file, 'wb', encoding='utf-8') as f: | 
 |     f.write(''.join(header_contents)) | 
 |   return 0 | 
 |  | 
 |  | 
 | def RewriteProtoFilesForSystemProtobuf(path): | 
 |   wrapper_dir = tempfile.mkdtemp() | 
 |   try: | 
 |     for filename in os.listdir(path): | 
 |       if not filename.endswith('.proto'): | 
 |         continue | 
 |       # pylint: disable=line-too-long | 
 |       with open( | 
 |           os.path.join(path, filename), 'r', encoding='utf-8') as src_file: | 
 |         with open( | 
 |             os.path.join(wrapper_dir, filename), 'w', | 
 |             encoding='utf-8') as dst_file: | 
 |           for line in src_file: | 
 |             # Remove lines that break build with system protobuf. | 
 |             # We cannot optimize for lite runtime, because system lite runtime | 
 |             # does not have a Chromium-specific hack to retain unknown fields. | 
 |             # Similarly, it does not understand corresponding option to control | 
 |             # the usage of that hack. | 
 |             if 'LITE_RUNTIME' in line or 'retain_unknown_fields' in line: | 
 |               continue | 
 |             dst_file.write(line) | 
 |       # pylint: enable=line-too-long | 
 |     return wrapper_dir | 
 |   except: | 
 |     shutil.rmtree(wrapper_dir) | 
 |     raise | 
 |  | 
 |  | 
 | def main(argv):  # pylint: disable=unused-argument | 
 |   parser = optparse.OptionParser() | 
 |   parser.add_option( | 
 |       '--include', | 
 |       dest='extra_header', | 
 |       help='The extra header to include. This must be specified ' | 
 |       'along with --protobuf.') | 
 |   parser.add_option( | 
 |       '--protobuf', | 
 |       dest='generated_header', | 
 |       help='The c++ protobuf header to add the extra header to. ' | 
 |       'This must be specified along with --include.') | 
 |   parser.add_option( | 
 |       '--proto-in-dir', help='The directory containing .proto files.') | 
 |   parser.add_option('--proto-in-file', help='Input file to compile.') | 
 |   parser.add_option( | 
 |       '--use-system-protobuf', | 
 |       type=int, | 
 |       default=0, | 
 |       help='Option to use system-installed protobuf ' | 
 |       'instead of bundled one.') | 
 |   (options, args) = parser.parse_args(sys.argv) | 
 |   if len(args) < 2: | 
 |     return 1 | 
 |  | 
 |   proto_path = options.proto_in_dir | 
 |   if options.use_system_protobuf == 1: | 
 |     proto_path = RewriteProtoFilesForSystemProtobuf(proto_path) | 
 |   try: | 
 |     # Run what is hopefully protoc. | 
 |     protoc_args = args[1:] | 
 |     protoc_args += [ | 
 |         f'--proto_path={proto_path}', | 
 |         os.path.join(proto_path, options.proto_in_file) | 
 |     ] | 
 |     ret = subprocess.call(protoc_args) | 
 |     if ret != 0: | 
 |       return ret | 
 |   finally: | 
 |     if options.use_system_protobuf == 1: | 
 |       # Remove temporary directory holding re-written files. | 
 |       shutil.rmtree(proto_path) | 
 |  | 
 |   # protoc succeeded, check to see if the generated cpp header needs editing. | 
 |   if not options.extra_header or not options.generated_header: | 
 |     return 0 | 
 |   return ModifyHeader(options.generated_header, options.extra_header) | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |   sys.exit(main(sys.argv)) |