From a3d06d00055ec44bb07d8d3dcfa744c0a08ad23b Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 12 Dec 2022 10:22:47 -0500 Subject: [PATCH] Move more commands into commands.rs (#1209) --- src/commands.rs | 155 ++++++++++++++++++++++++++++++++++++++++++++- src/main.rs | 164 +++--------------------------------------------- 2 files changed, 162 insertions(+), 157 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index da78ee0c04..58a9056474 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,15 +1,168 @@ +use std::io::{self, Read}; use std::path::{Path, PathBuf}; +use std::time::Instant; use anyhow::{bail, Result}; use itertools::Itertools; +use log::{debug, error}; +#[cfg(not(target_family = "wasm"))] +use rayon::prelude::*; +use rustpython_ast::Location; use serde::Serialize; -use crate::checks::CheckCode; +use crate::autofix::fixer; +use crate::checks::{CheckCode, CheckKind}; use crate::cli::Overrides; use crate::fs::collect_python_files; +use crate::iterators::par_iter; +use crate::linter::{add_noqa_to_path, autoformat_path, lint_path, lint_stdin, Diagnostics}; +use crate::message::Message; use crate::settings::types::SerializationFormat; use crate::{Configuration, Settings}; +/// Run the linter over a collection of files. +pub fn run( + files: &[PathBuf], + defaults: &Settings, + overrides: &Overrides, + cache: bool, + autofix: &fixer::Mode, +) -> Diagnostics { + // Collect all the files to check. + let start = Instant::now(); + let (paths, resolver) = collect_python_files(files, overrides, defaults); + let duration = start.elapsed(); + debug!("Identified files to lint in: {:?}", duration); + + let start = Instant::now(); + let mut diagnostics: Diagnostics = par_iter(&paths) + .map(|entry| { + match entry { + Ok(entry) => { + let path = entry.path(); + let settings = resolver.resolve(path).unwrap_or(defaults); + lint_path(path, settings, &cache.into(), autofix) + .map_err(|e| (Some(path.to_owned()), e.to_string())) + } + Err(e) => Err(( + e.path().map(Path::to_owned), + e.io_error() + .map_or_else(|| e.to_string(), io::Error::to_string), + )), + } + .unwrap_or_else(|(path, message)| { + if let Some(path) = &path { + let settings = resolver.resolve(path).unwrap_or(defaults); + if settings.enabled.contains(&CheckCode::E902) { + Diagnostics::new(vec![Message { + kind: CheckKind::IOError(message), + location: Location::default(), + end_location: Location::default(), + fix: None, + filename: path.to_string_lossy().to_string(), + source: None, + }]) + } else { + error!("Failed to check {}: {message}", path.to_string_lossy()); + Diagnostics::default() + } + } else { + error!("{message}"); + Diagnostics::default() + } + }) + }) + .reduce(Diagnostics::default, |mut acc, item| { + acc += item; + acc + }); + + diagnostics.messages.sort_unstable(); + let duration = start.elapsed(); + debug!("Checked files in: {:?}", duration); + + diagnostics +} + +/// Read a `String` from `stdin`. +fn read_from_stdin() -> Result { + let mut buffer = String::new(); + io::stdin().lock().read_to_string(&mut buffer)?; + Ok(buffer) +} + +/// Run the linter over a single file, read from `stdin`. +pub fn run_stdin( + settings: &Settings, + filename: &Path, + autofix: &fixer::Mode, +) -> Result { + let stdin = read_from_stdin()?; + let mut diagnostics = lint_stdin(filename, &stdin, settings, autofix)?; + diagnostics.messages.sort_unstable(); + Ok(diagnostics) +} + +/// Add `noqa` directives to a collection of files. +pub fn add_noqa(files: &[PathBuf], defaults: &Settings, overrides: &Overrides) -> usize { + // Collect all the files to check. + let start = Instant::now(); + let (paths, resolver) = collect_python_files(files, overrides, defaults); + let duration = start.elapsed(); + debug!("Identified files to lint in: {:?}", duration); + + let start = Instant::now(); + let modifications: usize = par_iter(&paths) + .flatten() + .filter_map(|entry| { + let path = entry.path(); + let settings = resolver.resolve(path).unwrap_or(defaults); + match add_noqa_to_path(path, settings) { + Ok(count) => Some(count), + Err(e) => { + error!("Failed to add noqa to {}: {e}", path.to_string_lossy()); + None + } + } + }) + .sum(); + + let duration = start.elapsed(); + debug!("Added noqa to files in: {:?}", duration); + + modifications +} + +/// Automatically format a collection of files. +pub fn autoformat(files: &[PathBuf], defaults: &Settings, overrides: &Overrides) -> usize { + // Collect all the files to format. + let start = Instant::now(); + let (paths, resolver) = collect_python_files(files, overrides, defaults); + let duration = start.elapsed(); + debug!("Identified files to lint in: {:?}", duration); + + let start = Instant::now(); + let modifications = par_iter(&paths) + .flatten() + .filter_map(|entry| { + let path = entry.path(); + let settings = resolver.resolve(path).unwrap_or(defaults); + match autoformat_path(path, settings) { + Ok(()) => Some(()), + Err(e) => { + error!("Failed to autoformat {}: {e}", path.to_string_lossy()); + None + } + } + }) + .count(); + + let duration = start.elapsed(); + debug!("Auto-formatted files in: {:?}", duration); + + modifications +} + /// Print the user-facing configuration settings. pub fn show_settings(configuration: &Configuration, pyproject: Option<&Path>) { println!("Resolved configuration: {configuration:#?}"); diff --git a/src/main.rs b/src/main.rs index 7d0b6f367d..3f6e12f15b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,20 +11,14 @@ clippy::too_many_lines )] -use std::io::{self, Read}; +use std::io::{self}; use std::path::{Path, PathBuf}; use std::process::ExitCode; use std::sync::mpsc::channel; -use std::time::Instant; use ::ruff::autofix::fixer; -use ::ruff::checks::{CheckCode, CheckKind}; -use ::ruff::cli::{extract_log_level, Cli, Overrides}; -use ::ruff::fs::collect_python_files; -use ::ruff::iterators::par_iter; -use ::ruff::linter::{add_noqa_to_path, autoformat_path, lint_path, lint_stdin, Diagnostics}; +use ::ruff::cli::{extract_log_level, Cli}; use ::ruff::logging::{set_up_logging, LogLevel}; -use ::ruff::message::Message; use ::ruff::printer::Printer; use ::ruff::settings::configuration::Configuration; use ::ruff::settings::types::SerializationFormat; @@ -35,150 +29,8 @@ use ::ruff::{cache, commands}; use anyhow::Result; use clap::{CommandFactory, Parser}; use colored::Colorize; -use log::{debug, error}; use notify::{recommended_watcher, RecursiveMode, Watcher}; use path_absolutize::path_dedot; -#[cfg(not(target_family = "wasm"))] -use rayon::prelude::*; -use rustpython_ast::Location; - -fn read_from_stdin() -> Result { - let mut buffer = String::new(); - io::stdin().lock().read_to_string(&mut buffer)?; - Ok(buffer) -} - -fn run_once_stdin( - settings: &Settings, - filename: &Path, - autofix: &fixer::Mode, -) -> Result { - let stdin = read_from_stdin()?; - let mut diagnostics = lint_stdin(filename, &stdin, settings, autofix)?; - diagnostics.messages.sort_unstable(); - Ok(diagnostics) -} - -fn run_once( - files: &[PathBuf], - defaults: &Settings, - overrides: &Overrides, - cache: bool, - autofix: &fixer::Mode, -) -> Diagnostics { - // Collect all the files to check. - let start = Instant::now(); - let (paths, resolver) = collect_python_files(files, overrides, defaults); - let duration = start.elapsed(); - debug!("Identified files to lint in: {:?}", duration); - - let start = Instant::now(); - let mut diagnostics: Diagnostics = par_iter(&paths) - .map(|entry| { - match entry { - Ok(entry) => { - let path = entry.path(); - let settings = resolver.resolve(path).unwrap_or(defaults); - lint_path(path, settings, &cache.into(), autofix) - .map_err(|e| (Some(path.to_owned()), e.to_string())) - } - Err(e) => Err(( - e.path().map(Path::to_owned), - e.io_error() - .map_or_else(|| e.to_string(), io::Error::to_string), - )), - } - .unwrap_or_else(|(path, message)| { - if let Some(path) = &path { - let settings = resolver.resolve(path).unwrap_or(defaults); - if settings.enabled.contains(&CheckCode::E902) { - Diagnostics::new(vec![Message { - kind: CheckKind::IOError(message), - location: Location::default(), - end_location: Location::default(), - fix: None, - filename: path.to_string_lossy().to_string(), - source: None, - }]) - } else { - error!("Failed to check {}: {message}", path.to_string_lossy()); - Diagnostics::default() - } - } else { - error!("{message}"); - Diagnostics::default() - } - }) - }) - .reduce(Diagnostics::default, |mut acc, item| { - acc += item; - acc - }); - - diagnostics.messages.sort_unstable(); - let duration = start.elapsed(); - debug!("Checked files in: {:?}", duration); - - diagnostics -} - -fn add_noqa(files: &[PathBuf], defaults: &Settings, overrides: &Overrides) -> usize { - // Collect all the files to check. - let start = Instant::now(); - let (paths, resolver) = collect_python_files(files, overrides, defaults); - let duration = start.elapsed(); - debug!("Identified files to lint in: {:?}", duration); - - let start = Instant::now(); - let modifications: usize = par_iter(&paths) - .flatten() - .filter_map(|entry| { - let path = entry.path(); - let settings = resolver.resolve(path).unwrap_or(defaults); - match add_noqa_to_path(path, settings) { - Ok(count) => Some(count), - Err(e) => { - error!("Failed to add noqa to {}: {e}", path.to_string_lossy()); - None - } - } - }) - .sum(); - - let duration = start.elapsed(); - debug!("Added noqa to files in: {:?}", duration); - - modifications -} - -fn autoformat(files: &[PathBuf], defaults: &Settings, overrides: &Overrides) -> usize { - // Collect all the files to format. - let start = Instant::now(); - let (paths, resolver) = collect_python_files(files, overrides, defaults); - let duration = start.elapsed(); - debug!("Identified files to lint in: {:?}", duration); - - let start = Instant::now(); - let modifications = par_iter(&paths) - .flatten() - .filter_map(|entry| { - let path = entry.path(); - let settings = resolver.resolve(path).unwrap_or(defaults); - match autoformat_path(path, settings) { - Ok(()) => Some(()), - Err(e) => { - error!("Failed to autoformat {}: {e}", path.to_string_lossy()); - None - } - } - }) - .count(); - - let duration = start.elapsed(); - debug!("Auto-formatted files in: {:?}", duration); - - modifications -} fn inner_main() -> Result { // Extract command-line arguments. @@ -268,7 +120,7 @@ fn inner_main() -> Result { printer.clear_screen()?; printer.write_to_user("Starting linter in watch mode...\n"); - let messages = run_once( + let messages = commands::run( &cli.files, &defaults, &overrides, @@ -297,7 +149,7 @@ fn inner_main() -> Result { printer.clear_screen()?; printer.write_to_user("File change detected...\n"); - let messages = run_once( + let messages = commands::run( &cli.files, &defaults, &overrides, @@ -311,12 +163,12 @@ fn inner_main() -> Result { } } } else if cli.add_noqa { - let modifications = add_noqa(&cli.files, &defaults, &overrides); + let modifications = commands::add_noqa(&cli.files, &defaults, &overrides); if modifications > 0 && log_level >= LogLevel::Default { println!("Added {modifications} noqa directives."); } } else if cli.autoformat { - let modifications = autoformat(&cli.files, &defaults, &overrides); + let modifications = commands::autoformat(&cli.files, &defaults, &overrides); if modifications > 0 && log_level >= LogLevel::Default { println!("Formatted {modifications} files."); } @@ -327,9 +179,9 @@ fn inner_main() -> Result { let diagnostics = if is_stdin { let filename = cli.stdin_filename.unwrap_or_else(|| "-".to_string()); let path = Path::new(&filename); - run_once_stdin(&defaults, path, &fix)? + commands::run_stdin(&defaults, path, &fix)? } else { - run_once(&cli.files, &defaults, &overrides, cache_enabled, &fix) + commands::run(&cli.files, &defaults, &overrides, cache_enabled, &fix) }; // Always try to print violations (the printer itself may suppress output),