blob: c791f31f651c025f2b0d569d7e7d4d6c1fa68f70 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2020 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Checks the visibility of all cobalt gn targets"""
from __future__ import print_function
import subprocess
import json
import os
# Find the root directory of the cobalt core repository (One directory up from the tools/ directory)
cobalt_root = os.path.abspath(
os.path.join(os.path.join(os.path.dirname(__file__), '..')))
global_visibility_whitelist = ['//src/public', '//src/lib/client']
# This is the list of targets that are currently used out-of-tree.
#
# Any new targets used outside of the tree should be accessible through //src/public or //src/lib/client
#
# DO NOT ADD ANY NEW ENTRIES TO THIS DICT
out_of_tree_visibility_whitelist = {
'//src/cobalt/bin/app:cobalt_app_unittests': [
'//src/logger:fake_logger',
'//src/logger:logger_test_utils',
],
'//src/cobalt/bin/app:lib': [
'//src/lib/util:file_util',
'//src/lib/util:pem_util',
'//src/lib/util:posix_file_system',
'//src/logger:logger',
'//src/system_data:configuration_data',
'//src/system_data:system_data',
],
'//src/cobalt/bin/testapp:cobalt_testapp': [
'//src/lib/util:datetime_util',
'//src/registry:cobalt_registry_proto',
],
'//src/cobalt/bin/utils:fuchsia_http_client': [
'//src/lib/statusor:statusor',
],
}
def main():
out_path = os.path.join(cobalt_root, 'out')
p = subprocess.Popen(
['gn', 'desc', out_path, '//src/*', 'visibility', '--format=json'],
stdout=subprocess.PIPE)
out, err = p.communicate()
if p.returncode != 0:
print('Received non-zero return code (%s)' % p.returncode)
print(out.decode())
return 1
data = json.loads(out)
globally_visibile = []
out_of_tree_visibility = {}
errors = 0
for target, attributes in data.items():
whitelisted = False
for whitelist in global_visibility_whitelist:
if target.startswith(whitelist):
whitelisted = True
if whitelisted:
continue
if len(attributes['visibility']) == 0:
print('Empty visibility for target %s', target)
return 1
visibility = set(attributes['visibility'])
# Targets with visibility of '$cobalt_root/*' look like '//*' when printed by gn desc. This type
# of target visibility is always considered okay since it is limited to cobalt core.
visibility -= {'//*'}
if len(visibility) == 0:
# Proper visibility, limited to cobalt core repo
continue
# Any target with global visibility that isn't in the global_visibility_whitelist are errors.
if '*' in visibility:
globally_visibile.append(target)
continue
unfound_visibility = set()
for vis in visibility:
visibility_path = vis
if vis in out_of_tree_visibility_whitelist:
if target in out_of_tree_visibility_whitelist[vis]:
continue
# This converts GN targets to their directory.
#
# e.g. '//src/algorithms/random:durations' becomes 'src/algorithms/random'
# e.g. '//src/algorithms/random/*' becomes 'src/algorithms/random/'
if visibility_path.startswith('//'):
visibility_path = visibility_path[2:]
visibility_path = visibility_path.split(':')[0]
visibility_path = visibility_path.split('*')[0]
# Generate the absolute path from cobalt root referred to by the visibility_path.
path_to_visibility_spec = os.path.join(cobalt_root, visibility_path)
if os.path.isfile(path_to_visibility_spec) or os.path.isdir(
path_to_visibility_spec):
# This visibility spec has been found somewhere in the cobalt core repository. Explicit
# visibilities for extant paths is always allowed.
continue
unfound_visibility.add(vis)
for vis in unfound_visibility:
out_of_tree_visibility.setdefault(vis, []).append(target)
if len(globally_visibile) > 0:
print('Found %d targets with global visibility:' % len(globally_visibile))
for target in sorted(globally_visibile):
print(' | %s' % target)
errors += 1
for vis in sorted(out_of_tree_visibility.keys()):
targets = out_of_tree_visibility[vis]
print('Found %s targets with out-of-tree visibility `%s`' %
(len(targets), vis))
for target in sorted(targets):
print(' | %s' % target)
errors += 1
if errors > 0:
print()
print('Found %d Errors' % errors)
else:
print('No visibility issues found')
return errors
if __name__ == '__main__':
exit(main())