| #!/usr/bin/env python3 |
| # Copyright 2022 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. |
| """Convert the binary Bazel workspace log to text format.""" |
| |
| import argparse |
| import os |
| import platform |
| import shlex |
| import subprocess |
| import sys |
| |
| from typing import Optional |
| |
| _SCRIPT_DIR = os.path.dirname(__file__) |
| _FUCHSIA_DIR = os.path.abspath(os.path.join(_SCRIPT_DIR, "..", "..", "..")) |
| |
| |
| def get_host_platform() -> str: |
| """Return host platform name, following Fuchsia conventions.""" |
| if sys.platform == "linux": |
| return "linux" |
| elif sys.platform == "darwin": |
| return "mac" |
| else: |
| return os.uname().sysname |
| |
| |
| def get_host_arch() -> str: |
| """Return host CPU architecture, following Fuchsia conventions.""" |
| host_arch = os.uname().machine |
| if host_arch == "x86_64": |
| return "x64" |
| elif host_arch.startswith(("armv8", "aarch64")): |
| return "arm64" |
| else: |
| return host_arch |
| |
| |
| def get_host_tag() -> str: |
| """Return host tag, following Fuchsia conventions.""" |
| return "%s-%s" % (get_host_platform(), get_host_arch()) |
| |
| |
| def find_fuchsia_dir(from_dir: Optional[str] = None) -> Optional[str]: |
| """Return Fuchsia directory path. |
| |
| Args: |
| from_dir: Optional starting directory for the search. If None, |
| uses the current directory. |
| |
| Returns: |
| Fuchsia directory path, or None if it could not be found. |
| """ |
| if from_dir is None: |
| from_dir = os.getcwd() |
| while True: |
| if os.path.exists(os.path.join(from_dir, ".jiri_root")): |
| return from_dir |
| new_dir = os.path.dirname(from_dir) |
| if new_dir == from_dir: |
| # The top-level path was reached. |
| return None |
| from_dir = new_dir |
| |
| |
| def find_ninja_build_dir(fuchsia_dir: str) -> Optional[str]: |
| """Find Ninja build directory. |
| |
| Args: |
| fuchsia_dir: Fuchsia directory path. |
| |
| Returns: |
| The Ninja build directory, or None if it could not be determined, |
| which happens if `fx set` was not called previously. |
| """ |
| fx_build_dir = os.path.join(fuchsia_dir, ".fx-build-dir") |
| if not os.path.exists(fx_build_dir): |
| print("ERROR: Could not find %s" % fx_build_dir, file=sys.stderr) |
| return None |
| |
| with open(fx_build_dir) as f: |
| build_dir = f.read().strip() |
| |
| if not build_dir: |
| print("ERROR: Empty .fx-build-dir!", file=sys.stderr) |
| return None |
| |
| return os.path.join(fuchsia_dir, build_dir) |
| |
| |
| def find_bazel_top_dir(fuchsia_dir: str, ninja_build_dir: str) -> Optional[str]: |
| """Find Bazel top directory |
| |
| Args: |
| fuchsia_dir: Fuchsia source directory. |
| ninja_build_dir: Ninja build directory. |
| |
| Returns: |
| Bazel topdir path, or None if it could not be found. |
| """ |
| top_dir_file = os.path.join( |
| fuchsia_dir, "build", "bazel", "config", "main_workspace_top_dir" |
| ) |
| with open(top_dir_file) as f: |
| top_dir_relative = f.read().strip() |
| return os.path.join(ninja_build_dir, top_dir_relative) |
| |
| |
| def find_default_log_file() -> Optional[str]: |
| """Find the location of the default log file. |
| |
| Returns: |
| Path to the default log file, or None if it could not be determined. |
| """ |
| fuchsia_dir = find_fuchsia_dir() |
| if not fuchsia_dir: |
| return None |
| |
| build_dir = find_ninja_build_dir(fuchsia_dir) |
| if not build_dir: |
| return None |
| |
| top_dir = find_bazel_top_dir(fuchsia_dir, build_dir) |
| log_file = os.path.join(top_dir, "logs", "workspace-events.log") |
| return log_file |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument( |
| "--jre", |
| help="Specify Java JRE used to run the parser, default uses the prebuilt Bazel JRE.", |
| ) |
| parser.add_argument( |
| "--log-parser-jar", |
| help="Specify alternative location for parser .jar file.", |
| ) |
| parser.add_argument( |
| "--exclude_rule", |
| action="append", |
| default=[], |
| help="Rule(s) to filter out while parsing.", |
| ) |
| parser.add_argument( |
| "--output_path", |
| help="Output file location. If not used, output goes to stdout.", |
| ) |
| parser.add_argument("--log_file", help="Input log file (auto-detected).") |
| parser.add_argument( |
| "--verbose", action="store_true", help="Enable verbose mode." |
| ) |
| args = parser.parse_args() |
| |
| # Find the Java Runtime Environment to run the parser first. |
| java_binary = os.path.join("bin", "java") |
| if sys.platform.startswith("win"): |
| java_binary += ".exe" |
| |
| def find_java_binary(jre_path: str) -> Optional[str]: |
| path = os.path.join(jre_path, java_binary) |
| return path if os.path.exists(path) else None |
| |
| if args.jre: |
| java_launcher = find_java_binary(args.jre) |
| if not java_launcher: |
| parser.error("Invalid JRE path: " + args.jre) |
| return 1 |
| else: |
| # Auto-detect the prebuilt bazel JRE first |
| prebuilt_bazel_jdk = os.path.join( |
| _FUCHSIA_DIR, |
| "prebuilt", |
| "third_party", |
| "bazel", |
| get_host_tag(), |
| "install_base", |
| "embedded_tools", |
| "jdk", |
| ) |
| java_launcher = find_java_binary(prebuilt_bazel_jdk) |
| if not java_launcher: |
| print( |
| "ERROR: Missing prebuilt Bazel JDK launcher, please use --jre=<DIR>: %s/%s" |
| % (prebuilt_bazel_jdk, java_binary), |
| file=sys.stderr, |
| ) |
| return 1 |
| |
| def verbose(msg): |
| if args.verbose: |
| print("DEBUG: " + msg, file=sys.stderr) |
| |
| # Find the parser JAR file now. |
| if args.log_parser_jar: |
| log_parser_jar = args.log_parser_jar |
| else: |
| log_parser_jar = os.path.join( |
| _FUCHSIA_DIR, |
| "prebuilt", |
| "third_party", |
| "bazel_workspacelogparser", |
| "bazel_workspacelogparser.jar", |
| ) |
| |
| if not os.path.exists(log_parser_jar): |
| parser.error("Missing parser file: " + log_parser_jar) |
| |
| verbose("Using jar file at: " + log_parser_jar) |
| |
| log_file = args.log_file |
| if not args.log_file: |
| log_file = find_default_log_file() |
| if not log_file: |
| print( |
| "ERROR: Could not find default log file, please use --log_file=FILE", |
| file=sys.stderr, |
| ) |
| return 1 |
| |
| verbose("Using log file at: " + log_file) |
| |
| cmd = [java_launcher, "-jar", log_parser_jar, "--log_path=" + log_file] |
| cmd += ["--exclude_rule=" + rule for rule in args.exclude_rule] |
| if args.output_path: |
| cmd += ["--output_path=" + args.output_path] |
| |
| verbose("Running command: %s" % " ".join([shlex.quote(c) for c in cmd])) |
| |
| return subprocess.run(cmd).returncode |
| |
| |
| if __name__ == "__main__": |
| sys.exit(main()) |