mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:47 +00:00
Support linting input from stdin (#387)
This commit is contained in:
parent
209dce2033
commit
8ba872ece4
6 changed files with 176 additions and 3 deletions
69
Cargo.lock
generated
69
Cargo.lock
generated
|
@ -64,6 +64,20 @@ dependencies = [
|
||||||
"term",
|
"term",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "assert_cmd"
|
||||||
|
version = "2.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93ae1ddd39efd67689deb1979d80bad3bf7f2b09c6e6117c8d1f2443b5e2f83e"
|
||||||
|
dependencies = [
|
||||||
|
"bstr",
|
||||||
|
"doc-comment",
|
||||||
|
"predicates",
|
||||||
|
"predicates-core",
|
||||||
|
"predicates-tree",
|
||||||
|
"wait-timeout",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-channel"
|
name = "async-channel"
|
||||||
version = "1.7.1"
|
version = "1.7.1"
|
||||||
|
@ -580,6 +594,12 @@ version = "0.1.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "difflib"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
|
@ -658,6 +678,12 @@ dependencies = [
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "doc-comment"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
@ -1685,6 +1711,33 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "predicates"
|
||||||
|
version = "2.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c"
|
||||||
|
dependencies = [
|
||||||
|
"difflib",
|
||||||
|
"itertools",
|
||||||
|
"predicates-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "predicates-core"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da1c2388b1513e1b605fcec39a95e0a9e8ef088f71443ef37099fa9ae6673fcb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "predicates-tree"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4d86de6de25020a36c6d3643a86d9a6a9f552107c0559c60ea03551b5e16c032"
|
||||||
|
dependencies = [
|
||||||
|
"predicates-core",
|
||||||
|
"termtree",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
@ -1910,6 +1963,7 @@ name = "ruff"
|
||||||
version = "0.0.68"
|
version = "0.0.68"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"assert_cmd",
|
||||||
"bincode",
|
"bincode",
|
||||||
"cacache",
|
"cacache",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
@ -2345,6 +2399,12 @@ dependencies = [
|
||||||
"phf_codegen 0.8.0",
|
"phf_codegen 0.8.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termtree"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.37"
|
version = "1.0.37"
|
||||||
|
@ -2593,6 +2653,15 @@ version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8e76fae08f03f96e166d2dfda232190638c10e0383841252416f9cfe2ae60e6"
|
checksum = "f8e76fae08f03f96e166d2dfda232190638c10e0383841252416f9cfe2ae60e6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wait-timeout"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "waker-fn"
|
name = "waker-fn"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
|
@ -40,6 +40,7 @@ strum_macros = "0.24.3"
|
||||||
num-bigint = "0.4.3"
|
num-bigint = "0.4.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
assert_cmd = "2.0.4"
|
||||||
insta = { version = "1.19.1", features = ["yaml"] }
|
insta = { version = "1.19.1", features = ["yaml"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
@ -78,6 +78,9 @@ pub struct Cli {
|
||||||
// TODO(charlie): This should be a sub-command.
|
// TODO(charlie): This should be a sub-command.
|
||||||
#[arg(long, hide = true)]
|
#[arg(long, hide = true)]
|
||||||
pub autoformat: bool,
|
pub autoformat: bool,
|
||||||
|
/// The name of the file when passing it through stdin.
|
||||||
|
#[arg(long)]
|
||||||
|
pub stdin_filename: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Warnable {
|
pub enum Warnable {
|
||||||
|
|
|
@ -83,6 +83,36 @@ pub(crate) fn check_path(
|
||||||
Ok(checks)
|
Ok(checks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn lint_stdin(path: &Path, stdin: &str, settings: &Settings) -> Result<Vec<Message>> {
|
||||||
|
// Tokenize once.
|
||||||
|
let tokens: Vec<LexResult> = tokenize(stdin);
|
||||||
|
|
||||||
|
// Determine the noqa line for every line in the source.
|
||||||
|
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,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Convert to messages.
|
||||||
|
Ok(checks
|
||||||
|
.into_iter()
|
||||||
|
.map(|check| Message {
|
||||||
|
kind: check.kind,
|
||||||
|
fixed: check.fix.map(|fix| fix.applied).unwrap_or_default(),
|
||||||
|
location: check.location,
|
||||||
|
end_location: check.end_location,
|
||||||
|
filename: path.to_string_lossy().to_string(),
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn lint_path(
|
pub fn lint_path(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
settings: &Settings,
|
settings: &Settings,
|
||||||
|
|
29
src/main.rs
29
src/main.rs
|
@ -1,4 +1,4 @@
|
||||||
use std::io;
|
use std::io::{self, Read};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
|
@ -19,7 +19,7 @@ use ruff::cli::{warn_on, Cli, Warnable};
|
||||||
use ruff::fs::iter_python_files;
|
use ruff::fs::iter_python_files;
|
||||||
use ruff::linter::add_noqa_to_path;
|
use ruff::linter::add_noqa_to_path;
|
||||||
use ruff::linter::autoformat_path;
|
use ruff::linter::autoformat_path;
|
||||||
use ruff::linter::lint_path;
|
use ruff::linter::{lint_path, lint_stdin};
|
||||||
use ruff::logging::set_up_logging;
|
use ruff::logging::set_up_logging;
|
||||||
use ruff::message::Message;
|
use ruff::message::Message;
|
||||||
use ruff::printer::{Printer, SerializationFormat};
|
use ruff::printer::{Printer, SerializationFormat};
|
||||||
|
@ -75,6 +75,19 @@ fn show_files(files: &[PathBuf], settings: &Settings) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_from_stdin() -> Result<String> {
|
||||||
|
let mut buffer = String::new();
|
||||||
|
io::stdin().lock().read_to_string(&mut buffer)?;
|
||||||
|
Ok(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_once_stdin(settings: &Settings, filename: &Path) -> Result<Vec<Message>> {
|
||||||
|
let stdin = read_from_stdin()?;
|
||||||
|
let mut messages = lint_stdin(filename, &stdin, settings)?;
|
||||||
|
messages.sort_unstable();
|
||||||
|
Ok(messages)
|
||||||
|
}
|
||||||
|
|
||||||
fn run_once(
|
fn run_once(
|
||||||
files: &[PathBuf],
|
files: &[PathBuf],
|
||||||
settings: &Settings,
|
settings: &Settings,
|
||||||
|
@ -352,7 +365,17 @@ fn inner_main() -> Result<ExitCode> {
|
||||||
println!("Formatted {modifications} files.");
|
println!("Formatted {modifications} files.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let messages = run_once(&cli.files, &settings, !cli.no_cache, cli.fix)?;
|
let messages = if cli.files == vec![PathBuf::from("-")] {
|
||||||
|
if cli.fix {
|
||||||
|
eprintln!("Warning: --fix is not enabled when reading from stdin.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let filename = cli.stdin_filename.unwrap_or_else(|| "-".to_string());
|
||||||
|
let path = Path::new(&filename);
|
||||||
|
run_once_stdin(&settings, path)?
|
||||||
|
} else {
|
||||||
|
run_once(&cli.files, &settings, !cli.no_cache, cli.fix)?
|
||||||
|
};
|
||||||
if !cli.quiet {
|
if !cli.quiet {
|
||||||
printer.write_once(&messages)?;
|
printer.write_once(&messages)?;
|
||||||
}
|
}
|
||||||
|
|
47
tests/integration_test.rs
Normal file
47
tests/integration_test.rs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use assert_cmd::{crate_name, Command};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_stdin_success() -> Result<()> {
|
||||||
|
let mut cmd = Command::cargo_bin(crate_name!())?;
|
||||||
|
cmd.args(&["-"]).write_stdin("").assert().success();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_stdin_error() -> Result<()> {
|
||||||
|
let mut cmd = Command::cargo_bin(crate_name!())?;
|
||||||
|
let output = cmd
|
||||||
|
.args(&["-"])
|
||||||
|
.write_stdin("import os\n")
|
||||||
|
.assert()
|
||||||
|
.failure();
|
||||||
|
assert!(str::from_utf8(&output.get_output().stdout)?.contains("-:1:1: F401"));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_stdin_filename() -> Result<()> {
|
||||||
|
let mut cmd = Command::cargo_bin(crate_name!())?;
|
||||||
|
let output = cmd
|
||||||
|
.args(&["-", "--stdin-filename", "F401.py"])
|
||||||
|
.write_stdin("import os\n")
|
||||||
|
.assert()
|
||||||
|
.failure();
|
||||||
|
assert!(str::from_utf8(&output.get_output().stdout)?.contains("F401.py:1:1: F401"));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_stdin_autofix() -> Result<()> {
|
||||||
|
let mut cmd = Command::cargo_bin(crate_name!())?;
|
||||||
|
let output = cmd
|
||||||
|
.args(&["-", "--fix"])
|
||||||
|
.write_stdin("import os\n")
|
||||||
|
.assert()
|
||||||
|
.failure();
|
||||||
|
assert!(str::from_utf8(&output.get_output().stdout)?.contains("-:1:1: F401"));
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue