1*bb4ee6a4SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*bb4ee6a4SAndroid Build Coastguard Worker# Copyright 2022 The ChromiumOS Authors 3*bb4ee6a4SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*bb4ee6a4SAndroid Build Coastguard Worker# found in the LICENSE file. 5*bb4ee6a4SAndroid Build Coastguard Worker 6*bb4ee6a4SAndroid Build Coastguard Workerimport os 7*bb4ee6a4SAndroid Build Coastguard Workerimport typing 8*bb4ee6a4SAndroid Build Coastguard Workerfrom typing import Generator, List, Literal, Optional, Tuple, Union 9*bb4ee6a4SAndroid Build Coastguard Worker 10*bb4ee6a4SAndroid Build Coastguard Workerfrom impl.common import ( 11*bb4ee6a4SAndroid Build Coastguard Worker CROSVM_ROOT, 12*bb4ee6a4SAndroid Build Coastguard Worker TOOLS_ROOT, 13*bb4ee6a4SAndroid Build Coastguard Worker Triple, 14*bb4ee6a4SAndroid Build Coastguard Worker argh, 15*bb4ee6a4SAndroid Build Coastguard Worker chdir, 16*bb4ee6a4SAndroid Build Coastguard Worker cmd, 17*bb4ee6a4SAndroid Build Coastguard Worker run_main, 18*bb4ee6a4SAndroid Build Coastguard Worker) 19*bb4ee6a4SAndroid Build Coastguard Workerfrom impl.presubmit import Check, CheckContext, run_checks, Group 20*bb4ee6a4SAndroid Build Coastguard Worker 21*bb4ee6a4SAndroid Build Coastguard Workerpython = cmd("python3") 22*bb4ee6a4SAndroid Build Coastguard Workermypy = cmd("mypy").with_color_env("MYPY_FORCE_COLOR") 23*bb4ee6a4SAndroid Build Coastguard Workerblack = cmd("black").with_color_arg(always="--color", never="--no-color") 24*bb4ee6a4SAndroid Build Coastguard Workermdformat = cmd("mdformat") 25*bb4ee6a4SAndroid Build Coastguard Workerlucicfg = cmd("third_party/depot_tools/lucicfg") 26*bb4ee6a4SAndroid Build Coastguard Worker 27*bb4ee6a4SAndroid Build Coastguard Worker# All supported platforms as a type and a list. 28*bb4ee6a4SAndroid Build Coastguard WorkerPlatform = Literal["x86_64", "aarch64", "mingw64", "armhf"] 29*bb4ee6a4SAndroid Build Coastguard WorkerPLATFORMS: Tuple[Platform, ...] = typing.get_args(Platform) 30*bb4ee6a4SAndroid Build Coastguard Worker 31*bb4ee6a4SAndroid Build Coastguard WorkerClippyOnlyPlatform = Literal["android"] 32*bb4ee6a4SAndroid Build Coastguard WorkerCLIPPY_ONLY_PLATFORMS: Tuple[ClippyOnlyPlatform, ...] = typing.get_args(ClippyOnlyPlatform) 33*bb4ee6a4SAndroid Build Coastguard Worker 34*bb4ee6a4SAndroid Build Coastguard Worker 35*bb4ee6a4SAndroid Build Coastguard Workerdef platform_is_supported(platform: Union[Platform, ClippyOnlyPlatform]): 36*bb4ee6a4SAndroid Build Coastguard Worker "Returns true if the platform is available as a target in rustup." 37*bb4ee6a4SAndroid Build Coastguard Worker triple = Triple.from_shorthand(platform) 38*bb4ee6a4SAndroid Build Coastguard Worker installed_toolchains = cmd("rustup target list --installed").lines() 39*bb4ee6a4SAndroid Build Coastguard Worker return str(triple) in installed_toolchains 40*bb4ee6a4SAndroid Build Coastguard Worker 41*bb4ee6a4SAndroid Build Coastguard Worker 42*bb4ee6a4SAndroid Build Coastguard Worker#################################################################################################### 43*bb4ee6a4SAndroid Build Coastguard Worker# Check methods 44*bb4ee6a4SAndroid Build Coastguard Worker# 45*bb4ee6a4SAndroid Build Coastguard Worker# Each check returns a Command (or list of Commands) to be run to execute the check. They are 46*bb4ee6a4SAndroid Build Coastguard Worker# registered and configured in the CHECKS list below. 47*bb4ee6a4SAndroid Build Coastguard Worker# 48*bb4ee6a4SAndroid Build Coastguard Worker# Some check functions are factory functions that return a check command for all supported 49*bb4ee6a4SAndroid Build Coastguard Worker# platforms. 50*bb4ee6a4SAndroid Build Coastguard Worker 51*bb4ee6a4SAndroid Build Coastguard Worker 52*bb4ee6a4SAndroid Build Coastguard Workerdef check_python_tests(_: CheckContext): 53*bb4ee6a4SAndroid Build Coastguard Worker "Runs unit tests for python dev tooling." 54*bb4ee6a4SAndroid Build Coastguard Worker PYTHON_TESTS = [ 55*bb4ee6a4SAndroid Build Coastguard Worker # Disabled due to b/309148074 56*bb4ee6a4SAndroid Build Coastguard Worker # "tests.cl_tests", 57*bb4ee6a4SAndroid Build Coastguard Worker "impl.common", 58*bb4ee6a4SAndroid Build Coastguard Worker ] 59*bb4ee6a4SAndroid Build Coastguard Worker return [python.with_cwd(TOOLS_ROOT).with_args("-m", file) for file in PYTHON_TESTS] 60*bb4ee6a4SAndroid Build Coastguard Worker 61*bb4ee6a4SAndroid Build Coastguard Worker 62*bb4ee6a4SAndroid Build Coastguard Workerdef check_python_types(context: CheckContext): 63*bb4ee6a4SAndroid Build Coastguard Worker "Run mypy type checks on python dev tooling." 64*bb4ee6a4SAndroid Build Coastguard Worker return [mypy("--pretty", file) for file in context.all_files] 65*bb4ee6a4SAndroid Build Coastguard Worker 66*bb4ee6a4SAndroid Build Coastguard Worker 67*bb4ee6a4SAndroid Build Coastguard Workerdef check_python_format(context: CheckContext): 68*bb4ee6a4SAndroid Build Coastguard Worker "Runs the black formatter on python dev tooling." 69*bb4ee6a4SAndroid Build Coastguard Worker return black.with_args( 70*bb4ee6a4SAndroid Build Coastguard Worker "--check" if not context.fix else None, 71*bb4ee6a4SAndroid Build Coastguard Worker *context.modified_files, 72*bb4ee6a4SAndroid Build Coastguard Worker ) 73*bb4ee6a4SAndroid Build Coastguard Worker 74*bb4ee6a4SAndroid Build Coastguard Worker 75*bb4ee6a4SAndroid Build Coastguard Workerdef check_markdown_format(context: CheckContext): 76*bb4ee6a4SAndroid Build Coastguard Worker "Runs mdformat on all markdown files." 77*bb4ee6a4SAndroid Build Coastguard Worker if "blaze" in mdformat("--version").stdout(): 78*bb4ee6a4SAndroid Build Coastguard Worker raise Exception( 79*bb4ee6a4SAndroid Build Coastguard Worker "You are using google's mdformat. " 80*bb4ee6a4SAndroid Build Coastguard Worker + "Please update your PATH to ensure the pip installed mdformat is available." 81*bb4ee6a4SAndroid Build Coastguard Worker ) 82*bb4ee6a4SAndroid Build Coastguard Worker return mdformat.with_args( 83*bb4ee6a4SAndroid Build Coastguard Worker "--wrap 100", 84*bb4ee6a4SAndroid Build Coastguard Worker "--check" if not context.fix else "", 85*bb4ee6a4SAndroid Build Coastguard Worker *context.modified_files, 86*bb4ee6a4SAndroid Build Coastguard Worker ) 87*bb4ee6a4SAndroid Build Coastguard Worker 88*bb4ee6a4SAndroid Build Coastguard Worker 89*bb4ee6a4SAndroid Build Coastguard Workerdef check_rust_format(context: CheckContext): 90*bb4ee6a4SAndroid Build Coastguard Worker "Runs rustfmt on all modified files." 91*bb4ee6a4SAndroid Build Coastguard Worker rustfmt = cmd(cmd("rustup +nightly which rustfmt").stdout()) 92*bb4ee6a4SAndroid Build Coastguard Worker # Windows doesn't accept very long arguments: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa#:~:text=The%20maximum%20length%20of%20this%20string%20is%2032%2C767%20characters%2C%20including%20the%20Unicode%20terminating%20null%20character.%20If%20lpApplicationName%20is%20NULL%2C%20the%20module%20name%20portion%20of%20lpCommandLine%20is%20limited%20to%20MAX_PATH%20characters. 93*bb4ee6a4SAndroid Build Coastguard Worker return list( 94*bb4ee6a4SAndroid Build Coastguard Worker rustfmt.with_color_flag() 95*bb4ee6a4SAndroid Build Coastguard Worker .with_args("--check" if not context.fix else "") 96*bb4ee6a4SAndroid Build Coastguard Worker .foreach(context.modified_files, batch_size=10) 97*bb4ee6a4SAndroid Build Coastguard Worker ) 98*bb4ee6a4SAndroid Build Coastguard Worker 99*bb4ee6a4SAndroid Build Coastguard Worker 100*bb4ee6a4SAndroid Build Coastguard Workerdef check_cargo_doc(_: CheckContext): 101*bb4ee6a4SAndroid Build Coastguard Worker "Runs cargo-doc and verifies that no warnings are emitted." 102*bb4ee6a4SAndroid Build Coastguard Worker return cmd("./tools/cargo-doc").with_env("RUSTDOCFLAGS", "-D warnings").with_color_flag() 103*bb4ee6a4SAndroid Build Coastguard Worker 104*bb4ee6a4SAndroid Build Coastguard Worker 105*bb4ee6a4SAndroid Build Coastguard Workerdef check_doc_tests(_: CheckContext): 106*bb4ee6a4SAndroid Build Coastguard Worker "Runs cargo doc tests. These cannot be run via nextest and run_tests." 107*bb4ee6a4SAndroid Build Coastguard Worker return cmd( 108*bb4ee6a4SAndroid Build Coastguard Worker "cargo test", 109*bb4ee6a4SAndroid Build Coastguard Worker "--doc", 110*bb4ee6a4SAndroid Build Coastguard Worker "--workspace", 111*bb4ee6a4SAndroid Build Coastguard Worker "--features=all-x86_64", 112*bb4ee6a4SAndroid Build Coastguard Worker ).with_color_flag() 113*bb4ee6a4SAndroid Build Coastguard Worker 114*bb4ee6a4SAndroid Build Coastguard Worker 115*bb4ee6a4SAndroid Build Coastguard Workerdef check_mdbook(_: CheckContext): 116*bb4ee6a4SAndroid Build Coastguard Worker "Runs cargo-doc and verifies that no warnings are emitted." 117*bb4ee6a4SAndroid Build Coastguard Worker return cmd("mdbook build docs/book/") 118*bb4ee6a4SAndroid Build Coastguard Worker 119*bb4ee6a4SAndroid Build Coastguard Worker 120*bb4ee6a4SAndroid Build Coastguard Workerdef check_crosvm_tests(platform: Platform): 121*bb4ee6a4SAndroid Build Coastguard Worker def check(_: CheckContext): 122*bb4ee6a4SAndroid Build Coastguard Worker if not platform_is_supported(platform): 123*bb4ee6a4SAndroid Build Coastguard Worker return None 124*bb4ee6a4SAndroid Build Coastguard Worker dut = None 125*bb4ee6a4SAndroid Build Coastguard Worker if os.access("/dev/kvm", os.W_OK): 126*bb4ee6a4SAndroid Build Coastguard Worker if platform == "x86_64": 127*bb4ee6a4SAndroid Build Coastguard Worker dut = "--dut=vm" 128*bb4ee6a4SAndroid Build Coastguard Worker elif platform == "aarch64": 129*bb4ee6a4SAndroid Build Coastguard Worker dut = "--dut=vm" 130*bb4ee6a4SAndroid Build Coastguard Worker return cmd("./tools/run_tests --verbose --platform", platform, dut).with_color_flag() 131*bb4ee6a4SAndroid Build Coastguard Worker 132*bb4ee6a4SAndroid Build Coastguard Worker check.__doc__ = f"Runs all crosvm tests for {platform}." 133*bb4ee6a4SAndroid Build Coastguard Worker 134*bb4ee6a4SAndroid Build Coastguard Worker return check 135*bb4ee6a4SAndroid Build Coastguard Worker 136*bb4ee6a4SAndroid Build Coastguard Worker 137*bb4ee6a4SAndroid Build Coastguard Workerdef check_crosvm_unit_tests(platform: Platform): 138*bb4ee6a4SAndroid Build Coastguard Worker def check(_: CheckContext): 139*bb4ee6a4SAndroid Build Coastguard Worker if not platform_is_supported(platform): 140*bb4ee6a4SAndroid Build Coastguard Worker return None 141*bb4ee6a4SAndroid Build Coastguard Worker return cmd("./tools/run_tests --verbose --platform", platform).with_color_flag() 142*bb4ee6a4SAndroid Build Coastguard Worker 143*bb4ee6a4SAndroid Build Coastguard Worker check.__doc__ = f"Runs crosvm unit tests for {platform}." 144*bb4ee6a4SAndroid Build Coastguard Worker 145*bb4ee6a4SAndroid Build Coastguard Worker return check 146*bb4ee6a4SAndroid Build Coastguard Worker 147*bb4ee6a4SAndroid Build Coastguard Worker 148*bb4ee6a4SAndroid Build Coastguard Workerdef check_crosvm_build( 149*bb4ee6a4SAndroid Build Coastguard Worker platform: Platform, features: Optional[str] = None, no_default_features: bool = False 150*bb4ee6a4SAndroid Build Coastguard Worker): 151*bb4ee6a4SAndroid Build Coastguard Worker def check(_: CheckContext): 152*bb4ee6a4SAndroid Build Coastguard Worker return cmd( 153*bb4ee6a4SAndroid Build Coastguard Worker "./tools/run_tests --no-run --verbose --platform", 154*bb4ee6a4SAndroid Build Coastguard Worker platform, 155*bb4ee6a4SAndroid Build Coastguard Worker f"--features={features}" if features is not None else None, 156*bb4ee6a4SAndroid Build Coastguard Worker "--no-default-features" if no_default_features else None, 157*bb4ee6a4SAndroid Build Coastguard Worker ).with_color_flag() 158*bb4ee6a4SAndroid Build Coastguard Worker 159*bb4ee6a4SAndroid Build Coastguard Worker check.__doc__ = f"Builds crosvm for {platform} with features {features}." 160*bb4ee6a4SAndroid Build Coastguard Worker 161*bb4ee6a4SAndroid Build Coastguard Worker return check 162*bb4ee6a4SAndroid Build Coastguard Worker 163*bb4ee6a4SAndroid Build Coastguard Worker 164*bb4ee6a4SAndroid Build Coastguard Workerdef check_clippy(platform: Union[Platform, ClippyOnlyPlatform]): 165*bb4ee6a4SAndroid Build Coastguard Worker def check(context: CheckContext): 166*bb4ee6a4SAndroid Build Coastguard Worker if not platform_is_supported(platform): 167*bb4ee6a4SAndroid Build Coastguard Worker return None 168*bb4ee6a4SAndroid Build Coastguard Worker return cmd( 169*bb4ee6a4SAndroid Build Coastguard Worker "./tools/clippy --platform", 170*bb4ee6a4SAndroid Build Coastguard Worker platform, 171*bb4ee6a4SAndroid Build Coastguard Worker "--fix" if context.fix else None, 172*bb4ee6a4SAndroid Build Coastguard Worker ).with_color_flag() 173*bb4ee6a4SAndroid Build Coastguard Worker 174*bb4ee6a4SAndroid Build Coastguard Worker check.__doc__ = f"Runs clippy for {platform}." 175*bb4ee6a4SAndroid Build Coastguard Worker 176*bb4ee6a4SAndroid Build Coastguard Worker return check 177*bb4ee6a4SAndroid Build Coastguard Worker 178*bb4ee6a4SAndroid Build Coastguard Worker 179*bb4ee6a4SAndroid Build Coastguard Workerdef custom_check(name: str, can_fix: bool = False): 180*bb4ee6a4SAndroid Build Coastguard Worker "Custom checks are written in python in tools/custom_checks. This is a wrapper to call them." 181*bb4ee6a4SAndroid Build Coastguard Worker 182*bb4ee6a4SAndroid Build Coastguard Worker def check(context: CheckContext): 183*bb4ee6a4SAndroid Build Coastguard Worker return cmd( 184*bb4ee6a4SAndroid Build Coastguard Worker TOOLS_ROOT / "custom_checks", 185*bb4ee6a4SAndroid Build Coastguard Worker name, 186*bb4ee6a4SAndroid Build Coastguard Worker *context.modified_files, 187*bb4ee6a4SAndroid Build Coastguard Worker "--fix" if can_fix and context.fix else None, 188*bb4ee6a4SAndroid Build Coastguard Worker ) 189*bb4ee6a4SAndroid Build Coastguard Worker 190*bb4ee6a4SAndroid Build Coastguard Worker check.__name__ = name.replace("-", "_") 191*bb4ee6a4SAndroid Build Coastguard Worker check.__doc__ = f"Runs tools/custom_check {name}" 192*bb4ee6a4SAndroid Build Coastguard Worker return check 193*bb4ee6a4SAndroid Build Coastguard Worker 194*bb4ee6a4SAndroid Build Coastguard Worker 195*bb4ee6a4SAndroid Build Coastguard Worker#################################################################################################### 196*bb4ee6a4SAndroid Build Coastguard Worker# Checks configuration 197*bb4ee6a4SAndroid Build Coastguard Worker# 198*bb4ee6a4SAndroid Build Coastguard Worker# Configures which checks are available and on which files they are run. 199*bb4ee6a4SAndroid Build Coastguard Worker# Check names default to the function name minus the check_ prefix 200*bb4ee6a4SAndroid Build Coastguard Worker 201*bb4ee6a4SAndroid Build Coastguard WorkerCHECKS: List[Check] = [ 202*bb4ee6a4SAndroid Build Coastguard Worker Check( 203*bb4ee6a4SAndroid Build Coastguard Worker check_rust_format, 204*bb4ee6a4SAndroid Build Coastguard Worker files=["**.rs"], 205*bb4ee6a4SAndroid Build Coastguard Worker exclude=["system_api/src/bindings/*"], 206*bb4ee6a4SAndroid Build Coastguard Worker can_fix=True, 207*bb4ee6a4SAndroid Build Coastguard Worker ), 208*bb4ee6a4SAndroid Build Coastguard Worker Check( 209*bb4ee6a4SAndroid Build Coastguard Worker check_mdbook, 210*bb4ee6a4SAndroid Build Coastguard Worker files=["docs/**/*"], 211*bb4ee6a4SAndroid Build Coastguard Worker ), 212*bb4ee6a4SAndroid Build Coastguard Worker Check( 213*bb4ee6a4SAndroid Build Coastguard Worker check_cargo_doc, 214*bb4ee6a4SAndroid Build Coastguard Worker files=["**.rs", "**Cargo.toml"], 215*bb4ee6a4SAndroid Build Coastguard Worker priority=True, 216*bb4ee6a4SAndroid Build Coastguard Worker ), 217*bb4ee6a4SAndroid Build Coastguard Worker Check( 218*bb4ee6a4SAndroid Build Coastguard Worker check_doc_tests, 219*bb4ee6a4SAndroid Build Coastguard Worker files=["**.rs", "**Cargo.toml"], 220*bb4ee6a4SAndroid Build Coastguard Worker priority=True, 221*bb4ee6a4SAndroid Build Coastguard Worker ), 222*bb4ee6a4SAndroid Build Coastguard Worker Check( 223*bb4ee6a4SAndroid Build Coastguard Worker check_python_tests, 224*bb4ee6a4SAndroid Build Coastguard Worker files=["tools/**.py"], 225*bb4ee6a4SAndroid Build Coastguard Worker python_tools=True, 226*bb4ee6a4SAndroid Build Coastguard Worker priority=True, 227*bb4ee6a4SAndroid Build Coastguard Worker ), 228*bb4ee6a4SAndroid Build Coastguard Worker Check( 229*bb4ee6a4SAndroid Build Coastguard Worker check_python_types, 230*bb4ee6a4SAndroid Build Coastguard Worker files=["tools/**.py"], 231*bb4ee6a4SAndroid Build Coastguard Worker exclude=[ 232*bb4ee6a4SAndroid Build Coastguard Worker "tools/windows/*", 233*bb4ee6a4SAndroid Build Coastguard Worker "tools/contrib/memstats_chart/*", 234*bb4ee6a4SAndroid Build Coastguard Worker "tools/contrib/cros_tracing_analyser/*", 235*bb4ee6a4SAndroid Build Coastguard Worker ], 236*bb4ee6a4SAndroid Build Coastguard Worker python_tools=True, 237*bb4ee6a4SAndroid Build Coastguard Worker ), 238*bb4ee6a4SAndroid Build Coastguard Worker Check( 239*bb4ee6a4SAndroid Build Coastguard Worker check_python_format, 240*bb4ee6a4SAndroid Build Coastguard Worker files=["**.py"], 241*bb4ee6a4SAndroid Build Coastguard Worker python_tools=True, 242*bb4ee6a4SAndroid Build Coastguard Worker exclude=["infra/recipes.py"], 243*bb4ee6a4SAndroid Build Coastguard Worker can_fix=True, 244*bb4ee6a4SAndroid Build Coastguard Worker ), 245*bb4ee6a4SAndroid Build Coastguard Worker Check( 246*bb4ee6a4SAndroid Build Coastguard Worker check_markdown_format, 247*bb4ee6a4SAndroid Build Coastguard Worker files=["**.md"], 248*bb4ee6a4SAndroid Build Coastguard Worker exclude=[ 249*bb4ee6a4SAndroid Build Coastguard Worker "infra/README.recipes.md", 250*bb4ee6a4SAndroid Build Coastguard Worker "docs/book/src/appendix/memory_layout.md", 251*bb4ee6a4SAndroid Build Coastguard Worker ], 252*bb4ee6a4SAndroid Build Coastguard Worker can_fix=True, 253*bb4ee6a4SAndroid Build Coastguard Worker ), 254*bb4ee6a4SAndroid Build Coastguard Worker *( 255*bb4ee6a4SAndroid Build Coastguard Worker Check( 256*bb4ee6a4SAndroid Build Coastguard Worker check_crosvm_build(platform, features="default"), 257*bb4ee6a4SAndroid Build Coastguard Worker custom_name=f"crosvm_build_default_{platform}", 258*bb4ee6a4SAndroid Build Coastguard Worker files=["**.rs"], 259*bb4ee6a4SAndroid Build Coastguard Worker priority=True, 260*bb4ee6a4SAndroid Build Coastguard Worker ) 261*bb4ee6a4SAndroid Build Coastguard Worker for platform in PLATFORMS 262*bb4ee6a4SAndroid Build Coastguard Worker ), 263*bb4ee6a4SAndroid Build Coastguard Worker *( 264*bb4ee6a4SAndroid Build Coastguard Worker Check( 265*bb4ee6a4SAndroid Build Coastguard Worker check_crosvm_build(platform, features="", no_default_features=True), 266*bb4ee6a4SAndroid Build Coastguard Worker custom_name=f"crosvm_build_no_default_{platform}", 267*bb4ee6a4SAndroid Build Coastguard Worker files=["**.rs"], 268*bb4ee6a4SAndroid Build Coastguard Worker priority=True, 269*bb4ee6a4SAndroid Build Coastguard Worker ) 270*bb4ee6a4SAndroid Build Coastguard Worker # TODO: b/260607247 crosvm does not compile with no-default-features on mingw64 271*bb4ee6a4SAndroid Build Coastguard Worker for platform in PLATFORMS 272*bb4ee6a4SAndroid Build Coastguard Worker if platform != "mingw64" 273*bb4ee6a4SAndroid Build Coastguard Worker ), 274*bb4ee6a4SAndroid Build Coastguard Worker *( 275*bb4ee6a4SAndroid Build Coastguard Worker Check( 276*bb4ee6a4SAndroid Build Coastguard Worker check_crosvm_tests(platform), 277*bb4ee6a4SAndroid Build Coastguard Worker custom_name=f"crosvm_tests_{platform}", 278*bb4ee6a4SAndroid Build Coastguard Worker files=["**.rs"], 279*bb4ee6a4SAndroid Build Coastguard Worker priority=True, 280*bb4ee6a4SAndroid Build Coastguard Worker ) 281*bb4ee6a4SAndroid Build Coastguard Worker for platform in PLATFORMS 282*bb4ee6a4SAndroid Build Coastguard Worker ), 283*bb4ee6a4SAndroid Build Coastguard Worker *( 284*bb4ee6a4SAndroid Build Coastguard Worker Check( 285*bb4ee6a4SAndroid Build Coastguard Worker check_crosvm_unit_tests(platform), 286*bb4ee6a4SAndroid Build Coastguard Worker custom_name=f"crosvm_unit_tests_{platform}", 287*bb4ee6a4SAndroid Build Coastguard Worker files=["**.rs"], 288*bb4ee6a4SAndroid Build Coastguard Worker priority=True, 289*bb4ee6a4SAndroid Build Coastguard Worker ) 290*bb4ee6a4SAndroid Build Coastguard Worker for platform in PLATFORMS 291*bb4ee6a4SAndroid Build Coastguard Worker ), 292*bb4ee6a4SAndroid Build Coastguard Worker *( 293*bb4ee6a4SAndroid Build Coastguard Worker Check( 294*bb4ee6a4SAndroid Build Coastguard Worker check_clippy(platform), 295*bb4ee6a4SAndroid Build Coastguard Worker custom_name=f"clippy_{platform}", 296*bb4ee6a4SAndroid Build Coastguard Worker files=["**.rs"], 297*bb4ee6a4SAndroid Build Coastguard Worker can_fix=True, 298*bb4ee6a4SAndroid Build Coastguard Worker priority=True, 299*bb4ee6a4SAndroid Build Coastguard Worker ) 300*bb4ee6a4SAndroid Build Coastguard Worker for platform in (*PLATFORMS, *CLIPPY_ONLY_PLATFORMS) 301*bb4ee6a4SAndroid Build Coastguard Worker ), 302*bb4ee6a4SAndroid Build Coastguard Worker Check( 303*bb4ee6a4SAndroid Build Coastguard Worker custom_check("check-copyright-header"), 304*bb4ee6a4SAndroid Build Coastguard Worker files=["**.rs", "**.py", "**.c", "**.h", "**.policy", "**.sh"], 305*bb4ee6a4SAndroid Build Coastguard Worker exclude=[ 306*bb4ee6a4SAndroid Build Coastguard Worker "infra/recipes.py", 307*bb4ee6a4SAndroid Build Coastguard Worker "hypervisor/src/whpx/whpx_sys/*.h", 308*bb4ee6a4SAndroid Build Coastguard Worker "third_party/vmm_vhost/*", 309*bb4ee6a4SAndroid Build Coastguard Worker "net_sys/src/lib.rs", 310*bb4ee6a4SAndroid Build Coastguard Worker "system_api/src/bindings/*", 311*bb4ee6a4SAndroid Build Coastguard Worker ], 312*bb4ee6a4SAndroid Build Coastguard Worker python_tools=True, 313*bb4ee6a4SAndroid Build Coastguard Worker can_fix=True, 314*bb4ee6a4SAndroid Build Coastguard Worker ), 315*bb4ee6a4SAndroid Build Coastguard Worker Check( 316*bb4ee6a4SAndroid Build Coastguard Worker custom_check("check-rust-features"), 317*bb4ee6a4SAndroid Build Coastguard Worker files=["**Cargo.toml"], 318*bb4ee6a4SAndroid Build Coastguard Worker ), 319*bb4ee6a4SAndroid Build Coastguard Worker Check( 320*bb4ee6a4SAndroid Build Coastguard Worker custom_check("check-rust-lockfiles"), 321*bb4ee6a4SAndroid Build Coastguard Worker files=["**Cargo.toml"], 322*bb4ee6a4SAndroid Build Coastguard Worker ), 323*bb4ee6a4SAndroid Build Coastguard Worker Check( 324*bb4ee6a4SAndroid Build Coastguard Worker custom_check("check-line-endings"), 325*bb4ee6a4SAndroid Build Coastguard Worker ), 326*bb4ee6a4SAndroid Build Coastguard Worker Check( 327*bb4ee6a4SAndroid Build Coastguard Worker custom_check("check-file-ends-with-newline"), 328*bb4ee6a4SAndroid Build Coastguard Worker exclude=[ 329*bb4ee6a4SAndroid Build Coastguard Worker "**.h264", 330*bb4ee6a4SAndroid Build Coastguard Worker "**.vp8", 331*bb4ee6a4SAndroid Build Coastguard Worker "**.vp9", 332*bb4ee6a4SAndroid Build Coastguard Worker "**.ivf", 333*bb4ee6a4SAndroid Build Coastguard Worker "**.bin", 334*bb4ee6a4SAndroid Build Coastguard Worker "**.png", 335*bb4ee6a4SAndroid Build Coastguard Worker "**.min.js", 336*bb4ee6a4SAndroid Build Coastguard Worker "**.drawio", 337*bb4ee6a4SAndroid Build Coastguard Worker "**.json", 338*bb4ee6a4SAndroid Build Coastguard Worker "**.dtb", 339*bb4ee6a4SAndroid Build Coastguard Worker "**.dtbo", 340*bb4ee6a4SAndroid Build Coastguard Worker ], 341*bb4ee6a4SAndroid Build Coastguard Worker ), 342*bb4ee6a4SAndroid Build Coastguard Worker] 343*bb4ee6a4SAndroid Build Coastguard Worker 344*bb4ee6a4SAndroid Build Coastguard Worker#################################################################################################### 345*bb4ee6a4SAndroid Build Coastguard Worker# Group configuration 346*bb4ee6a4SAndroid Build Coastguard Worker# 347*bb4ee6a4SAndroid Build Coastguard Worker# Configures pre-defined groups of checks. Some are configured for CI builders and others 348*bb4ee6a4SAndroid Build Coastguard Worker# are configured for convenience during local development. 349*bb4ee6a4SAndroid Build Coastguard Worker 350*bb4ee6a4SAndroid Build Coastguard WorkerGROUPS: List[Group] = [ 351*bb4ee6a4SAndroid Build Coastguard Worker # The default group is run if no check or group is explicitly set 352*bb4ee6a4SAndroid Build Coastguard Worker Group( 353*bb4ee6a4SAndroid Build Coastguard Worker name="default", 354*bb4ee6a4SAndroid Build Coastguard Worker doc="Checks run by default", 355*bb4ee6a4SAndroid Build Coastguard Worker checks=[ 356*bb4ee6a4SAndroid Build Coastguard Worker "default_health_checks", 357*bb4ee6a4SAndroid Build Coastguard Worker # Run only one task per platform to prevent blocking on the build cache. 358*bb4ee6a4SAndroid Build Coastguard Worker "crosvm_tests_x86_64", 359*bb4ee6a4SAndroid Build Coastguard Worker "crosvm_unit_tests_aarch64", 360*bb4ee6a4SAndroid Build Coastguard Worker "crosvm_unit_tests_mingw64", 361*bb4ee6a4SAndroid Build Coastguard Worker "clippy_armhf", 362*bb4ee6a4SAndroid Build Coastguard Worker ], 363*bb4ee6a4SAndroid Build Coastguard Worker ), 364*bb4ee6a4SAndroid Build Coastguard Worker Group( 365*bb4ee6a4SAndroid Build Coastguard Worker name="quick", 366*bb4ee6a4SAndroid Build Coastguard Worker doc="Runs a quick subset of presubmit checks.", 367*bb4ee6a4SAndroid Build Coastguard Worker checks=[ 368*bb4ee6a4SAndroid Build Coastguard Worker "default_health_checks", 369*bb4ee6a4SAndroid Build Coastguard Worker "crosvm_unit_tests_x86_64", 370*bb4ee6a4SAndroid Build Coastguard Worker "clippy_aarch64", 371*bb4ee6a4SAndroid Build Coastguard Worker ], 372*bb4ee6a4SAndroid Build Coastguard Worker ), 373*bb4ee6a4SAndroid Build Coastguard Worker Group( 374*bb4ee6a4SAndroid Build Coastguard Worker name="all", 375*bb4ee6a4SAndroid Build Coastguard Worker doc="Run checks of all builders.", 376*bb4ee6a4SAndroid Build Coastguard Worker checks=[ 377*bb4ee6a4SAndroid Build Coastguard Worker "health_checks", 378*bb4ee6a4SAndroid Build Coastguard Worker *(f"linux_{platform}" for platform in PLATFORMS), 379*bb4ee6a4SAndroid Build Coastguard Worker *(f"clippy_{platform}" for platform in CLIPPY_ONLY_PLATFORMS), 380*bb4ee6a4SAndroid Build Coastguard Worker ], 381*bb4ee6a4SAndroid Build Coastguard Worker ), 382*bb4ee6a4SAndroid Build Coastguard Worker # Convenience groups for local usage: 383*bb4ee6a4SAndroid Build Coastguard Worker Group( 384*bb4ee6a4SAndroid Build Coastguard Worker name="clippy", 385*bb4ee6a4SAndroid Build Coastguard Worker doc="Runs clippy for all platforms", 386*bb4ee6a4SAndroid Build Coastguard Worker checks=[f"clippy_{platform}" for platform in PLATFORMS + CLIPPY_ONLY_PLATFORMS], 387*bb4ee6a4SAndroid Build Coastguard Worker ), 388*bb4ee6a4SAndroid Build Coastguard Worker Group( 389*bb4ee6a4SAndroid Build Coastguard Worker name="unit_tests", 390*bb4ee6a4SAndroid Build Coastguard Worker doc="Runs unit tests for all platforms", 391*bb4ee6a4SAndroid Build Coastguard Worker checks=[f"crosvm_unit_tests_{platform}" for platform in PLATFORMS], 392*bb4ee6a4SAndroid Build Coastguard Worker ), 393*bb4ee6a4SAndroid Build Coastguard Worker Group( 394*bb4ee6a4SAndroid Build Coastguard Worker name="format", 395*bb4ee6a4SAndroid Build Coastguard Worker doc="Runs all formatting checks (or fixes)", 396*bb4ee6a4SAndroid Build Coastguard Worker checks=[ 397*bb4ee6a4SAndroid Build Coastguard Worker "rust_format", 398*bb4ee6a4SAndroid Build Coastguard Worker "markdown_format", 399*bb4ee6a4SAndroid Build Coastguard Worker "python_format", 400*bb4ee6a4SAndroid Build Coastguard Worker ], 401*bb4ee6a4SAndroid Build Coastguard Worker ), 402*bb4ee6a4SAndroid Build Coastguard Worker Group( 403*bb4ee6a4SAndroid Build Coastguard Worker name="default_health_checks", 404*bb4ee6a4SAndroid Build Coastguard Worker doc="Health checks to run by default", 405*bb4ee6a4SAndroid Build Coastguard Worker checks=[ 406*bb4ee6a4SAndroid Build Coastguard Worker # Check if lockfiles need updating first. Otherwise another step may do the update. 407*bb4ee6a4SAndroid Build Coastguard Worker "rust_lockfiles", 408*bb4ee6a4SAndroid Build Coastguard Worker "copyright_header", 409*bb4ee6a4SAndroid Build Coastguard Worker "file_ends_with_newline", 410*bb4ee6a4SAndroid Build Coastguard Worker "line_endings", 411*bb4ee6a4SAndroid Build Coastguard Worker "markdown_format", 412*bb4ee6a4SAndroid Build Coastguard Worker "mdbook", 413*bb4ee6a4SAndroid Build Coastguard Worker "cargo_doc", 414*bb4ee6a4SAndroid Build Coastguard Worker "python_format", 415*bb4ee6a4SAndroid Build Coastguard Worker "python_types", 416*bb4ee6a4SAndroid Build Coastguard Worker "rust_features", 417*bb4ee6a4SAndroid Build Coastguard Worker "rust_format", 418*bb4ee6a4SAndroid Build Coastguard Worker ], 419*bb4ee6a4SAndroid Build Coastguard Worker ), 420*bb4ee6a4SAndroid Build Coastguard Worker # The groups below are used by builders in CI: 421*bb4ee6a4SAndroid Build Coastguard Worker Group( 422*bb4ee6a4SAndroid Build Coastguard Worker name="health_checks", 423*bb4ee6a4SAndroid Build Coastguard Worker doc="Checks run on the health_check builder", 424*bb4ee6a4SAndroid Build Coastguard Worker checks=[ 425*bb4ee6a4SAndroid Build Coastguard Worker "default_health_checks", 426*bb4ee6a4SAndroid Build Coastguard Worker "doc_tests", 427*bb4ee6a4SAndroid Build Coastguard Worker "python_tests", 428*bb4ee6a4SAndroid Build Coastguard Worker ], 429*bb4ee6a4SAndroid Build Coastguard Worker ), 430*bb4ee6a4SAndroid Build Coastguard Worker Group( 431*bb4ee6a4SAndroid Build Coastguard Worker name="android-aarch64", 432*bb4ee6a4SAndroid Build Coastguard Worker doc="Checks run on the android-aarch64 builder", 433*bb4ee6a4SAndroid Build Coastguard Worker checks=[ 434*bb4ee6a4SAndroid Build Coastguard Worker "clippy_android", 435*bb4ee6a4SAndroid Build Coastguard Worker ], 436*bb4ee6a4SAndroid Build Coastguard Worker ), 437*bb4ee6a4SAndroid Build Coastguard Worker *( 438*bb4ee6a4SAndroid Build Coastguard Worker Group( 439*bb4ee6a4SAndroid Build Coastguard Worker name=f"linux_{platform}", 440*bb4ee6a4SAndroid Build Coastguard Worker doc=f"Checks run on the linux-{platform} builder", 441*bb4ee6a4SAndroid Build Coastguard Worker checks=[ 442*bb4ee6a4SAndroid Build Coastguard Worker f"crosvm_tests_{platform}", 443*bb4ee6a4SAndroid Build Coastguard Worker f"clippy_{platform}", 444*bb4ee6a4SAndroid Build Coastguard Worker f"crosvm_build_default_{platform}", 445*bb4ee6a4SAndroid Build Coastguard Worker ] 446*bb4ee6a4SAndroid Build Coastguard Worker # TODO: b/260607247 crosvm does not compile with no-default-features on mingw64 447*bb4ee6a4SAndroid Build Coastguard Worker + ([f"crosvm_build_no_default_{platform}"] if platform != "mingw64" else []), 448*bb4ee6a4SAndroid Build Coastguard Worker ) 449*bb4ee6a4SAndroid Build Coastguard Worker for platform in PLATFORMS 450*bb4ee6a4SAndroid Build Coastguard Worker ), 451*bb4ee6a4SAndroid Build Coastguard Worker] 452*bb4ee6a4SAndroid Build Coastguard Worker 453*bb4ee6a4SAndroid Build Coastguard Worker# Turn both lists into dicts for convenience 454*bb4ee6a4SAndroid Build Coastguard WorkerCHECKS_DICT = dict((c.name, c) for c in CHECKS) 455*bb4ee6a4SAndroid Build Coastguard WorkerGROUPS_DICT = dict((c.name, c) for c in GROUPS) 456*bb4ee6a4SAndroid Build Coastguard Worker 457*bb4ee6a4SAndroid Build Coastguard Worker 458*bb4ee6a4SAndroid Build Coastguard Workerdef validate_config(): 459*bb4ee6a4SAndroid Build Coastguard Worker "Validates the CHECKS and GROUPS configuration." 460*bb4ee6a4SAndroid Build Coastguard Worker for group in GROUPS: 461*bb4ee6a4SAndroid Build Coastguard Worker for check in group.checks: 462*bb4ee6a4SAndroid Build Coastguard Worker if check not in CHECKS_DICT and check not in GROUPS_DICT: 463*bb4ee6a4SAndroid Build Coastguard Worker raise Exception(f"Group {group.name} includes non-existing item {check}.") 464*bb4ee6a4SAndroid Build Coastguard Worker 465*bb4ee6a4SAndroid Build Coastguard Worker def find_in_group(check: Check): 466*bb4ee6a4SAndroid Build Coastguard Worker for group in GROUPS: 467*bb4ee6a4SAndroid Build Coastguard Worker if check.name in group.checks: 468*bb4ee6a4SAndroid Build Coastguard Worker return True 469*bb4ee6a4SAndroid Build Coastguard Worker return False 470*bb4ee6a4SAndroid Build Coastguard Worker 471*bb4ee6a4SAndroid Build Coastguard Worker for check in CHECKS: 472*bb4ee6a4SAndroid Build Coastguard Worker if not find_in_group(check): 473*bb4ee6a4SAndroid Build Coastguard Worker raise Exception(f"Check {check.name} is not included in any group.") 474*bb4ee6a4SAndroid Build Coastguard Worker 475*bb4ee6a4SAndroid Build Coastguard Worker all_names = [c.name for c in CHECKS] + [g.name for g in GROUPS] 476*bb4ee6a4SAndroid Build Coastguard Worker for name in all_names: 477*bb4ee6a4SAndroid Build Coastguard Worker if all_names.count(name) > 1: 478*bb4ee6a4SAndroid Build Coastguard Worker raise Exception(f"Check or group {name} is defined multiple times.") 479*bb4ee6a4SAndroid Build Coastguard Worker 480*bb4ee6a4SAndroid Build Coastguard Worker 481*bb4ee6a4SAndroid Build Coastguard Workerdef get_check_names_in_group(group: Group) -> Generator[str, None, None]: 482*bb4ee6a4SAndroid Build Coastguard Worker for name in group.checks: 483*bb4ee6a4SAndroid Build Coastguard Worker if name in GROUPS_DICT: 484*bb4ee6a4SAndroid Build Coastguard Worker yield from get_check_names_in_group(GROUPS_DICT[name]) 485*bb4ee6a4SAndroid Build Coastguard Worker else: 486*bb4ee6a4SAndroid Build Coastguard Worker yield name 487*bb4ee6a4SAndroid Build Coastguard Worker 488*bb4ee6a4SAndroid Build Coastguard Worker 489*bb4ee6a4SAndroid Build Coastguard Worker@argh.arg("--list-checks", default=False, help="List names of available checks and exit.") 490*bb4ee6a4SAndroid Build Coastguard Worker@argh.arg("--fix", default=False, help="Asks checks to fix problems where possible.") 491*bb4ee6a4SAndroid Build Coastguard Worker@argh.arg("--no-delta", default=False, help="Run on all files instead of just modified files.") 492*bb4ee6a4SAndroid Build Coastguard Worker@argh.arg("--no-parallel", default=False, help="Do not run checks in parallel.") 493*bb4ee6a4SAndroid Build Coastguard Worker@argh.arg( 494*bb4ee6a4SAndroid Build Coastguard Worker "checks_or_groups", 495*bb4ee6a4SAndroid Build Coastguard Worker help="List of checks or groups to run. Defaults to run the `default` group.", 496*bb4ee6a4SAndroid Build Coastguard Worker) 497*bb4ee6a4SAndroid Build Coastguard Workerdef main( 498*bb4ee6a4SAndroid Build Coastguard Worker list_checks: bool = False, 499*bb4ee6a4SAndroid Build Coastguard Worker fix: bool = False, 500*bb4ee6a4SAndroid Build Coastguard Worker no_delta: bool = False, 501*bb4ee6a4SAndroid Build Coastguard Worker no_parallel: bool = False, 502*bb4ee6a4SAndroid Build Coastguard Worker *checks_or_groups: str, 503*bb4ee6a4SAndroid Build Coastguard Worker): 504*bb4ee6a4SAndroid Build Coastguard Worker chdir(CROSVM_ROOT) 505*bb4ee6a4SAndroid Build Coastguard Worker validate_config() 506*bb4ee6a4SAndroid Build Coastguard Worker 507*bb4ee6a4SAndroid Build Coastguard Worker if not checks_or_groups: 508*bb4ee6a4SAndroid Build Coastguard Worker checks_or_groups = ("default",) 509*bb4ee6a4SAndroid Build Coastguard Worker 510*bb4ee6a4SAndroid Build Coastguard Worker # Resolve and validate the groups and checks provided 511*bb4ee6a4SAndroid Build Coastguard Worker check_names: List[str] = [] 512*bb4ee6a4SAndroid Build Coastguard Worker for check_or_group in checks_or_groups: 513*bb4ee6a4SAndroid Build Coastguard Worker if check_or_group in CHECKS_DICT: 514*bb4ee6a4SAndroid Build Coastguard Worker check_names.append(check_or_group) 515*bb4ee6a4SAndroid Build Coastguard Worker elif check_or_group in GROUPS_DICT: 516*bb4ee6a4SAndroid Build Coastguard Worker check_names += list(get_check_names_in_group(GROUPS_DICT[check_or_group])) 517*bb4ee6a4SAndroid Build Coastguard Worker else: 518*bb4ee6a4SAndroid Build Coastguard Worker raise Exception(f"No such check or group: {check_or_group}") 519*bb4ee6a4SAndroid Build Coastguard Worker 520*bb4ee6a4SAndroid Build Coastguard Worker # Remove duplicates while preserving order 521*bb4ee6a4SAndroid Build Coastguard Worker check_names = list(dict.fromkeys(check_names)) 522*bb4ee6a4SAndroid Build Coastguard Worker 523*bb4ee6a4SAndroid Build Coastguard Worker if list_checks: 524*bb4ee6a4SAndroid Build Coastguard Worker for check in check_names: 525*bb4ee6a4SAndroid Build Coastguard Worker print(check) 526*bb4ee6a4SAndroid Build Coastguard Worker return 527*bb4ee6a4SAndroid Build Coastguard Worker 528*bb4ee6a4SAndroid Build Coastguard Worker check_list = [CHECKS_DICT[name] for name in check_names] 529*bb4ee6a4SAndroid Build Coastguard Worker 530*bb4ee6a4SAndroid Build Coastguard Worker run_checks( 531*bb4ee6a4SAndroid Build Coastguard Worker check_list, 532*bb4ee6a4SAndroid Build Coastguard Worker fix=fix, 533*bb4ee6a4SAndroid Build Coastguard Worker run_on_all_files=no_delta, 534*bb4ee6a4SAndroid Build Coastguard Worker parallel=not no_parallel, 535*bb4ee6a4SAndroid Build Coastguard Worker ) 536*bb4ee6a4SAndroid Build Coastguard Worker 537*bb4ee6a4SAndroid Build Coastguard Worker 538*bb4ee6a4SAndroid Build Coastguard Workerdef usage(): 539*bb4ee6a4SAndroid Build Coastguard Worker groups = "\n".join(f" {group.name}: {group.doc}" for group in GROUPS) 540*bb4ee6a4SAndroid Build Coastguard Worker checks = "\n".join(f" {check.name}: {check.doc}" for check in CHECKS) 541*bb4ee6a4SAndroid Build Coastguard Worker return f"""\ 542*bb4ee6a4SAndroid Build Coastguard WorkerRuns checks on the crosvm codebase. 543*bb4ee6a4SAndroid Build Coastguard Worker 544*bb4ee6a4SAndroid Build Coastguard WorkerBasic usage, to run a default selection of checks: 545*bb4ee6a4SAndroid Build Coastguard Worker 546*bb4ee6a4SAndroid Build Coastguard Worker ./tools/presubmit 547*bb4ee6a4SAndroid Build Coastguard Worker 548*bb4ee6a4SAndroid Build Coastguard WorkerSome checkers can fix issues they find (e.g. formatters, clippy, etc): 549*bb4ee6a4SAndroid Build Coastguard Worker 550*bb4ee6a4SAndroid Build Coastguard Worker ./tools/presubmit --fix 551*bb4ee6a4SAndroid Build Coastguard Worker 552*bb4ee6a4SAndroid Build Coastguard Worker 553*bb4ee6a4SAndroid Build Coastguard WorkerVarious groups of presubmit checks can be run via: 554*bb4ee6a4SAndroid Build Coastguard Worker 555*bb4ee6a4SAndroid Build Coastguard Worker ./tools/presubmit group_name 556*bb4ee6a4SAndroid Build Coastguard Worker 557*bb4ee6a4SAndroid Build Coastguard WorkerAvailable groups are: 558*bb4ee6a4SAndroid Build Coastguard Worker{groups} 559*bb4ee6a4SAndroid Build Coastguard Worker 560*bb4ee6a4SAndroid Build Coastguard WorkerYou can also provide the names of specific checks to run: 561*bb4ee6a4SAndroid Build Coastguard Worker 562*bb4ee6a4SAndroid Build Coastguard Worker ./tools/presubmit check1 check2 563*bb4ee6a4SAndroid Build Coastguard Worker 564*bb4ee6a4SAndroid Build Coastguard WorkerAvailable checks are: 565*bb4ee6a4SAndroid Build Coastguard Worker{checks} 566*bb4ee6a4SAndroid Build Coastguard Worker""" 567*bb4ee6a4SAndroid Build Coastguard Worker 568*bb4ee6a4SAndroid Build Coastguard Worker 569*bb4ee6a4SAndroid Build Coastguard Workerif __name__ == "__main__": 570*bb4ee6a4SAndroid Build Coastguard Worker run_main(main, usage=usage()) 571