aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/run_tests/sanity/check_bazel_workspace.py
blob: 62a6229c5d76aba65a38c03068ad75bc6d1960a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/env python

# Copyright 2016 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import print_function

import ast
import os
import re
import subprocess
import sys

os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '../../..'))

git_hash_pattern = re.compile('[0-9a-f]{40}')

# Parse git hashes from submodules
git_submodules = subprocess.check_output(
    'git submodule', shell=True).strip().split('\n')
git_submodule_hashes = {
    re.search(git_hash_pattern, s).group()
    for s in git_submodules
}

_BAZEL_TOOLCHAINS_DEP_NAME = 'com_github_bazelbuild_bazeltoolchains'

_GRPC_DEP_NAMES = [
    'boringssl',
    'com_github_madler_zlib',
    'com_google_protobuf',
    'com_github_google_googletest',
    'com_github_gflags_gflags',
    'com_github_google_benchmark',
    'com_github_cares_cares',
    'com_google_absl',
    _BAZEL_TOOLCHAINS_DEP_NAME,
]


class BazelEvalState(object):

    def __init__(self, names_and_urls, overridden_name=None):
        self.names_and_urls = names_and_urls
        self.overridden_name = overridden_name

    def http_archive(self, **args):
        self.archive(**args)

    def new_http_archive(self, **args):
        self.archive(**args)

    def bind(self, **args):
        pass

    def existing_rules(self):
        if self.overridden_name:
            return [self.overridden_name]
        return []

    def archive(self, **args):
        if args['name'] == _BAZEL_TOOLCHAINS_DEP_NAME:
            self.names_and_urls[args['name']] = 'dont care'
            return
        self.names_and_urls[args['name']] = args['url']


# Parse git hashes from bazel/grpc_deps.bzl {new_}http_archive rules
with open(os.path.join('bazel', 'grpc_deps.bzl'), 'r') as f:
    names_and_urls = {}
    eval_state = BazelEvalState(names_and_urls)
    bazel_file = f.read()

# grpc_deps.bzl only defines 'grpc_deps', add this to call it
bazel_file += '\ngrpc_deps()\n'
build_rules = {
    'native': eval_state,
}
exec bazel_file in build_rules
for name in _GRPC_DEP_NAMES:
    assert name in names_and_urls.keys()
assert len(_GRPC_DEP_NAMES) == len(names_and_urls.keys())

# bazeltoolschains is an exception to this sanity check,
# we don't require that there is a corresponding git module.
names_without_bazeltoolchains = names_and_urls.keys()
names_without_bazeltoolchains.remove(_BAZEL_TOOLCHAINS_DEP_NAME)
archive_urls = [names_and_urls[name] for name in names_without_bazeltoolchains]
workspace_git_hashes = {
    re.search(git_hash_pattern, url).group()
    for url in archive_urls
}
if len(workspace_git_hashes) == 0:
    print("(Likely) parse error, did not find any bazel git dependencies.")
    sys.exit(1)

# Validate the equivalence of the git submodules and Bazel git dependencies. The
# condition we impose is that there is a git submodule for every dependency in
# the workspace, but not necessarily conversely. E.g. Bloaty is a dependency
# not used by any of the targets built by Bazel.
if len(workspace_git_hashes - git_submodule_hashes) > 0:
    print(
        "Found discrepancies between git submodules and Bazel WORKSPACE dependencies"
    )
    sys.exit(1)

# Also check that we can override each dependency
for name in _GRPC_DEP_NAMES:
    names_and_urls_with_overridden_name = {}
    state = BazelEvalState(
        names_and_urls_with_overridden_name, overridden_name=name)
    rules = {
        'native': state,
    }
    exec bazel_file in rules
    assert name not in names_and_urls_with_overridden_name.keys()

sys.exit(0)