## Summary We want to ensure that once formatted content stays the same when formatted again, which is known as formatter stability or formatter idempotency, and that the formatter prints syntactically valid code. As our test cases cover only a limited amount of code, this allows checking entire repositories. This adds a new subcommand to `ruff_dev` which can be invoked as `cargo run --bin ruff_dev -- check-formatter-stability <repo>`. While initially only intended to check stability, it has also found cases where the formatter printed invalid syntax or panicked. ## Test Plan Running this on cpython is already identifying bugs (https://github.com/astral-sh/ruff/pull/5089)
103 lines
3.5 KiB
Rust
103 lines
3.5 KiB
Rust
//! This crate implements an internal CLI for developers of Ruff.
|
|
//!
|
|
//! Within the ruff repository you can run it with `cargo dev`.
|
|
|
|
use anyhow::Result;
|
|
use clap::{Parser, Subcommand};
|
|
use ruff::logging::{set_up_logging, LogLevel};
|
|
use ruff_cli::check;
|
|
use std::process::ExitCode;
|
|
|
|
mod check_formatter_stability;
|
|
mod generate_all;
|
|
mod generate_cli_help;
|
|
mod generate_docs;
|
|
mod generate_json_schema;
|
|
mod generate_options;
|
|
mod generate_rules_table;
|
|
mod print_ast;
|
|
mod print_cst;
|
|
mod print_tokens;
|
|
mod round_trip;
|
|
|
|
const ROOT_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../");
|
|
|
|
#[derive(Parser)]
|
|
#[command(author, version, about, long_about = None)]
|
|
#[command(propagate_version = true)]
|
|
struct Args {
|
|
#[command(subcommand)]
|
|
command: Command,
|
|
}
|
|
|
|
#[derive(Subcommand)]
|
|
#[allow(clippy::large_enum_variant)]
|
|
enum Command {
|
|
/// Run all code and documentation generation steps.
|
|
GenerateAll(generate_all::Args),
|
|
/// Generate JSON schema for the TOML configuration file.
|
|
GenerateJSONSchema(generate_json_schema::Args),
|
|
/// Generate a Markdown-compatible table of supported lint rules.
|
|
GenerateRulesTable,
|
|
/// Generate a Markdown-compatible listing of configuration options.
|
|
GenerateOptions,
|
|
/// Generate CLI help.
|
|
GenerateCliHelp(generate_cli_help::Args),
|
|
/// Generate Markdown docs.
|
|
GenerateDocs(generate_docs::Args),
|
|
/// Print the AST for a given Python file.
|
|
PrintAST(print_ast::Args),
|
|
/// Print the LibCST CST for a given Python file.
|
|
PrintCST(print_cst::Args),
|
|
/// Print the token stream for a given Python file.
|
|
PrintTokens(print_tokens::Args),
|
|
/// Run round-trip source code generation on a given Python file.
|
|
RoundTrip(round_trip::Args),
|
|
/// Run a ruff command n times for profiling/benchmarking
|
|
Repeat {
|
|
#[clap(flatten)]
|
|
args: ruff_cli::args::CheckArgs,
|
|
#[clap(flatten)]
|
|
log_level_args: ruff_cli::args::LogLevelArgs,
|
|
/// Run this many times
|
|
#[clap(long, short = 'n')]
|
|
repeat: usize,
|
|
},
|
|
/// Format a repository twice and ensure that it looks that the first and second formatting
|
|
/// look the same. Same arguments as `ruff check`
|
|
CheckFormatterStability(check_formatter_stability::Args),
|
|
}
|
|
|
|
fn main() -> Result<ExitCode> {
|
|
let args = Args::parse();
|
|
#[allow(clippy::print_stdout)]
|
|
match args.command {
|
|
Command::GenerateAll(args) => generate_all::main(&args)?,
|
|
Command::GenerateJSONSchema(args) => generate_json_schema::main(&args)?,
|
|
Command::GenerateRulesTable => println!("{}", generate_rules_table::generate()),
|
|
Command::GenerateOptions => println!("{}", generate_options::generate()),
|
|
Command::GenerateCliHelp(args) => generate_cli_help::main(&args)?,
|
|
Command::GenerateDocs(args) => generate_docs::main(&args)?,
|
|
Command::PrintAST(args) => print_ast::main(&args)?,
|
|
Command::PrintCST(args) => print_cst::main(&args)?,
|
|
Command::PrintTokens(args) => print_tokens::main(&args)?,
|
|
Command::RoundTrip(args) => round_trip::main(&args)?,
|
|
Command::Repeat {
|
|
args,
|
|
repeat,
|
|
log_level_args,
|
|
} => {
|
|
let log_level = LogLevel::from(&log_level_args);
|
|
set_up_logging(&log_level)?;
|
|
for _ in 0..repeat {
|
|
check(args.clone(), log_level)?;
|
|
}
|
|
}
|
|
Command::CheckFormatterStability(args) => {
|
|
let exit_code = check_formatter_stability::main(&args)?;
|
|
return Ok(exit_code);
|
|
}
|
|
}
|
|
Ok(ExitCode::SUCCESS)
|
|
}
|