<commit_before>extern crate crossbeam;
#[macro_use] extern crate version;
extern crate walkdir;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;

const DBG_FLAG: &'static str = "--debug";

fn help(cmds: Vec<String>) {
    println!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:
    "#);

    for cmd in cmds.iter() {
        println!("\t{}", cmd);
    }

    println!(r#"

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 <NAME> and contributors"#);
}

fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .map(String::from)
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn find_command() -> Option<String> {
    env::args().skip(1).filter(|x| !x.starts_with("-")).next()
}

fn find_flag() -> Option<String> {
    env::args().skip(1).filter(|x| x.starts_with("-")).next()
}

fn is_debug_flag<T: AsRef<str>>(ref s: &T) -> bool {
    s.as_ref() == DBG_FLAG
}

fn find_args(command: &str) -> Vec<String> {
    env::args()
        .skip(1)
        .position(|e| e == command)
        .map(|pos| env::args().skip(pos + 2).collect::<Vec<String>>())
        .unwrap_or(vec![])
}

fn main() {
    let commands  = get_commands();
    let mut args  = env::args();
    let _         = args.next();
    let first_arg = match find_command() {
        Some(s) => s,
        None    => match find_flag() {
            Some(s) => s,
            None => {
                help(commands);
                exit(0);
            },
        },
    };
    let is_debug = env::args().skip(1).find(is_debug_flag).is_some();

    match &first_arg[..] {
        "--help" | "-h" => {
            help(commands);
            exit(0);
        },

        "--version"  => println!("imag {}", &version!()[..]),

        "--versions" => {
            let mut result = vec![];
            for command in commands.iter() {
                result.push(crossbeam::scope(|scope| {
                    scope.spawn(|| {
                        let v = Command::new(command).arg("--version").output();
                        match v {
                            Ok(v) => match String::from_utf8(v.stdout) {
                                Ok(s) => format!("{} -> {}", command, s),
                                Err(e) => format!("Failed calling {} -> {:?}", command, e),
                            },
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        }
                    })
                }))
            }

            for versionstring in result.into_iter().map(|handle| handle.join()) {
                println!("{}", versionstring);
            }
        },

        s => {
            let mut subcommand_args = find_args(s);
            if is_debug && subcommand_args.iter().find(is_debug_flag).is_none() {
                subcommand_args.push(String::from(DBG_FLAG));
            }
            match Command::new(format!("imag-{}", s))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .args(&subcommand_args[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        println!("{} exited with non-zero exit code", s);
                        exit(exit_status.code().unwrap_or(42));
                    }
                },

                Err(e) => {<commit_msg>Debug flag is now inserted at the beginning of the arguments.<commit_after>extern crate crossbeam;
#[macro_use] extern crate version;
extern crate walkdir;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;

const DBG_FLAG: &'static str = "--debug";

fn help(cmds: Vec<String>) {
    println!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:
    "#);

    for cmd in cmds.iter() {
        println!("\t{}", cmd);
    }

    println!(r#"

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 <NAME> and contributors"#);
}

fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .map(String::from)
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn find_command() -> Option<String> {
    env::args().skip(1).filter(|x| !x.starts_with("-")).next()
}

fn find_flag() -> Option<String> {
    env::args().skip(1).filter(|x| x.starts_with("-")).next()
}

fn is_debug_flag<T: AsRef<str>>(ref s: &T) -> bool {
    s.as_ref() == DBG_FLAG
}

fn find_args(command: &str) -> Vec<String> {
    env::args()
        .skip(1)
        .position(|e| e == command)
        .map(|pos| env::args().skip(pos + 2).collect::<Vec<String>>())
        .unwrap_or(vec![])
}

fn main() {
    let commands  = get_commands();
    let mut args  = env::args();
    let _         = args.next();
    let first_arg = match find_command() {
        Some(s) => s,
        None    => match find_flag() {
            Some(s) => s,
            None => {
                help(commands);
                exit(0);
            },
        },
    };
    let is_debug = env::args().skip(1).find(is_debug_flag).is_some();

    match &first_arg[..] {
        "--help" | "-h" => {
            help(commands);
            exit(0);
        },

        "--version"  => println!("imag {}", &version!()[..]),

        "--versions" => {
            let mut result = vec![];
            for command in commands.iter() {
                result.push(crossbeam::scope(|scope| {
                    scope.spawn(|| {
                        let v = Command::new(command).arg("--version").output();
                        match v {
                            Ok(v) => match String::from_utf8(v.stdout) {
                                Ok(s) => format!("{} -> {}", command, s),
                                Err(e) => format!("Failed calling {} -> {:?}", command, e),
                            },
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        }
                    })
                }))
            }

            for versionstring in result.into_iter().map(|handle| handle.join()) {
                println!("{}", versionstring);
            }
        },

        s => {
            let mut subcommand_args = find_args(s);
            if is_debug && subcommand_args.iter().find(is_debug_flag).is_none() {
                subcommand_args.insert(0, String::from(DBG_FLAG));
            }
            match Command::new(format!("imag-{}", s))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .args(&subcommand_args[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        println!("{} exited with non-zero exit code", s);
                        exit(exit_status.code().unwrap_or(42));
                    }
                },

                Err(e) => {
{'fraction_non_alphanumeric': 0.15752165922814387, 'fraction_numerical': 0.0032379452174674016, 'mean_word_length': 1.3843104527435843, 'pattern_counts': {'":': 2, '<': 37, '<?xml version=': 0, '>': 85, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2589128', 'n_tokens_mistral': 3375, 'n_tokens_neox': 3226, 'n_words': 705}