misc.python.materialize.cli.fmt
fmt — formats Rust, Python & Protobuf files in parallel.
1# Copyright Materialize, Inc. and contributors. All rights reserved. 2# 3# Use of this software is governed by the Business Source License 4# included in the LICENSE file at the root of this repository. 5# 6# As of the Change Date specified in that file, in accordance with 7# the Business Source License, use of this software will be governed 8# by the Apache License, Version 2.0. 9 10"""fmt — formats Rust, Python & Protobuf files in parallel.""" 11 12import argparse 13import json 14import math 15import os 16import subprocess 17 18from materialize import MZ_ROOT 19from materialize.parallel_task import TaskSpec, run_parallel 20 21 22def main() -> int: 23 parser = argparse.ArgumentParser(prog="fmt") 24 parser.add_argument("--check", action="store_true") 25 args = parser.parse_args() 26 27 tasks: list[tuple[str, TaskSpec]] = [ 28 ("rustfmt", _rustfmt_fn(check=args.check)), 29 ("buf", _buf_cmd(check=args.check)), 30 ] 31 32 if not os.environ.get("MZDEV_NO_PYTHON"): 33 tasks += [ 34 ("black", _black_cmd(check=args.check)), 35 ("ruff", _ruff_cmd(check=args.check)), 36 ("ruff-dbt", _ruff_dbt_cmd(check=args.check)), 37 ] 38 39 return 1 if run_parallel(tasks, spinner_suffix="formatters") else 0 40 41 42def _rustfmt_fn(*, check: bool): 43 """Return a callable that runs cargo metadata + parallel rustfmt.""" 44 45 def run() -> tuple[bool, str]: 46 ncpus = os.cpu_count() or 8 47 48 result = subprocess.run( 49 ["cargo", "metadata", "--no-deps", "--format-version=1"], 50 capture_output=True, 51 text=True, 52 ) 53 if result.returncode != 0: 54 return False, result.stderr.strip() 55 56 meta = json.loads(result.stdout) 57 kinds = {"lib", "bin", "bench", "test", "example", "proc-macro", "custom-build"} 58 paths = [ 59 t["src_path"] 60 for pkg in meta["packages"] 61 for t in pkg["targets"] 62 if kinds & set(t["kind"]) 63 ] 64 if not paths: 65 return True, "" 66 67 # Split into batches and run rustfmt in parallel. 68 batch_size = math.ceil(len(paths) / ncpus) 69 batches = [paths[i : i + batch_size] for i in range(0, len(paths), batch_size)] 70 71 cmd_base = ["rustfmt", "--config", "error_on_line_overflow=true"] 72 if check: 73 cmd_base.append("--check") 74 75 procs = [ 76 subprocess.Popen( 77 cmd_base + batch, 78 stdout=subprocess.PIPE, 79 stderr=subprocess.STDOUT, 80 ) 81 for batch in batches 82 ] 83 84 all_output = [] 85 all_ok = True 86 for proc in procs: 87 stdout, _ = proc.communicate() 88 if proc.returncode != 0: 89 all_ok = False 90 out = stdout.decode("utf-8").strip() 91 if out: 92 all_output.append(out) 93 94 return all_ok, "\n".join(all_output) 95 96 return run 97 98 99def _buf_cmd(*, check: bool) -> list[str]: 100 if check: 101 return ["buf", "format", "src", "--diff", "--exit-code"] 102 return ["buf", "format", "src", "-w"] 103 104 105def _black_cmd(*, check: bool) -> list[str]: 106 args = "--check --quiet" if check else "--quiet" 107 return [ 108 "bash", 109 "-c", 110 f'. misc/shlib/shlib.bash && git_files "*.py" | xargs bin/pyactivate -m black {args}', 111 ] 112 113 114def _ruff_cmd(*, check: bool) -> list[str]: 115 fix = "" if check else " --fix" 116 return [ 117 "bash", 118 "-c", 119 f'. misc/shlib/shlib.bash && git_files "*.py" | grep -v "^misc/dbt-materialize/" | xargs bin/pyactivate -m ruff{fix}', 120 ] 121 122 123def _ruff_dbt_cmd(*, check: bool) -> list[str]: 124 fix = "" if check else " --fix" 125 return [ 126 "bash", 127 "-c", 128 f'. misc/shlib/shlib.bash && git_files "misc/dbt-materialize/*.py" | xargs bin/pyactivate -m ruff --target-version=py38{fix}', 129 ] 130 131 132if __name__ == "__main__": 133 os.chdir(MZ_ROOT) 134 exit(main())
def
main() -> int:
23def main() -> int: 24 parser = argparse.ArgumentParser(prog="fmt") 25 parser.add_argument("--check", action="store_true") 26 args = parser.parse_args() 27 28 tasks: list[tuple[str, TaskSpec]] = [ 29 ("rustfmt", _rustfmt_fn(check=args.check)), 30 ("buf", _buf_cmd(check=args.check)), 31 ] 32 33 if not os.environ.get("MZDEV_NO_PYTHON"): 34 tasks += [ 35 ("black", _black_cmd(check=args.check)), 36 ("ruff", _ruff_cmd(check=args.check)), 37 ("ruff-dbt", _ruff_dbt_cmd(check=args.check)), 38 ] 39 40 return 1 if run_parallel(tasks, spinner_suffix="formatters") else 0