Adding flag and logic for different output format (#185)

This commit is contained in:
Patrick Haller 2022-09-14 16:43:32 +02:00 committed by GitHub
parent 85dcaa8d3c
commit bda34945a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 99 additions and 56 deletions

View File

@ -10,6 +10,7 @@ pub mod fs;
pub mod linter;
pub mod logging;
pub mod message;
pub mod printer;
mod pyproject;
mod python;
pub mod settings;

View File

@ -3,15 +3,16 @@ use fern;
#[macro_export]
macro_rules! tell_user {
($($arg:tt)*) => {
println!(
($writer:expr,$($arg:tt)*) => {
writeln!(
$writer,
"[{}] {}",
chrono::Local::now()
.format("%H:%M:%S %p")
.to_string()
.dimmed(),
format_args!($($arg)*)
)
)?
}
}

View File

@ -1,3 +1,4 @@
use std::io::{stdout, BufWriter, Write};
use std::path::PathBuf;
use std::process::ExitCode;
use std::sync::mpsc::channel;
@ -18,6 +19,7 @@ use ::ruff::fs::iter_python_files;
use ::ruff::linter::lint_path;
use ::ruff::logging::set_up_logging;
use ::ruff::message::Message;
use ::ruff::printer::{Printer, SerializationFormat};
use ::ruff::settings::Settings;
use ::ruff::tell_user;
@ -57,6 +59,9 @@ struct Cli {
/// List of file and/or directory patterns to exclude from checks.
#[clap(long, multiple = true)]
exclude: Vec<Pattern>,
/// Output formatting of linting messages
#[clap(long, arg_enum, default_value_t=SerializationFormat::Text)]
format: SerializationFormat,
}
#[cfg(feature = "update-informer")]
@ -130,60 +135,14 @@ fn run_once(
Ok(messages)
}
fn report_once(messages: &[Message]) -> Result<()> {
let (fixed, outstanding): (Vec<&Message>, Vec<&Message>) =
messages.iter().partition(|message| message.fixed);
let num_fixable = outstanding
.iter()
.filter(|message| message.kind.fixable())
.count();
if !outstanding.is_empty() {
for message in &outstanding {
println!("{}", message);
}
println!();
}
if !fixed.is_empty() {
println!(
"Found {} error(s) ({} fixed).",
outstanding.len(),
fixed.len()
);
} else {
println!("Found {} error(s).", outstanding.len());
}
if num_fixable > 0 {
println!("{num_fixable} potentially fixable with the --fix option.");
}
Ok(())
}
fn report_continuously(messages: &[Message]) -> Result<()> {
tell_user!(
"Found {} error(s). Watching for file changes.",
messages.len(),
);
if !messages.is_empty() {
println!();
for message in messages {
println!("{}", message);
}
}
Ok(())
}
fn inner_main() -> Result<ExitCode> {
let cli = Cli::parse();
set_up_logging(cli.verbose)?;
let mut settings = Settings::from_paths(&cli.files);
let mut printer = Printer::new(BufWriter::new(stdout()), cli.format);
if !cli.select.is_empty() {
settings.select(cli.select);
}
@ -201,11 +160,11 @@ fn inner_main() -> Result<ExitCode> {
// Perform an initial run instantly.
clearscreen::clear()?;
tell_user!("Starting linter in watch mode...\n");
tell_user!(printer.writer, "Starting linter in watch mode...\n");
let messages = run_once(&cli.files, &settings, !cli.no_cache, false)?;
if !cli.quiet {
report_continuously(&messages)?;
printer.write_continuously(&messages)?;
}
// Configure the file watcher.
@ -221,11 +180,11 @@ fn inner_main() -> Result<ExitCode> {
if let Some(path) = e.path {
if path.to_string_lossy().ends_with(".py") {
clearscreen::clear()?;
tell_user!("File change detected...\n");
tell_user!(printer.writer, "File change detected...\n");
let messages = run_once(&cli.files, &settings, !cli.no_cache, false)?;
if !cli.quiet {
report_continuously(&messages)?;
printer.write_continuously(&messages)?;
}
}
}
@ -236,7 +195,7 @@ fn inner_main() -> Result<ExitCode> {
} else {
let messages = run_once(&cli.files, &settings, !cli.no_cache, cli.fix)?;
if !cli.quiet {
report_once(&messages)?;
printer.write_once(&messages)?;
}
#[cfg(feature = "update-informer")]

82
src/printer.rs Normal file
View File

@ -0,0 +1,82 @@
use colored::Colorize;
use std::io::Write;
use anyhow::Result;
use clap::ValueEnum;
use crate::message::Message;
use crate::tell_user;
#[derive(Clone, ValueEnum, PartialEq, Eq, Debug)]
pub enum SerializationFormat {
Text,
Json,
}
pub struct Printer<W> {
pub writer: W,
format: SerializationFormat,
}
impl<W: Write> Printer<W> {
pub fn new(writer: W, format: SerializationFormat) -> Self {
Self { writer, format }
}
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
.iter()
.filter(|message| message.kind.fixable())
.count();
match self.format {
SerializationFormat::Json => {
writeln!(self.writer, "{}", serde_json::to_string_pretty(&messages)?)?
}
SerializationFormat::Text => {
if !fixed.is_empty() {
writeln!(
self.writer,
"Found {} error(s) ({} fixed).",
outstanding.len(),
fixed.len()
)?
} else {
writeln!(self.writer, "Found {} error(s).", outstanding.len())?
}
for message in outstanding {
writeln!(self.writer, "{}", message)?
}
if num_fixable > 0 {
writeln!(
self.writer,
"{num_fixable} potentially fixable with the --fix option."
)?
}
}
}
Ok(())
}
pub fn write_continuously(&mut self, messages: &[Message]) -> Result<()> {
tell_user!(
self.writer,
"Found {} error(s). Watching for file changes.",
messages.len(),
);
if !messages.is_empty() {
writeln!(self.writer, "\n")?;
for message in messages {
writeln!(self.writer, "{}", message)?
}
}
Ok(())
}
}