Home | History | Annotate | Download | only in proto
      1 # Copyright (C) 2016 The Android Open Source Project
      2 #
      3 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
      4 # use this file except in compliance with the License. You may obtain a copy of
      5 # the License at
      6 #
      7 # http://www.apache.org/licenses/LICENSE-2.0
      8 #
      9 # Unless required by applicable law or agreed to in writing, software
     10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     12 # License for the specific language governing permissions and limitations under
     13 # the License.
     14 import logging
     15 import os
     16 import subprocess
     17 import sys
     18 from distutils.spawn import find_executable
     19 from google import protobuf
     20 from importlib import import_module
     21 
     22 
     23 def compile_proto(proto_path, output_dir):
     24     """Invoke Protocol Compiler to generate python from given source .proto."""
     25     # Find compiler path
     26     protoc = None
     27     if 'PROTOC' in os.environ and os.path.exists(os.environ['PROTOC']):
     28         protoc = os.environ['PROTOC']
     29     if not protoc:
     30         protoc = find_executable('protoc')
     31     if not protoc:
     32         logging.error(
     33             "Cannot find protobuf compiler (>=3.0.0), please install"
     34             "protobuf-compiler package. Prefer copying from <top>/prebuilts/tools"
     35         )
     36         logging.error("    prebuilts/tools/linux-x86_64/protoc/bin/protoc")
     37         logging.error("If prebuilts are not available, use apt-get:")
     38         logging.error("    sudo apt-get install protobuf-compiler")
     39         return None
     40     # Validate input proto path
     41     if not os.path.exists(proto_path):
     42         logging.error('Can\'t find required file: %s\n' % proto_path)
     43         return None
     44     # Validate output py-proto path
     45     if not os.path.exists(output_dir):
     46         os.mkdirs(output_dir)
     47     elif not os.path.isdir(output_dir):
     48         logging.error("Output path is not a valid directory: %s" %
     49                       (output_dir))
     50         return None
     51     input_dir = os.path.dirname(proto_path)
     52     output_filename = os.path.basename(proto_path).replace('.proto', '_pb2.py')
     53     output_path = os.path.join(output_dir, output_filename)
     54     # Compiling proto
     55     logging.info('Generating %s' % output_path)
     56     protoc_command = [
     57         protoc, '-I=%s' % (input_dir), '--python_out=%s' % (output_dir),
     58         proto_path
     59     ]
     60     if subprocess.call(protoc_command, stderr=subprocess.STDOUT) != 0:
     61         logging.error("Fail to compile proto")
     62         return None
     63     output_module_name = os.path.splitext(output_filename)[0]
     64     return output_module_name
     65 
     66 
     67 def compile_import_proto(output_dir, proto_path):
     68     """
     69     Compile protobuf from PROTO_PATH and put the result in OUTPUT_DIR.
     70     Return the imported module to caller.
     71     :param output_dir: To store generated python proto library
     72     :param proto_path: Path to the .proto file that needs to be compiled
     73     :return: python proto module
     74     """
     75     output_module_name = compile_proto(proto_path, output_dir)
     76     if not output_module_name:
     77         return None
     78     sys.path.append(output_dir)
     79     output_module = None
     80     try:
     81         output_module = import_module(output_module_name)
     82     except ImportError:
     83         logging.error("Cannot import generated py-proto %s" %
     84                       (output_module_name))
     85     return output_module
     86 
     87 
     88 def parse_proto_to_ascii(binary_proto_msg):
     89     """
     90     Parse binary protobuf message to human readable ascii string
     91     :param binary_proto_msg:
     92     :return: ascii string of the message
     93     """
     94     return protobuf.text_format.MessageToString(binary_proto_msg)
     95