Skip to content

Commit

Permalink
Merge pull request #3522 from topecongiro/issue-3521
Browse files Browse the repository at this point in the history
Add a path to the parent dir of rustfmt.toml as a prefix to paths in ignore
  • Loading branch information
topecongiro authored Apr 24, 2019
2 parents 05547d9 + f520f7e commit aeb556e
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 31 deletions.
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

0 comments on commit aeb556e

Please sign in to comment.