Skip to content

Add a path to the parent dir of rustfmt.toml as a prefix to paths in ignore #3522

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/config/config_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ macro_rules! create_config {
ConfigWasSet(self)
}

fn fill_from_parsed_config(mut self, parsed: PartialConfig) -> Config {
fn fill_from_parsed_config(mut self, parsed: PartialConfig, dir: &Path) -> Config {
$(
if let Some(val) = parsed.$i {
if self.$i.3 {
Expand All @@ -160,6 +160,7 @@ macro_rules! create_config {
)+
self.set_heuristics();
self.set_license_template();
self.set_ignore(dir);
self
}

Expand Down Expand Up @@ -286,6 +287,9 @@ macro_rules! create_config {
}
}

fn set_ignore(&mut self, dir: &Path) {
self.ignore.2.add_prefix(dir);
}

/// Returns `true` if the config key was explicitly set and is the default value.
pub fn is_default(&self, key: &str) -> bool {
Expand Down
9 changes: 5 additions & 4 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,8 @@ impl Config {
let mut file = File::open(&file_path)?;
let mut toml = String::new();
file.read_to_string(&mut toml)?;
Config::from_toml(&toml).map_err(|err| Error::new(ErrorKind::InvalidData, err))
Config::from_toml(&toml, file_path.parent().unwrap())
.map_err(|err| Error::new(ErrorKind::InvalidData, err))
}

/// Resolves the config for input in `dir`.
Expand Down Expand Up @@ -252,7 +253,7 @@ impl Config {
}
}

pub(crate) fn from_toml(toml: &str) -> Result<Config, String> {
pub(crate) fn from_toml(toml: &str, dir: &Path) -> Result<Config, String> {
let parsed: ::toml::Value = toml
.parse()
.map_err(|e| format!("Could not parse TOML: {}", e))?;
Expand All @@ -271,7 +272,7 @@ impl Config {
if !err.is_empty() {
eprint!("{}", err);
}
Ok(Config::default().fill_from_parsed_config(parsed_config))
Ok(Config::default().fill_from_parsed_config(parsed_config, dir))
}
Err(e) => {
err.push_str("Error: Decoding config file failed:\n");
Expand Down Expand Up @@ -425,7 +426,7 @@ mod test {

#[test]
fn test_was_set() {
let config = Config::from_toml("hard_tabs = true").unwrap();
let config = Config::from_toml("hard_tabs = true", Path::new("")).unwrap();

assert_eq!(config.was_set().hard_tabs(), true);
assert_eq!(config.was_set().verbose(), false);
Expand Down
64 changes: 48 additions & 16 deletions src/config/options.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::collections::{hash_set, HashSet};
use std::fmt;
use std::path::{Path, PathBuf};

use atty;
use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor};

use crate::config::config_type::ConfigType;
use crate::config::lists::*;
Expand Down Expand Up @@ -396,33 +398,63 @@ impl Default for EmitMode {
}

/// A set of directories, files and modules that rustfmt should ignore.
#[derive(Default, Deserialize, Serialize, Clone, Debug, PartialEq)]
pub struct IgnoreList(HashSet<PathBuf>);
#[derive(Default, Serialize, Clone, Debug, PartialEq)]
pub struct IgnoreList {
/// A set of path specified in rustfmt.toml.
#[serde(flatten)]
path_set: HashSet<PathBuf>,
/// A path to rustfmt.toml.
#[serde(skip_serializing)]
rustfmt_toml_path: PathBuf,
}

impl<'de> Deserialize<'de> for IgnoreList {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct HashSetVisitor;
impl<'v> Visitor<'v> for HashSetVisitor {
type Value = HashSet<PathBuf>;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a sequence of path")
}

fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'v>,
{
let mut path_set = HashSet::new();
while let Some(elem) = seq.next_element()? {
path_set.insert(elem);
}
Ok(path_set)
}
}
Ok(IgnoreList {
path_set: deserializer.deserialize_seq(HashSetVisitor)?,
rustfmt_toml_path: PathBuf::new(),
})
}
}

impl<'a> IntoIterator for &'a IgnoreList {
type Item = &'a PathBuf;
type IntoIter = hash_set::Iter<'a, PathBuf>;

fn into_iter(self) -> Self::IntoIter {
self.0.iter()
self.path_set.iter()
}
}

impl IgnoreList {
pub fn add_prefix(&mut self, dir: &Path) {
self.0 = self
.0
.iter()
.map(|s| {
if s.has_root() {
s.clone()
} else {
let mut path = PathBuf::from(dir);
path.push(s);
path
}
})
.collect();
self.rustfmt_toml_path = dir.to_path_buf();
}

pub fn rustfmt_toml_path(&self) -> &Path {
&self.rustfmt_toml_path
}
}

Expand Down
13 changes: 8 additions & 5 deletions src/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ fn format_project<T: FormatHandler>(
let main_file = input.file_name();
let input_is_stdin = main_file == FileName::Stdin;

let ignore_path_set = match IgnorePathSet::from_ignore_list(&config.ignore()) {
Ok(set) => set,
Err(e) => return Err(ErrorKind::InvalidGlobPattern(e)),
};
if config.skip_children() && ignore_path_set.is_match(&main_file) {
return Ok(FormatReport::new());
}

// Parse the crate.
let source_map = Rc::new(SourceMap::new(FilePathMapping::empty()));
let mut parse_session = make_parse_sess(source_map.clone(), config);
Expand All @@ -91,11 +99,6 @@ fn format_project<T: FormatHandler>(
parse_session.span_diagnostic = Handler::with_emitter(true, None, silent_emitter);

let mut context = FormatContext::new(&krate, report, parse_session, config, handler);
let ignore_path_set = match IgnorePathSet::from_ignore_list(&config.ignore()) {
Ok(set) => set,
Err(e) => return Err(ErrorKind::InvalidGlobPattern(e)),
};

let files = modules::ModResolver::new(
context.parse_session.source_map(),
directory_ownership.unwrap_or(parse::DirectoryOwnership::UnownedViaMod(false)),
Expand Down
10 changes: 6 additions & 4 deletions src/ignore_path.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use ignore::{self, gitignore};
use std::path::PathBuf;

use crate::config::{FileName, IgnoreList};

Expand All @@ -9,7 +8,7 @@ pub struct IgnorePathSet {

impl IgnorePathSet {
pub fn from_ignore_list(ignore_list: &IgnoreList) -> Result<Self, ignore::Error> {
let mut ignore_builder = gitignore::GitignoreBuilder::new(PathBuf::from(""));
let mut ignore_builder = gitignore::GitignoreBuilder::new(ignore_list.rustfmt_toml_path());

for ignore_path in ignore_list {
ignore_builder.add_line(None, ignore_path.to_str().unwrap())?;
Expand All @@ -33,16 +32,19 @@ impl IgnorePathSet {

#[cfg(test)]
mod test {
use std::path::{Path, PathBuf};

use crate::config::{Config, FileName};
use crate::ignore_path::IgnorePathSet;
use std::path::PathBuf;

#[test]
fn test_ignore_path_set() {
match option_env!("CFG_RELEASE_CHANNEL") {
// this test requires nightly
None | Some("nightly") => {
let config = Config::from_toml(r#"ignore = ["foo.rs", "bar_dir/*"]"#).unwrap();
let config =
Config::from_toml(r#"ignore = ["foo.rs", "bar_dir/*"]"#, Path::new(""))
.unwrap();
let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap();

assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/foo.rs"))));
Expand Down
2 changes: 1 addition & 1 deletion src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ fn get_config(config_file: Option<&Path>) -> Config {
.read_to_string(&mut def_config)
.expect("Couldn't read config");

Config::from_toml(&def_config).expect("invalid TOML")
Config::from_toml(&def_config, Path::new("tests/config/")).expect("invalid TOML")
}

// Reads significant comments of the form: `// rustfmt-key: value` into a hash map.
Expand Down