<commit_before>extern crate getopts;

use std::env;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use self::getopts::Options;
use command;
use git;

pub enum ParsedArgv {
    Help,
    Version,
    Parsed(command::Options, bool),
}

type ErrorMsg = String;

fn normalize_repo_format(mut s: String, dir: &PathBuf) -> Result<String, ErrorMsg> {
    if let Ok(url) = git::new(dir)?.remote_url(&s) {
        return Ok(url);
    }

    if !s.ends_with(".git") {
        s.push_str(".git");
    }

    if s.starts_with("git@") || s.starts_with("https://") || s.starts_with("http://") {
        return Ok(s);
    }

    match s.chars().filter(|c| *c == '/').count() {
        1 => Ok(format!("https://github.com/{}", s)),
        2 => Ok(format!("https://{}", s)),
        _ => Err(format!("Error: Invalid repository format '{}'. Format must be one of 'user/repo', 'service/user/repo' or remote name or Git URL.", s)),
    }
}

pub fn parse_options(argv: Vec<String>) -> Result<ParsedArgv, ErrorMsg> {
    let program = argv[0].clone();
    let mut opts = Options::new();

    opts.optopt("r", "repo", "Shorthand format (user/repo, service/user/repo) or remote name (e.g. origin) or Git URL you want to see", "REPO");
    opts.optopt("b", "branch", "Branch name of the repository", "BRANCH");
    opts.optopt("d", "dir", "Directory path to your repository", "PATH");
    opts.optflag("u", "url", "Output URL to STDOUT instead of opening in browser");
    opts.optflag("h", "help", "Print this help");
    opts.optflag("v", "version", "Show version");

    let matches = opts.parse(&argv[1..]).map_err(|f| format!("{}", f))?;

    if matches.opt_present("h") {
        let brief = format!("Usage: {} [Options] {{Args}}", program);
        errorln!("{}", opts.usage(&brief));
        return Ok(ParsedArgv::Help);
    }

    if matches.opt_present("v") {
        println!("{}", option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"));
        return Ok(ParsedArgv::Version);
    }

    let dir = match matches.opt_str("d") {
        Some(d) => fs::canonicalize(d).map_err(|e| format!("Error on --dir option: {}", e))?,
        // XXX: Should use 'git rev-parse --show-cdup' to get proper --git-dir
        None => env::current_dir().map_err(|e| format!("Error on --dir option: {}", e))?,
    };

    let (repo, branch) = match (matches.opt_str("r"), matches.opt_str("b")) {
        (Some(r), Some(b)) => (normalize_repo_format(r, &dir)?, b),
        (Some(r), None) => (normalize_repo_format(r, &dir)?, git::new(&dir)?.tracking_remote()?.1),
        (None, Some(b)) => (git::new(&dir)?.tracking_remote()?.0, b),
        (None, None) => git::new(&dir)?.tracking_remote()?,
    };
<commit_msg>change current working directory if --dir specified<commit_after>extern crate getopts;

use std::env;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use self::getopts::Options;
use command;
use git;

pub enum ParsedArgv {
    Help,
    Version,
    Parsed(command::Options, bool),
}

type ErrorMsg = String;

fn normalize_repo_format(mut s: String, dir: &PathBuf) -> Result<String, ErrorMsg> {
    if let Ok(url) = git::new(dir)?.remote_url(&s) {
        return Ok(url);
    }

    if !s.ends_with(".git") {
        s.push_str(".git");
    }

    if s.starts_with("git@") || s.starts_with("https://") || s.starts_with("http://") {
        return Ok(s);
    }

    match s.chars().filter(|c| *c == '/').count() {
        1 => Ok(format!("https://github.com/{}", s)),
        2 => Ok(format!("https://{}", s)),
        _ => Err(format!("Error: Invalid repository format '{}'. Format must be one of 'user/repo', 'service/user/repo' or remote name or Git URL.", s)),
    }
}

pub fn parse_options(argv: Vec<String>) -> Result<ParsedArgv, ErrorMsg> {
    let program = argv[0].clone();
    let mut opts = Options::new();

    opts.optopt("r", "repo", "Shorthand format (user/repo, service/user/repo) or remote name (e.g. origin) or Git URL you want to see", "REPO");
    opts.optopt("b", "branch", "Branch name of the repository", "BRANCH");
    opts.optopt("d", "dir", "Directory path to your repository", "PATH");
    opts.optflag("u", "url", "Output URL to STDOUT instead of opening in browser");
    opts.optflag("h", "help", "Print this help");
    opts.optflag("v", "version", "Show version");

    let matches = opts.parse(&argv[1..]).map_err(|f| format!("{}", f))?;

    if matches.opt_present("h") {
        let brief = format!("Usage: {} [Options] {{Args}}", program);
        errorln!("{}", opts.usage(&brief));
        return Ok(ParsedArgv::Help);
    }

    if matches.opt_present("v") {
        println!("{}", option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"));
        return Ok(ParsedArgv::Version);
    }

    let dir = match matches.opt_str("d") {
        Some(d) => {
            let c = fs::canonicalize(&d).map_err(|e| format!("Error on --dir option: {}", e))?;
            env::set_current_dir(&c).map_err(|e| format!("Error on setting current direcotry to {}: {}", d, e))?;
            c
        },
        None => env::current_dir().map_err(|e| format!("Error on --dir option: {}", e))?,
    };

    let (repo, branch) = match (matches.opt_str("r"), matches.opt_str("b")) {
        (Some(r), Some(b)) => (normalize_repo_format(r, &dir)?, b),
        (Some(r), None) => (normalize_repo_format(r, &dir)?, git::new(&dir)?.tracking_remote()?.1),
        (None, Some(b)) => (git::new(&dir)?.tracking_remote()?.0, b),
        (None, None) => git::new(&dir)?.tracking_remote()?,
    };

{'fraction_non_alphanumeric': 0.21461021261130292, 'fraction_numerical': 0.0021806287479556605, 'mean_word_length': 3.3509881422924903, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 31, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3039933', 'n_tokens_mistral': 1900, 'n_tokens_neox': 1894, 'n_words': 448}