diff --git a/src/bin/rustfmt.rs b/src/bin/rustfmt.rs index 062c60e1065..aced6f6348c 100644 --- a/src/bin/rustfmt.rs +++ b/src/bin/rustfmt.rs @@ -17,7 +17,7 @@ extern crate toml; extern crate env_logger; extern crate getopts; -use rustfmt::{run, run_from_stdin}; +use rustfmt::{run, run_from_stdin, check}; use rustfmt::config::{Config, WriteMode}; use std::env; @@ -54,6 +54,11 @@ enum Operation { InvalidInput { reason: String, }, + /// Check for any style issues, returning non-zero error code if any problems are found + Check { + files: Vec, + config_path: Option, + }, /// No file specified, read from stdin Stdin { input: String, @@ -147,6 +152,7 @@ fn execute() -> i32 { opts.optflag("h", "help", "show this message"); opts.optflag("V", "version", "show version information"); opts.optflag("v", "verbose", "show progress"); + opts.optflag("c", "check", "check for style errors, don't modify files"); opts.optopt("", "write-mode", "mode to write in (not usable when piping from stdin)", @@ -200,11 +206,12 @@ fn execute() -> i32 { run_from_stdin(input, &config); 0 } - Operation::Format { files, config_path } => { + Operation::Format { ref files, ref config_path } | + Operation::Check { ref files, ref config_path } => { let mut config = Config::default(); let mut path = None; // Load the config path file if provided - if let Some(config_file) = config_path { + if let Some(ref config_file) = *config_path { let (cfg_tmp, path_tmp) = resolve_config(config_file.as_ref()) .expect(&format!("Error resolving config for {:?}", config_file)); @@ -214,6 +221,9 @@ fn execute() -> i32 { if let Some(path) = path.as_ref() { msg!("Using rustfmt config file {}", path.display()); } + + let mut error_result: i32 = 0; + for file in files { // Check the file directory if the config-path could not be read or not provided if path.is_none() { @@ -233,9 +243,15 @@ fn execute() -> i32 { print_usage(&opts, &e); return 1; } - run(&file, &config); + + if let Operation::Check { files: _, config_path: _ } = operation { + error_result += check(&file, &config); + } else { + run(&file, &config); + } } - 0 + + error_result } } } @@ -309,6 +325,13 @@ fn determine_operation(matches: &Matches) -> Operation { let files: Vec<_> = matches.free.iter().map(PathBuf::from).collect(); + if matches.opt_present("check") { + return Operation::Check { + files: files, + config_path: config_path, + }; + } + Operation::Format { files: files, config_path: config_path, diff --git a/src/filemap.rs b/src/filemap.rs index f41915b8cff..ca8c4dc354d 100644 --- a/src/filemap.rs +++ b/src/filemap.rs @@ -80,6 +80,51 @@ pub fn write_system_newlines(writer: T, } } +fn source_and_formatted_text(text: &StringBuffer, + filename: &str, + config: &Config) + -> Result<(String, String), io::Error> { + let mut f = try!(File::open(filename)); + let mut ori_text = String::new(); + try!(f.read_to_string(&mut ori_text)); + let mut v = Vec::new(); + try!(write_system_newlines(&mut v, text, config)); + let fmt_text = String::from_utf8(v).unwrap(); + Ok((ori_text, fmt_text)) +} + +fn create_diff(filename: &str, + text: &StringBuffer, + config: &Config) + -> Result, io::Error> { + let (ori, fmt) = try!(source_and_formatted_text(text, filename, config)); + Ok(make_diff(&ori, &fmt, 3)) +} + +pub fn check_all_files(file_map: &FileMap, mut out: T, config: &Config) -> usize + where T: Write +{ + let mut error_count = 0; + for filename in file_map.keys() { + let diff = create_diff(filename, &file_map[filename], config); + match diff { + Ok(result) => { + let file_errors = result.len(); + if file_errors > 0 { + error_count += file_errors; + let _ = write!(out, "{} contains {} errors\n", filename, file_errors); + } + } + Err(error) => { + error_count += 1; + let _ = write!(out, "Error processing {}: {}", filename, error); + } + }; + } + + error_count +} + pub fn write_file(text: &StringBuffer, filename: &str, out: &mut T, @@ -87,28 +132,6 @@ pub fn write_file(text: &StringBuffer, -> Result, io::Error> where T: Write { - - fn source_and_formatted_text(text: &StringBuffer, - filename: &str, - config: &Config) - -> Result<(String, String), io::Error> { - let mut f = try!(File::open(filename)); - let mut ori_text = String::new(); - try!(f.read_to_string(&mut ori_text)); - let mut v = Vec::new(); - try!(write_system_newlines(&mut v, text, config)); - let fmt_text = String::from_utf8(v).unwrap(); - Ok((ori_text, fmt_text)) - } - - fn create_diff(filename: &str, - text: &StringBuffer, - config: &Config) - -> Result, io::Error> { - let (ori, fmt) = try!(source_and_formatted_text(text, filename, config)); - Ok(make_diff(&ori, &fmt, 3)) - } - match config.write_mode { WriteMode::Replace => { if let Ok((ori, fmt)) = source_and_formatted_text(text, filename, config) { diff --git a/src/lib.rs b/src/lib.rs index 3443db338cf..f3f1daeaa08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -440,6 +440,13 @@ pub fn run(file: &Path, config: &Config) { } } +pub fn check(file: &Path, config: &Config) -> i32 { + let mut result = format(file, config); + print!("{}", fmt_lines(&mut result, config)); + let out = stdout(); + filemap::check_all_files(&result, out, config) as i32 +} + // Similar to run, but takes an input String instead of a file to format pub fn run_from_stdin(input: String, config: &Config) { let mut result = format_string(input, config);