Move from String to PathBuf where applicable

This commit is contained in:
Oliver Schneider 2017-12-08 14:16:47 +01:00 committed by topecongiro
parent 4ee7911f4b
commit fad903fd14
9 changed files with 152 additions and 114 deletions

View File

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(rustc_private)]
#![cfg(not(test))]
extern crate env_logger;
@ -22,7 +23,7 @@ use std::str::FromStr;
use getopts::{Matches, Options};
use rustfmt::{run, Input, Summary};
use rustfmt::{run, FileName, Input, Summary};
use rustfmt::file_lines::FileLines;
use rustfmt::config::{get_toml_path, Color, Config, WriteMode};
@ -243,8 +244,9 @@ fn execute(opts: &Options) -> FmtResult<Summary> {
if let Some(ref file_lines) = matches.opt_str("file-lines") {
config.set().file_lines(file_lines.parse()?);
for f in config.file_lines().files() {
if f != "stdin" {
eprintln!("Warning: Extra file listed in file_lines option '{}'", f);
match *f {
FileName::Custom(ref f) if f == "stdin" => {}
_ => eprintln!("Warning: Extra file listed in file_lines option '{}'", f),
}
}
}
@ -264,8 +266,12 @@ fn execute(opts: &Options) -> FmtResult<Summary> {
let options = CliOptions::from_matches(&matches)?;
for f in options.file_lines.files() {
if !files.contains(&PathBuf::from(f)) {
eprintln!("Warning: Extra file listed in file_lines option '{}'", f);
match *f {
FileName::Real(ref f) if files.contains(f) => {}
FileName::Real(_) => {
eprintln!("Warning: Extra file listed in file_lines option '{}'", f)
}
_ => eprintln!("Warning: Not a file '{}'", f),
}
}

View File

@ -9,6 +9,7 @@
// except according to those terms.
use std::io::{self, Write};
use std::path::Path;
use config::WriteMode;
use rustfmt_diff::{DiffLine, Mismatch};
@ -41,13 +42,13 @@ where
pub fn output_checkstyle_file<T>(
mut writer: T,
filename: &str,
filename: &Path,
diff: Vec<Mismatch>,
) -> Result<(), io::Error>
where
T: Write,
{
write!(writer, "<file name=\"{}\">", filename)?;
write!(writer, "<file name=\"{}\">", filename.display())?;
for mismatch in diff {
for line in mismatch.lines {
// Do nothing with `DiffLine::Context` and `DiffLine::Resulting`.

View File

@ -13,7 +13,7 @@
use std::rc::Rc;
use syntax::codemap::{BytePos, CodeMap, FileMap, Span};
use syntax::codemap::{BytePos, CodeMap, FileMap, FileName, Span};
use comment::FindUncommented;
@ -25,8 +25,8 @@ pub struct LineRange {
}
impl LineRange {
pub fn file_name(&self) -> &str {
self.file.as_ref().name.as_str()
pub fn file_name(&self) -> &FileName {
&self.file.name
}
}

View File

@ -10,12 +10,14 @@
//! This module contains types and functions to support formatting specific line ranges.
use std::{cmp, iter, path, str};
use std::{cmp, iter, str};
use std::collections::HashMap;
use serde::de::{Deserialize, Deserializer};
use serde_json as json;
use codemap::LineRange;
use syntax::codemap::FileName;
/// A range that is inclusive of both ends.
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, Deserialize)]
@ -84,11 +86,11 @@ impl Range {
/// non-overlapping ranges sorted by their start point. An inner `None` is interpreted to mean all
/// lines in all files.
#[derive(Clone, Debug, Default)]
pub struct FileLines(Option<HashMap<String, Vec<Range>>>);
pub struct FileLines(Option<HashMap<FileName, Vec<Range>>>);
/// Normalizes the ranges so that the invariants for `FileLines` hold: ranges are non-overlapping,
/// and ordered by their start point.
fn normalize_ranges(ranges: &mut HashMap<String, Vec<Range>>) {
fn normalize_ranges(ranges: &mut HashMap<FileName, Vec<Range>>) {
for ranges in ranges.values_mut() {
ranges.sort();
let mut result = vec![];
@ -117,7 +119,7 @@ impl FileLines {
FileLines(None)
}
pub fn from_ranges(mut ranges: HashMap<String, Vec<Range>>) -> FileLines {
pub fn from_ranges(mut ranges: HashMap<FileName, Vec<Range>>) -> FileLines {
normalize_ranges(&mut ranges);
FileLines(Some(ranges))
}
@ -129,7 +131,7 @@ impl FileLines {
/// Returns true if `self` includes all lines in all files. Otherwise runs `f` on all ranges in
/// the designated file (if any) and returns true if `f` ever does.
fn file_range_matches<F>(&self, file_name: &str, f: F) -> bool
fn file_range_matches<F>(&self, file_name: &FileName, f: F) -> bool
where
F: FnMut(&Range) -> bool,
{
@ -156,35 +158,31 @@ impl FileLines {
}
/// Returns true if `line` from `file_name` is in `self`.
pub fn contains_line(&self, file_name: &str, line: usize) -> bool {
pub fn contains_line(&self, file_name: &FileName, line: usize) -> bool {
self.file_range_matches(file_name, |r| r.lo <= line && r.hi >= line)
}
/// Returns true if any of the lines between `lo` and `hi` from `file_name` are in `self`.
pub fn intersects_range(&self, file_name: &str, lo: usize, hi: usize) -> bool {
pub fn intersects_range(&self, file_name: &FileName, lo: usize, hi: usize) -> bool {
self.file_range_matches(file_name, |r| r.intersects(Range::new(lo, hi)))
}
}
/// `FileLines` files iterator.
pub struct Files<'a>(Option<::std::collections::hash_map::Keys<'a, String, Vec<Range>>>);
pub struct Files<'a>(Option<::std::collections::hash_map::Keys<'a, FileName, Vec<Range>>>);
impl<'a> iter::Iterator for Files<'a> {
type Item = &'a String;
type Item = &'a FileName;
fn next(&mut self) -> Option<&'a String> {
fn next(&mut self) -> Option<&'a FileName> {
self.0.as_mut().and_then(Iterator::next)
}
}
fn canonicalize_path_string(s: &str) -> Option<String> {
if s == "stdin" {
return Some(s.to_string());
}
match path::PathBuf::from(s).canonicalize() {
Ok(canonicalized) => canonicalized.to_str().map(|s| s.to_string()),
_ => None,
fn canonicalize_path_string(file: &FileName) -> Option<FileName> {
match *file {
FileName::Real(ref path) => path.canonicalize().ok().map(FileName::Real),
_ => Some(file.clone()),
}
}
@ -206,12 +204,21 @@ impl str::FromStr for FileLines {
// For JSON decoding.
#[derive(Clone, Debug, Deserialize)]
struct JsonSpan {
file: String,
#[serde(deserialize_with = "deserialize_filename")] file: FileName,
range: (usize, usize),
}
fn deserialize_filename<'de, D: Deserializer<'de>>(d: D) -> Result<FileName, D::Error> {
let s = String::deserialize(d)?;
if s == "stdin" {
Ok(FileName::Custom(s))
} else {
Ok(FileName::Real(s.into()))
}
}
impl JsonSpan {
fn into_tuple(self) -> Result<(String, Range), String> {
fn into_tuple(self) -> Result<(FileName, Range), String> {
let (lo, hi) = self.range;
let canonical = canonicalize_path_string(&self.file)
.ok_or_else(|| format!("Can't canonicalize {}", &self.file))?;

View File

@ -12,15 +12,17 @@
use std::fs::{self, File};
use std::io::{self, BufWriter, Read, Write};
use std::path::Path;
use checkstyle::{output_checkstyle_file, output_footer, output_header};
use config::{Config, NewlineStyle, WriteMode};
use rustfmt_diff::{make_diff, print_diff, Mismatch};
use syntax::codemap::FileName;
// A map of the files of a crate, with their new content
pub type FileMap = Vec<FileRecord>;
pub type FileRecord = (String, String);
pub type FileRecord = (FileName, String);
// Append a newline to the end of each file.
pub fn append_newline(s: &mut String) {
@ -80,7 +82,7 @@ where
pub fn write_file<T>(
text: &str,
filename: &str,
filename: &FileName,
out: &mut T,
config: &Config,
) -> Result<bool, io::Error>
@ -89,7 +91,7 @@ where
{
fn source_and_formatted_text(
text: &str,
filename: &str,
filename: &Path,
config: &Config,
) -> Result<(String, String), io::Error> {
let mut f = File::open(filename)?;
@ -102,7 +104,7 @@ where
}
fn create_diff(
filename: &str,
filename: &Path,
text: &str,
config: &Config,
) -> Result<Vec<Mismatch>, io::Error> {
@ -110,15 +112,21 @@ where
Ok(make_diff(&ori, &fmt, 3))
}
let filename_to_path = || match *filename {
FileName::Real(ref path) => path,
_ => panic!("cannot format `{}` with WriteMode::Replace", filename),
};
match config.write_mode() {
WriteMode::Replace => {
if let Ok((ori, fmt)) = source_and_formatted_text(text, filename, config) {
let filename = filename_to_path();
if let Ok((ori, fmt)) = source_and_formatted_text(text, &filename, config) {
if fmt != ori {
// Do a little dance to make writing safer - write to a temp file
// rename the original to a .bk, then rename the temp file to the
// original.
let tmp_name = filename.to_owned() + ".tmp";
let bk_name = filename.to_owned() + ".bk";
let tmp_name = filename.with_extension("tmp");
let bk_name = filename.with_extension("bk");
{
// Write text to temp file
let tmp_file = File::create(&tmp_name)?;
@ -132,7 +140,8 @@ where
}
WriteMode::Overwrite => {
// Write text directly over original file if there is a diff.
let (source, formatted) = source_and_formatted_text(text, filename, config)?;
let filename = filename_to_path();
let (source, formatted) = source_and_formatted_text(text, &filename, config)?;
if source != formatted {
let file = File::create(filename)?;
write_system_newlines(file, text, config)?;
@ -146,19 +155,21 @@ where
write_system_newlines(out, text, config)?;
}
WriteMode::Diff => {
if let Ok((ori, fmt)) = source_and_formatted_text(text, filename, config) {
let filename = filename_to_path();
if let Ok((ori, fmt)) = source_and_formatted_text(text, &filename, config) {
let mismatch = make_diff(&ori, &fmt, 3);
let has_diff = !mismatch.is_empty();
print_diff(
mismatch,
|line_num| format!("Diff in {} at line {}:", filename, line_num),
|line_num| format!("Diff in {} at line {}:", filename.display(), line_num),
config.color(),
);
return Ok(has_diff);
}
}
WriteMode::Checkstyle => {
let diff = create_diff(filename, text, config)?;
let filename = filename_to_path();
let diff = create_diff(&filename, text, config)?;
output_checkstyle_file(out, filename, diff)?;
}
}

View File

@ -29,13 +29,14 @@ use std::collections::HashMap;
use std::fmt;
use std::io::{self, stdout, Write};
use std::iter::repeat;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::rc::Rc;
use errors::{DiagnosticBuilder, Handler};
use errors::emitter::{ColorConfig, EmitterWriter};
use syntax::ast;
use syntax::codemap::{CodeMap, FilePathMapping};
pub use syntax::codemap::FileName;
use syntax::parse::{self, ParseSess};
use checkstyle::{output_footer, output_header};
@ -146,7 +147,7 @@ impl FormattingError {
pub struct FormatReport {
// Maps stringified file paths to their associated formatting errors.
file_error_map: HashMap<String, Vec<FormattingError>>,
file_error_map: HashMap<FileName, Vec<FormattingError>>,
}
impl FormatReport {
@ -295,12 +296,12 @@ impl fmt::Display for FormatReport {
fn format_ast<F>(
krate: &ast::Crate,
parse_session: &mut ParseSess,
main_file: &Path,
main_file: &FileName,
config: &Config,
mut after_file: F,
) -> Result<(FileMap, bool), io::Error>
where
F: FnMut(&str, &mut String, &[(usize, usize)]) -> Result<bool, io::Error>,
F: FnMut(&FileName, &mut String, &[(usize, usize)]) -> Result<bool, io::Error>,
{
let mut result = FileMap::new();
// diff mode: check if any files are differing
@ -310,12 +311,11 @@ where
// nothing to distinguish the nested module contents.
let skip_children = config.skip_children() || config.write_mode() == config::WriteMode::Plain;
for (path, module) in modules::list_files(krate, parse_session.codemap())? {
if skip_children && path.as_path() != main_file {
if skip_children && path != *main_file {
continue;
}
let path_str = path.to_str().unwrap();
if config.verbose() {
println!("Formatting {}", path_str);
println!("Formatting {}", path);
}
let filemap = parse_session
.codemap()
@ -325,7 +325,7 @@ where
let snippet_provider = SnippetProvider::new(filemap.start_pos, big_snippet);
let mut visitor = FmtVisitor::from_codemap(parse_session, config, &snippet_provider);
// Format inner attributes if available.
if !krate.attrs.is_empty() && path == main_file {
if !krate.attrs.is_empty() && path == *main_file {
visitor.skip_empty_lines(filemap.end_pos);
if visitor.visit_attrs(&krate.attrs, ast::AttrStyle::Inner) {
visitor.push_rewrite(module.inner, None);
@ -343,16 +343,17 @@ where
::utils::count_newlines(&format!("{}", visitor.buffer))
);
has_diff |= match after_file(path_str, &mut visitor.buffer, &visitor.skipped_range) {
let filename = path.clone();
has_diff |= match after_file(&filename, &mut visitor.buffer, &visitor.skipped_range) {
Ok(result) => result,
Err(e) => {
// Create a new error with path_str to help users see which files failed
let err_msg = path_str.to_string() + &": ".to_string() + &e.to_string();
let err_msg = format!("{}: {}", path, e);
return Err(io::Error::new(e.kind(), err_msg));
}
};
result.push((path_str.to_owned(), visitor.buffer));
result.push((filename, visitor.buffer));
}
Ok((result, has_diff))
@ -389,7 +390,7 @@ fn should_report_error(
// FIXME(#20) other stuff for parity with make tidy
fn format_lines(
text: &mut String,
name: &str,
name: &FileName,
skipped_range: &[(usize, usize)],
config: &Config,
report: &mut FormatReport,
@ -491,7 +492,7 @@ fn format_lines(
}
}
report.file_error_map.insert(name.to_owned(), errors);
report.file_error_map.insert(name.clone(), errors);
}
fn parse_input(
@ -505,8 +506,11 @@ fn parse_input(
parser.parse_crate_mod()
}
Input::Text(text) => {
let mut parser =
parse::new_parser_from_source_str(parse_session, "stdin".to_owned(), text);
let mut parser = parse::new_parser_from_source_str(
parse_session,
FileName::Custom("stdin".to_owned()),
text,
);
parser.cfg_mods = false;
parser.parse_crate_mod()
}
@ -547,8 +551,8 @@ pub fn format_input<T: Write>(
let mut parse_session = ParseSess::with_span_handler(tty_handler, codemap.clone());
let main_file = match input {
Input::File(ref file) => file.clone(),
Input::Text(..) => PathBuf::from("stdin"),
Input::File(ref file) => FileName::Real(file.clone()),
Input::Text(..) => FileName::Custom("stdin".to_owned()),
};
let krate = match parse_input(input, &parse_session) {

View File

@ -11,7 +11,7 @@
use std::borrow::Cow;
use std::iter::repeat;
use syntax::codemap::{BytePos, Pos, Span};
use syntax::codemap::{BytePos, FileName, Pos, Span};
use codemap::LineRangeUtils;
use comment::{rewrite_comment, CodeCharKind, CommentCodeSlices};
@ -260,7 +260,7 @@ impl<'a> FmtVisitor<'a> {
snippet: &str,
subslice: &str,
offset: usize,
file_name: &str,
file_name: &FileName,
) {
for (mut i, c) in subslice.char_indices() {
i += offset;

View File

@ -13,7 +13,7 @@ use std::path::{Path, PathBuf};
use std::io;
use syntax::ast;
use syntax::codemap;
use syntax::codemap::{self, FileName};
use syntax::parse::parser;
use utils::contains_skip;
@ -23,15 +23,16 @@ use utils::contains_skip;
pub fn list_files<'a>(
krate: &'a ast::Crate,
codemap: &codemap::CodeMap,
) -> Result<BTreeMap<PathBuf, &'a ast::Mod>, io::Error> {
) -> Result<BTreeMap<FileName, &'a ast::Mod>, io::Error> {
let mut result = BTreeMap::new(); // Enforce file order determinism
let root_filename: PathBuf = codemap.span_to_filename(krate.span).into();
list_submodules(
&krate.module,
root_filename.parent().unwrap(),
codemap,
&mut result,
)?;
let root_filename = codemap.span_to_filename(krate.span);
{
let parent = match root_filename {
FileName::Real(ref path) => path.parent().unwrap(),
_ => Path::new(""),
};
list_submodules(&krate.module, parent, codemap, &mut result)?;
}
result.insert(root_filename, &krate.module);
Ok(result)
}
@ -41,7 +42,7 @@ fn list_submodules<'a>(
module: &'a ast::Mod,
search_dir: &Path,
codemap: &codemap::CodeMap,
result: &mut BTreeMap<PathBuf, &'a ast::Mod>,
result: &mut BTreeMap<FileName, &'a ast::Mod>,
) -> Result<(), io::Error> {
debug!("list_submodules: search_dir: {:?}", search_dir);
for item in &module.items {
@ -54,7 +55,7 @@ fn list_submodules<'a>(
} else {
let mod_path = module_file(item.ident, &item.attrs, search_dir, codemap)?;
let dir_path = mod_path.parent().unwrap().to_owned();
result.insert(mod_path, sub_mod);
result.insert(FileName::Real(mod_path), sub_mod);
dir_path
};
list_submodules(sub_mod, &dir_path, codemap, result)?;

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(rustc_private)]
#[macro_use]
extern crate log;
extern crate regex;
@ -28,10 +30,8 @@ use rustfmt::rustfmt_diff::*;
const DIFF_CONTEXT_SIZE: usize = 3;
fn get_path_string(dir_entry: io::Result<fs::DirEntry>) -> String {
let path = dir_entry.expect("Couldn't get DirEntry").path();
path.to_str().expect("Couldn't stringify path").to_owned()
fn get_path_string(dir_entry: io::Result<fs::DirEntry>) -> PathBuf {
dir_entry.expect("Couldn't get DirEntry").path().to_owned()
}
// Integration tests. The files in the tests/source are formatted and compared
@ -68,12 +68,12 @@ fn coverage_tests() {
fn checkstyle_test() {
let filename = "tests/writemode/source/fn-single-line.rs";
let expected_filename = "tests/writemode/target/checkstyle.xml";
assert_output(filename, expected_filename);
assert_output(Path::new(filename), Path::new(expected_filename));
}
// Helper function for comparing the results of rustfmt
// to a known output file generated by one of the write modes.
fn assert_output(source: &str, expected_filename: &str) {
fn assert_output(source: &Path, expected_filename: &Path) {
let config = read_config(source);
let (file_map, _report) = format_file(source, &config);
@ -91,7 +91,7 @@ fn assert_output(source: &str, expected_filename: &str) {
let compare = make_diff(&expected_text, &output, DIFF_CONTEXT_SIZE);
if !compare.is_empty() {
let mut failures = HashMap::new();
failures.insert(source.to_string(), compare);
failures.insert(source.to_owned(), compare);
print_mismatches(failures);
assert!(false, "Text does not match expected output");
}
@ -121,8 +121,8 @@ fn self_tests() {
.chain(fs::read_dir("tests").expect("Couldn't read tests dir"))
.map(get_path_string);
// Hack because there's no `IntoIterator` impl for `[T; N]`.
let files = files.chain(Some("src/lib.rs".to_owned()).into_iter());
let files = files.chain(Some("build.rs".to_owned()).into_iter());
let files = files.chain(Some(PathBuf::from("src/lib.rs")).into_iter());
let files = files.chain(Some(PathBuf::from("build.rs")).into_iter());
let (reports, count, fails) = check_files(files);
let mut warnings = 0;
@ -152,9 +152,11 @@ fn stdin_formatting_smoke_test() {
format_input::<io::Stdout>(input, &config, None).unwrap();
assert!(error_summary.has_no_errors());
for &(ref file_name, ref text) in &file_map {
if file_name == "stdin" {
assert_eq!(text.to_string(), "fn main() {}\n");
return;
if let FileName::Custom(ref file_name) = *file_name {
if file_name == "stdin" {
assert_eq!(text.to_string(), "fn main() {}\n");
return;
}
}
}
panic!("no stdin");
@ -197,14 +199,14 @@ fn format_lines_errors_are_reported() {
// Returns the number of files checked and the number of failures.
fn check_files<I>(files: I) -> (Vec<FormatReport>, u32, u32)
where
I: Iterator<Item = String>,
I: Iterator<Item = PathBuf>,
{
let mut count = 0;
let mut fails = 0;
let mut reports = vec![];
for file_name in files.filter(|f| f.ends_with(".rs")) {
debug!("Testing '{}'...", file_name);
for file_name in files.filter(|f| f.extension().map_or(false, |f| f == "rs")) {
debug!("Testing '{}'...", file_name.display());
match idempotent_check(file_name) {
Ok(ref report) if report.has_warnings() => {
@ -224,13 +226,13 @@ where
(reports, count, fails)
}
fn print_mismatches(result: HashMap<String, Vec<Mismatch>>) {
fn print_mismatches(result: HashMap<PathBuf, Vec<Mismatch>>) {
let mut t = term::stdout().unwrap();
for (file_name, diff) in result {
print_diff(
diff,
|line_num| format!("\nMismatch at {}:{}:", file_name, line_num),
|line_num| format!("\nMismatch at {}:{}:", file_name.display(), line_num),
Color::Auto,
);
}
@ -238,20 +240,15 @@ fn print_mismatches(result: HashMap<String, Vec<Mismatch>>) {
t.reset().unwrap();
}
fn read_config(filename: &str) -> Config {
fn read_config(filename: &Path) -> Config {
let sig_comments = read_significant_comments(filename);
// Look for a config file... If there is a 'config' property in the significant comments, use
// that. Otherwise, if there are no significant comments at all, look for a config file with
// the same name as the test file.
let mut config = if !sig_comments.is_empty() {
get_config(sig_comments.get("config").map(|x| &(*x)[..]))
get_config(sig_comments.get("config").map(Path::new))
} else {
get_config(
Path::new(filename)
.with_extension("toml")
.file_name()
.and_then(std::ffi::OsStr::to_str),
)
get_config(filename.with_extension("toml").file_name().map(Path::new))
};
for (key, val) in &sig_comments {
@ -274,7 +271,9 @@ fn format_file<P: Into<PathBuf>>(filepath: P, config: &Config) -> (FileMap, Form
(file_map, report)
}
pub fn idempotent_check(filename: String) -> Result<FormatReport, HashMap<String, Vec<Mismatch>>> {
pub fn idempotent_check(
filename: PathBuf,
) -> Result<FormatReport, HashMap<PathBuf, Vec<Mismatch>>> {
let sig_comments = read_significant_comments(&filename);
let config = read_config(&filename);
let (file_map, format_report) = format_file(filename, &config);
@ -286,7 +285,9 @@ pub fn idempotent_check(filename: String) -> Result<FormatReport, HashMap<String
write_system_newlines(&mut v, text, &config).unwrap();
// Won't panic, we are writing correct utf8.
let one_result = String::from_utf8(v).unwrap();
write_result.insert(filename.clone(), one_result);
if let FileName::Real(ref filename) = *filename {
write_result.insert(filename.to_owned(), one_result);
}
}
let target = sig_comments.get("target").map(|x| &(*x)[..]);
@ -297,13 +298,13 @@ pub fn idempotent_check(filename: String) -> Result<FormatReport, HashMap<String
// Reads test config file using the supplied (optional) file name. If there's no file name or the
// file doesn't exist, just return the default config. Otherwise, the file must be read
// successfully.
fn get_config(config_file: Option<&str>) -> Config {
fn get_config(config_file: Option<&Path>) -> Config {
let config_file_name = match config_file {
None => return Default::default(),
Some(file_name) => {
let mut full_path = "tests/config/".to_owned();
full_path.push_str(file_name);
if !Path::new(&full_path).exists() {
let mut full_path = PathBuf::from("tests/config/");
full_path.push(file_name);
if !full_path.exists() {
return Default::default();
};
full_path
@ -321,8 +322,9 @@ fn get_config(config_file: Option<&str>) -> Config {
// Reads significant comments of the form: // rustfmt-key: value
// into a hash map.
fn read_significant_comments(file_name: &str) -> HashMap<String, String> {
let file = fs::File::open(file_name).expect(&format!("Couldn't read file {}", file_name));
fn read_significant_comments(file_name: &Path) -> HashMap<String, String> {
let file =
fs::File::open(file_name).expect(&format!("Couldn't read file {}", file_name.display()));
let reader = BufReader::new(file);
let pattern = r"^\s*//\s*rustfmt-([^:]+):\s*(\S+)";
let regex = regex::Regex::new(pattern).expect("Failed creating pattern 1");
@ -357,9 +359,9 @@ fn read_significant_comments(file_name: &str) -> HashMap<String, String> {
// Compare output to input.
// TODO: needs a better name, more explanation.
fn handle_result(
result: HashMap<String, String>,
result: HashMap<PathBuf, String>,
target: Option<&str>,
) -> Result<(), HashMap<String, Vec<Mismatch>>> {
) -> Result<(), HashMap<PathBuf, Vec<Mismatch>>> {
let mut failures = HashMap::new();
for (file_name, fmt_text) in result {
@ -391,15 +393,21 @@ fn handle_result(
}
// Map source file paths to their target paths.
fn get_target(file_name: &str, target: Option<&str>) -> String {
if file_name.contains("source") {
let target_file_name = file_name.replace("source", "target");
fn get_target(file_name: &Path, target: Option<&str>) -> PathBuf {
if let Some(n) = file_name
.components()
.position(|c| c.as_os_str() == "source")
{
let mut target_file_name = PathBuf::new();
for (i, c) in file_name.components().enumerate() {
if i == n {
target_file_name.push("target");
} else {
target_file_name.push(c.as_os_str());
}
}
if let Some(replace_name) = target {
Path::new(&target_file_name)
.with_file_name(replace_name)
.into_os_string()
.into_string()
.unwrap()
target_file_name.with_file_name(replace_name)
} else {
target_file_name
}