1import sys
2import subprocess
3import os.path
4
5import traceback
6
7def has_grpcio_protoc(verbose = False):
8    # type: () -> bool
9    """ checks if grpcio-tools protoc is installed"""
10
11    try:
12        import grpc_tools.protoc
13    except ImportError:
14        if verbose:
15            sys.stderr.write("Failed to import grpc_tools: %s\n" % traceback.format_exc())
16        return False
17
18    return True
19
20def get_grpc_tools_proto_path():
21    if sys.hexversion > 0x03090000:
22        import importlib.resources as ir
23        with ir.as_file(ir.files('grpc_tools') / '_proto') as path:
24            return str(path)
25    else:
26        import pkg_resources
27        return pkg_resources.resource_filename('grpc_tools', '_proto')
28
29def get_proto_builtin_include_path():
30    """Find include path for standard google/protobuf includes and for
31    nanopb.proto.
32    """
33
34    if getattr(sys, 'frozen', False):
35        # Pyinstaller package
36        paths = [
37            os.path.join(os.path.dirname(os.path.abspath(sys.executable)), 'proto'),
38            os.path.join(os.path.dirname(os.path.abspath(sys.executable)), 'grpc_tools', '_proto')
39        ]
40
41    else:
42        # Stand-alone script
43        paths = [
44            os.path.dirname(os.path.abspath(__file__))
45        ]
46
47        if has_grpcio_protoc():
48            paths.append(get_grpc_tools_proto_path())
49
50    return paths
51
52def invoke_protoc(argv):
53    # type: (list) -> typing.Any
54    """
55    Invoke protoc.
56
57    This routine will use grpcio-provided protoc if it exists,
58    using system-installed protoc as a fallback.
59
60    Args:
61        argv: protoc CLI invocation, first item must be 'protoc'
62    """
63
64    # Add current directory to include path if nothing else is specified
65    if not [x for x in argv if x.startswith('-I')]:
66        argv.append("-I.")
67
68    # Add default protoc include paths
69    for incpath in get_proto_builtin_include_path():
70        argv.append('-I' + incpath)
71
72    if has_grpcio_protoc():
73        import grpc_tools.protoc as protoc
74        return protoc.main(argv)
75    else:
76        return subprocess.call(argv)
77
78def print_versions():
79    try:
80        if has_grpcio_protoc(verbose = True):
81            import grpc_tools.protoc
82            sys.stderr.write("Using grpcio-tools protoc from " + grpc_tools.protoc.__file__ + "\n")
83        else:
84            sys.stderr.write("Using protoc from system path\n")
85
86        invoke_protoc(['protoc', '--version'])
87    except Exception as e:
88        sys.stderr.write("Failed to determine protoc version: " + str(e) + "\n")
89
90    try:
91        sys.stderr.write("protoc builtin include path: " + str(get_proto_builtin_include_path()) + "\n")
92    except Exception as e:
93        sys.stderr.write("Failed to construct protoc include path: " + str(e) + "\n")
94
95    try:
96        import google.protobuf
97        sys.stderr.write("Python version " + sys.version + "\n")
98        sys.stderr.write("Using python-protobuf from " + google.protobuf.__file__ + "\n")
99        sys.stderr.write("Python-protobuf version: " + google.protobuf.__version__ + "\n")
100    except Exception as e:
101        sys.stderr.write("Failed to determine python-protobuf version: " + str(e) + "\n")
102
103if __name__ == '__main__':
104    print_versions()
105