Make --quiet more aggressive (#566)

This commit is contained in:
Charlie Marsh 2022-11-03 10:08:15 -04:00 committed by GitHub
parent 9f9cbb5520
commit a3f7de2257
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 135 additions and 65 deletions

View file

@ -7,6 +7,7 @@ use log::warn;
use regex::Regex;
use crate::checks_gen::CheckCodePrefix;
use crate::logging::LogLevel;
use crate::printer::SerializationFormat;
use crate::settings::configuration::Configuration;
use crate::settings::types::{PatternPrefixPair, PythonVersion};
@ -93,6 +94,19 @@ pub struct Cli {
pub stdin_filename: Option<String>,
}
/// Map the CLI settings to a `LogLevel`.
pub fn extract_log_level(cli: &Cli) -> LogLevel {
if cli.silent {
LogLevel::Silent
} else if cli.quiet {
LogLevel::Quiet
} else if cli.verbose {
LogLevel::Verbose
} else {
LogLevel::Default
}
}
pub enum Warnable {
Select,
ExtendSelect,

View file

@ -15,7 +15,36 @@ macro_rules! tell_user {
}
}
pub fn set_up_logging(verbose: bool) -> Result<()> {
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)]
pub enum LogLevel {
// No output (+ `log::LevelFilter::Off`).
Silent,
// Only show lint violations, with no decorative output (+ `log::LevelFilter::Off`).
Quiet,
// All user-facing output (+ `log::LevelFilter::Info`).
Default,
// All user-facing output (+ `log::LevelFilter::Debug`).
Verbose,
}
impl LogLevel {
fn level_filter(&self) -> log::LevelFilter {
match self {
LogLevel::Default => log::LevelFilter::Info,
LogLevel::Verbose => log::LevelFilter::Debug,
LogLevel::Quiet => log::LevelFilter::Off,
LogLevel::Silent => log::LevelFilter::Off,
}
}
}
impl Default for LogLevel {
fn default() -> Self {
LogLevel::Default
}
}
pub fn set_up_logging(level: &LogLevel) -> Result<()> {
fern::Dispatch::new()
.format(|out, message, record| {
out.finish(format_args!(
@ -26,12 +55,22 @@ pub fn set_up_logging(verbose: bool) -> Result<()> {
message
))
})
.level(if verbose {
log::LevelFilter::Debug
} else {
log::LevelFilter::Info
})
.level(level.level_filter())
.chain(std::io::stdout())
.apply()
.map_err(|e| e.into())
}
#[cfg(test)]
mod tests {
use crate::logging::LogLevel;
#[test]
fn ordering() {
assert!(LogLevel::Default > LogLevel::Silent);
assert!(LogLevel::Default >= LogLevel::Default);
assert!(LogLevel::Quiet > LogLevel::Silent);
assert!(LogLevel::Verbose > LogLevel::Default);
assert!(LogLevel::Verbose > LogLevel::Silent);
}
}

View file

@ -16,17 +16,16 @@ use rayon::prelude::*;
use ruff::cache;
use ruff::checks::{CheckCode, CheckKind};
use ruff::checks_gen::CheckCodePrefix;
use ruff::cli::{collect_per_file_ignores, warn_on, Cli, Warnable};
use ruff::cli::{collect_per_file_ignores, extract_log_level, warn_on, Cli, Warnable};
use ruff::fs::iter_python_files;
use ruff::linter::{add_noqa_to_path, autoformat_path, lint_path, lint_stdin};
use ruff::logging::set_up_logging;
use ruff::logging::{set_up_logging, LogLevel};
use ruff::message::Message;
use ruff::printer::{Printer, SerializationFormat};
use ruff::settings::configuration::Configuration;
use ruff::settings::types::FilePattern;
use ruff::settings::user::UserConfiguration;
use ruff::settings::{pyproject, Settings};
use ruff::tell_user;
use walkdir::DirEntry;
#[cfg(feature = "update-informer")]
@ -223,10 +222,10 @@ fn autoformat(files: &[PathBuf], settings: &Settings) -> Result<usize> {
}
fn inner_main() -> Result<ExitCode> {
let mut cli = Cli::parse();
cli.quiet |= cli.silent;
let cli = Cli::parse();
set_up_logging(cli.verbose)?;
let log_level = extract_log_level(&cli);
set_up_logging(&log_level)?;
// Find the project root and pyproject.toml.
let project_root = pyproject::find_project_root(&cli.files);
@ -320,7 +319,7 @@ fn inner_main() -> Result<ExitCode> {
#[cfg(not(target_family = "wasm"))]
cache::init()?;
let mut printer = Printer::new(cli.format, cli.verbose);
let printer = Printer::new(&cli.format, &log_level);
if cli.watch {
if cli.fix {
eprintln!("Warning: --fix is not enabled in watch mode.");
@ -340,12 +339,10 @@ fn inner_main() -> Result<ExitCode> {
// Perform an initial run instantly.
printer.clear_screen()?;
tell_user!("Starting linter in watch mode...\n");
printer.write_to_user("Starting linter in watch mode...\n");
let messages = run_once(&cli.files, &settings, !cli.no_cache, false)?;
if !cli.silent {
printer.write_continuously(&messages)?;
}
// Configure the file watcher.
let (tx, rx) = channel();
@ -360,51 +357,48 @@ fn inner_main() -> Result<ExitCode> {
if let Some(path) = e.path {
if path.to_string_lossy().ends_with(".py") {
printer.clear_screen()?;
tell_user!("File change detected...\n");
printer.write_to_user("File change detected...\n");
let messages = run_once(&cli.files, &settings, !cli.no_cache, false)?;
if !cli.silent {
printer.write_continuously(&messages)?;
}
}
}
}
Err(e) => return Err(e.into()),
}
}
} else if cli.add_noqa {
let modifications = add_noqa(&cli.files, &settings)?;
if modifications > 0 {
if modifications > 0 && log_level >= LogLevel::Default {
println!("Added {modifications} noqa directives.");
}
} else if cli.autoformat {
let modifications = autoformat(&cli.files, &settings)?;
if modifications > 0 {
if modifications > 0 && log_level >= LogLevel::Default {
println!("Formatted {modifications} files.");
}
} else {
let (messages, should_print_messages, should_check_updates) =
if cli.files == vec![PathBuf::from("-")] {
let is_stdin = cli.files == vec![PathBuf::from("-")];
// Generate lint violations.
let messages = if is_stdin {
let filename = cli.stdin_filename.unwrap_or_else(|| "-".to_string());
let path = Path::new(&filename);
(
run_once_stdin(&settings, path, cli.fix)?,
!cli.silent && !cli.fix,
false,
)
run_once_stdin(&settings, path, cli.fix)?
} else {
(
run_once(&cli.files, &settings, !cli.no_cache, cli.fix)?,
!cli.silent,
!cli.quiet,
)
run_once(&cli.files, &settings, !cli.no_cache, cli.fix)?
};
if should_print_messages {
// Always try to print violations (the printer itself may suppress output),
// unless we're writing fixes via stdin (in which case, the transformed
// source code goes to stdout).
if !(is_stdin && cli.fix) {
printer.write_once(&messages)?;
}
// Check for updates if we're in a non-silent log level.
#[cfg(feature = "update-informer")]
if should_check_updates {
if !is_stdin && log_level >= LogLevel::Default {
check_for_updates();
}

View file

@ -5,6 +5,7 @@ use rustpython_parser::ast::Location;
use serde::Serialize;
use crate::checks::{CheckCode, CheckKind};
use crate::logging::LogLevel;
use crate::message::Message;
use crate::tell_user;
@ -25,17 +26,27 @@ struct ExpandedMessage<'a> {
filename: &'a String,
}
pub struct Printer {
format: SerializationFormat,
verbose: bool,
pub struct Printer<'a> {
format: &'a SerializationFormat,
log_level: &'a LogLevel,
}
impl Printer {
pub fn new(format: SerializationFormat, verbose: bool) -> Self {
Self { format, verbose }
impl<'a> Printer<'a> {
pub fn new(format: &'a SerializationFormat, log_level: &'a LogLevel) -> Self {
Self { format, log_level }
}
pub fn write_to_user(&self, message: &str) {
if self.log_level >= &LogLevel::Default {
tell_user!("{}", message);
}
}
pub fn write_once(&self, messages: &[Message]) -> Result<()> {
if matches!(self.log_level, LogLevel::Silent) {
return Ok(());
}
pub fn write_once(&mut self, messages: &[Message]) -> Result<()> {
let (fixed, outstanding): (Vec<&Message>, Vec<&Message>) =
messages.iter().partition(|message| message.fixed);
let num_fixable = outstanding
@ -64,37 +75,49 @@ impl Printer {
)
}
SerializationFormat::Text => {
if self.log_level >= &LogLevel::Default {
if !fixed.is_empty() {
println!(
"Found {} error(s) ({} fixed).",
outstanding.len(),
fixed.len()
)
} else if !outstanding.is_empty() || self.verbose {
} else if !outstanding.is_empty() {
println!("Found {} error(s).", outstanding.len())
}
}
for message in outstanding {
println!("{}", message)
}
if self.log_level >= &LogLevel::Default {
if num_fixable > 0 {
println!("{num_fixable} potentially fixable with the --fix option.")
}
}
}
}
Ok(())
}
pub fn write_continuously(&mut self, messages: &[Message]) -> Result<()> {
pub fn write_continuously(&self, messages: &[Message]) -> Result<()> {
if matches!(self.log_level, LogLevel::Silent) {
return Ok(());
}
if self.log_level >= &LogLevel::Default {
tell_user!(
"Found {} error(s). Watching for file changes.",
messages.len(),
);
}
if !messages.is_empty() {
if self.log_level >= &LogLevel::Default {
println!();
}
for message in messages {
println!("{}", message)
}
@ -103,7 +126,7 @@ impl Printer {
Ok(())
}
pub fn clear_screen(&mut self) -> Result<()> {
pub fn clear_screen(&self) -> Result<()> {
#[cfg(not(target_family = "wasm"))]
clearscreen::clear()?;
Ok(())