#!/usr/bin/env python3
"""
Runs run-clang-tidy. A bit meta. Maybe it will replace run-clang-tidy one day
because the run-clang-tidy UX is so questionable.
"""

# I hereby dedicate this script to fuck you meson.
# I cannot simply write my code to invoke a subprocess in a meson file because
# Meson corrupts backslashes in command line args to subprocesses.
# This is allegedly for "Windows support", but last time I checked Windows
# neither needs nor wants you to corrupt its command lines.
# https://github.com/mesonbuild/meson/issues/1564

import multiprocessing
import subprocess
import os
import sys
from pathlib import Path


def default_concurrency():
    return min(multiprocessing.cpu_count(),
               int(os.environ.get("NIX_BUILD_CORES", "16")))


def go(exe: str, plugin_path: Path, compile_commands_json_dir: Path, jobs: int,
       paths: list[Path], werror: bool, fix: bool):
    args = [
        # XXX: This explicitly invokes it with python because of a nixpkgs bug
        # where clang-unwrapped does not patch interpreters in run-clang-tidy.
        # However, making clang-unwrapped depend on python is also silly, so idk.
        sys.executable,
        exe,
        '-quiet',
        '-load',
        plugin_path,
        '-p',
        compile_commands_json_dir,
        '-j',
        str(jobs),
        '-header-filter',
        r'src/[^/]+/.*\.hh'
    ]
    if werror:
        args += ['-warnings-as-errors', '*']
    if fix:
        args += ['-fix']
    args += ['--']
    args += paths
    os.execvp(sys.executable, args)


def main():
    import argparse

    ap = argparse.ArgumentParser(description='Runs run-clang-tidy for you')
    ap.add_argument('--jobs',
                    '-j',
                    type=int,
                    default=default_concurrency(),
                    help='Parallel linting jobs to run')
    ap.add_argument('--plugin-path',
                    type=Path,
                    help='Path to the Lix clang-tidy plugin')
    # FIXME: maybe we should integrate this so it just fixes the compdb for you and throws it in a tempdir?
    ap.add_argument(
        '--compdb-path',
        type=Path,
        help=
        'Path to the directory containing the fixed-up compilation database from clean_compdb'
    )
    ap.add_argument('--werror',
                    action='store_true',
                    help='Warnings get turned into errors')
    ap.add_argument('--fix',
                    action='store_true',
                    help='Apply fixes for warnings')
    ap.add_argument('--run-clang-tidy-path',
                    default='run-clang-tidy',
                    help='Path to run-clang-tidy')
    ap.add_argument('paths', nargs='*', help='Source paths to check')
    args = ap.parse_args()

    go(args.run_clang_tidy_path, args.plugin_path, args.compdb_path, args.jobs,
       args.paths, args.werror, args.fix)


if __name__ == '__main__':
    main()
