mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-28 12:55:05 +00:00
Write unchanged, excluded files to stdout when read via stdin (#8596)
## Summary When you run Ruff via stdin, and pass `format` or `check --fix`, we typically write the changed or unchanged contents to stdout. It turns out we forgot to do this when the file is _excluded_, so if you run `ruff format /path/to/excluded/file.py`, we don't write _anything_ to `stdout`. This led to a bug in the LSP whereby we deleted file contents for third-party files. The right thing to do here is write back the unchanged contents, as it should always be safe to write the output of stdout back to a file.
This commit is contained in:
parent
346a828db2
commit
7968e190dd
4 changed files with 32 additions and 4 deletions
|
@ -8,7 +8,7 @@ use ruff_workspace::resolver::{match_exclusion, python_file_at_path, PyprojectCo
|
|||
|
||||
use crate::args::CliOverrides;
|
||||
use crate::diagnostics::{lint_stdin, Diagnostics};
|
||||
use crate::stdin::read_from_stdin;
|
||||
use crate::stdin::{parrot_stdin, read_from_stdin};
|
||||
|
||||
/// Run the linter over a single file, read from `stdin`.
|
||||
pub(crate) fn check_stdin(
|
||||
|
@ -21,6 +21,9 @@ pub(crate) fn check_stdin(
|
|||
if pyproject_config.settings.file_resolver.force_exclude {
|
||||
if let Some(filename) = filename {
|
||||
if !python_file_at_path(filename, pyproject_config, overrides)? {
|
||||
if fix_mode.is_apply() {
|
||||
parrot_stdin()?;
|
||||
}
|
||||
return Ok(Diagnostics::default());
|
||||
}
|
||||
|
||||
|
@ -29,14 +32,17 @@ pub(crate) fn check_stdin(
|
|||
.file_name()
|
||||
.is_some_and(|name| match_exclusion(filename, name, &lint_settings.exclude))
|
||||
{
|
||||
if fix_mode.is_apply() {
|
||||
parrot_stdin()?;
|
||||
}
|
||||
return Ok(Diagnostics::default());
|
||||
}
|
||||
}
|
||||
}
|
||||
let stdin = read_from_stdin()?;
|
||||
let package_root = filename.and_then(Path::parent).and_then(|path| {
|
||||
packaging::detect_package_root(path, &pyproject_config.settings.linter.namespace_packages)
|
||||
});
|
||||
let stdin = read_from_stdin()?;
|
||||
let mut diagnostics = lint_stdin(
|
||||
filename,
|
||||
package_root,
|
||||
|
|
|
@ -15,7 +15,7 @@ use crate::commands::format::{
|
|||
FormatResult, FormattedSource,
|
||||
};
|
||||
use crate::resolve::resolve;
|
||||
use crate::stdin::read_from_stdin;
|
||||
use crate::stdin::{parrot_stdin, read_from_stdin};
|
||||
use crate::ExitStatus;
|
||||
|
||||
/// Run the formatter over a single file, read from `stdin`.
|
||||
|
@ -34,6 +34,9 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
|
|||
if pyproject_config.settings.file_resolver.force_exclude {
|
||||
if let Some(filename) = cli.stdin_filename.as_deref() {
|
||||
if !python_file_at_path(filename, &pyproject_config, overrides)? {
|
||||
if mode.is_write() {
|
||||
parrot_stdin()?;
|
||||
}
|
||||
return Ok(ExitStatus::Success);
|
||||
}
|
||||
|
||||
|
@ -42,6 +45,9 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
|
|||
.file_name()
|
||||
.is_some_and(|name| match_exclusion(filename, name, &format_settings.exclude))
|
||||
{
|
||||
if mode.is_write() {
|
||||
parrot_stdin()?;
|
||||
}
|
||||
return Ok(ExitStatus::Success);
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +56,9 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
|
|||
let path = cli.stdin_filename.as_deref();
|
||||
|
||||
let SourceType::Python(source_type) = path.map(SourceType::from).unwrap_or_default() else {
|
||||
if mode.is_write() {
|
||||
parrot_stdin()?;
|
||||
}
|
||||
return Ok(ExitStatus::Success);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
/// Read a string from `stdin`.
|
||||
pub(crate) fn read_from_stdin() -> Result<String, io::Error> {
|
||||
|
@ -7,3 +7,11 @@ pub(crate) fn read_from_stdin() -> Result<String, io::Error> {
|
|||
io::stdin().lock().read_to_string(&mut buffer)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
/// Read bytes from `stdin` and write them to `stdout`.
|
||||
pub(crate) fn parrot_stdin() -> Result<(), io::Error> {
|
||||
let mut buffer = String::new();
|
||||
io::stdin().lock().read_to_string(&mut buffer)?;
|
||||
io::stdout().write_all(buffer.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -320,6 +320,11 @@ if __name__ == '__main__':
|
|||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
from test import say_hy
|
||||
|
||||
if __name__ == '__main__':
|
||||
say_hy("dear Ruff contributor")
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
Ok(())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue