mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 18:28:24 +00:00

Until https://github.com/astral-sh/ruff/issues/8076 is ready, it seems beneficial to get feedback on preview mode changes. Tested locally, updated logs to output the flags passed to `ruff` and verified `--preview` is used.
175 lines
5 KiB
Python
175 lines
5 KiB
Python
import argparse
|
|
import asyncio
|
|
import logging
|
|
import os
|
|
import shutil
|
|
import sys
|
|
import sysconfig
|
|
import tempfile
|
|
from contextlib import nullcontext
|
|
from pathlib import Path
|
|
from signal import SIGINT, SIGTERM
|
|
|
|
from ruff_ecosystem import logger
|
|
from ruff_ecosystem.defaults import DEFAULT_TARGETS
|
|
from ruff_ecosystem.main import OutputFormat, main
|
|
from ruff_ecosystem.projects import RuffCommand
|
|
|
|
|
|
def excepthook(type, value, tb):
|
|
if hasattr(sys, "ps1") or not sys.stderr.isatty():
|
|
# we are in interactive mode or we don't have a tty so call the default
|
|
sys.__excepthook__(type, value, tb)
|
|
else:
|
|
import pdb
|
|
import traceback
|
|
|
|
traceback.print_exception(type, value, tb)
|
|
print()
|
|
pdb.post_mortem(tb)
|
|
|
|
|
|
def entrypoint():
|
|
args = parse_args()
|
|
|
|
if args.pdb:
|
|
sys.excepthook = excepthook
|
|
|
|
if args.verbose:
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
else:
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
# Use a temporary directory for caching if no cache is specified
|
|
cache_context = (
|
|
tempfile.TemporaryDirectory() if not args.cache else nullcontext(args.cache)
|
|
)
|
|
|
|
ruff_baseline = args.ruff_baseline
|
|
if not args.ruff_baseline.exists():
|
|
ruff_baseline = get_executable_path(str(args.ruff_baseline))
|
|
if not ruff_baseline:
|
|
print(
|
|
f"Could not find ruff baseline executable: {args.ruff_baseline}",
|
|
sys.stderr,
|
|
)
|
|
exit(1)
|
|
logger.info(
|
|
"Resolved baseline executable %s to %s", args.ruff_baseline, ruff_baseline
|
|
)
|
|
|
|
ruff_comparison = args.ruff_comparison
|
|
if not args.ruff_comparison.exists():
|
|
ruff_comparison = get_executable_path(str(args.ruff_comparison))
|
|
if not ruff_comparison:
|
|
print(
|
|
f"Could not find ruff comparison executable: {args.ruff_comparison}",
|
|
sys.stderr,
|
|
)
|
|
exit(1)
|
|
logger.info(
|
|
"Resolved comparison executable %s to %s",
|
|
args.ruff_comparison,
|
|
ruff_comparison,
|
|
)
|
|
|
|
targets = DEFAULT_TARGETS
|
|
if args.force_preview:
|
|
targets = [target.with_preview_enabled() for target in targets]
|
|
|
|
with cache_context as cache:
|
|
loop = asyncio.get_event_loop()
|
|
main_task = asyncio.ensure_future(
|
|
main(
|
|
command=RuffCommand(args.ruff_command),
|
|
ruff_baseline_executable=ruff_baseline,
|
|
ruff_comparison_executable=ruff_comparison,
|
|
targets=targets,
|
|
format=OutputFormat(args.output_format),
|
|
project_dir=Path(cache),
|
|
raise_on_failure=args.pdb,
|
|
)
|
|
)
|
|
# https://stackoverflow.com/a/58840987/3549270
|
|
for signal in [SIGINT, SIGTERM]:
|
|
loop.add_signal_handler(signal, main_task.cancel)
|
|
try:
|
|
loop.run_until_complete(main_task)
|
|
finally:
|
|
loop.close()
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(
|
|
description="Check two versions of ruff against a corpus of open-source code.",
|
|
)
|
|
|
|
# TODO: Support non-default `--targets`
|
|
# parser.add_argument(
|
|
# "--targets",
|
|
# type=Path,
|
|
# help=(
|
|
# "Optional JSON files to use over the default repositories. "
|
|
# "Supports both github_search_*.jsonl and known-github-tomls.jsonl."
|
|
# ),
|
|
# )
|
|
parser.add_argument(
|
|
"--cache",
|
|
type=Path,
|
|
help="Location for caching cloned repositories",
|
|
)
|
|
parser.add_argument(
|
|
"--output-format",
|
|
choices=[option.name for option in OutputFormat],
|
|
default="json",
|
|
help="Location for caching cloned repositories",
|
|
)
|
|
parser.add_argument(
|
|
"-v",
|
|
"--verbose",
|
|
action="store_true",
|
|
help="Enable debug logging",
|
|
)
|
|
parser.add_argument(
|
|
"--pdb",
|
|
action="store_true",
|
|
help="Enable debugging on failure",
|
|
)
|
|
parser.add_argument(
|
|
"--force-preview",
|
|
action="store_true",
|
|
help="Force preview mode to be enabled for all projects",
|
|
)
|
|
parser.add_argument(
|
|
"ruff_command",
|
|
choices=[option.name for option in RuffCommand],
|
|
help="The Ruff command to test",
|
|
)
|
|
parser.add_argument(
|
|
"ruff_baseline",
|
|
type=Path,
|
|
)
|
|
parser.add_argument(
|
|
"ruff_comparison",
|
|
type=Path,
|
|
)
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
def get_executable_path(name: str) -> Path | None:
|
|
# Add suffix for Windows executables
|
|
name += ".exe" if sys.platform == "win32" and not name.endswith(".exe") else ""
|
|
|
|
path = os.path.join(sysconfig.get_path("scripts"), name)
|
|
|
|
# The executable in the current interpreter's scripts directory.
|
|
if os.path.exists(path):
|
|
return Path(path)
|
|
|
|
# The executable in the global environment.
|
|
environment_path = shutil.which(name)
|
|
if environment_path:
|
|
return Path(environment_path)
|
|
|
|
return None
|