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 ast 20import os 21import re 22import subprocess 23import sys 24 25os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '../../..')) 26 27git_hash_pattern = re.compile('[0-9a-f]{40}') 28 29# Parse git hashes from submodules 30git_submodules = subprocess.check_output( 31 'git submodule', shell=True).strip().split('\n') 32git_submodule_hashes = { 33 re.search(git_hash_pattern, s).group() 34 for s in git_submodules 35} 36 37_BAZEL_TOOLCHAINS_DEP_NAME = 'com_github_bazelbuild_bazeltoolchains' 38_TWISTED_TWISTED_DEP_NAME = 'com_github_twisted_twisted' 39_YAML_PYYAML_DEP_NAME = 'com_github_yaml_pyyaml' 40_TWISTED_INCREMENTAL_DEP_NAME = 'com_github_twisted_incremental' 41_ZOPEFOUNDATION_ZOPE_INTERFACE_DEP_NAME = 'com_github_zopefoundation_zope_interface' 42_TWISTED_CONSTANTLY_DEP_NAME = 'com_github_twisted_constantly' 43 44_GRPC_DEP_NAMES = [ 45 'boringssl', 46 'com_github_madler_zlib', 47 'com_google_protobuf', 48 'com_github_google_googletest', 49 'com_github_gflags_gflags', 50 'com_github_nanopb_nanopb', 51 'com_github_google_benchmark', 52 'com_github_cares_cares', 53 'com_google_absl', 54 'io_opencensus_cpp', 55 _BAZEL_TOOLCHAINS_DEP_NAME, 56 _TWISTED_TWISTED_DEP_NAME, 57 _YAML_PYYAML_DEP_NAME, 58 _TWISTED_INCREMENTAL_DEP_NAME, 59 _ZOPEFOUNDATION_ZOPE_INTERFACE_DEP_NAME, 60 _TWISTED_CONSTANTLY_DEP_NAME, 61] 62 63_GRPC_BAZEL_ONLY_DEPS = [ 64 _BAZEL_TOOLCHAINS_DEP_NAME, 65 _TWISTED_TWISTED_DEP_NAME, 66 _YAML_PYYAML_DEP_NAME, 67 _TWISTED_INCREMENTAL_DEP_NAME, 68 _ZOPEFOUNDATION_ZOPE_INTERFACE_DEP_NAME, 69 _TWISTED_CONSTANTLY_DEP_NAME, 70] 71 72 73class BazelEvalState(object): 74 75 def __init__(self, names_and_urls, overridden_name=None): 76 self.names_and_urls = names_and_urls 77 self.overridden_name = overridden_name 78 79 def http_archive(self, **args): 80 self.archive(**args) 81 82 def new_http_archive(self, **args): 83 self.archive(**args) 84 85 def bind(self, **args): 86 pass 87 88 def existing_rules(self): 89 if self.overridden_name: 90 return [self.overridden_name] 91 return [] 92 93 def archive(self, **args): 94 assert self.names_and_urls.get(args['name']) is None 95 if args['name'] in _GRPC_BAZEL_ONLY_DEPS: 96 self.names_and_urls[args['name']] = 'dont care' 97 return 98 self.names_and_urls[args['name']] = args['url'] 99 100 101# Parse git hashes from bazel/grpc_deps.bzl {new_}http_archive rules 102with open(os.path.join('bazel', 'grpc_deps.bzl'), 'r') as f: 103 names_and_urls = {} 104 eval_state = BazelEvalState(names_and_urls) 105 bazel_file = f.read() 106 107# grpc_deps.bzl only defines 'grpc_deps' and 'grpc_test_only_deps', add these 108# lines to call them. 109bazel_file += '\ngrpc_deps()\n' 110bazel_file += '\ngrpc_test_only_deps()\n' 111build_rules = { 112 'native': eval_state, 113} 114exec bazel_file in build_rules 115for name in _GRPC_DEP_NAMES: 116 assert name in names_and_urls.keys() 117assert len(_GRPC_DEP_NAMES) == len(names_and_urls.keys()) 118 119# There are some "bazel-only" deps that are exceptions to this sanity check, 120# we don't require that there is a corresponding git module for these. 121names_without_bazel_only_deps = names_and_urls.keys() 122for dep_name in _GRPC_BAZEL_ONLY_DEPS: 123 names_without_bazel_only_deps.remove(dep_name) 124archive_urls = [names_and_urls[name] for name in names_without_bazel_only_deps] 125# Exclude nanopb from the check: it's not a submodule for distribution reasons, 126# but it's a workspace dependency to enable users to use their own version. 127workspace_git_hashes = { 128 re.search(git_hash_pattern, url).group() 129 for url in archive_urls 130 if 'nanopb' not in url 131} 132if len(workspace_git_hashes) == 0: 133 print("(Likely) parse error, did not find any bazel git dependencies.") 134 sys.exit(1) 135 136# Validate the equivalence of the git submodules and Bazel git dependencies. The 137# condition we impose is that there is a git submodule for every dependency in 138# the workspace, but not necessarily conversely. E.g. Bloaty is a dependency 139# not used by any of the targets built by Bazel. 140if len(workspace_git_hashes - git_submodule_hashes) > 0: 141 print( 142 "Found discrepancies between git submodules and Bazel WORKSPACE dependencies" 143 ) 144 145# Also check that we can override each dependency 146for name in _GRPC_DEP_NAMES: 147 names_and_urls_with_overridden_name = {} 148 state = BazelEvalState( 149 names_and_urls_with_overridden_name, overridden_name=name) 150 rules = { 151 'native': state, 152 } 153 exec bazel_file in rules 154 assert name not in names_and_urls_with_overridden_name.keys() 155 156sys.exit(0) 157