git_gsub/
lib.rs

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