1#!/usr/bin/env python 2 3# Copyright 2016 gRPC authors. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17from __future__ import print_function 18 19import errno 20import filecmp 21import glob 22import os 23import os.path 24import shutil 25import subprocess 26import sys 27import traceback 28import uuid 29 30DEPS_FILE_CONTENT = """ 31# Copyright 2017 gRPC authors. 32# 33# Licensed under the Apache License, Version 2.0 (the "License"); 34# you may not use this file except in compliance with the License. 35# You may obtain a copy of the License at 36# 37# http://www.apache.org/licenses/LICENSE-2.0 38# 39# Unless required by applicable law or agreed to in writing, software 40# distributed under the License is distributed on an "AS IS" BASIS, 41# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 42# See the License for the specific language governing permissions and 43# limitations under the License. 44 45# AUTO-GENERATED BY make_grpcio_tools.py! 46CC_FILES={cc_files} 47PROTO_FILES={proto_files} 48 49CC_INCLUDE={cc_include} 50PROTO_INCLUDE={proto_include} 51 52{commit_hash} 53""" 54 55COMMIT_HASH_PREFIX = 'PROTOBUF_SUBMODULE_VERSION="' 56COMMIT_HASH_SUFFIX = '"' 57 58# Bazel query result prefix for expected source files in protobuf. 59PROTOBUF_CC_PREFIX = '//:src/' 60PROTOBUF_PROTO_PREFIX = '//:src/' 61 62GRPC_ROOT = os.path.abspath( 63 os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', '..')) 64 65GRPC_PYTHON_ROOT = os.path.join(GRPC_ROOT, 'tools', 'distrib', 'python', 66 'grpcio_tools') 67 68GRPC_PYTHON_PROTOBUF_RELATIVE_ROOT = os.path.join('third_party', 'protobuf', 69 'src') 70GRPC_PROTOBUF = os.path.join(GRPC_ROOT, GRPC_PYTHON_PROTOBUF_RELATIVE_ROOT) 71GRPC_PROTOBUF_SUBMODULE_ROOT = os.path.join(GRPC_ROOT, 'third_party', 72 'protobuf') 73GRPC_PROTOC_PLUGINS = os.path.join(GRPC_ROOT, 'src', 'compiler') 74GRPC_PYTHON_PROTOBUF = os.path.join(GRPC_PYTHON_ROOT, 'third_party', 'protobuf', 75 'src') 76GRPC_PYTHON_PROTOC_PLUGINS = os.path.join(GRPC_PYTHON_ROOT, 'grpc_root', 'src', 77 'compiler') 78GRPC_PYTHON_PROTOC_LIB_DEPS = os.path.join(GRPC_PYTHON_ROOT, 79 'protoc_lib_deps.py') 80 81GRPC_INCLUDE = os.path.join(GRPC_ROOT, 'include') 82GRPC_PYTHON_INCLUDE = os.path.join(GRPC_PYTHON_ROOT, 'grpc_root', 'include') 83 84BAZEL_DEPS = os.path.join(GRPC_ROOT, 'tools', 'distrib', 'python', 85 'bazel_deps.sh') 86BAZEL_DEPS_PROTOC_LIB_QUERY = '//:protoc_lib' 87BAZEL_DEPS_COMMON_PROTOS_QUERY = '//:well_known_protos' 88 89 90def protobuf_submodule_commit_hash(): 91 """Gets the commit hash for the HEAD of the protobuf submodule currently 92 checked out.""" 93 cwd = os.getcwd() 94 os.chdir(GRPC_PROTOBUF_SUBMODULE_ROOT) 95 output = subprocess.check_output(['git', 'rev-parse', 'HEAD']) 96 os.chdir(cwd) 97 return output.splitlines()[0].strip() 98 99 100def bazel_query(query): 101 print('Running "bazel query %s"' % query) 102 output = subprocess.check_output([BAZEL_DEPS, query]) 103 return output.splitlines() 104 105 106def get_deps(): 107 """Write the result of the bazel query `query` against protobuf to 108 `out_file`.""" 109 cc_files_output = bazel_query(BAZEL_DEPS_PROTOC_LIB_QUERY) 110 cc_files = [ 111 name[len(PROTOBUF_CC_PREFIX):] 112 for name in cc_files_output 113 if name.endswith('.cc') and name.startswith(PROTOBUF_CC_PREFIX) 114 ] 115 proto_files_output = bazel_query(BAZEL_DEPS_COMMON_PROTOS_QUERY) 116 proto_files = [ 117 name[len(PROTOBUF_PROTO_PREFIX):] 118 for name in proto_files_output 119 if name.endswith('.proto') and name.startswith(PROTOBUF_PROTO_PREFIX) 120 ] 121 commit_hash = protobuf_submodule_commit_hash() 122 deps_file_content = DEPS_FILE_CONTENT.format( 123 cc_files=cc_files, 124 proto_files=proto_files, 125 cc_include=repr(GRPC_PYTHON_PROTOBUF_RELATIVE_ROOT), 126 proto_include=repr(GRPC_PYTHON_PROTOBUF_RELATIVE_ROOT), 127 commit_hash=COMMIT_HASH_PREFIX + commit_hash + COMMIT_HASH_SUFFIX) 128 return deps_file_content 129 130 131def long_path(path): 132 if os.name == 'nt': 133 return '\\\\?\\' + path 134 else: 135 return path 136 137 138def main(): 139 os.chdir(GRPC_ROOT) 140 141 for source, target in [(GRPC_PROTOBUF, GRPC_PYTHON_PROTOBUF), 142 (GRPC_PROTOC_PLUGINS, GRPC_PYTHON_PROTOC_PLUGINS), 143 (GRPC_INCLUDE, GRPC_PYTHON_INCLUDE)]: 144 for source_dir, _, files in os.walk(source): 145 target_dir = os.path.abspath( 146 os.path.join(target, os.path.relpath(source_dir, source))) 147 try: 148 os.makedirs(target_dir) 149 except OSError as error: 150 if error.errno != errno.EEXIST: 151 raise 152 for relative_file in files: 153 source_file = os.path.abspath( 154 os.path.join(source_dir, relative_file)) 155 target_file = os.path.abspath( 156 os.path.join(target_dir, relative_file)) 157 shutil.copyfile(source_file, target_file) 158 159 try: 160 print('Invoking "bazel query" to gather the protobuf dependencies.') 161 protoc_lib_deps_content = get_deps() 162 except Exception as error: 163 # We allow this script to succeed even if we couldn't get the dependencies, 164 # as then we can assume that even without a successful bazel run the 165 # dependencies currently in source control are 'good enough'. 166 sys.stderr.write("Got non-fatal error:\n") 167 traceback.print_exc(file=sys.stderr) 168 return 169 # If we successfully got the dependencies, truncate and rewrite the deps file. 170 with open(GRPC_PYTHON_PROTOC_LIB_DEPS, 'w') as deps_file: 171 deps_file.write(protoc_lib_deps_content) 172 print('File "%s" updated.' % GRPC_PYTHON_PROTOC_LIB_DEPS) 173 print('Done.') 174 175 176if __name__ == '__main__': 177 main() 178