1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
extern crate shlex; extern crate getopts; use std::env; use getopts::Options; use std::process::exit; use std::process::Command; fn print_usage(program: &str, opts: Options) { let brief = format!("Usage: {} <from> <to> [target_files]", program); print!("{}", opts.usage(&brief)); } fn print_version() { println!("{}", env!("CARGO_PKG_VERSION")); } fn is_gsed_installed() -> bool { Command::new("which") .arg("gsed") .output() .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) }) .status .success() } fn quote_args(args: &Vec<String>) -> (String, String, String) { let quoted_args: Vec<String> = args[1..].iter().map(|x| shlex::quote(x).to_string() ).collect(); ( quoted_args[0].clone(), quoted_args[1].clone(), if quoted_args.len() > 2 { quoted_args[2].clone() } else { ".".to_string() } ) } pub fn substitute(args: &Vec<String>) -> () { let (from, to, path) = quote_args(&args); let output = Command::new("git") .args(&["grep", "-l"]) .arg(&from) .arg(&path) .output() .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) }); let stdout = String::from_utf8_lossy(&output.stdout); let target_files: Vec<&str> = stdout.lines_any().collect(); if target_files.len() == 0 { exit(0); } let re = format!("s/{}/{}/g", &from, &to); if is_gsed_installed() { Command::new("gsed") .arg("-i") .arg(&re) .args(&target_files) .status() .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) }); } else { Command::new("sed") .args(&["-i", "", "-e"]) .arg(&re) .args(&target_files) .status() .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) }); } } pub fn run(args: env::Args) -> () { let args: Vec<String> = args.collect(); let ref program = args[0]; let mut opts = Options::new(); opts.optflag("h", "help", "print this help menu"); opts.optflag("v", "version", "print version"); let matches = match opts.parse(&args[1..]) { Ok(m) => { m } Err(f) => { panic!(f.to_string()) } }; if matches.opt_present("v") { return print_version(); } else if matches.opt_present("h") || args.len() <= 2 { return print_usage(&program, opts); } substitute(&args); }