mirror of
https://github.com/crate-ci/typos.git
synced 2024-12-23 08:02:15 -05:00
feat(config): Support for pyproject.toml
files (#790)
This PR adds support for parsing `pyproject.toml` config files. The convention for these files is to put any tooling related configuration into the `tool.NAME` section, so in this case, `tool.typos`. I have verified that the changes are pulled correctly, even if the `tool.typos` section is not present. Closes #361
This commit is contained in:
parent
65d2fb6b91
commit
b856b9603f
2 changed files with 56 additions and 22 deletions
|
@ -68,8 +68,10 @@ fn run_dump_config(args: &args::Args, output_path: &std::path::Path) -> proc_exi
|
||||||
if let Some(path) = args.custom_config.as_ref() {
|
if let Some(path) = args.custom_config.as_ref() {
|
||||||
let custom = typos_cli::config::Config::from_file(path)
|
let custom = typos_cli::config::Config::from_file(path)
|
||||||
.with_code(proc_exit::sysexits::CONFIG_ERR)?;
|
.with_code(proc_exit::sysexits::CONFIG_ERR)?;
|
||||||
|
if let Some(custom) = custom {
|
||||||
overrides.update(&custom);
|
overrides.update(&custom);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
overrides.update(&args.config.to_config());
|
overrides.update(&args.config.to_config());
|
||||||
engine.set_overrides(overrides);
|
engine.set_overrides(overrides);
|
||||||
|
|
||||||
|
@ -119,8 +121,10 @@ fn run_type_list(args: &args::Args) -> proc_exit::ExitResult {
|
||||||
if let Some(path) = args.custom_config.as_ref() {
|
if let Some(path) = args.custom_config.as_ref() {
|
||||||
let custom = typos_cli::config::Config::from_file(path)
|
let custom = typos_cli::config::Config::from_file(path)
|
||||||
.with_code(proc_exit::sysexits::CONFIG_ERR)?;
|
.with_code(proc_exit::sysexits::CONFIG_ERR)?;
|
||||||
|
if let Some(custom) = custom {
|
||||||
overrides.update(&custom);
|
overrides.update(&custom);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
overrides.update(&args.config.to_config());
|
overrides.update(&args.config.to_config());
|
||||||
engine.set_overrides(overrides);
|
engine.set_overrides(overrides);
|
||||||
|
|
||||||
|
@ -154,8 +158,10 @@ fn run_checks(args: &args::Args) -> proc_exit::ExitResult {
|
||||||
if let Some(path) = args.custom_config.as_ref() {
|
if let Some(path) = args.custom_config.as_ref() {
|
||||||
let custom = typos_cli::config::Config::from_file(path)
|
let custom = typos_cli::config::Config::from_file(path)
|
||||||
.with_code(proc_exit::sysexits::CONFIG_ERR)?;
|
.with_code(proc_exit::sysexits::CONFIG_ERR)?;
|
||||||
|
if let Some(custom) = custom {
|
||||||
overrides.update(&custom);
|
overrides.update(&custom);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
overrides.update(&args.config.to_config());
|
overrides.update(&args.config.to_config());
|
||||||
engine.set_overrides(overrides);
|
engine.set_overrides(overrides);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@ use kstring::KString;
|
||||||
|
|
||||||
use crate::file_type_specifics;
|
use crate::file_type_specifics;
|
||||||
|
|
||||||
pub const SUPPORTED_FILE_NAMES: &[&str] = &["typos.toml", "_typos.toml", ".typos.toml"];
|
pub const SUPPORTED_FILE_NAMES: &[&str] =
|
||||||
|
&["typos.toml", "_typos.toml", ".typos.toml", "pyproject.toml"];
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
|
@ -19,18 +20,33 @@ pub struct Config {
|
||||||
pub overrides: EngineConfig,
|
pub overrides: EngineConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
pub fn from_dir(cwd: &std::path::Path) -> Result<Option<Self>, anyhow::Error> {
|
#[serde(default)]
|
||||||
let config = if let Some(path) = find_project_file(cwd, SUPPORTED_FILE_NAMES) {
|
#[serde(rename_all = "kebab-case")]
|
||||||
log::debug!("Loading {}", path.display());
|
pub struct PyprojectTomlConfig {
|
||||||
Some(Self::from_file(&path)?)
|
pub tool: PyprojectTomlTool,
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
Ok(config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_file(path: &std::path::Path) -> Result<Self, anyhow::Error> {
|
#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
pub struct PyprojectTomlTool {
|
||||||
|
pub typos: Option<Config>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn from_dir(cwd: &std::path::Path) -> Result<Option<Self>, anyhow::Error> {
|
||||||
|
for file in find_project_files(cwd, SUPPORTED_FILE_NAMES) {
|
||||||
|
log::debug!("Loading {}", file.display());
|
||||||
|
if let Some(config) = Self::from_file(&file)? {
|
||||||
|
return Ok(Some(config));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_file(path: &std::path::Path) -> Result<Option<Self>, anyhow::Error> {
|
||||||
let s = std::fs::read_to_string(path).map_err(|err| {
|
let s = std::fs::read_to_string(path).map_err(|err| {
|
||||||
let kind = err.kind();
|
let kind = err.kind();
|
||||||
std::io::Error::new(
|
std::io::Error::new(
|
||||||
|
@ -38,7 +54,20 @@ impl Config {
|
||||||
format!("could not read config at `{}`", path.display()),
|
format!("could not read config at `{}`", path.display()),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
Self::from_toml(&s)
|
|
||||||
|
if path.file_name().unwrap() == "pyproject.toml" {
|
||||||
|
let config = toml::from_str::<PyprojectTomlConfig>(&s)?;
|
||||||
|
|
||||||
|
if config.tool.typos.is_none() {
|
||||||
|
log::debug!("No `tool.typos` section found in `pyproject.toml`, skipping");
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Ok(config.tool.typos)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Self::from_toml(&s).map(Some)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_toml(data: &str) -> Result<Self, anyhow::Error> {
|
pub fn from_toml(data: &str) -> Result<Self, anyhow::Error> {
|
||||||
|
@ -455,15 +484,14 @@ impl DictConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_project_file(dir: &std::path::Path, names: &[&str]) -> Option<std::path::PathBuf> {
|
fn find_project_files<'a>(
|
||||||
let mut file_path = dir.join("placeholder");
|
dir: &'a std::path::Path,
|
||||||
for name in names {
|
names: &'a [&'a str],
|
||||||
file_path.set_file_name(name);
|
) -> impl Iterator<Item = std::path::PathBuf> + 'a {
|
||||||
if file_path.exists() {
|
names
|
||||||
return Some(file_path);
|
.iter()
|
||||||
}
|
.map(|name| dir.join(name))
|
||||||
}
|
.filter(|path| path.exists())
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for DictConfig {
|
impl PartialEq for DictConfig {
|
||||||
|
|
Loading…
Reference in a new issue