<commit_before>extern crate regex;
extern crate getopts;
#[macro_use]
extern crate lazy_static;
use std::collections::HashMap;
use std::{env, fs, io};
use std::io::prelude::*;
mod options;
use options::*;
use std::process;
use std::collections::hash_map::Entry::{Occupied, Vacant};

macro_rules! regex { ($re:expr) => { ::regex::Regex::new($re).unwrap() } }
macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
        )
    );

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const KEY_FILE: &'static str = "KEY_FILE";
const ENV: &'static str = "ENV";
const MISSING: &'static str = "Missing properties";

fn replace_var(line: String,
               keys: &Option<KeysAndSources>,
               props_first: bool,
               used_keys: &mut HashMap<String, Vec<(String, String)>>,
               result: &mut Vec<String>) {
    let re = regex!(r"(?P<full>\$\{\s*(?P<var>[^\}]*)\s*\})");
    let mut str_line: String = line.clone();

    for cap in re.captures_iter(&*str_line.clone()) {
        cap.name("var")
           .map(|v| {
               let env_prop = env_or_prop(v.trim(), props_first, keys)
                                  .map(|v2| {
                                      str_line = re.replace(&*str_line,
                                                            &*(v2.1.value));
                                      (v2.0, v2.1)
                                  });

               env_prop.and_then(|v2| {
                   used_keys.get_mut(&v2.1.source)
                            .and_then(|r| {
                                Some(r.push((v2.0.clone(), v2.1.value.clone())))
                            })
                            .or_else(|| {
                                used_keys.insert(v2.1.source.clone(),
                                                 vec![(v2.0.clone(),
                                                       v2.1.value.clone())]);
                                Some(())
                            })
               })
           });
    }
    result.push(str_line.to_string());
}

fn no_property(key: &str, env: Option<String>) -> Option<(String, ValueAndSource)> {
    match env {
        Some(e) => {
            Some((key.to_string(),
                  ValueAndSource {
                value: e.to_string(),
                source: ENV.to_string(),
            }))
        }
        None => {
            Some((key.to_string(),
                  ValueAndSource {
                value: key.to_string(),
                source: MISSING.to_string(),
            }))
        }
    }
}

fn env_or_prop(key: &str,
               props_first: bool,
               keys: &Option<KeysAndSources>)
               -> Option<(String, ValueAndSource)> {
    match keys {
        &Some(ref k) => {
            let dict = &(k.dictionary);
            let prop = dict.get(key).and_then(|v| Some(v.clone()));
            let env = env::var_os(key)
                          .map(|v2| v2.clone().into_string().ok().unwrap());
            match (prop, props_first) {
                (Some(prop), true) => {
                    Some((key.to_string(),
                          ValueAndSource {
                        value: prop.value.clone(),
                        source: prop.source.clone(),
                    }))
                }
                (Some(prop), false) => {
                    match env {
                        Some(e) => {
                            println!("[WARNING]: key \"${{{}}}\" from \"{}\" was overridden by an \
                                      environment variable.",
                                     key.to_string(),
                                     prop.source);
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: e.to_string(),
                                source: ENV.to_string(),
                            }))
                        }
                        None => {
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: prop.value.clone(),
                                source: prop.source.clone(),
                            }))
                        }
                    }
                }
                (None, true) => {
                    no_property(key, env)
                }
                (None, false) => {
                    no_property(key, env)
                }
            }
        }
        &None => {
            match env::var_os(key)
                      .map(|v| v.into_string().ok())
                      .unwrap_or(None) {
                Some(e) => {
                    Some((key.to_string(),
                          ValueAndSource {
                        value: e.to_string(),
                        source: ENV.to_string(),
                    }))
                }
                None => {
                    Some((key.to_string(),
                          ValueAndSource {
                        value: key.to_string(),
                        source: MISSING.to_string(),
                    }))
                }
            }
        }
    }
}

fn process(file: fs::File,
           used_keys: &mut HashMap<String, Vec<(String, String)>>,
           dict: &Option<KeysAndSources>,
           props_first: bool)
           -> Vec<String> {
    let buf_reader = io::BufReader::new(&file);
    let mut result: Vec<String> = vec![];

    for line in buf_reader.lines() {
        replace_var(line.unwrap(), &dict, props_first, used_keys, &mut result);
    }

    result
}

fn extract_keys(file: fs::File) -> HashMap<String, String> {
    let key_regex = regex!(r"^\s*(?P<key>\S*)\s*=\s*(?P<val>.*)");
    let buf_reader = io::BufReader::new(&file);
    let mut keys = HashMap::new();

    for line in buf_reader.lines().enumerate() {
        for cap in key_regex.captures_iter(&*line.1
                                                 .ok()
                                                 .expect("Could not read \
                                                          line")) {
            let key = cap.name("key")
                         .unwrap_or("???");
            let val = cap.name("val")
                         .unwrap_or("???");
            if !keys.contains_key(key) {
                keys.insert(key.to_string(), val.to_string());
            }
        }
    }

    keys
}

#[derive(Debug)]
#[derive(Clone)]
struct ValueAndSource {
    value: String,
    source: String,
}

fn insert_if_not_exist(dict: &mut HashMap<String, ValueAndSource>,
                       keys_from_files: &mut HashMap<String, Vec<String>>,
                       matches: HashMap<String, String>,
                       filename: String) {
    for key_val in matches.iter() {
        let key: String = (*key_val.0).clone();
        let val: String = (*key_val.1).clone();
        match dict.entry(key.clone()) {
            Vacant(e) => {
                e.insert(ValueAndSource {
                    value: val,
                    source: filename.clone(),
                });
                match keys_from_files.entry(filename.clone()) {
                    Vacant(k) => {
                        k.insert(vec![key.clone()]);
                    }
                    Occupied(mut k) => {
                        k.get_mut().push(key.clone());
                    }
                }

                // keys_from_files.insert(filename.clone(), key.clone());
            }
            Occupied(e) => {
                println!("[ERROR]: key ({}) in file ({}) tried to override \
                          the same key from file ({})",
                         key,
                         filename,
                         e.get().source);
                process::exit(1);
            }
        }
    }
}

fn read_keyfiles_to_dict(key_filenames: Vec<String>) -> Option<KeysAndSources> {
    let mut dict: HashMap<String, ValueAndSource> = HashMap::new();
    let mut keys_from_files = HashMap::new();
    for filename in key_filenames {
        fs::File::open(&filename)
            .and_then(|f| Ok(extract_keys(f)))
            .map(|v| {
                insert_if_not_exist(&mut dict,
                                    &mut keys_from_files,
                                    v,
                                    filename);
            });
    }

    match dict.len() {
        0 => None,
        _ => {
            Some(KeysAndSources {
                dictionary: Box::new(dict),
                sources: Box::new(keys_from_files),
            })
        }
    }
}

fn create_file(filename: &String) -> fs::File {
    match fs::File::create(filename) {
        Ok(f) => Some(f),
        Err(e) => {
            println_stderr!("[ERROR]: Could not create file: {}\n{}\n",
                            filename,
                            e);
            APP.print_usage_and_panic();
            None
        }
    }
    .unwrap()
}

fn open_file(filename: &String) -> fs::File {
    match fs::File::open(filename) {
        Ok(f) => Some(f),
        Err(e) => {
            println_stderr!("[ERROR]: Could not open file: {}\n{}\n",
                            filename,
                            e);
            APP.print_usage_and_panic();
            None
        }
    }
    .unwrap()
}

struct Settings<'a> {
    key_filenames: Vec<String>,
    prop_filename: &'a String,
    result_filename: &'a String,
    props_first: bool,
}

struct KeysAndSources {
    dictionary: Box<HashMap<String, ValueAndSource>>,
    sources: Box<HashMap<String, Vec<String>>>,
}

fn print_result(used_keys: &mut HashMap<String, Vec<(String, String)>>,
                prop_filename: &String) {

    println!("======== RESULTS ========");

    let env_vars = &used_keys.remove(ENV);
    if env_vars.is_some() {
        let vars = env_vars.clone().unwrap();
        println!("# Environment variables:");
        for v in vars {
            println!("${{{}}}", v.0);
        }
        println!("");
    }

    for src in used_keys.iter() {
        println!("# {}:", src.0);
        let mut keys_src = src.1.clone();
        keys_src.sort();
        for s in keys_src {
            println!("${{{}}}", s.0);
        }
        println!("");
    }

    let missing_vars = used_keys.get(MISSING);
    if missing_vars.is_some() {
        let vars = missing_vars.unwrap();
        println!("Missing variables found in {}:", prop_filename);
        for v in vars {
            println!("${{{}}}", v.0);
        }
        println!("");
        println_stderr!("ERROR: Must replace all found variables\n\n");
        process::exit(1);
    }

    if env_vars.is_none() && used_keys.len() == 0 && missing_vars.is_none() {
        println!("[No variables to substitute!]\n");
    }

    println!("...DONE!");
}

fn calc_result(settings: Settings) {
    let prop_file = open_file(&settings.prop_filename);
    let mut result_buff = Vec::new();
    let mut used_keys = HashMap::new();
    let keys_and_sources = read_keyfiles_to_dict(settings.key_filenames);

    let processed_buffer = process(prop_file,
                                   &mut used_keys,
                                   &keys_and_sources,
                                   settings.props_first);

    for line in processed_buffer.iter() {
        result_buff.push(line.clone());
    }

    let mut result_file = create_file(settings.result_filename);

    for line in result_buff {
        result_file.write_all(&format!("{}\n", line).as_bytes()).unwrap();
    }
    result_file.flush().unwrap();

    print_result(&mut used_keys, settings.prop_filename);
}

fn get_arg_parser() -> ApplicationOptions {
    ApplicationOptions::new(|| {
        let mut o = OptionsAndFlags::new();
        o.parsing_style(getopts::ParsingStyle::StopAtFirstFree);
        o.opt("k",
              "keys",
              "keyfile(s) with variable substitutions, can occur multiple \
               times",
              "FILE(s)",
              getopts::HasArg::Yes,
              getopts::Occur::Multi)
         .unwrap();
        o.opt("p",
              "props-first",
              "properties takes precedence over environment variables \
               (default: off)",
              "",
              getopts::HasArg::No,
              getopts::Occur::Optional)
         .unwrap();
        o.opt("?",
              "help",
              "print this help menu",
              "",
              getopts::HasArg::No,
              getopts::Occur::Optional)
         .unwrap();
        o.opt("V",
              "version",
              "prints current version number",
              "",
              getopts::HasArg::No,
              getopts::Occur::Optional)
         .unwrap();
        Ok(o)
    })
}

struct PropAndResultFilenames<'a> {
    prop_filename: &'a String,
    result_filename: &'a String,
}

fn get_prop_and_result_filename<'a>(free_args: &'a Vec<String>)
                                    -> PropAndResultFilenames<'a> {
    match free_args.len() {
        1 => {
            // Replace vars in the provided file
            PropAndResultFilenames {
                prop_filename: &free_args[0],
                result_filename: &free_args[0],
            }
        }
        2 => {
            // Replace vars into a separate output file
            PropAndResultFilenames {
                prop_filename: &free_args[0],
                result_filename: &free_args[1],
            }
        }
        _ => {
            println_stderr!("Wrong number of file parameters: {}",
                            free_args.len());
            APP.print_usage();
            process::exit(1);
        }
    }
}

fn get_props_first(matches: &Box<getopts::Matches>) -> bool {
    if matches.opt_present("p") {
        true
    } else {
        false
    }

}

fn get_parsed_args() -> Box<getopts::Matches> {
    Box::new(APP.parse().unwrap_or_else(|e| {
        println_stderr!("{}", e);
        process::exit(1);
    }))
}

// Singletons
lazy_static! {
    static ref APP: ApplicationOptions = get_arg_parser();
}

#[allow(dead_code)]
fn main() {
    let matches = get_parsed_args();

    if matches.opt_present("V") {
        println!("proper: v{}", VERSION);
        process::exit(0);
    }

    let prop_and_result_filenames = get_prop_and_result_filename(&matches.free);
    calc_result(Settings {
        key_filenames: matches.opt_strs("k"),
        prop_filename: prop_and_result_filenames.prop_filename,
        result_filename: prop_and_result_filenames.result_filename,
        props_first: get_props_first(&matches),
    });
}

#[cfg(test)]
mod tests {
    use super::replace_var;
    use std::collections::HashMap;
    use super::ValueAndSource;

    struct TestData {
        key_map: HashMap<String, ValueAndSource>,
        used_keys: HashMap<&'static str, Vec<(String, String)>>,
        result: Vec<String>,
    }

    fn create_test_data(keys: Vec<(&str, &str)>) -> TestData {
        let mut test_data = TestData {
            key_map: HashMap::new(),
            used_keys: HashMap::new(),
            result: Vec::new(),
        };

        for k in keys {
            test_data.key_map.insert(k.0.to_string(),
                                     ValueAndSource {
                                         value: k.1.to_string(),
                                         source: "".to_string(),
                                     });
        }

        test_data
    }

    #[test]
    fn can_sub_single_var() {
        let mut test_data = create_test_data(vec![("val", "world!")]);
        replace_var("Hello ${val}".to_string(),
                    &Some(test_data.key_map),
                    true,
                    &mut test_data.used_keys,
                    &mut test_data.result);
        assert!(test_data.result.len() == 1);
        assert!(test_data.used_keys[super::KEY_FILE][0].0 == "val".to_string());
        assert!(test_data.result[0] == "Hello world!".to_string());
    }
}
<commit_msg>Fixed failing tests<commit_after>extern crate regex;
extern crate getopts;
#[macro_use]
extern crate lazy_static;
use std::collections::HashMap;
use std::{env, fs, io};
use std::io::prelude::*;
mod options;
use options::*;
use std::process;
use std::collections::hash_map::Entry::{Occupied, Vacant};

macro_rules! regex { ($re:expr) => { ::regex::Regex::new($re).unwrap() } }
macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
        )
    );

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const KEY_FILE: &'static str = "KEY_FILE";
const ENV: &'static str = "ENV";
const MISSING: &'static str = "Missing properties";

fn replace_var(line: String,
               keys: &Option<KeysAndSources>,
               props_first: bool,
               used_keys: &mut HashMap<String, Vec<(String, String)>>,
               result: &mut Vec<String>) {
    let re = regex!(r"(?P<full>\$\{\s*(?P<var>[^\}]*)\s*\})");
    let mut str_line: String = line.clone();

    for cap in re.captures_iter(&*str_line.clone()) {
        cap.name("var")
           .map(|v| {
               let env_prop = env_or_prop(v.trim(), props_first, keys)
                                  .map(|v2| {
                                      str_line = re.replace(&*str_line,
                                                            &*(v2.1.value));
                                      (v2.0, v2.1)
                                  });

               env_prop.and_then(|v2| {
                   used_keys.get_mut(&v2.1.source)
                            .and_then(|r| {
                                Some(r.push((v2.0.clone(), v2.1.value.clone())))
                            })
                            .or_else(|| {
                                used_keys.insert(v2.1.source.clone(),
                                                 vec![(v2.0.clone(),
                                                       v2.1.value.clone())]);
                                Some(())
                            })
               })
           });
    }
    result.push(str_line.to_string());
}

fn no_property(key: &str,
               env: Option<String>)
               -> Option<(String, ValueAndSource)> {
    match env {
        Some(e) => {
            Some((key.to_string(),
                  ValueAndSource {
                value: e.to_string(),
                source: ENV.to_string(),
            }))
        }
        None => {
            Some((key.to_string(),
                  ValueAndSource {
                value: key.to_string(),
                source: MISSING.to_string(),
            }))
        }
    }
}

fn env_or_prop(key: &str,
               props_first: bool,
               keys: &Option<KeysAndSources>)
               -> Option<(String, ValueAndSource)> {
    match keys {
        &Some(ref k) => {
            let dict = &(k.dictionary);
            let prop = dict.get(key).and_then(|v| Some(v.clone()));
            let env = env::var_os(key)
                          .map(|v2| v2.clone().into_string().ok().unwrap());
            match (prop, props_first) {
                (Some(prop), true) => {
                    Some((key.to_string(),
                          ValueAndSource {
                        value: prop.value.clone(),
                        source: prop.source.clone(),
                    }))
                }
                (Some(prop), false) => {
                    match env {
                        Some(e) => {
                            println!("[WARNING]: key \"${{{}}}\" from \"{}\" \
                                      was overridden by an environment \
                                      variable.",
                                     key.to_string(),
                                     prop.source);
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: e.to_string(),
                                source: ENV.to_string(),
                            }))
                        }
                        None => {
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: prop.value.clone(),
                                source: prop.source.clone(),
                            }))
                        }
                    }
                }
                (None, true) => {
                    no_property(key, env)
                }
                (None, false) => {
                    no_property(key, env)
                }
            }
        }
        &None => {
            match env::var_os(key)
                      .map(|v| v.into_string().ok())
                      .unwrap_or(None) {
                Some(e) => {
                    Some((key.to_string(),
                          ValueAndSource {
                        value: e.to_string(),
                        source: ENV.to_string(),
                    }))
                }
                None => {
                    Some((key.to_string(),
                          ValueAndSource {
                        value: key.to_string(),
                        source: MISSING.to_string(),
                    }))
                }
            }
        }
    }
}

fn process(file: fs::File,
           used_keys: &mut HashMap<String, Vec<(String, String)>>,
           dict: &Option<KeysAndSources>,
           props_first: bool)
           -> Vec<String> {
    let buf_reader = io::BufReader::new(&file);
    let mut result: Vec<String> = vec![];

    for line in buf_reader.lines() {
        replace_var(line.unwrap(), &dict, props_first, used_keys, &mut result);
    }

    result
}

fn extract_keys(file: fs::File) -> HashMap<String, String> {
    let key_regex = regex!(r"^\s*(?P<key>\S*)\s*=\s*(?P<val>.*)");
    let buf_reader = io::BufReader::new(&file);
    let mut keys = HashMap::new();

    for line in buf_reader.lines().enumerate() {
        for cap in key_regex.captures_iter(&*line.1
                                                 .ok()
                                                 .expect("Could not read \
                                                          line")) {
            let key = cap.name("key")
                         .unwrap_or("???");
            let val = cap.name("val")
                         .unwrap_or("???");
            if !keys.contains_key(key) {
                keys.insert(key.to_string(), val.to_string());
            }
        }
    }

    keys
}

#[derive(Debug)]
#[derive(Clone)]
struct ValueAndSource {
    value: String,
    source: String,
}

fn insert_if_not_exist(dict: &mut HashMap<String, ValueAndSource>,
                       keys_from_files: &mut HashMap<String, Vec<String>>,
                       matches: HashMap<String, String>,
                       filename: String) {
    for key_val in matches.iter() {
        let key: String = (*key_val.0).clone();
        let val: String = (*key_val.1).clone();
        match dict.entry(key.clone()) {
            Vacant(e) => {
                e.insert(ValueAndSource {
                    value: val,
                    source: filename.clone(),
                });
                match keys_from_files.entry(filename.clone()) {
                    Vacant(k) => {
                        k.insert(vec![key.clone()]);
                    }
                    Occupied(mut k) => {
                        k.get_mut().push(key.clone());
                    }
                }

                // keys_from_files.insert(filename.clone(), key.clone());
            }
            Occupied(e) => {
                println!("[ERROR]: key ({}) in file ({}) tried to override \
                          the same key from file ({})",
                         key,
                         filename,
                         e.get().source);
                process::exit(1);
            }
        }
    }
}

fn read_keyfiles_to_dict(key_filenames: Vec<String>) -> Option<KeysAndSources> {
    let mut dict: HashMap<String, ValueAndSource> = HashMap::new();
    let mut keys_from_files = HashMap::new();
    for filename in key_filenames {
        fs::File::open(&filename)
            .and_then(|f| Ok(extract_keys(f)))
            .map(|v| {
                insert_if_not_exist(&mut dict,
                                    &mut keys_from_files,
                                    v,
                                    filename);
            });
    }

    match dict.len() {
        0 => None,
        _ => {
            Some(KeysAndSources {
                dictionary: Box::new(dict),
                sources: Box::new(keys_from_files),
            })
        }
    }
}

fn create_file(filename: &String) -> fs::File {
    match fs::File::create(filename) {
        Ok(f) => Some(f),
        Err(e) => {
            println_stderr!("[ERROR]: Could not create file: {}\n{}\n",
                            filename,
                            e);
            APP.print_usage_and_panic();
            None
        }
    }
    .unwrap()
}

fn open_file(filename: &String) -> fs::File {
    match fs::File::open(filename) {
        Ok(f) => Some(f),
        Err(e) => {
            println_stderr!("[ERROR]: Could not open file: {}\n{}\n",
                            filename,
                            e);
            APP.print_usage_and_panic();
            None
        }
    }
    .unwrap()
}

struct Settings<'a> {
    key_filenames: Vec<String>,
    prop_filename: &'a String,
    result_filename: &'a String,
    props_first: bool,
}

struct KeysAndSources {
    dictionary: Box<HashMap<String, ValueAndSource>>,
    sources: Box<HashMap<String, Vec<String>>>,
}

fn print_result(used_keys: &mut HashMap<String, Vec<(String, String)>>,
                prop_filename: &String) {

    println!("======== RESULTS ========");

    let env_vars = &used_keys.remove(ENV);
    if env_vars.is_some() {
        let vars = env_vars.clone().unwrap();
        println!("# Environment variables:");
        for v in vars {
            println!("${{{}}}", v.0);
        }
        println!("");
    }

    for src in used_keys.iter() {
        println!("# {}:", src.0);
        let mut keys_src = src.1.clone();
        keys_src.sort();
        for s in keys_src {
            println!("${{{}}}", s.0);
        }
        println!("");
    }

    let missing_vars = used_keys.get(MISSING);
    if missing_vars.is_some() {
        let vars = missing_vars.unwrap();
        println!("Missing variables found in {}:", prop_filename);
        for v in vars {
            println!("${{{}}}", v.0);
        }
        println!("");
        println_stderr!("ERROR: Must replace all found variables\n\n");
        process::exit(1);
    }

    if env_vars.is_none() && used_keys.len() == 0 && missing_vars.is_none() {
        println!("[No variables to substitute!]\n");
    }

    println!("...DONE!");
}

fn calc_result(settings: Settings) {
    let prop_file = open_file(&settings.prop_filename);
    let mut result_buff = Vec::new();
    let mut used_keys = HashMap::new();
    let keys_and_sources = read_keyfiles_to_dict(settings.key_filenames);

    let processed_buffer = process(prop_file,
                                   &mut used_keys,
                                   &keys_and_sources,
                                   settings.props_first);

    for line in processed_buffer.iter() {
        result_buff.push(line.clone());
    }

    let mut result_file = create_file(settings.result_filename);

    for line in result_buff {
        result_file.write_all(&format!("{}\n", line).as_bytes()).unwrap();
    }
    result_file.flush().unwrap();

    print_result(&mut used_keys, settings.prop_filename);
}

fn get_arg_parser() -> ApplicationOptions {
    ApplicationOptions::new(|| {
        let mut o = OptionsAndFlags::new();
        o.parsing_style(getopts::ParsingStyle::StopAtFirstFree);
        o.opt("k",
              "keys",
              "keyfile(s) with variable substitutions, can occur multiple \
               times",
              "FILE(s)",
              getopts::HasArg::Yes,
              getopts::Occur::Multi)
         .unwrap();
        o.opt("p",
              "props-first",
              "properties takes precedence over environment variables \
               (default: off)",
              "",
              getopts::HasArg::No,
              getopts::Occur::Optional)
         .unwrap();
        o.opt("?",
              "help",
              "print this help menu",
              "",
              getopts::HasArg::No,
              getopts::Occur::Optional)
         .unwrap();
        o.opt("V",
              "version",
              "prints current version number",
              "",
              getopts::HasArg::No,
              getopts::Occur::Optional)
         .unwrap();
        Ok(o)
    })
}

struct PropAndResultFilenames<'a> {
    prop_filename: &'a String,
    result_filename: &'a String,
}

fn get_prop_and_result_filename<'a>(free_args: &'a Vec<String>)
                                    -> PropAndResultFilenames<'a> {
    match free_args.len() {
        1 => {
            // Replace vars in the provided file
            PropAndResultFilenames {
                prop_filename: &free_args[0],
                result_filename: &free_args[0],
            }
        }
        2 => {
            // Replace vars into a separate output file
            PropAndResultFilenames {
                prop_filename: &free_args[0],
                result_filename: &free_args[1],
            }
        }
        _ => {
            println_stderr!("Wrong number of file parameters: {}",
                            free_args.len());
            APP.print_usage();
            process::exit(1);
        }
    }
}

fn get_props_first(matches: &Box<getopts::Matches>) -> bool {
    if matches.opt_present("p") {
        true
    } else {
        false
    }

}

fn get_parsed_args() -> Box<getopts::Matches> {
    Box::new(APP.parse().unwrap_or_else(|e| {
        println_stderr!("{}", e);
        process::exit(1);
    }))
}

// Singletons
lazy_static! {
    static ref APP: ApplicationOptions = get_arg_parser();
}

#[allow(dead_code)]
fn main() {
    let matches = get_parsed_args();

    if matches.opt_present("V") {
        println!("proper: v{}", VERSION);
        process::exit(0);
    }

    let prop_and_result_filenames = get_prop_and_result_filename(&matches.free);
    calc_result(Settings {
        key_filenames: matches.opt_strs("k"),
        prop_filename: prop_and_result_filenames.prop_filename,
        result_filename: prop_and_result_filenames.result_filename,
        props_first: get_props_first(&matches),
    });
}

#[cfg(test)]
mod tests {
    use super::replace_var;
    use std::collections::HashMap;
    use super::ValueAndSource;
    use super::KeysAndSources;

    struct TestData {
        key_map: KeysAndSources,
        used_keys: HashMap<String, Vec<(String, String)>>,
        result: Vec<String>,
    }

    fn create_test_data(keys: Vec<(&str, &str)>) -> TestData {
        let mut test_data = TestData {
            key_map: KeysAndSources {
                dictionary: Box::new(HashMap::new()),
                sources: Box::new(HashMap::new()),
            },
            used_keys: HashMap::new(),
            result: Vec::new(),
        };

        for k in keys {
            test_data.key_map.dictionary.insert(k.0.to_string(),
                                                ValueAndSource {
                                                    value: k.1.to_string(),
                                                    source: "source_file".to_string(),
                                                });
        }

        test_data
    }

    #[test]
    fn can_sub_single_var() {
        let mut test_data = create_test_data(vec![("val", "world!")]);
        replace_var("Hello ${val}".to_string(),
                    &Some(test_data.key_map),
                    true,
                    &mut test_data.used_keys,
                    &mut test_data.result);
        assert!(test_data.result.len() == 1);
        assert!(test_data.used_keys["source_file"][0].0 == "val".to_string());
        assert!(test_data.result[0] == "Hello world!".to_string());
    }
}
<|endoftext|>


<commit_before>#![feature(conservative_impl_trait)]

extern crate cgmath;
extern crate png;

use std::fs::File;

use cgmath::prelude::*;
use cgmath::vec3;
use png::HasParameters;

use camera::Camera;
use light::Light;
use material::Material;
use math::*;
use primitive::Primitive;
use raytracer::Raytracer;
use scene::Scene;
use texture::checkerboard;

mod camera;
mod color;
mod intersection;
mod light;
mod material;
#[macro_use] mod math;
mod primitive;
mod ray;
mod raytracer;
mod scene;
mod texture;

fn main() {
    let raytracer = Raytracer {
        scene: example_scene(),
        camera: Camera::new(Point::zero(), Vector::unit_z(), 90.0f32.to_radians()),
    };

    let (w, h) = (512, 512);
    let mut output_data = Vec::with_capacity(w * h);
    for y in 0 .. h {
        for x in 0 .. w {
            let screen_coords = (x as f32 / w as f32, y as f32 / h as f32);
            let ray = raytracer.camera.primary_ray(screen_coords);
            let result = raytracer.trace(ray, 10);

            let (r, g, b) = result.as_bytes();
            output_data.push(r);
            output_data.push(g);
            output_data.push(b);
        }
    }

    // TODO: add command line options to configure this.
    let output = File::create("output.png").expect("Couldn't create output file.");

    let mut encoder = png::Encoder::new(output, w as u32, h as u32);
    encoder.set(png::ColorType::RGB).set(png::BitDepth::Eight);
    encoder.write_header()
        .unwrap()
        .write_image_data(&output_data)
        .unwrap();
}

fn example_scene() -> Scene {
    let mut scene = Scene::new(color::Color::from_u32(0x8cbed6));

    scene.add_primitive(
        Primitive::plane(
            Material::solid(
                checkerboard(color!(1.0), color!(0.0), (0.5, 0.5)),
                0.0,
            ),
            vec3(0.0, -1.0, 0.0),
            Vector::unit_y(),
        )
    );

    scene.add_primitive(
        Primitive::sphere(
            Material::solid(color!(0.35, 0.99, 0.35), 0.6),
            vec3(0.0, 0.0, 2.0),
            1.0,
        )
    );

    scene.add_light(
        Light::point(vec3(2.0, 2.0, 2.0).into(), vec3(0.0, 1.0, 0.5)),
    );

    scene
}
<commit_msg>Add walls to the example scene<commit_after>#![feature(conservative_impl_trait)]

extern crate cgmath;
extern crate png;

use std::fs::File;

use cgmath::prelude::*;
use cgmath::vec3;
use png::HasParameters;

use camera::Camera;
use light::Light;
use material::Material;
use math::*;
use primitive::Primitive;
use raytracer::Raytracer;
use scene::Scene;
use texture::checkerboard;

mod camera;
mod color;
mod intersection;
mod light;
mod material;
#[macro_use] mod math;
mod primitive;
mod ray;
mod raytracer;
mod scene;
mod texture;

fn main() {
    let raytracer = Raytracer {
        scene: example_scene(),
        camera: Camera::new(Point::zero(), Vector::unit_z(), 90.0f32.to_radians()),
    };

    let (w, h) = (512, 512);
    let mut output_data = Vec::with_capacity(w * h);
    for y in 0 .. h {
        for x in 0 .. w {
            let screen_coords = (x as f32 / w as f32, y as f32 / h as f32);
            let ray = raytracer.camera.primary_ray(screen_coords);
            let result = raytracer.trace(ray, 10);

            let (r, g, b) = result.as_bytes();
            output_data.push(r);
            output_data.push(g);
            output_data.push(b);
        }
    }

    // TODO: add command line options to configure this.
    let output = File::create("output.png").expect("Couldn't create output file.");

    let mut encoder = png::Encoder::new(output, w as u32, h as u32);
    encoder.set(png::ColorType::RGB).set(png::BitDepth::Eight);
    encoder.write_header()
        .unwrap()
        .write_image_data(&output_data)
        .unwrap();
}

fn example_scene() -> Scene {
    let mut scene = Scene::new(color!(0.1, 0.1, 0.1));

    let white = color!(1.0, 1.0, 1.0);
    let red = color!(1.0, 0.0, 0.0);
    let green = color!(0.0, 1.0, 0.0);

    // floor
    scene.add_primitive(
        Primitive::plane(
            Material::solid(
                checkerboard(color!(1.0), color!(0.0), (0.5, 0.5)),
                0.0,
            ),
            vec3(0.0, -1.0, 0.0),
            Vector::unit_y(),
        )
    );

    // left
    scene.add_primitive(
        Primitive::plane(
            Material::solid(red, 0.0),
            vec3(-1.0, 0.0, 0.0),
            Vector::unit_x(),
        )
    );

    // right
    scene.add_primitive(
        Primitive::plane(
            Material::solid(green, 0.0),
            vec3(1.0, 0.0, 0.0),
            -Vector::unit_x(),
        )
    );

    // ceiling
    scene.add_primitive(
        Primitive::plane(
            Material::solid(white, 0.0),
            vec3(0.0, 1.0, 0.0),
            -Vector::unit_y(),
        )
    );

    // back
    scene.add_primitive(
        Primitive::plane(
            Material::solid(white, 0.0),
            vec3(0.0, 0.0, 2.0),
            -Vector::unit_z(),
        )
    );

    //front
    scene.add_primitive(
        Primitive::plane(
            Material::solid(white, 0.0),
            vec3(0.0, 0.0, -2.0),
            Vector::unit_z(),
        )
    );

    scene.add_primitive(
        Primitive::sphere(
            Material::solid(color!(0.1, 0.1, 0.1), 0.6),
            vec3(0.0, 0.0, 2.0),
            1.0,
        )
    );

    scene.add_light(
        Light::point(color!(4.0, 4.0, 4.0), vec3(0.0, 0.0, 0.0)),
    );

    scene
}
<|endoftext|>


<commit_before>#![feature(core)]
#![feature(path)]

#![feature(plugin)]
#![plugin(regex_macros)]
extern crate regex;
extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Branch, BranchType, DiffLine,
    Commit, Diff, DiffFormat, DiffDelta, DiffHunk, Error, Oid};
use docopt::Docopt;
use std::old_io as io;
use std::old_io::BufferedReader;
use std::old_io::File;
use std::str;
use regex::Regex;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: transit <repo> [<old> <new>]

If no commits are given, transit will revwalk from latest to oldest.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_repo: String,
    arg_old: Option<String>,
    arg_new: Option<String>,
}

fn main() {
    // Parse the args above or die.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    // Pull up the revwalk.
    let path = Path::new(args.arg_repo);
    let repo = Repository::discover(&path)
        .ok().expect("Unable to find repo.");
    // If we can destructures the two optional args into real things.
    if let (Some(old_string), Some(new_string)) = (args.arg_old, args.arg_new) {
        // Compare a specific commit pair.
        // Fist, get the commits. (Error checked)
        let old = Oid::from_str(&old_string[]).and_then(|oid| repo.find_commit(oid));
        let new = Oid::from_str(&new_string[]).and_then(|oid| repo.find_commit(oid));
        if old.is_ok() && new.is_ok() {
            let output = find_moves(&repo, &old.unwrap(), &new.unwrap()).unwrap();
            make_output(output);
        } else {
            panic!("Commit ids were not valid.");
        }
    } else {
        // Revwalk.
        let mut revwalk = repo.revwalk()
            .ok().expect("Unable to get revwalk.");
        // Setup some options.
        revwalk.simplify_first_parent(); // TODO: Maybe remove?
        let mut flags = git2::Sort::empty();
        flags.insert(git2::SORT_TIME);
        flags.insert(git2::SORT_TOPOLOGICAL);
        revwalk.set_sorting(flags);
        // Push HEAD to the revwalk.
        revwalk.push_head()
            .ok().expect("Unable to push HEAD.");
        // We sadly must collect here to use `.windows()`
        let history = revwalk.filter_map(|id| repo.find_commit(id).ok())
            .collect::<Vec<Commit>>();
        // Walk through each pair of commits.
        for pair in history.windows(2) {let (old, new) = (&pair[1], &pair[0]);
			let output = find_moves(&repo, old.clone(), new.clone()).unwrap();
			// mangle the vectors here to make pretty output
			make_output(output);
		}
	}
}

fn make_output(output: Vec<Output>) {
	println!("make_output:");
    println!("\toutput.len()={}", output.len());
    for i in range(0, output.len()) {
            println!("\told_commit={}",         output[i].old_commit);
            println!("\tnew_commit={}",         output[i].new_commit);
            println!("\torigin_line={}",        output[i].origin_line);
            println!("\tdestintation_line={}",  output[i].destination_line);
            println!("\tnum_lines={}",          output[i].num_lines);
    }
}

#[derive(Debug)]
enum State {
    Other, Addition, Deletion
}

fn dump_diffdelta(delta: DiffDelta) {
    println!("delta: nfiles={} status={:?} old_file=(id={} path_bytes={:?} path={:?} tsize={}) new_file=(id={} path_bytes={:?} path={:?} tsize={})",
            delta.nfiles(), delta.status(),
            delta.old_file().id(), delta.old_file().path_bytes(), delta.old_file().path(), delta.old_file().size(),
            delta.new_file().id(), delta.new_file().path_bytes(), delta.new_file().path(), delta.new_file().size());
}

fn format_key(key: String) -> String {
    let removeWhiteSpace = regex!(r"\s{2,}"); // 2 or more whitespaces    // TODO Removes whitespace from a string.
    removeWhiteSpace.replace_all(key.as_slice(), "")
}

fn find_moves(repo: &Repository, old: &Commit, new: &Commit) -> Result<Vec<Output>, Error> {

    println!("\nFIND MOVES---------------------");

	let old_tree = try!(old.tree());
	let new_tree = try!(new.tree());
	// Build up a diff of the two trees.
	let diff = try!(Diff::tree_to_tree(repo, Some(&old_tree), Some(&new_tree), None));

    let mut state = State::Other;
    let mut added = String::new();
    let mut deleted = String::new();

    let mut keys: Vec<String> = Vec::new();  // TODO Will become hashmap.

	// Read about this function in http://alexcrichton.com/git2-rs/git2/struct.Diff.html#method.print
	// It's a bit weird, but I think it will provide the necessary information.
	diff.print(DiffFormat::Patch, |delta, maybe_hunk, line| -> bool {

		// Thinking:
		//  * If is not a hunk, keep going.
		//  * If it's a hunk, do regex magic.
		//  * Stick regex output into a hashmap as a hash.
		//  * Later, we will iterate through and output pased on the values.
		// Filter out all the boring context lines.
		// If we're not interested in this line just return since it will iterate to the next.
		if maybe_hunk.is_none() { return true }; // Return early.

        println!("top of loop: keys={:?}", keys);
        println!("top of loop: added={:?} deleted={:?}", added, deleted);

        // 'origin' is wrapped in pipes to ease displaying space characters.
        print!("line: old={:?} new={:?} offset={} |origin|=|{}|\n      content={}",
                 line.old_lineno(), line.new_lineno(), line.content_offset(),
                 line.origin(), str::from_utf8(line.content()).unwrap());

        //dump_diffdelta(delta);

		match line.origin() {
			// Additions
			'+' | '>' => {
                println!("In additions. state={:?}", state);

                added.push_str(str::from_utf8(line.content()).unwrap());

                match state {
                    State::Deletion => {
                        keys.push(format_key(deleted.clone()));
                        deleted = String::new();
                    },
                    _ => (),
                }

                state = State::Addition;
				true
			},
			// Deletions
			'-' | '<' => {
                println!("In deletion. state={:?}", state);

                deleted.push_str(str::from_utf8(line.content()).unwrap());

                match state {
                    State::Addition => {
                        keys.push(format_key(added.clone()));
                        added = String::new();
                    },
                    _ => (),
                }

                state = State::Deletion;
				true
			},
			// Other
			_         => {
                println!("in _. state={:?}", state);

                match state {
                    State::Addition => {
                        keys.push(format_key(added.clone()));
                        added = String::new();
                    },
                    State::Deletion => {
                        keys.push(format_key(deleted.clone()));
                        deleted = String::new();
                    },
                    State::Other => (),
                }

                state = State::Other;
                true
            }
		}
	});

    println!("KEYS={:?}", keys);

    Ok(vec![Output {
	    old_commit: old.id(),
	    new_commit: new.id(),
        old_filename: String::from_str("oldfilename"),
        new_filename: String::from_str("newfilename"),
	    origin_line: 0,
	    destination_line: 0,
	    num_lines: 0
    }])
}

#[derive(Debug)]
struct Output {
    old_commit: Oid,
    new_commit: Oid,
    old_filename: String,
    new_filename: String,
    origin_line: u32,
    destination_line: u32,
    num_lines: u32,
}
<commit_msg>Add Found struct.<commit_after>#![feature(core)]
#![feature(path)]

#![feature(plugin)]
#![plugin(regex_macros)]
extern crate regex;
extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Branch, BranchType, DiffLine,
    Commit, Diff, DiffFormat, DiffDelta, DiffHunk, Error, Oid};
use docopt::Docopt;
use std::old_io as io;
use std::old_io::BufferedReader;
use std::old_io::File;
use std::str;
use regex::Regex;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: transit <repo> [<old> <new>]

If no commits are given, transit will revwalk from latest to oldest.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_repo: String,
    arg_old: Option<String>,
    arg_new: Option<String>,
}

fn main() {
    // Parse the args above or die.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    // Pull up the revwalk.
    let path = Path::new(args.arg_repo);
    let repo = Repository::discover(&path)
        .ok().expect("Unable to find repo.");
    // If we can destructures the two optional args into real things.
    if let (Some(old_string), Some(new_string)) = (args.arg_old, args.arg_new) {
        // Compare a specific commit pair.
        // Fist, get the commits. (Error checked)
        let old = Oid::from_str(&old_string[]).and_then(|oid| repo.find_commit(oid));
        let new = Oid::from_str(&new_string[]).and_then(|oid| repo.find_commit(oid));
        if old.is_ok() && new.is_ok() {
            let output = find_moves(&repo, &old.unwrap(), &new.unwrap()).unwrap();
            make_output(output);
        } else {
            panic!("Commit ids were not valid.");
        }
    } else {
        // Revwalk.
        let mut revwalk = repo.revwalk()
            .ok().expect("Unable to get revwalk.");
        // Setup some options.
        revwalk.simplify_first_parent(); // TODO: Maybe remove?
        let mut flags = git2::Sort::empty();
        flags.insert(git2::SORT_TIME);
        flags.insert(git2::SORT_TOPOLOGICAL);
        revwalk.set_sorting(flags);
        // Push HEAD to the revwalk.
        revwalk.push_head()
            .ok().expect("Unable to push HEAD.");
        // We sadly must collect here to use `.windows()`
        let history = revwalk.filter_map(|id| repo.find_commit(id).ok())
            .collect::<Vec<Commit>>();
        // Walk through each pair of commits.
        for pair in history.windows(2) {let (old, new) = (&pair[1], &pair[0]);
			let output = find_moves(&repo, old.clone(), new.clone()).unwrap();
			// mangle the vectors here to make pretty output
			make_output(output);
		}
	}
}

fn make_output(output: Vec<Output>) {
	println!("make_output:");
    println!("\toutput.len()={}", output.len());
    for i in range(0, output.len()) {
            println!("\told_commit={}",         output[i].old_commit);
            println!("\tnew_commit={}",         output[i].new_commit);
            println!("\torigin_line={}",        output[i].origin_line);
            println!("\tdestintation_line={}",  output[i].destination_line);
            println!("\tnum_lines={}",          output[i].num_lines);
    }
}

#[derive(Debug)]
enum State {
    Other, Addition, Deletion
}

#[derive(Debug)]
enum FoundState {
    Added, Deleted
}

fn dump_diffdelta(delta: &DiffDelta) {
    println!("delta: nfiles={} status={:?} old_file=(id={} path_bytes={:?} path={:?} tsize={}) new_file=(id={} path_bytes={:?} path={:?} tsize={})",
            delta.nfiles(), delta.status(),
            delta.old_file().id(), delta.old_file().path_bytes(), delta.old_file().path(), delta.old_file().size(),
            delta.new_file().id(), delta.new_file().path_bytes(), delta.new_file().path(), delta.new_file().size());
}

fn format_key(key: String) -> String {
    let removeWhiteSpace = regex!(r"\s{2,}"); // 2 or more whitespaces    // TODO Removes whitespace from a string.
    removeWhiteSpace.replace_all(key.as_slice(), "")
}

#[derive(Debug)]
struct Found {
    filename: Path,
    key: String,
    state: FoundState,
}

fn find_moves(repo: &Repository, old: &Commit, new: &Commit) -> Result<Vec<Output>, Error> {

    println!("\nFIND MOVES---------------------");

	let old_tree = try!(old.tree());
	let new_tree = try!(new.tree());
	// Build up a diff of the two trees.
	let diff = try!(Diff::tree_to_tree(repo, Some(&old_tree), Some(&new_tree), None));

    let mut state = State::Other;
    let mut added = String::new();
    let mut deleted = String::new();

    let mut keys: Vec<String> = Vec::new();  // TODO Will become hashmap.

    let mut founds: Vec<Found> = Vec::new();

	// Read about this function in http://alexcrichton.com/git2-rs/git2/struct.Diff.html#method.print
	// It's a bit weird, but I think it will provide the necessary information.
	diff.print(DiffFormat::Patch, |delta, maybe_hunk, line| -> bool {

        // Have not defined behaviour for number of files != 2.
        assert!(delta.nfiles() == 2);

		// Thinking:
		//  * If is not a hunk, keep going.
		//  * If it's a hunk, do regex magic.
		//  * Stick regex output into a hashmap as a hash.
		//  * Later, we will iterate through and output pased on the values.
		// Filter out all the boring context lines.
		// If we're not interested in this line just return since it will iterate to the next.
		if maybe_hunk.is_none() { return true }; // Return early.

        //println!("top of loop: keys={:?}", keys);
        //println!("top of loop: added={:?} deleted={:?}", added, deleted);

        // 'origin' is wrapped in pipes to ease displaying space characters.
        print!("line: old={:?} new={:?} offset={} |origin|=|{}|\n      content={}",
                 line.old_lineno(), line.new_lineno(), line.content_offset(),
                 line.origin(), str::from_utf8(line.content()).unwrap());

        //dump_diffdelta(&delta);

		match line.origin() {
			// Additions
			'+' | '>' => {
                println!("In additions. state={:?}", state);

                added.push_str(str::from_utf8(line.content()).unwrap());

                match state {
                    State::Deletion => {
                        founds.push(Found {
                            filename: delta.old_file().path().unwrap().clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                        });
                        deleted = String::new();
                    },
                    _ => (),
                }

                state = State::Addition;
				true
			},
			// Deletions
			'-' | '<' => {
                println!("In deletion. state={:?}", state);

                deleted.push_str(str::from_utf8(line.content()).unwrap());

                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: delta.new_file().path().unwrap().clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                        });
                        added = String::new();
                    },
                    _ => (),
                }

                state = State::Deletion;
				true
			},
			// Other
			_         => {
                println!("in _. state={:?}", state);

                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: delta.new_file().path().unwrap().clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                        });
                        added = String::new();
                    },
                    State::Deletion => {
                        founds.push(Found {
                            filename: delta.old_file().path().unwrap().clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                        });
                        deleted = String::new();
                    },
                    _ => (),
                }

                state = State::Other;
                true
            }
		}
	});

    println!("KEYS={:?}", keys);
    println!("FOUNDS={:?}", founds);

    Ok(vec![Output {
	    old_commit: old.id(),
	    new_commit: new.id(),
        old_filename: String::from_str("oldfilename"),
        new_filename: String::from_str("newfilename"),
	    origin_line: 0,
	    destination_line: 0,
	    num_lines: 0
    }])
}

#[derive(Debug)]
struct Output {
    old_commit: Oid,
    new_commit: Oid,
    old_filename: String,
    new_filename: String,
    origin_line: u32,
    destination_line: u32,
    num_lines: u32,
}
<|endoftext|>


<commit_before>extern crate actix_files;
extern crate actix_web;
extern crate atty;
#[macro_use]
extern crate clap;
extern crate chrono;
#[macro_use]
extern crate lazy_static;
extern crate ctrlc;
extern crate notify;
extern crate termcolor;
extern crate url;
extern crate ws;

extern crate site;
#[macro_use]
extern crate errors;
extern crate front_matter;
extern crate rebuild;
extern crate utils;

use std::time::Instant;

use utils::net::{get_available_port, port_is_available};

mod cli;
mod cmd;
mod console;
mod prompt;

fn main() {
    let matches = cli::build_cli().get_matches();

    let config_file = matches.value_of("config").unwrap();

    match matches.subcommand() {
        ("init", Some(matches)) => {
            match cmd::create_new_project(matches.value_of("name").unwrap()) {
                Ok(()) => (),
                Err(e) => {
                    console::unravel_errors("Failed to create the project", &e);
                    ::std::process::exit(1);
                }
            };
        }
        ("build", Some(matches)) => {
            console::info("Building site...");
            let start = Instant::now();
            let output_dir = matches.value_of("output_dir").unwrap();
            match cmd::build(config_file, matches.value_of("base_url"), output_dir) {
                Ok(()) => console::report_elapsed_time(start),
                Err(e) => {
                    console::unravel_errors("Failed to build the site", &e);
                    ::std::process::exit(1);
                }
            };
        }
        ("serve", Some(matches)) => {
            let interface = matches.value_of("interface").unwrap_or("127.0.0.1");
            let mut port: u16 = match matches.value_of("port").unwrap().parse() {
                Ok(x) => x,
                Err(_) => {
                    console::error("The request port needs to be an integer");
                    ::std::process::exit(1);
                }
            };
            // Default one
            if port != 1111 && !port_is_available(port) {
                console::error("The requested port is not available");
                ::std::process::exit(1);
            }

            if !port_is_available(port) {
                port = if let Some(p) = get_available_port(1111) {
                    p
                } else {
                    console::error("No port available.");
                    ::std::process::exit(1);
                }
            }
            let watch_only = matches.is_present("watch_only");
            let output_dir = matches.value_of("output_dir").unwrap();
            let base_url = matches.value_of("base_url").unwrap();
            console::info("Building site...");
            match cmd::serve(interface, port, output_dir, base_url, config_file, watch_only) {
                Ok(()) => (),
                Err(e) => {
                    console::unravel_errors("", &e);
                    ::std::process::exit(1);
                }
            };
        }
        ("check", Some(matches)) => {
            console::info("Checking site...");
            let start = Instant::now();
            match cmd::check(
                config_file,
                matches.value_of("base_path"),
                matches.value_of("base_url"),
            ) {
                Ok(()) => console::report_elapsed_time(start),
                Err(e) => {
                    console::unravel_errors("Failed to check the site", &e);
                    ::std::process::exit(1);
                }
            };
        }
        _ => unreachable!(),
    }
}
<commit_msg>Only check for port availability when not in watch-only for serve<commit_after>extern crate actix_files;
extern crate actix_web;
extern crate atty;
#[macro_use]
extern crate clap;
extern crate chrono;
#[macro_use]
extern crate lazy_static;
extern crate ctrlc;
extern crate notify;
extern crate termcolor;
extern crate url;
extern crate ws;

extern crate site;
#[macro_use]
extern crate errors;
extern crate front_matter;
extern crate rebuild;
extern crate utils;

use std::time::Instant;

use utils::net::{get_available_port, port_is_available};

mod cli;
mod cmd;
mod console;
mod prompt;

fn main() {
    let matches = cli::build_cli().get_matches();

    let config_file = matches.value_of("config").unwrap();

    match matches.subcommand() {
        ("init", Some(matches)) => {
            match cmd::create_new_project(matches.value_of("name").unwrap()) {
                Ok(()) => (),
                Err(e) => {
                    console::unravel_errors("Failed to create the project", &e);
                    ::std::process::exit(1);
                }
            };
        }
        ("build", Some(matches)) => {
            console::info("Building site...");
            let start = Instant::now();
            let output_dir = matches.value_of("output_dir").unwrap();
            match cmd::build(config_file, matches.value_of("base_url"), output_dir) {
                Ok(()) => console::report_elapsed_time(start),
                Err(e) => {
                    console::unravel_errors("Failed to build the site", &e);
                    ::std::process::exit(1);
                }
            };
        }
        ("serve", Some(matches)) => {
            let interface = matches.value_of("interface").unwrap_or("127.0.0.1");
            let mut port: u16 = match matches.value_of("port").unwrap().parse() {
                Ok(x) => x,
                Err(_) => {
                    console::error("The request port needs to be an integer");
                    ::std::process::exit(1);
                }
            };
            let watch_only = matches.is_present("watch_only");

            // Default one
            if port != 1111 && !watch_only && !port_is_available(port) {
                console::error("The requested port is not available");
                ::std::process::exit(1);
            }

            if  !watch_only && !port_is_available(port) {
                port = if let Some(p) = get_available_port(1111) {
                    p
                } else {
                    console::error("No port available.");
                    ::std::process::exit(1);
                }
            }
            let output_dir = matches.value_of("output_dir").unwrap();
            let base_url = matches.value_of("base_url").unwrap();
            console::info("Building site...");
            match cmd::serve(interface, port, output_dir, base_url, config_file, watch_only) {
                Ok(()) => (),
                Err(e) => {
                    console::unravel_errors("", &e);
                    ::std::process::exit(1);
                }
            };
        }
        ("check", Some(matches)) => {
            console::info("Checking site...");
            let start = Instant::now();
            match cmd::check(
                config_file,
                matches.value_of("base_path"),
                matches.value_of("base_url"),
            ) {
                Ok(()) => console::report_elapsed_time(start),
                Err(e) => {
                    console::unravel_errors("Failed to check the site", &e);
                    ::std::process::exit(1);
                }
            };
        }
        _ => unreachable!(),
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate env_logger;
extern crate ignore;
extern crate prettytable;

mod metrics;

use std::fs::File;
use std::io::{Read, BufReader};
use std::path::PathBuf;
use ignore::Walk;
use prettytable::Table;
use prettytable::row::Row;
use prettytable::cell::Cell;

fn main() {
    env_logger::init().expect("logger init failed");
    warn!("Starting");

    let project_source_paths = determine_realtive_source_paths();
    let path_and_loc = read_files_and_count_loc(project_source_paths);
    let result_table = create_table(path_and_loc);
    result_table.printstd();
}

fn read_files_and_count_loc(project_source_paths: Vec<PathBuf>) -> Vec<(PathBuf, usize)> {
    let mut path_and_loc: Vec<(PathBuf, usize)> = project_source_paths
        .into_iter()
        .filter_map(|path| match File::open(path.clone()) {
            Ok(file) => Some((path, file)),
            Err(_) => None,
        })
        .filter_map(|path_and_file| {
            let mut file_content = String::new();
            let mut buf_reader = BufReader::new(path_and_file.1);
            match buf_reader.read_to_string(&mut file_content) {
            	Ok(_) => Some((path_and_file.0, metrics::loc(file_content))),
            	Err(_) => None
            }
        })
        .collect();
    path_and_loc.sort_by(|a, b| b.1.cmp(&a.1));
    path_and_loc
}

fn create_table(path_and_loc: Vec<(PathBuf, usize)>) -> Table {
    let initial_table = init_table_with_header();
    path_and_loc.into_iter().fold(
        initial_table,
        |mut result_table,
         path_and_count| {
            let path = &path_and_count.0.display().to_string();
            let count = &path_and_count.1.to_string();
            result_table.add_row(Row::new(vec![Cell::new(path), Cell::new(count)]));
            result_table
        },
    )
}

fn init_table_with_header() -> Table {
    let mut initial_table = Table::new();
    initial_table.add_row(Row::new(vec![Cell::new("Path"), Cell::new("LOC")]));
    initial_table
}

fn determine_realtive_source_paths() -> Vec<PathBuf> {
    Walk::new("./")
        .into_iter()
        .filter_map(|entry_result| entry_result.ok())
        .map(|dir_entry| dir_entry.path().to_path_buf())
        .filter(|path| !path.is_dir())
        .collect()
}
<commit_msg>log example<commit_after>#[macro_use]
extern crate log;
extern crate env_logger;
extern crate ignore;
extern crate prettytable;

mod metrics;

use std::fs::File;
use std::io::{Read, BufReader};
use std::path::PathBuf;
use ignore::Walk;
use prettytable::Table;
use prettytable::row::Row;
use prettytable::cell::Cell;

fn main() {
    env_logger::init().expect("logger init failed");

    let project_source_paths = determine_realtive_source_paths();
    let path_and_loc = read_files_and_count_loc(project_source_paths);
    let result_table = create_table(path_and_loc);
    result_table.printstd();
}

fn read_files_and_count_loc(project_source_paths: Vec<PathBuf>) -> Vec<(PathBuf, usize)> {
    let mut path_and_loc: Vec<(PathBuf, usize)> = project_source_paths
        .into_iter()
        .filter_map(|path| match File::open(path.clone()) {
            Ok(file) => Some((path, file)),
            Err(_) => {
                warn!("skipped {}", path.to_string_lossy());
                None
            },
        })
        .filter_map(|path_and_file| {
            let path = path_and_file.0;
            let file = path_and_file.1;
            let mut file_content = String::new();
            let mut buf_reader = BufReader::new(file);
            match buf_reader.read_to_string(&mut file_content) {
            	Ok(_) => Some((path, metrics::loc(file_content))),
            	Err(_) => {
            	    warn!("skipped {}", path.to_string_lossy());
            	    None
           	    }
            }
        })
        .collect();
    path_and_loc.sort_by(|a, b| b.1.cmp(&a.1));
    path_and_loc
}

fn create_table(path_and_loc: Vec<(PathBuf, usize)>) -> Table {
    let initial_table = init_table_with_header();
    path_and_loc.into_iter().fold(
        initial_table,
        |mut result_table,
         path_and_count| {
            let path = &path_and_count.0.display().to_string();
            let count = &path_and_count.1.to_string();
            result_table.add_row(Row::new(vec![Cell::new(path), Cell::new(count)]));
            result_table
        },
    )
}

fn init_table_with_header() -> Table {
    let mut initial_table = Table::new();
    initial_table.add_row(Row::new(vec![Cell::new("Path"), Cell::new("LOC")]));
    initial_table
}

fn determine_realtive_source_paths() -> Vec<PathBuf> {
    Walk::new("./")
        .into_iter()
        .filter_map(|entry_result| entry_result.ok())
        .map(|dir_entry| dir_entry.path().to_path_buf())
        .filter(|path| !path.is_dir())
        .collect()
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Generate some cool shit.<commit_after>extern crate noise;

use noise::{simplectic2, simplectic3, simplectic4, Seed, Point2};

fn render(x:u8) -> char {
  match x / 53 {
    0 => ' ',
    1 => ' ',
    2 => '▩',
    3 => '█',
    _ => '█' }}

fn main() {
  for i in range(0, 25) {
    for j in range(0, 50) {
      let x = (i*4) as f32;
      let y = (j*4) as f32;
      let v = simplectic2(&Seed::new(9), &[x, y]);
      let r = (128.0 + v*256.0) as u8;
      print!("{}", render(r)); }
    println!(""); }}
<|endoftext|>


<commit_before>extern crate term_painter;
extern crate regex;

use regex::Regex;

use term_painter::ToStyle;
use term_painter::Color::*;
use term_painter::Attr::*;
use std::io::Read;

enum Message {
    Header(String, String),
    Warning(String),
    Note(String),
    Error(String),
    Help(String),
    FollowUp(String),
    Source(String, String),
    Marker(String),
    NewLine,
    Wat,
}

impl Message {
    fn parse(s: &str) -> Vec<Self> {
        use Message::*;

        let mut res = Vec::new();
        let mut file = String::new();

        for l in s.lines() {
            let re_header = Regex::new(r"([0-9A-Za-z_\.\\/]+):(\d+):.*(warning: |note: |error: |help: )(.*)").unwrap();
            let re_source = Regex::new(r"(\d+) (.*)").unwrap();
            if re_header.is_match(l) {
                res.push(NewLine);

                let caps = re_header.captures(l).unwrap();
                file = caps.at(1).unwrap_or("?").to_string();

                res.push(Header(file.clone(), caps.at(2).unwrap_or("?").to_string()));

                let msg = caps.at(4).unwrap_or("?").to_string();

                // Warning, header or note?
                match caps.at(3).unwrap_or("?") {
                    "warning: " => res.push(Warning(msg)),
                    "note: " =>    res.push(Note(msg)),
                    "error: " =>   res.push(Error(msg)),
                    "help: " =>    res.push(Help(msg)),
                    _ =>           res.push(Wat),
                }
            } else if l.len() > file.len() && re_source.is_match(&l[file.len()..]) {
                let caps = re_source.captures(l).unwrap();

                res.push(Source(caps.at(1).unwrap_or("?").to_string(), caps.at(2).unwrap_or("????").to_string()));
            } else if l.chars().next() == Some(' ') && l.contains("^") {

                let offset = if let Some(&Source(ref line, _)) = res.last() {
                    file.len() + line.len() - 7
                } else {
                    0
                };

                if offset < l.len() {
                    res.push(Marker(l[offset..].to_string()));
                }
            } else {
                res.push(FollowUp(l.to_string()));
            }
        }
        res
    }

    fn to_string(self) -> String {
        use Message::*;

        match self {
            Header(ref file, ref line) =>  format!("+---- {} : {} ----+", Blue.paint(file), line),
            Warning(warn) =>           format!("      =====>  {}{}", Yellow.paint("warning: "), warn),
            Note(note) =>              format!("      =====>  {}{}", Green.paint("note: "), note),
            Error(err) =>              format!("      =====>  {}{}", Red.paint("error: "), err),
            Help(err) =>               format!("      =====>  {}{}", Blue.paint("help: "), err),
            FollowUp(msg) =>           format!("           >  {}", msg),
            Source(line, code) =>      format!(" {} |>  {}", Magenta.paint(line), code),
            Marker(ref mrk) =>         format!("{}", Yellow.paint(mrk)),
            NewLine =>                 format!("\n"),
            Wat =>                     format!("Dafuq?"),
        }
    }
}

fn main() {
    let mut input = String::new();
    std::io::stdin().read_to_string(&mut input);

    print!("{}", Message::parse(&input).into_iter().map(|x| x.to_string()).collect::<Vec<_>>().join("\n"));
}
<commit_msg>Fix coloring<commit_after>extern crate term_painter;
extern crate regex;

use regex::Regex;

use term_painter::ToStyle;
use term_painter::Color::*;
use term_painter::Attr::*;

use std::io::Read;

enum Message {
    Header(String, String),
    Warning(String),
    Note(String),
    Error(String),
    Help(String),
    FollowUp(String),
    Source(String, String),
    Marker(String),
    NewLine,
    Wat,
}

impl Message {
    fn parse(s: &str) -> Vec<Self> {
        use Message::*;

        let mut res = Vec::new();
        let mut file = String::new();

        for l in s.lines() {
            let re_header = Regex::new(r"([0-9A-Za-z_\.\\/]+):(\d+):.*(warning: |note: |error: |help: )(.*)").unwrap();
            let re_source = Regex::new(r"(\d+) (.*)").unwrap();
            if re_header.is_match(l) {
                res.push(NewLine);

                let caps = re_header.captures(l).unwrap();
                file = caps.at(1).unwrap_or("?").to_string();

                res.push(Header(file.clone(), caps.at(2).unwrap_or("?").to_string()));

                let msg = caps.at(4).unwrap_or("?").to_string();

                // Warning, header or note?
                match caps.at(3).unwrap_or("?") {
                    "warning: " => res.push(Warning(msg)),
                    "note: " =>    res.push(Note(msg)),
                    "error: " =>   res.push(Error(msg)),
                    "help: " =>    res.push(Help(msg)),
                    _ =>           res.push(Wat),
                }
            } else if l.len() > file.len() && re_source.is_match(&l[file.len()..]) {
                let caps = re_source.captures(l).unwrap();

                res.push(Source(caps.at(1).unwrap_or("?").to_string(), caps.at(2).unwrap_or("????").to_string()));
            } else if l.chars().next() == Some(' ') && l.contains("^") {

                let offset = if let Some(&Source(ref line, _)) = res.last() {
                    file.len() + line.len() - 7
                } else {
                    0
                };

                if offset < l.len() {
                    res.push(Marker(l[offset..].to_string()));
                }
            } else {
                res.push(FollowUp(l.to_string()));
            }
        }
        res
    }

    fn print(self) {
        use Message::*;

        match self {
            Header(ref file, ref line) =>  println!("+---- {} : {} ----+", Blue.paint(file), Blue.paint(line)),
            Warning(warn) =>               println!("      =====>  {}{}", Yellow.paint("warning: "), warn),
            Note(note) =>                  println!("      =====>  {}{}", Green.paint("note: "), note),
            Error(err) =>                  println!("      =====>  {}{}", Red.paint("error: "), err),
            Help(err) =>                   println!("      =====>  {}{}", Blue.paint("help: "), err),
            FollowUp(msg) =>               println!("           >  {}", msg),
            Source(line, code) =>          println!(" {}  {}", Magenta.paint(format!("{} |>", line)), code),
            Marker(ref mrk) =>             println!("{}", Yellow.paint(mrk)),
            NewLine =>                     println!("\n"),
            Wat =>                         println!("Dafuq?"),
        }
    }
}

fn main() {
    let mut input = String::new();
    std::io::stdin().read_to_string(&mut input);

    for i in Message::parse(&input) {
        i.print();
    }
}
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
#![feature(io)]

#[macro_use] extern crate clap;

use std::io::{self, Read, Write, BufRead, BufReader, BufWriter};
use std::fs::{File};
use std::char;
use std::iter::Iterator;
use clap::App;

const base: u32 = 127991;

fn main() {
    let cli_spec = load_yaml!("cli.yml");
    let cli_args = App::from_yaml(cli_spec).get_matches();

    let mut reader = {
        if let Some(path) = cli_args.value_of("input") {
            Box::new(BufReader::new(match File::open(path) {
                Ok(path) => path,
                _ => {
                    writeln!(io::stderr(), "base💯: no such file: {}", path).expect("base💯: stderr write error");
                    return;
                }
            })) as Box<BufRead>
        } else {
            Box::new(BufReader::new(io::stdin())) as Box<BufRead>
        }
    };

    let mut writer = BufWriter::new(io::stdout());
    let mut write_buf = [0u8; 65536];
    let mut buffer = [0u8; 65536];

    if cli_args.is_present("decode") {
        while let Ok(num_read) = reader.read(&mut buffer) {
            if num_read == 0 {
                break;
            }
            let decoded_str = if cli_args.is_present("fast") {
                unsafe {
                    std::str::from_utf8_unchecked(&buffer)
                }
            } else {
                match std::str::from_utf8(&buffer) {
                    Ok(string) => string,
                    _ => {
                        writeln!(io::stderr(), "base💯: write error").expect("base💯: stderr write error");
                        return;
                    }
                }
            };
            match writer.write(decoded_str.chars()
                               .map(|ch| { (ch as u32 - base) as u8 })
                               .collect::<Vec<u8>>().as_slice()) {
                Ok(_) => (),
                _ => {
                    writeln!(io::stderr(), "base💯: write error").expect("base💯: stderr write error");
                    return;
                }
            }
        }
    } else {
        while let Ok(num_read) = reader.read(&mut buffer) {
            if num_read == 0 {
                break;
            }

            for byte in buffer.iter().take(num_read) {
                let ch: char = char::from_u32(base + (*byte as u32)).unwrap();
                match writer.write(ch.encode_utf8(&mut write_buf).as_bytes()) {
                    Ok(_) => (),
                    _ => {
                        writeln!(io::stderr(), "base💯: write error").expect("base💯: stderr write error");
                        return;
                    }
                }
            }
        }
    }
    writer.flush().expect("Write error");
}
<commit_msg>Support stable rust<commit_after>#![allow(non_upper_case_globals)]

#[macro_use] extern crate clap;

use std::io::{self, Read, Write, BufRead, BufReader, BufWriter};
use std::fs::{File};
use std::char;
use std::iter::Iterator;
use clap::App;

const base: u32 = 127991;

fn main() {
    let cli_spec = load_yaml!("cli.yml");
    let cli_args = App::from_yaml(cli_spec).get_matches();

    let mut reader = {
        if let Some(path) = cli_args.value_of("input") {
            Box::new(BufReader::new(match File::open(path) {
                Ok(path) => path,
                _ => {
                    writeln!(io::stderr(), "base💯: no such file: {}", path).expect("base💯: stderr write error");
                    return;
                }
            })) as Box<BufRead>
        } else {
            Box::new(BufReader::new(io::stdin())) as Box<BufRead>
        }
    };

    let mut writer = BufWriter::new(io::stdout());
    let mut write_buf = [0u8; 65536];
    let mut buffer = [0u8; 65536];

    if cli_args.is_present("decode") {
        while let Ok(num_read) = reader.read(&mut buffer) {
            if num_read == 0 {
                break;
            }
            let decoded_str = if cli_args.is_present("fast") {
                unsafe {
                    std::str::from_utf8_unchecked(&buffer)
                }
            } else {
                match std::str::from_utf8(&buffer) {
                    Ok(string) => string,
                    _ => {
                        writeln!(io::stderr(), "base💯: write error").expect("base💯: stderr write error");
                        return;
                    }
                }
            };
            match writer.write(decoded_str.chars()
                               .map(|ch| { (ch as u32 - base) as u8 })
                               .collect::<Vec<u8>>().as_slice()) {
                Ok(_) => (),
                _ => {
                    writeln!(io::stderr(), "base💯: write error").expect("base💯: stderr write error");
                    return;
                }
            }
        }
    } else {
        while let Ok(num_read) = reader.read(&mut buffer) {
            if num_read == 0 {
                break;
            }

            for byte in buffer.iter().take(num_read) {
                let ch: char = char::from_u32(base + (*byte as u32)).unwrap();
                match writer.write(ch.encode_utf8(&mut write_buf).as_bytes()) {
                    Ok(_) => (),
                    _ => {
                        writeln!(io::stderr(), "base💯: write error").expect("base💯: stderr write error");
                        return;
                    }
                }
            }
        }
    }
    writer.flush().expect("Write error");
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

#[macro_use]
mod internal;

mod app;
mod exec;
mod exit_codes;
pub mod fshelper;
mod output;
mod walk;

use std::env;
use std::error::Error;
use std::path::{Path, PathBuf};
use std::process;
use std::sync::Arc;
use std::time;

use atty::Stream;
use lscolors::LsColors;
use regex::{RegexBuilder, RegexSetBuilder};

use crate::exec::CommandTemplate;
use crate::internal::{
    filter::{SizeFilter, TimeFilter},
    opts::FdOptions,
    pattern_has_uppercase_char, transform_args_with_exec, FileTypes,
};

fn main() {
    let checked_args = transform_args_with_exec(env::args_os());
    let matches = app::build_app().get_matches_from(checked_args);

    // Get the search pattern
    let pattern = matches.value_of("pattern").unwrap_or("");

    // Get the current working directory
    let current_dir = Path::new(".");
    if !fshelper::is_dir(current_dir) {
        print_error_and_exit!("Could not get current directory.");
    }

    // Get one or more root directories to search.
    let mut dir_vec: Vec<_> = match matches
        .values_of("path")
        .or_else(|| matches.values_of("search-path"))
    {
        Some(paths) => paths
            .map(|path| {
                let path_buffer = PathBuf::from(path);
                if !fshelper::is_dir(&path_buffer) {
                    print_error_and_exit!(
                        "'{}' is not a directory.",
                        path_buffer.to_string_lossy()
                    );
                }
                path_buffer
            })
            .collect::<Vec<_>>(),
        None => vec![current_dir.to_path_buf()],
    };

    if matches.is_present("absolute-path") {
        dir_vec = dir_vec
            .iter()
            .map(|path_buffer| {
                path_buffer
                    .canonicalize()
                    .and_then(|pb| fshelper::absolute_path(pb.as_path()))
                    .unwrap()
            })
            .collect();
    }

    // Detect if the user accidentally supplied a path instead of a search pattern
    if !matches.is_present("full-path")
        && pattern.contains(std::path::MAIN_SEPARATOR)
        && fshelper::is_dir(Path::new(pattern))
    {
        print_error_and_exit!(
            "The search pattern '{pattern}' contains a path-separation character ('{sep}') \
             and will not lead to any search results.\n\n\
             If you want to search for all files inside the '{pattern}' directory, use a match-all pattern:\n\n  \
             fd . '{pattern}'\n\n\
             Instead, if you want to search for the pattern in the full path, use:\n\n  \
             fd --full-path '{pattern}'",
            pattern = pattern,
            sep = std::path::MAIN_SEPARATOR,
        );
    }

    // Treat pattern as literal string if '--fixed-strings' is used
    let pattern_regex = if matches.is_present("fixed-strings") {
        regex::escape(pattern)
    } else {
        String::from(pattern)
    };

    // The search will be case-sensitive if the command line flag is set or
    // if the pattern has an uppercase character (smart case).
    let case_sensitive = !matches.is_present("ignore-case")
        && (matches.is_present("case-sensitive") || pattern_has_uppercase_char(&pattern_regex));

    let colored_output = match matches.value_of("color") {
        Some("always") => true,
        Some("never") => false,
        _ => atty::is(Stream::Stdout),
    };

    let path_separator: Option<String> =
        matches.value_of("path-separator").map(|str| str.to_owned());

    #[cfg(windows)]
    let colored_output = colored_output && ansi_term::enable_ansi_support().is_ok();

    let ls_colors = if colored_output {
        Some(LsColors::from_env().unwrap_or_default())
    } else {
        None
    };

    let command = matches
        .values_of("exec")
        .map(CommandTemplate::new)
        .or_else(|| {
            matches.values_of("exec-batch").map(|m| {
                CommandTemplate::new_batch(m).unwrap_or_else(|e| {
                    print_error_and_exit!("{}", e);
                })
            })
        });

    let size_limits: Vec<SizeFilter> = matches
        .values_of("size")
        .map(|v| {
            v.map(|sf| {
                if let Some(f) = SizeFilter::from_string(sf) {
                    return f;
                }
                print_error_and_exit!("'{}' is not a valid size constraint. See 'fd --help'.", sf);
            })
            .collect()
        })
        .unwrap_or_else(|| vec![]);

    let now = time::SystemTime::now();
    let mut time_constraints: Vec<TimeFilter> = Vec::new();
    if let Some(t) = matches.value_of("changed-within") {
        if let Some(f) = TimeFilter::after(&now, t) {
            time_constraints.push(f);
        } else {
            print_error_and_exit!("'{}' is not a valid date or duration. See 'fd --help'.", t);
        }
    }
    if let Some(t) = matches.value_of("changed-before") {
        if let Some(f) = TimeFilter::before(&now, t) {
            time_constraints.push(f);
        } else {
            print_error_and_exit!("'{}' is not a valid date or duration. See 'fd --help'.", t);
        }
    }

    let config = FdOptions {
        case_sensitive,
        search_full_path: matches.is_present("full-path"),
        ignore_hidden: !(matches.is_present("hidden")
            || matches.occurrences_of("rg-alias-hidden-ignore") >= 2),
        read_fdignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")),
        read_vcsignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")
            || matches.is_present("no-ignore-vcs")),
        follow_links: matches.is_present("follow"),
        null_separator: matches.is_present("null_separator"),
        max_depth: matches
            .value_of("depth")
            .or_else(|| matches.value_of("rg-depth"))
            .and_then(|n| usize::from_str_radix(n, 10).ok()),
        threads: std::cmp::max(
            matches
                .value_of("threads")
                .and_then(|n| usize::from_str_radix(n, 10).ok())
                .unwrap_or_else(num_cpus::get),
            1,
        ),
        max_buffer_time: matches
            .value_of("max-buffer-time")
            .and_then(|n| u64::from_str_radix(n, 10).ok())
            .map(time::Duration::from_millis),
        ls_colors,
        file_types: matches.values_of("file-type").map(|values| {
            let mut file_types = FileTypes::default();
            for value in values {
                match value {
                    "f" | "file" => file_types.files = true,
                    "d" | "directory" => file_types.directories = true,
                    "l" | "symlink" => file_types.symlinks = true,
                    "x" | "executable" => {
                        file_types.executables_only = true;
                        file_types.files = true;
                    }
                    "e" | "empty" => {
                        file_types.empty_only = true;
                    }
                    _ => unreachable!(),
                }
            }

            // If only 'empty' was specified, search for both files and directories:
            if file_types.empty_only && !(file_types.files || file_types.directories) {
                file_types.files = true;
                file_types.directories = true;
            }

            file_types
        }),
        extensions: matches.values_of("extension").map(|exts| {
            let patterns = exts
                .map(|e| e.trim_start_matches('.'))
                .map(|e| format!(r".\.{}$", regex::escape(e)));
            match RegexSetBuilder::new(patterns)
                .case_insensitive(true)
                .build()
            {
                Ok(re) => re,
                Err(err) => {
                    print_error_and_exit!("{}", err.description());
                }
            }
        }),
        command: command.map(Arc::new),
        exclude_patterns: matches
            .values_of("exclude")
            .map(|v| v.map(|p| String::from("!") + p).collect())
            .unwrap_or_else(|| vec![]),
        ignore_files: matches
            .values_of("ignore-file")
            .map(|vs| vs.map(PathBuf::from).collect())
            .unwrap_or_else(|| vec![]),
        size_constraints: size_limits,
        time_constraints,
        show_filesystem_errors: matches.is_present("show-errors"),
        path_separator,
    };

    match RegexBuilder::new(&pattern_regex)
        .case_insensitive(!config.case_sensitive)
        .dot_matches_new_line(true)
        .build()
    {
        Ok(re) => {
            let exit_code = walk::scan(&dir_vec, Arc::new(re), Arc::new(config));
            process::exit(exit_code.into());
        }
        Err(err) => {
            print_error_and_exit!(
                "{}\nHint: You can use the '--fixed-strings' option to search for a \
                 literal string instead of a regular expression",
                err.description()
            );
        }
    }
}
<commit_msg>Remove type annotation.<commit_after>// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

#[macro_use]
mod internal;

mod app;
mod exec;
mod exit_codes;
pub mod fshelper;
mod output;
mod walk;

use std::env;
use std::error::Error;
use std::path::{Path, PathBuf};
use std::process;
use std::sync::Arc;
use std::time;

use atty::Stream;
use lscolors::LsColors;
use regex::{RegexBuilder, RegexSetBuilder};

use crate::exec::CommandTemplate;
use crate::internal::{
    filter::{SizeFilter, TimeFilter},
    opts::FdOptions,
    pattern_has_uppercase_char, transform_args_with_exec, FileTypes,
};

fn main() {
    let checked_args = transform_args_with_exec(env::args_os());
    let matches = app::build_app().get_matches_from(checked_args);

    // Get the search pattern
    let pattern = matches.value_of("pattern").unwrap_or("");

    // Get the current working directory
    let current_dir = Path::new(".");
    if !fshelper::is_dir(current_dir) {
        print_error_and_exit!("Could not get current directory.");
    }

    // Get one or more root directories to search.
    let mut dir_vec: Vec<_> = match matches
        .values_of("path")
        .or_else(|| matches.values_of("search-path"))
    {
        Some(paths) => paths
            .map(|path| {
                let path_buffer = PathBuf::from(path);
                if !fshelper::is_dir(&path_buffer) {
                    print_error_and_exit!(
                        "'{}' is not a directory.",
                        path_buffer.to_string_lossy()
                    );
                }
                path_buffer
            })
            .collect::<Vec<_>>(),
        None => vec![current_dir.to_path_buf()],
    };

    if matches.is_present("absolute-path") {
        dir_vec = dir_vec
            .iter()
            .map(|path_buffer| {
                path_buffer
                    .canonicalize()
                    .and_then(|pb| fshelper::absolute_path(pb.as_path()))
                    .unwrap()
            })
            .collect();
    }

    // Detect if the user accidentally supplied a path instead of a search pattern
    if !matches.is_present("full-path")
        && pattern.contains(std::path::MAIN_SEPARATOR)
        && fshelper::is_dir(Path::new(pattern))
    {
        print_error_and_exit!(
            "The search pattern '{pattern}' contains a path-separation character ('{sep}') \
             and will not lead to any search results.\n\n\
             If you want to search for all files inside the '{pattern}' directory, use a match-all pattern:\n\n  \
             fd . '{pattern}'\n\n\
             Instead, if you want to search for the pattern in the full path, use:\n\n  \
             fd --full-path '{pattern}'",
            pattern = pattern,
            sep = std::path::MAIN_SEPARATOR,
        );
    }

    // Treat pattern as literal string if '--fixed-strings' is used
    let pattern_regex = if matches.is_present("fixed-strings") {
        regex::escape(pattern)
    } else {
        String::from(pattern)
    };

    // The search will be case-sensitive if the command line flag is set or
    // if the pattern has an uppercase character (smart case).
    let case_sensitive = !matches.is_present("ignore-case")
        && (matches.is_present("case-sensitive") || pattern_has_uppercase_char(&pattern_regex));

    let colored_output = match matches.value_of("color") {
        Some("always") => true,
        Some("never") => false,
        _ => atty::is(Stream::Stdout),
    };

    let path_separator = matches.value_of("path-separator").map(|str| str.to_owned());

    #[cfg(windows)]
    let colored_output = colored_output && ansi_term::enable_ansi_support().is_ok();

    let ls_colors = if colored_output {
        Some(LsColors::from_env().unwrap_or_default())
    } else {
        None
    };

    let command = matches
        .values_of("exec")
        .map(CommandTemplate::new)
        .or_else(|| {
            matches.values_of("exec-batch").map(|m| {
                CommandTemplate::new_batch(m).unwrap_or_else(|e| {
                    print_error_and_exit!("{}", e);
                })
            })
        });

    let size_limits: Vec<SizeFilter> = matches
        .values_of("size")
        .map(|v| {
            v.map(|sf| {
                if let Some(f) = SizeFilter::from_string(sf) {
                    return f;
                }
                print_error_and_exit!("'{}' is not a valid size constraint. See 'fd --help'.", sf);
            })
            .collect()
        })
        .unwrap_or_else(|| vec![]);

    let now = time::SystemTime::now();
    let mut time_constraints: Vec<TimeFilter> = Vec::new();
    if let Some(t) = matches.value_of("changed-within") {
        if let Some(f) = TimeFilter::after(&now, t) {
            time_constraints.push(f);
        } else {
            print_error_and_exit!("'{}' is not a valid date or duration. See 'fd --help'.", t);
        }
    }
    if let Some(t) = matches.value_of("changed-before") {
        if let Some(f) = TimeFilter::before(&now, t) {
            time_constraints.push(f);
        } else {
            print_error_and_exit!("'{}' is not a valid date or duration. See 'fd --help'.", t);
        }
    }

    let config = FdOptions {
        case_sensitive,
        search_full_path: matches.is_present("full-path"),
        ignore_hidden: !(matches.is_present("hidden")
            || matches.occurrences_of("rg-alias-hidden-ignore") >= 2),
        read_fdignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")),
        read_vcsignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")
            || matches.is_present("no-ignore-vcs")),
        follow_links: matches.is_present("follow"),
        null_separator: matches.is_present("null_separator"),
        max_depth: matches
            .value_of("depth")
            .or_else(|| matches.value_of("rg-depth"))
            .and_then(|n| usize::from_str_radix(n, 10).ok()),
        threads: std::cmp::max(
            matches
                .value_of("threads")
                .and_then(|n| usize::from_str_radix(n, 10).ok())
                .unwrap_or_else(num_cpus::get),
            1,
        ),
        max_buffer_time: matches
            .value_of("max-buffer-time")
            .and_then(|n| u64::from_str_radix(n, 10).ok())
            .map(time::Duration::from_millis),
        ls_colors,
        file_types: matches.values_of("file-type").map(|values| {
            let mut file_types = FileTypes::default();
            for value in values {
                match value {
                    "f" | "file" => file_types.files = true,
                    "d" | "directory" => file_types.directories = true,
                    "l" | "symlink" => file_types.symlinks = true,
                    "x" | "executable" => {
                        file_types.executables_only = true;
                        file_types.files = true;
                    }
                    "e" | "empty" => {
                        file_types.empty_only = true;
                    }
                    _ => unreachable!(),
                }
            }

            // If only 'empty' was specified, search for both files and directories:
            if file_types.empty_only && !(file_types.files || file_types.directories) {
                file_types.files = true;
                file_types.directories = true;
            }

            file_types
        }),
        extensions: matches.values_of("extension").map(|exts| {
            let patterns = exts
                .map(|e| e.trim_start_matches('.'))
                .map(|e| format!(r".\.{}$", regex::escape(e)));
            match RegexSetBuilder::new(patterns)
                .case_insensitive(true)
                .build()
            {
                Ok(re) => re,
                Err(err) => {
                    print_error_and_exit!("{}", err.description());
                }
            }
        }),
        command: command.map(Arc::new),
        exclude_patterns: matches
            .values_of("exclude")
            .map(|v| v.map(|p| String::from("!") + p).collect())
            .unwrap_or_else(|| vec![]),
        ignore_files: matches
            .values_of("ignore-file")
            .map(|vs| vs.map(PathBuf::from).collect())
            .unwrap_or_else(|| vec![]),
        size_constraints: size_limits,
        time_constraints,
        show_filesystem_errors: matches.is_present("show-errors"),
        path_separator,
    };

    match RegexBuilder::new(&pattern_regex)
        .case_insensitive(!config.case_sensitive)
        .dot_matches_new_line(true)
        .build()
    {
        Ok(re) => {
            let exit_code = walk::scan(&dir_vec, Arc::new(re), Arc::new(config));
            process::exit(exit_code.into());
        }
        Err(err) => {
            print_error_and_exit!(
                "{}\nHint: You can use the '--fixed-strings' option to search for a \
                 literal string instead of a regular expression",
                err.description()
            );
        }
    }
}
<|endoftext|>