mirror of
https://github.com/astral-sh/ruff
synced 2026-01-21 05:20:49 -05:00
165 lines
4.3 KiB
Rust
165 lines
4.3 KiB
Rust
use std::env;
|
|
use std::hash::Hash;
|
|
use std::path::{Path, PathBuf};
|
|
use std::str::FromStr;
|
|
|
|
use anyhow::{anyhow, bail, Result};
|
|
use clap::ValueEnum;
|
|
use globset::{Glob, GlobSetBuilder};
|
|
use rustc_hash::FxHashSet;
|
|
use serde::{de, Deserialize, Deserializer, Serialize};
|
|
|
|
use crate::checks::CheckCode;
|
|
use crate::checks_gen::CheckCodePrefix;
|
|
use crate::fs;
|
|
|
|
#[derive(Clone, Copy, Debug, PartialOrd, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum PythonVersion {
|
|
Py33,
|
|
Py34,
|
|
Py35,
|
|
Py36,
|
|
Py37,
|
|
Py38,
|
|
Py39,
|
|
Py310,
|
|
Py311,
|
|
}
|
|
|
|
impl FromStr for PythonVersion {
|
|
type Err = anyhow::Error;
|
|
|
|
fn from_str(string: &str) -> Result<Self, Self::Err> {
|
|
match string {
|
|
"py33" => Ok(PythonVersion::Py33),
|
|
"py34" => Ok(PythonVersion::Py34),
|
|
"py35" => Ok(PythonVersion::Py35),
|
|
"py36" => Ok(PythonVersion::Py36),
|
|
"py37" => Ok(PythonVersion::Py37),
|
|
"py38" => Ok(PythonVersion::Py38),
|
|
"py39" => Ok(PythonVersion::Py39),
|
|
"py310" => Ok(PythonVersion::Py310),
|
|
"py311" => Ok(PythonVersion::Py311),
|
|
_ => Err(anyhow!("Unknown version: {string}")),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum FilePattern {
|
|
Builtin(&'static str),
|
|
User(String, PathBuf),
|
|
}
|
|
|
|
impl FilePattern {
|
|
pub fn add_to(self, builder: &mut GlobSetBuilder) -> Result<()> {
|
|
match self {
|
|
FilePattern::Builtin(pattern) => {
|
|
builder.add(Glob::from_str(pattern)?);
|
|
}
|
|
FilePattern::User(pattern, absolute) => {
|
|
// Add the absolute path.
|
|
builder.add(Glob::new(&absolute.to_string_lossy())?);
|
|
|
|
// Add basename path.
|
|
if !pattern.contains(std::path::MAIN_SEPARATOR) {
|
|
builder.add(Glob::from_str(&pattern)?);
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl FromStr for FilePattern {
|
|
type Err = anyhow::Error;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
let pattern = s.to_string();
|
|
let absolute = fs::normalize_path(Path::new(&pattern));
|
|
Ok(Self::User(pattern, absolute))
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct PerFileIgnore {
|
|
pub basename: String,
|
|
pub absolute: PathBuf,
|
|
pub codes: FxHashSet<CheckCode>,
|
|
}
|
|
|
|
impl PerFileIgnore {
|
|
pub fn new(basename: String, absolute: PathBuf, prefixes: &[CheckCodePrefix]) -> Self {
|
|
let codes = prefixes.iter().flat_map(CheckCodePrefix::codes).collect();
|
|
Self {
|
|
basename,
|
|
absolute,
|
|
codes,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
pub struct PatternPrefixPair {
|
|
pub pattern: String,
|
|
pub prefix: CheckCodePrefix,
|
|
}
|
|
|
|
impl PatternPrefixPair {
|
|
const EXPECTED_PATTERN: &'static str = "<FilePattern>:<CheckCode> pattern";
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for PatternPrefixPair {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
let str_result = String::deserialize(deserializer)?;
|
|
Self::from_str(str_result.as_str()).map_err(|_| {
|
|
de::Error::invalid_value(
|
|
de::Unexpected::Str(str_result.as_str()),
|
|
&Self::EXPECTED_PATTERN,
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
impl FromStr for PatternPrefixPair {
|
|
type Err = anyhow::Error;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
let (pattern_str, code_string) = {
|
|
let tokens = s.split(':').collect::<Vec<_>>();
|
|
if tokens.len() != 2 {
|
|
bail!("Expected {}", Self::EXPECTED_PATTERN);
|
|
}
|
|
(tokens[0].trim(), tokens[1].trim())
|
|
};
|
|
let pattern = pattern_str.into();
|
|
let prefix = CheckCodePrefix::from_str(code_string)?;
|
|
Ok(Self { pattern, prefix })
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, ValueEnum, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
|
#[serde(rename_all = "kebab-case")]
|
|
pub enum SerializationFormat {
|
|
Text,
|
|
Json,
|
|
Junit,
|
|
Grouped,
|
|
Github,
|
|
}
|
|
|
|
impl Default for SerializationFormat {
|
|
fn default() -> Self {
|
|
if let Ok(github_actions) = env::var("GITHUB_ACTIONS") {
|
|
if github_actions == "true" {
|
|
return Self::Github;
|
|
}
|
|
}
|
|
Self::Text
|
|
}
|
|
}
|