Add an option to forgo backups

This commit is contained in:
Marcus Klaas 2015-08-18 21:10:30 +02:00
parent 229415bca2
commit 10a80bb8be
5 changed files with 98 additions and 46 deletions

View File

@ -13,12 +13,18 @@ the rustfmt command. You can look at this repo for an example default.toml file.
`cargo test` to run all tests. `cargo test` to run all tests.
`cargo run filename` to run on a file, if the file includes out of line modules, `cargo run -- filename` to run on a file, if the file includes out of line modules,
then we reformat those too. So to run on a whole module or crate, you just need then we reformat those too. So to run on a whole module or crate, you just need
to run on the top file. You'll probably want to set the `WriteMode` in the call to run on the top file.
to `run` in `main()`. Eventually you should be able to set the mode from the
command line or from a config file or something.
You'll probably want to specify the write mode. Currently, there are the replace,
overwrite and display mode. The replace mode is the default and overwrites the
original files after renaming them. In overwrite mode, rustfmt does not backup
the source files. To print the output to stdout, use the display mode. The write
mode can be set by passing the `--write-mode` flag on the command line.
`cargo run -- filename --write-mode=display` prints the output of rustfmt to the
screen, for example.
## Use cases ## Use cases

View File

@ -9,23 +9,47 @@
// except according to those terms. // except according to those terms.
#![cfg(not(test))] #![cfg(not(test))]
#![feature(result_expect)]
extern crate rustfmt; extern crate rustfmt;
use rustfmt::{WriteMode, run}; use rustfmt::{WriteMode, run};
use rustfmt::config::Config;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use std::str::FromStr;
fn main() { fn main() {
let args: Vec<_> = std::env::args().collect();
let mut def_config_file = File::open("default.toml").unwrap_or_else(|e| { let mut def_config_file = File::open("default.toml").unwrap_or_else(|e| {
panic!("Unable to open configuration file [default.toml] {}",e) panic!("Unable to open configuration file [default.toml] {}",e)
}); });
let mut def_config = String::new(); let mut def_config = String::new();
def_config_file.read_to_string(&mut def_config).unwrap(); def_config_file.read_to_string(&mut def_config).unwrap();
let config = Box::new(Config::from_toml(&def_config));
let (args, write_mode) = determine_params(std::env::args());
run(args, WriteMode::Overwrite, &def_config); run(args, write_mode, config);
std::process::exit(0); std::process::exit(0);
} }
fn determine_params<I>(args: I) -> (Vec<String>, WriteMode)
where I: Iterator<Item = String>
{
let prefix = "--write-mode=";
let mut write_mode = WriteMode::Replace;
// The NewFile option currently isn't supported because it requires another
// parameter, but it can be added later.
let args = args.filter(|arg| {
if arg.starts_with(prefix) {
write_mode = FromStr::from_str(&arg[prefix.len()..]).expect("Unrecognized write mode");
false
} else {
true
}
}).collect();
(args, write_mode)
}

View File

@ -73,40 +73,46 @@ fn write_system_newlines<T>(mut writer: T,
} }
match mode { match mode {
WriteMode::Overwrite => { WriteMode::Replace => {
// Do a little dance to make writing safer - write to a temp file // 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 // rename the original to a .bk, then rename the temp file to the
// original. // original.
let tmp_name = filename.to_owned() + ".tmp"; let tmp_name = filename.to_owned() + ".tmp";
let bk_name = filename.to_owned() + ".bk"; let bk_name = filename.to_owned() + ".bk";
{ {
// Write text to temp file // Write text to temp file
let tmp_file = try!(File::create(&tmp_name)); let tmp_file = try!(File::create(&tmp_name));
try!(write_system_newlines(tmp_file, text, config)); try!(write_system_newlines(tmp_file, text, config));
} }
try!(fs::rename(filename, bk_name)); try!(fs::rename(filename, bk_name));
try!(fs::rename(tmp_name, filename)); try!(fs::rename(tmp_name, filename));
}
WriteMode::NewFile(extn) => {
let filename = filename.to_owned() + "." + extn;
let file = try!(File::create(&filename));
try!(write_system_newlines(file, text, config));
}
WriteMode::Display => {
println!("{}:\n", filename);
let stdout = stdout();
let stdout_lock = stdout.lock();
try!(write_system_newlines(stdout_lock, text, config));
}
WriteMode::Return(_) => {
// io::Write is not implemented for String, working around with Vec<u8>
let mut v = Vec::new();
try!(write_system_newlines(&mut v, text, config));
// won't panic, we are writing correct utf8
return Ok(Some(String::from_utf8(v).unwrap()));
}
} }
WriteMode::Overwrite => {
// Write text directly over original file.
let file = try!(File::create(filename));
try!(write_system_newlines(file, text, config));
}
WriteMode::NewFile(extn) => {
let filename = filename.to_owned() + "." + extn;
let file = try!(File::create(&filename));
try!(write_system_newlines(file, text, config));
}
WriteMode::Display => {
println!("{}:\n", filename);
let stdout = stdout();
let stdout_lock = stdout.lock();
try!(write_system_newlines(stdout_lock, text, config));
}
WriteMode::Return(_) => {
// io::Write is not implemented for String, working around with
// Vec<u8>
let mut v = Vec::new();
try!(write_system_newlines(&mut v, text, config));
// won't panic, we are writing correct utf8
return Ok(Some(String::from_utf8(v).unwrap()));
}
}
Ok(None) Ok(None)
} }

View File

@ -42,6 +42,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::mem::swap; use std::mem::swap;
use std::str::FromStr;
use issues::{BadIssueSeeker, Issue}; use issues::{BadIssueSeeker, Issue};
use filemap::FileMap; use filemap::FileMap;
@ -71,8 +72,11 @@
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum WriteMode { pub enum WriteMode {
// Backups the original file and overwrites the orignal.
Replace,
// Overwrites original file without backup.
Overwrite, Overwrite,
// str is the extension of the new file // str is the extension of the new file.
NewFile(&'static str), NewFile(&'static str),
// Write the output to stdout. // Write the output to stdout.
Display, Display,
@ -80,6 +84,19 @@ pub enum WriteMode {
Return(&'static Fn(HashMap<String, String>)), Return(&'static Fn(HashMap<String, String>)),
} }
impl FromStr for WriteMode {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"replace" => Ok(WriteMode::Replace),
"display" => Ok(WriteMode::Display),
"overwrite" => Ok(WriteMode::Overwrite),
_ => Err(())
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum NewlineStyle { pub enum NewlineStyle {
Windows, // \r\n Windows, // \r\n
@ -343,9 +360,7 @@ fn build_controller(&mut self, _: &Session) -> driver::CompileController<'a> {
// to the compiler. // to the compiler.
// write_mode determines what happens to the result of running rustfmt, see // write_mode determines what happens to the result of running rustfmt, see
// WriteMode. // WriteMode.
// default_config is a string of toml data to be used to configure rustfmt. pub fn run(args: Vec<String>, write_mode: WriteMode, config: Box<Config>) {
pub fn run(args: Vec<String>, write_mode: WriteMode, default_config: &str) { let mut call_ctxt = RustFmtCalls { write_mode: write_mode, config: Some(config) };
let config = Some(Box::new(config::Config::from_toml(default_config)));
let mut call_ctxt = RustFmtCalls { write_mode: write_mode, config: config };
rustc_driver::run_compiler(&args, &mut call_ctxt); rustc_driver::run_compiler(&args, &mut call_ctxt);
} }

View File

@ -19,6 +19,7 @@
use std::io::{self, Read, BufRead, BufReader}; use std::io::{self, Read, BufRead, BufReader};
use std::thread; use std::thread;
use rustfmt::*; use rustfmt::*;
use rustfmt::config::Config;
fn get_path_string(dir_entry: io::Result<fs::DirEntry>) -> String { fn get_path_string(dir_entry: io::Result<fs::DirEntry>) -> String {
let path = dir_entry.ok().expect("Couldn't get DirEntry.").path(); let path = dir_entry.ok().expect("Couldn't get DirEntry.").path();
@ -103,14 +104,14 @@ pub fn idempotent_check(filename: String) -> Result<(), HashMap<String, String>>
// panic to return a result in case of failure. This has the advantage of smoothing the road to // panic to return a result in case of failure. This has the advantage of smoothing the road to
// multithreaded rustfmt // multithreaded rustfmt
thread::catch_panic(move || { thread::catch_panic(move || {
run(args, WriteMode::Return(HANDLE_RESULT), &config); run(args, WriteMode::Return(HANDLE_RESULT), config);
}).map_err(|any| }).map_err(|any|
*any.downcast().ok().expect("Downcast failed.") *any.downcast().ok().expect("Downcast failed.")
) )
} }
// Reads test config file from comments and loads it // Reads test config file from comments and loads it
fn get_config(file_name: &str) -> String { fn get_config(file_name: &str) -> Box<Config> {
let config_file_name = read_significant_comment(file_name, "config") let config_file_name = read_significant_comment(file_name, "config")
.map(|file_name| { .map(|file_name| {
let mut full_path = "tests/config/".to_owned(); let mut full_path = "tests/config/".to_owned();
@ -123,7 +124,7 @@ fn get_config(file_name: &str) -> String {
let mut def_config = String::new(); let mut def_config = String::new();
def_config_file.read_to_string(&mut def_config).ok().expect("Couldn't read config."); def_config_file.read_to_string(&mut def_config).ok().expect("Couldn't read config.");
def_config Box::new(Config::from_toml(&def_config))
} }
fn read_significant_comment(file_name: &str, option: &str) -> Option<String> { fn read_significant_comment(file_name: &str, option: &str) -> Option<String> {