• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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