Implement --fix with stdin (#405)

This commit is contained in:
fsouza 2022-10-12 22:31:46 -04:00 committed by GitHub
parent 2f69be0d41
commit 720bfe0161
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 33 deletions

View File

@ -1,7 +1,3 @@
use std::fs;
use std::path::Path;
use anyhow::Result;
use itertools::Itertools;
use rustpython_parser::ast::Location;
@ -24,17 +20,15 @@ impl From<bool> for Mode {
}
/// Auto-fix errors in a file, and write the fixed source code to disk.
pub fn fix_file(checks: &mut [Check], contents: &str, path: &Path) -> Result<()> {
pub fn fix_file(checks: &mut [Check], contents: &str) -> Option<String> {
if checks.iter().all(|check| check.fix.is_none()) {
return Ok(());
return None;
}
let output = apply_fixes(
Some(apply_fixes(
checks.iter_mut().filter_map(|check| check.fix.as_mut()),
contents,
);
fs::write(path, output).map_err(|e| e.into())
))
}
/// Apply a series of fixes.

View File

@ -1,4 +1,6 @@
use std::fs::write;
use std::io;
use std::io::Write;
use std::path::Path;
use anyhow::Result;
@ -83,7 +85,12 @@ pub(crate) fn check_path(
Ok(checks)
}
pub fn lint_stdin(path: &Path, stdin: &str, settings: &Settings) -> Result<Vec<Message>> {
pub fn lint_stdin(
path: &Path,
stdin: &str,
settings: &Settings,
autofix: &fixer::Mode,
) -> Result<Vec<Message>> {
// Tokenize once.
let tokens: Vec<LexResult> = tokenize(stdin);
@ -91,14 +98,16 @@ pub fn lint_stdin(path: &Path, stdin: &str, settings: &Settings) -> Result<Vec<M
let noqa_line_for = noqa::extract_noqa_line_for(&tokens);
// Generate checks.
let checks = check_path(
path,
stdin,
tokens,
&noqa_line_for,
settings,
&fixer::Mode::None,
)?;
let mut checks = check_path(path, stdin, tokens, &noqa_line_for, settings, autofix)?;
// Apply autofix, write results to stdout.
if matches!(autofix, fixer::Mode::Apply) {
let output = match fix_file(&mut checks, stdin) {
None => stdin.to_string(),
Some(content) => content,
};
io::stdout().write_all(output.as_bytes())?;
}
// Convert to messages.
Ok(checks
@ -141,7 +150,9 @@ pub fn lint_path(
// Apply autofix.
if matches!(autofix, fixer::Mode::Apply) {
fix_file(&mut checks, &contents, path)?;
if let Some(fixed_contents) = fix_file(&mut checks, &contents) {
write(path, fixed_contents)?;
}
};
// Convert to messages.

View File

@ -81,9 +81,9 @@ fn read_from_stdin() -> Result<String> {
Ok(buffer)
}
fn run_once_stdin(settings: &Settings, filename: &Path) -> Result<Vec<Message>> {
fn run_once_stdin(settings: &Settings, filename: &Path, autofix: bool) -> Result<Vec<Message>> {
let stdin = read_from_stdin()?;
let mut messages = lint_stdin(filename, &stdin, settings)?;
let mut messages = lint_stdin(filename, &stdin, settings, &autofix.into())?;
messages.sort_unstable();
Ok(messages)
}
@ -365,18 +365,20 @@ fn inner_main() -> Result<ExitCode> {
println!("Formatted {modifications} files.");
}
} else {
let messages = if cli.files == vec![PathBuf::from("-")] {
if cli.fix {
eprintln!("Warning: --fix is not enabled when reading from stdin.");
}
let (messages, print_messages) = if cli.files == vec![PathBuf::from("-")] {
let filename = cli.stdin_filename.unwrap_or_else(|| "-".to_string());
let path = Path::new(&filename);
run_once_stdin(&settings, path)?
(
run_once_stdin(&settings, path, cli.fix)?,
!cli.quiet && !cli.fix,
)
} else {
run_once(&cli.files, &settings, !cli.no_cache, cli.fix)?
(
run_once(&cli.files, &settings, !cli.no_cache, cli.fix)?,
!cli.quiet,
)
};
if !cli.quiet {
if print_messages {
printer.write_once(&messages)?;
}

View File

@ -39,9 +39,42 @@ fn test_stdin_autofix() -> Result<()> {
let mut cmd = Command::cargo_bin(crate_name!())?;
let output = cmd
.args(&["-", "--fix"])
.write_stdin("import os\n")
.write_stdin("import os\nimport sys\n\nprint(sys.version)\n")
.assert()
.failure();
assert!(str::from_utf8(&output.get_output().stdout)?.contains("-:1:1: F401"));
.success();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
"import sys\n\nprint(sys.version)\n"
);
Ok(())
}
#[test]
fn test_stdin_autofix_when_not_fixable_should_still_print_contents() -> Result<()> {
let mut cmd = Command::cargo_bin(crate_name!())?;
let output = cmd
.args(&["-", "--fix"])
.write_stdin("import os\nimport sys\n\nif (1, 2):\n print(sys.version)\n")
.assert()
.failure();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
"import sys\n\nif (1, 2):\n print(sys.version)\n"
);
Ok(())
}
#[test]
fn test_stdin_autofix_when_no_issues_should_still_print_contents() -> Result<()> {
let mut cmd = Command::cargo_bin(crate_name!())?;
let output = cmd
.args(&["-", "--fix"])
.write_stdin("import sys\n\nprint(sys.version)\n")
.assert()
.success();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
"import sys\n\nprint(sys.version)\n"
);
Ok(())
}