| #!/usr/bin/env python3 |
| # Copyright 2023 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. |
| # |
| # IMPORTANT: This script should not depend on any Bazel workspace setup |
| # or specific environment. Only depend on standard Python3 modules |
| # and assume a minimum of Python3.8 is being used. |
| |
| """A tool to perform useful Bazel operations easily.""" |
| |
| import argparse |
| import os |
| import subprocess |
| import sys |
| from pathlib import Path |
| from typing import Sequence |
| |
| def make_bazel_quiet_command(bazel: str, command: str) -> Sequence[str]: |
| """Create command argument list for a Bazel command that does not print too much. |
| |
| Args: |
| bazel: Path to Bazel program. |
| command: Bazel command (e.g. 'query', 'build', etc..) |
| Returns: |
| A sequence of strings that can be used as a command line prefix. |
| """ |
| result = [ |
| bazel, |
| command, |
| "--noshow_loading_progress", |
| "--noshow_progress", |
| "--ui_event_filters=-info", |
| ] |
| if command != 'query': |
| result += [ "--show_result=0" ] |
| return result |
| |
| |
| def cmd_target_dump(args: argparse.Namespace) -> int: |
| """Implement the target_dump command.""" |
| bazel_cmd = make_bazel_quiet_command(args.bazel, 'query') + [ '--output=build' ] + args.target_set |
| buildifier_cmd = [args.buildifier, '--type=build', '--mode=fix', '--lint=off'] |
| proc1 = subprocess.Popen(bazel_cmd, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=None) |
| proc2 = subprocess.Popen(buildifier_cmd, stdin=proc1.stdout, stdout=None, stderr=None) |
| proc1.wait() |
| proc2.wait() |
| if proc1.returncode != 0: |
| return proc1.returncode |
| return proc2.returncode |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument('--bazel', default = 'bazel', help='Specify bazel executable') |
| parser.add_argument('--buildifier', default = 'buildifier', help='Specify buildifier executable') |
| parser.add_argument('--workspace', help='Specify workspace directory') |
| |
| subparsers = parser.add_subparsers(help='available commands') |
| |
| # The target_dump command. |
| parser_target_dump = subparsers.add_parser( |
| 'target_dump', |
| help='Dump definitions of Bazel targets.', |
| formatter_class=argparse.RawDescriptionHelpFormatter, |
| description=r''' |
| Print the real definition of a target, or set of targets, in a |
| Bazel graph, after all macros have been expanded. Note that: |
| |
| - Each TARGET_SET argument is a standard Bazel target set expression |
| (e.g. `//src/lib:foo` or `//:*`). |
| |
| - The output is pretty printed for readability. |
| |
| - For each target that is the result of a macro expansion, comments |
| are added to descirbe the call chain that led to it. |
| |
| - For each target generated by native.filegroup() in macros, new |
| `generator_{function,location,name}` fields are added to indicate |
| how it was generated. |
| ''') |
| parser_target_dump.add_argument('target_set', metavar='TARGET_SET', nargs = '+', help='Set of targets to dump.') |
| parser_target_dump.set_defaults(func=cmd_target_dump) |
| |
| args = parser.parse_args() |
| if args.workspace: |
| os.chdir(args.workspace) |
| |
| return args.func(args) |
| |
| if __name__ == "__main__": |
| sys.exit(main()) |