| #!/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 |
| # |
| # DO NOT ADD ANY NEW ENTRIES TO THIS DICT |
| out_of_tree_visibility_whitelist = { |
| '//src/cobalt/bin/*': [ |
| '//src/lib/clearcut:clearcut', |
| '//src/lib/statusor:statusor', |
| '//src/lib/util:clock', |
| '//src/lib/util:datetime_util', |
| '//src/lib/util:file_util', |
| '//src/lib/util:pem_util', |
| '//src/lib/util:posix_file_system', |
| '//src/logger:fake_logger', |
| '//src/logger:logger_test_utils', |
| '//src/registry:cobalt_registry_proto', |
| '//src/system_data:configuration_data', |
| '//src/system_data:system_data', |
| ], |
| '//src/cobalt/bin/app:lib': ['//src/logger:logger'], |
| '//src/cobalt/bin/system-metrics/*': ['//src/registry:buckets_config'], |
| '//src/ui/scenic/*': ['//src/registry:buckets_config'], |
| } |
| |
| |
| 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()) |