<commit_before>///! GIT REQ!
mod git;
mod remotes;

use clap::{crate_authors, crate_version, App, AppSettings, ArgMatches, YamlLoader};
use colored::*;
use git2::ErrorCode;
use lazy_static::lazy_static;
use log::{debug, error, info, trace};
use std::io::{self, stdin, stdout, Cursor, Write};
use std::{env, include_str, process};
use tabwriter::TabWriter;
use yaml_rust::Yaml;

lazy_static! {
    static ref APP_CFG: Yaml = {
        YamlLoader::load_from_str(include_str!("../cli-flags.yml"))
            .expect("Failed to load CLI config")
            .pop()
            .unwrap()
    };
}

/// Get the remote url
fn get_remote_url(remote_name: &str) -> String {
    git::get_remote_url(remote_name)
}

/// Get the remote for the current project
fn get_remote(remote_name: &str, fetch_api_key: bool) -> Result<Box<dyn remotes::Remote>, String> {
    let remote_url = get_remote_url(remote_name);
    remotes::get_remote(remote_name, &remote_url, !fetch_api_key)
}

/// Get the remote, fail hard otherwise
fn get_remote_hard(remote_name: &str, fetch_api_key: bool) -> Box<dyn remotes::Remote> {
    match get_remote(remote_name, fetch_api_key) {
        Ok(x) => x,
        Err(error) => {
            eprintln!(
                "{}",
                format!(
                    "There was a problem finding the remote Git repo: {}",
                    &error
                )
                .red()
            );
            process::exit(1);
        }
    }
}

/// Check out the branch corresponding to the MR ID and the remote's name
fn checkout_mr(remote_name: &str, mr_id: i64) {
    info!("Getting MR: {}", mr_id);
    let mut remote = get_remote_hard(remote_name, true);
    debug!("Found remote: {}", remote);
    let remote_branch_name = match remote.get_remote_req_branch(mr_id) {
        Ok(name) => name,
        Err(error) => {
            eprintln!(
                "{}",
                format!(
                    "There was a problem ascertaining the branch name: {}",
                    &error
                )
                .red()
            );
            process::exit(1);
        }
    };
    debug!("Got remote branch name: {}", remote_branch_name);
    match git::checkout_branch(
        remote_name,
        &remote_branch_name,
        &remote.get_local_req_branch(mr_id).unwrap(),
        remote.has_virtual_remote_branch_names(),
    ) {
        Ok(_) => {
            info!("Done!");
        }
        Err(error) => {
            eprintln!(
                "{}",
                format!("There was an error checking out the branch: {}", &error).red()
            );
            process::exit(1)
        }
    };
}

/// Clear the API key for the current domain
fn clear_domain_key(remote_name: &str) {
    trace!("Deleting domain key");
    let mut remote = get_remote_hard(remote_name, false);
    let deleted = match git::delete_req_config(&remote.get_domain(), "apikey") {
        Ok(_) => Ok(true),
        Err(e) => match e.code() {
            ErrorCode::NotFound => Ok(false),
            _ => Err(e),
        },
    };
    match deleted {
        Ok(_) => eprintln!("{}", "Domain key deleted!".green()),
        Err(e) => {
            error!("Git Config error: {}", e);
            eprintln!(
                "{}",
                format!(
                    "There was an error deleting the domain key: {}",
                    e.message()
                )
                .red()
            );
            process::exit(1)
        }
    }
}

/// Set the API key for the current domain
fn set_domain_key(remote_name: &str, new_key: &str) {
    trace!("Setting domain key: {}", new_key);
    let mut remote = get_remote_hard(remote_name, false);
    git::set_req_config(&remote.get_domain(), "apikey", new_key);
    eprintln!("{}", "Domain key changed!".green());
}

/// Delete the project ID entry
fn clear_project_id(remote_name: &str) {
    trace!("Deleting project ID for {}", remote_name);
    git::delete_config("projectid", remote_name);
    eprintln!("{}", "Project ID cleared!".green());
}

/// Set the project ID
fn set_project_id(remote_name: &str, new_id: &str) {
    trace!("Setting project ID: {} for remote: {}", new_id, remote_name);
    git::set_config("projectid", remote_name, new_id);
    eprintln!("{}", "New project ID set!".green());
}

/// Set the default remote for the repository
fn set_default_remote(remote_name: &str) {
    trace!("Setting default remote {}", remote_name);
    git::set_project_config("defaultremote", remote_name);
    eprintln!("{}", "New default remote set!".green());
}

/// Print the open requests
fn list_open_requests(remote_name: &str) {
    info!("Getting open requests");
    let mut remote = get_remote_hard(remote_name, true);
    debug!("Found remote: {}", remote);
    let mrs = remote.get_req_names().unwrap();
    let mut tw = TabWriter::new(io::stdout()).padding(4);
    for mr in &mrs {
        if remote.has_useful_branch_names() {
            writeln!(
                &mut tw,
                "{}\t{}\t{}",
                mr.id.to_string().green(),
                mr.source_branch.green().dimmed(),
                mr.title
            )
            .unwrap();
        } else {
            writeln!(&mut tw, "{}\t{}", mr.id.to_string().green(), mr.title).unwrap();
        }
    }
    tw.flush().unwrap();
}

/// Print a shell completion script
fn generate_completion(app: &mut App, shell_name: &str) {
    let mut buffer = Cursor::new(Vec::new());
    app.gen_completions_to("git-req", shell_name.parse().unwrap(), &mut buffer);
    let mut output = String::from_utf8(buffer.into_inner()).unwrap_or_else(|_| String::from(""));
    if shell_name == "zsh" {
        // Clap assigns the _files completor to the REQUEST_ID. This is undesirable.
        output = output.replace(":_files", ":");
    }
    print!("{}", &output);
}

/// Get the name of the remote to use for the operation
fn get_remote_name(matches: &ArgMatches) -> String {
    let default_remote_name = match git::get_project_config("defaultremote") {
        Some(remote_name) => remote_name,
        None => {
            let new_remote_name = match git::guess_default_remote_name() {
                Ok(guessed) => guessed,
                Err(_) => {
                    let mut new_remote_name = String::new();
                    println!("Multiple remotes detected. Enter the name of the default one.");
                    for remote in git::get_remotes() {
                        println!(" * {}", remote);
                    }
                    print!("Remote name: ");
                    let _ = stdout().flush();
                    stdin()
                        .read_line(&mut new_remote_name)
                        .expect("Did not input a name");
                    trace!("New remote: {}", &new_remote_name);
                    if !git::get_remotes().contains(new_remote_name.trim()) {
                        panic!("Invalid remote name provided")
                    }
                    new_remote_name
                }
            };
            git::set_project_config("defaultremote", &new_remote_name);
            new_remote_name
        }
    };
    // Not using Clap's default_value because of https://github.com/clap-rs/clap/issues/1140
    String::from(
        matches
            .value_of("REMOTE_NAME")
            .unwrap_or(&default_remote_name),
    )
}

/// Get the Clap app for CLI matching et al.
fn build_cli<'a>() -> App<'a, 'a> {
    App::from_yaml(&APP_CFG)
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .setting(AppSettings::ArgsNegateSubcommands)
        .usage("git req [OPTIONS] [REQUEST_ID]")
}

/// Do the thing
fn main() {
    color_backtrace::install();
    let _ = env_logger::Builder::new()
        .parse_filters(&env::var("REQ_LOG").unwrap_or_default())
        .try_init();

    let mut app = build_cli();

    let matches = app.get_matches();

    if let Some(project_id) = matches.value_of("NEW_PROJECT_ID") {
        set_project_id(&get_remote_name(&matches), project_id);
    } else if matches.is_present("CLEAR_PROJECT_ID") {
        clear_project_id(&get_remote_name(&matches));
    } else if matches.is_present("LIST_MR") {
        list_open_requests(&get_remote_name(&matches));
    } else if matches.is_present("CLEAR_DOMAIN_KEY") {
        clear_domain_key(&get_remote_name(&matches));
    } else if let Some(domain_key) = matches.value_of("NEW_DOMAIN_KEY") {
        set_domain_key(&get_remote_name(&matches), domain_key);
    } else if let Some(remote_name) = matches.value_of("NEW_DEFAULT_REMOTE") {
        set_default_remote(remote_name);
    } else if let Some(shell_name) = matches.value_of("GENERATE_COMPLETIONS") {
        app = build_cli();
        generate_completion(&mut app, &shell_name);
    } else {
        checkout_mr(
            &get_remote_name(&matches),
            matches.value_of("REQUEST_ID").unwrap().parse().unwrap(),
        );
    }
}
<commit_msg>Refactor away unnecessary function.<commit_after>///! GIT REQ!
mod git;
mod remotes;

use clap::{crate_authors, crate_version, App, AppSettings, ArgMatches, YamlLoader};
use colored::*;
use git2::ErrorCode;
use lazy_static::lazy_static;
use log::{debug, error, info, trace};
use std::io::{self, stdin, stdout, Cursor, Write};
use std::{env, include_str, process};
use tabwriter::TabWriter;
use yaml_rust::Yaml;

lazy_static! {
    static ref APP_CFG: Yaml = {
        YamlLoader::load_from_str(include_str!("../cli-flags.yml"))
            .expect("Failed to load CLI config")
            .pop()
            .unwrap()
    };
}

/// Get the remote for the current project
fn get_remote(remote_name: &str, fetch_api_key: bool) -> Result<Box<dyn remotes::Remote>, String> {
    let remote_url = git::get_remote_url(remote_name);
    remotes::get_remote(remote_name, &remote_url, !fetch_api_key)
}

/// Get the remote, fail hard otherwise
fn get_remote_hard(remote_name: &str, fetch_api_key: bool) -> Box<dyn remotes::Remote> {
    match get_remote(remote_name, fetch_api_key) {
        Ok(x) => x,
        Err(error) => {
            eprintln!(
                "{}",
                format!(
                    "There was a problem finding the remote Git repo: {}",
                    &error
                )
                .red()
            );
            process::exit(1);
        }
    }
}

/// Check out the branch corresponding to the MR ID and the remote's name
fn checkout_mr(remote_name: &str, mr_id: i64) {
    info!("Getting MR: {}", mr_id);
    let mut remote = get_remote_hard(remote_name, true);
    debug!("Found remote: {}", remote);
    let remote_branch_name = match remote.get_remote_req_branch(mr_id) {
        Ok(name) => name,
        Err(error) => {
            eprintln!(
                "{}",
                format!(
                    "There was a problem ascertaining the branch name: {}",
                    &error
                )
                .red()
            );
            process::exit(1);
        }
    };
    debug!("Got remote branch name: {}", remote_branch_name);
    match git::checkout_branch(
        remote_name,
        &remote_branch_name,
        &remote.get_local_req_branch(mr_id).unwrap(),
        remote.has_virtual_remote_branch_names(),
    ) {
        Ok(_) => {
            info!("Done!");
        }
        Err(error) => {
            eprintln!(
                "{}",
                format!("There was an error checking out the branch: {}", &error).red()
            );
            process::exit(1)
        }
    };
}

/// Clear the API key for the current domain
fn clear_domain_key(remote_name: &str) {
    trace!("Deleting domain key");
    let mut remote = get_remote_hard(remote_name, false);
    let deleted = match git::delete_req_config(&remote.get_domain(), "apikey") {
        Ok(_) => Ok(true),
        Err(e) => match e.code() {
            ErrorCode::NotFound => Ok(false),
            _ => Err(e),
        },
    };
    match deleted {
        Ok(_) => eprintln!("{}", "Domain key deleted!".green()),
        Err(e) => {
            error!("Git Config error: {}", e);
            eprintln!(
                "{}",
                format!(
                    "There was an error deleting the domain key: {}",
                    e.message()
                )
                .red()
            );
            process::exit(1)
        }
    }
}

/// Set the API key for the current domain
fn set_domain_key(remote_name: &str, new_key: &str) {
    trace!("Setting domain key: {}", new_key);
    let mut remote = get_remote_hard(remote_name, false);
    git::set_req_config(&remote.get_domain(), "apikey", new_key);
    eprintln!("{}", "Domain key changed!".green());
}

/// Delete the project ID entry
fn clear_project_id(remote_name: &str) {
    trace!("Deleting project ID for {}", remote_name);
    git::delete_config("projectid", remote_name);
    eprintln!("{}", "Project ID cleared!".green());
}

/// Set the project ID
fn set_project_id(remote_name: &str, new_id: &str) {
    trace!("Setting project ID: {} for remote: {}", new_id, remote_name);
    git::set_config("projectid", remote_name, new_id);
    eprintln!("{}", "New project ID set!".green());
}

/// Set the default remote for the repository
fn set_default_remote(remote_name: &str) {
    trace!("Setting default remote {}", remote_name);
    git::set_project_config("defaultremote", remote_name);
    eprintln!("{}", "New default remote set!".green());
}

/// Print the open requests
fn list_open_requests(remote_name: &str) {
    info!("Getting open requests");
    let mut remote = get_remote_hard(remote_name, true);
    debug!("Found remote: {}", remote);
    let mrs = remote.get_req_names().unwrap();
    let mut tw = TabWriter::new(io::stdout()).padding(4);
    for mr in &mrs {
        if remote.has_useful_branch_names() {
            writeln!(
                &mut tw,
                "{}\t{}\t{}",
                mr.id.to_string().green(),
                mr.source_branch.green().dimmed(),
                mr.title
            )
            .unwrap();
        } else {
            writeln!(&mut tw, "{}\t{}", mr.id.to_string().green(), mr.title).unwrap();
        }
    }
    tw.flush().unwrap();
}

/// Print a shell completion script
fn generate_completion(app: &mut App, shell_name: &str) {
    let mut buffer = Cursor::new(Vec::new());
    app.gen_completions_to("git-req", shell_name.parse().unwrap(), &mut buffer);
    let mut output = String::from_utf8(buffer.into_inner()).unwrap_or_else(|_| String::from(""));
    if shell_name == "zsh" {
        // Clap assigns the _files completor to the REQUEST_ID. This is undesirable.
        output = output.replace(":_files", ":");
    }
    print!("{}", &output);
}

/// Get the name of the remote to use for the operation
fn get_remote_name(matches: &ArgMatches) -> String {
    let default_remote_name = match git::get_project_config("defaultremote") {
        Some(remote_name) => remote_name,
        None => {
            let new_remote_name = match git::guess_default_remote_name() {
                Ok(guessed) => guessed,
                Err(_) => {
                    let mut new_remote_name = String::new();
                    println!("Multiple remotes detected. Enter the name of the default one.");
                    for remote in git::get_remotes() {
                        println!(" * {}", remote);
                    }
                    print!("Remote name: ");
                    let _ = stdout().flush();
                    stdin()
                        .read_line(&mut new_remote_name)
                        .expect("Did not input a name");
                    trace!("New remote: {}", &new_remote_name);
                    if !git::get_remotes().contains(new_remote_name.trim()) {
                        panic!("Invalid remote name provided")
                    }
                    new_remote_name
                }
            };
            git::set_project_config("defaultremote", &new_remote_name);
            new_remote_name
        }
    };
    // Not using Clap's default_value because of https://github.com/clap-rs/clap/issues/1140
    String::from(
        matches
            .value_of("REMOTE_NAME")
            .unwrap_or(&default_remote_name),
    )
}

/// Get the Clap app for CLI matching et al.
fn build_cli<'a>() -> App<'a, 'a> {
    App::from_yaml(&APP_CFG)
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .setting(AppSettings::ArgsNegateSubcommands)
        .usage("git req [OPTIONS] [REQUEST_ID]")
}

/// Do the thing
fn main() {
    color_backtrace::install();
    let _ = env_logger::Builder::new()
        .parse_filters(&env::var("REQ_LOG").unwrap_or_default())
        .try_init();

    let mut app = build_cli();

    let matches = app.get_matches();

    if let Some(project_id) = matches.value_of("NEW_PROJECT_ID") {
        set_project_id(&get_remote_name(&matches), project_id);
    } else if matches.is_present("CLEAR_PROJECT_ID") {
        clear_project_id(&get_remote_name(&matches));
    } else if matches.is_present("LIST_MR") {
        list_open_requests(&get_remote_name(&matches));
    } else if matches.is_present("CLEAR_DOMAIN_KEY") {
        clear_domain_key(&get_remote_name(&matches));
    } else if let Some(domain_key) = matches.value_of("NEW_DOMAIN_KEY") {
        set_domain_key(&get_remote_name(&matches), domain_key);
    } else if let Some(remote_name) = matches.value_of("NEW_DEFAULT_REMOTE") {
        set_default_remote(remote_name);
    } else if let Some(shell_name) = matches.value_of("GENERATE_COMPLETIONS") {
        app = build_cli();
        generate_completion(&mut app, &shell_name);
    } else {
        checkout_mr(
            &get_remote_name(&matches),
            matches.value_of("REQUEST_ID").unwrap().parse().unwrap(),
        );
    }
}
<|endoftext|>


<commit_before>#![feature(io)]
#![feature(core)]
#![feature(path)]
extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Branch, BranchType};
use docopt::Docopt;
use std::old_io as io;

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

Options:
    -f, --flag  Flags a flag, note the multiple spaces!
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_repo: String,
    arg_branch: Option<String>,
    flag_flag: bool,
}

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("Could not discover a repository.");
    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.");
    for id in revwalk {
        match repo.find_commit(id) {
            Ok(commit) =>
                println!("Commit: {:?} - {:?}", commit.id(), commit.message()
                    .expect("Commit message was not UTF-8.")),
            Err(error) => (),
        }
    }
}
<commit_msg>Got diffing working<commit_after>#![feature(core)]
#![feature(path)]
extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Branch, BranchType, Commit, Diff};
use docopt::Docopt;
use std::old_io as io;
use std::old_io::BufferedReader;
use std::old_io::File;
use std::str;

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

Options:
    -f, --flag  Flags a flag, note the multiple spaces!
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_repo: String,
    flag_flag: bool,
}

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("Could not discover a repository.");
    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>>();
    for pair in history.windows(2) {
        let (prev, next) = (&pair[0], &pair[1]);
        println!("\n{:?} - {:?}\n", prev.id(), next.id());
        let prev_tree = prev.tree()
            .ok().expect("Couldn't get prev tree");
        let next_tree = next.tree()
            .ok().expect("Couldn't get next tree.");
        let diff = Diff::tree_to_tree(&repo, Some(&prev_tree), Some(&next_tree), None)
            .ok().expect("Couldn't diff trees.");
        for delta in diff.deltas() {
            let old_file = repo.find_blob(delta.old_file().id())
                .ok().expect("Couldn't get blob");
            let new_file = repo.find_blob(delta.new_file().id())
                .ok().expect("Couldn't get blob");
            let old_content = str::from_utf8(&mut old_file.content())
                .ok().expect("Couldn't get content");
            let new_content = str::from_utf8(&mut new_file.content())
                .ok().expect("Couldn't get content");
            for (old, new) in old_content.lines().zip(new_content.lines()) {
                if (old != new) {
                    println!("{:?} - {:?}", old, new);
                } else { println!("Same"); }
            }
        }
    }
}
<|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 FoundState {
    Added, Deleted
}

fn dump_diffline(line: &DiffLine) {
    // '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());
}

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 remove_whitespace = regex!(r"\s{2,}"); // 2 or more whitespaces    // TODO Removes whitespace from a string.
    remove_whitespace.replace_all(key.as_slice(), "")
}

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

fn find_keys(diff: Diff) -> Vec<Found> {

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

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

    let mut state = State::Other;
    let mut added = String::new();
    let mut deleted = String::new();
    let mut old_path = Path::new("");
    let mut new_path = Path::new("");

    let mut length: u64 = 0;

	// 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 {

        assert!(delta.nfiles() == 2, "This only works on diffs between exactly 2 files.");

		// 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: founds={:?}", founds);
        println!("top of loop: added={:?} deleted={:?}", added, deleted);
        println!("top of loop: length={:?}", length);

        dump_diffline(&line);
        //dump_diffdelta(&delta);

        old_path = delta.old_file().path().unwrap().clone();
        new_path = delta.new_file().path().unwrap().clone();

		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: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                            length: length,
                        });
                        deleted = String::new();
                        length = 0;
                    },
                    State::Addition => { length += 1; },
                    State::Other    => { length = 1;  },
                }

                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: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                            length: length,
                        });
                        added = String::new();
                        length = 0;
                    },
                    State::Deletion => { length += 1; },
                    State::Other    => { length = 1;  },
                }

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

                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                            length: length,
                        });
                        added = String::new();
                    },
                    State::Deletion => {
                        founds.push(Found {
                            filename: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                            length: length,
                        });
                        deleted = String::new();
                    },
                    _ => (),
                }

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

    // Grab one.
    match state {
        State::Addition => {
            if added.len() > 0 {
                founds.push(Found {
                    filename: new_path,
                    key: format_key(added.clone()),
                    state: FoundState::Added,
                    length: length,
                });
            }
        },
        State::Deletion => {
            if deleted.len() > 0 {
                founds.push(Found {
                    filename: old_path,
                    key: format_key(deleted.clone()),
                    state: FoundState::Deleted,
                    length: length,
                });
            }
        },
        _ => (),
    }

    return founds;
}

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 founds: Vec<Found> = find_keys(diff);

    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,
}
<commit_msg>Rename variable.<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 FoundState {
    Added, Deleted
}

fn dump_diffline(line: &DiffLine) {
    // '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());
}

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 remove_whitespace = regex!(r"\s{2,}"); // 2 or more whitespaces    // TODO Removes whitespace from a string.
    remove_whitespace.replace_all(key.as_slice(), "")
}

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

fn find_keys(diff: Diff) -> Vec<Found> {

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

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

    let mut state = State::Other;
    let mut added = String::new();
    let mut deleted = String::new();
    let mut old_path = Path::new("");
    let mut new_path = Path::new("");

    let mut line_count: u64 = 0;

	// 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 {

        assert!(delta.nfiles() == 2, "This only works on diffs between exactly 2 files.");

		// 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: founds={:?}", founds);
        println!("top of loop: added={:?} deleted={:?}", added, deleted);
        println!("top of loop: line_count={:?}", line_count);

        dump_diffline(&line);
        //dump_diffdelta(&delta);

        old_path = delta.old_file().path().unwrap().clone();
        new_path = delta.new_file().path().unwrap().clone();

		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: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                            line_count: line_count,
                        });
                        deleted = String::new();
                        line_count = 0;
                    },
                    State::Addition => { line_count += 1; },
                    State::Other    => { line_count = 1;  },
                }

                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: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                            line_count: line_count,
                        });
                        added = String::new();
                        line_count = 0;
                    },
                    State::Deletion => { line_count += 1; },
                    State::Other    => { line_count = 1;  },
                }

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

                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                            line_count: line_count,
                        });
                        added = String::new();
                    },
                    State::Deletion => {
                        founds.push(Found {
                            filename: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                            line_count: line_count,
                        });
                        deleted = String::new();
                    },
                    _ => (),
                }

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

    // Grab one.
    match state {
        State::Addition => {
            if added.len() > 0 {
                founds.push(Found {
                    filename: new_path,
                    key: format_key(added.clone()),
                    state: FoundState::Added,
                    line_count: line_count,
                });
            }
        },
        State::Deletion => {
            if deleted.len() > 0 {
                founds.push(Found {
                    filename: old_path,
                    key: format_key(deleted.clone()),
                    state: FoundState::Deleted,
                    line_count: line_count,
                });
            }
        },
        _ => (),
    }

    return founds;
}

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 founds: Vec<Found> = find_keys(diff);

    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>//! Coredump implementation of the Space API server.
//!
//! Start this via the commandline:
//!
//!     ./coredump_status [-p PORT] [-i IP]
extern crate env_logger;
extern crate docopt;
extern crate rustc_serialize;
extern crate spaceapi_server;

mod utils;

use std::sync::{Arc, Mutex};
use docopt::Docopt;
use spaceapi_server::SpaceapiServer;
use spaceapi_server::api;
use spaceapi_server::api::sensors::{TemperatureSensorTemplate, PeopleNowPresentSensorTemplate};
use spaceapi_server::api::Optional::{Value, Absent};
use spaceapi_server::datastore::{DataStore, RedisStore};
use utils::Ipv4;

static USAGE: &'static str = "
Usage: coredump_status [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 3000].
    -i IP    The ipv4 address to listen on [default: 127.0.0.1].
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_p: u16,
    flag_i: Ipv4,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    env_logger::init().unwrap();

    // Parse arguments
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode())
                                       .unwrap_or_else(|e| e.exit());
    let host = args.flag_i.ip;
    let port = args.flag_p;

    // Create new Status instance
    let mut status = api::Status::new(
        "coredump",
        "https://www.coredump.ch/logo.png",
        "https://www.coredump.ch/",
        api::Location {
            address: Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".into()),
            lat: 47.22936,
            lon: 8.82949,
        },
        api::Contact {
            irc: Value("irc://freenode.net/#coredump".into()),
            twitter: Value("@coredump_ch".into()),
            foursquare: Value("525c20e5498e875d8231b1e5".into()),
            email: Value("vorstand@lists.coredump.ch".into()),
        },
        vec![
            "email".into(),
            "twitter".into(),
        ],
    );

    // Add optional data
    status.spacefed = Value(api::Spacefed {
        spacenet: false,
        spacesaml: false,
        spacephone: false,
    });
    status.feeds = Value(api::Feeds {
        blog: Value(api::Feed {
            _type: Value("rss".into()),
            url: "https://www.coredump.ch/feed/".into(),
        }),
        wiki: Absent,
        calendar: Absent,
        flickr: Absent,
    });
    status.projects = Value(vec![
        "https://www.coredump.ch/projekte/".into(),
        "https://discourse.coredump.ch/c/projects".into(),
        "https://github.com/coredump-ch/".into(),
    ]);
    status.cam = Value(vec![
        "https://webcam.coredump.ch/cams/ultimaker_0.jpg".into(),
        "https://webcam.coredump.ch/cams/ultimaker_1.jpg".into(),
        "https://webcam.coredump.ch/cams/ultimaker_2.jpg".into(),
    ]);
    status.state.message = Value("Open Mondays from 20:00".into());

    // Set up datastore
    let datastore = Arc::new(Mutex::new(Box::new(RedisStore::new().unwrap()) as Box<DataStore>));

    // Set up server
    let mut server = SpaceapiServer::new(host, port, status, datastore);

    // Register sensors
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".into(),
        location: "Hackerspace".into(),
        name: Value("Raspberry CPU".into()),
        description: Absent,
    }), "raspi_temperature".into());
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".into(),
        location: "Hackerspace".into(),
        name: Value("Room Temperature".into()),
        description: Absent,
    }), "room_temperature".into());
    server.register_sensor(Box::new(PeopleNowPresentSensorTemplate {
        location: Value("Hackerspace".into()),
        name: Absent,
        description: Absent,
        names: Absent,
    }), "people_present".into());

    // Serve!
    server.serve();
}
<commit_msg>Fix link to coredump projects<commit_after>//! Coredump implementation of the Space API server.
//!
//! Start this via the commandline:
//!
//!     ./coredump_status [-p PORT] [-i IP]
extern crate env_logger;
extern crate docopt;
extern crate rustc_serialize;
extern crate spaceapi_server;

mod utils;

use std::sync::{Arc, Mutex};
use docopt::Docopt;
use spaceapi_server::SpaceapiServer;
use spaceapi_server::api;
use spaceapi_server::api::sensors::{TemperatureSensorTemplate, PeopleNowPresentSensorTemplate};
use spaceapi_server::api::Optional::{Value, Absent};
use spaceapi_server::datastore::{DataStore, RedisStore};
use utils::Ipv4;

static USAGE: &'static str = "
Usage: coredump_status [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 3000].
    -i IP    The ipv4 address to listen on [default: 127.0.0.1].
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_p: u16,
    flag_i: Ipv4,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    env_logger::init().unwrap();

    // Parse arguments
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode())
                                       .unwrap_or_else(|e| e.exit());
    let host = args.flag_i.ip;
    let port = args.flag_p;

    // Create new Status instance
    let mut status = api::Status::new(
        "coredump",
        "https://www.coredump.ch/logo.png",
        "https://www.coredump.ch/",
        api::Location {
            address: Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".into()),
            lat: 47.22936,
            lon: 8.82949,
        },
        api::Contact {
            irc: Value("irc://freenode.net/#coredump".into()),
            twitter: Value("@coredump_ch".into()),
            foursquare: Value("525c20e5498e875d8231b1e5".into()),
            email: Value("vorstand@lists.coredump.ch".into()),
        },
        vec![
            "email".into(),
            "twitter".into(),
        ],
    );

    // Add optional data
    status.spacefed = Value(api::Spacefed {
        spacenet: false,
        spacesaml: false,
        spacephone: false,
    });
    status.feeds = Value(api::Feeds {
        blog: Value(api::Feed {
            _type: Value("rss".into()),
            url: "https://www.coredump.ch/feed/".into(),
        }),
        wiki: Absent,
        calendar: Absent,
        flickr: Absent,
    });
    status.projects = Value(vec![
        "https://www.coredump.ch/projekte/".into(),
        "https://forum.coredump.ch/c/projects".into(),
        "https://github.com/coredump-ch/".into(),
    ]);
    status.cam = Value(vec![
        "https://webcam.coredump.ch/cams/ultimaker_0.jpg".into(),
        "https://webcam.coredump.ch/cams/ultimaker_1.jpg".into(),
        "https://webcam.coredump.ch/cams/ultimaker_2.jpg".into(),
    ]);
    status.state.message = Value("Open Mondays from 20:00".into());

    // Set up datastore
    let datastore = Arc::new(Mutex::new(Box::new(RedisStore::new().unwrap()) as Box<DataStore>));

    // Set up server
    let mut server = SpaceapiServer::new(host, port, status, datastore);

    // Register sensors
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".into(),
        location: "Hackerspace".into(),
        name: Value("Raspberry CPU".into()),
        description: Absent,
    }), "raspi_temperature".into());
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".into(),
        location: "Hackerspace".into(),
        name: Value("Room Temperature".into()),
        description: Absent,
    }), "room_temperature".into());
    server.register_sensor(Box::new(PeopleNowPresentSensorTemplate {
        location: Value("Hackerspace".into()),
        name: Absent,
        description: Absent,
        names: Absent,
    }), "people_present".into());

    // Serve!
    server.serve();
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate nalgebra;
extern crate riscan_pro;
extern crate rustc_serialize;

use docopt::Docopt;
use nalgebra::{Iterable, Transpose};
use riscan_pro::{Matrix, Project, ScanPosition};
use rustc_serialize::json::{Json, ToJson};
use std::collections::HashMap;

const USAGE: &'static str = "
RiSCAN PRO utilities.

Usage:
    riscan-pro export-filters <project> [<scan-position>]
    riscan-pro socs-to-glcs <project> [<scan-position>] [<x> <y> <z>]
    riscan-pro scan-positions <project>
    riscan-pro (-h | --help)

Options:
    -h --help                       Show this screen.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_export_filters: bool,
    cmd_socs_to_glcs: bool,
    cmd_scan_positions: bool,
    arg_project: String,
    arg_scan_position: Option<String>,
    arg_x: Option<f64>,
    arg_y: Option<f64>,
    arg_z: Option<f64>,
}

fn main() {
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());
    if args.cmd_socs_to_glcs {
        let scan_position = if let Some(scan_position) = args.arg_scan_position {
            let project = Project::from_path(args.arg_project).unwrap();
            project.scan_position(&scan_position).unwrap().clone()
        } else {
            ScanPosition::from_path(args.arg_project).unwrap()
        };
        let glcs = scan_position.socs_to_glcs((args.arg_x.unwrap_or(0.),
                                               args.arg_y.unwrap_or(0.),
                                               args.arg_z.unwrap_or(0.)));
        println!("{:.2}, {:.2}, {:.2}", glcs.0, glcs.1, glcs.2);
    } else if args.cmd_scan_positions {
        let project = Project::from_path(args.arg_project).unwrap();
        for scan_position in project.scan_positions() {
            let glcs = scan_position.socs_to_glcs((0., 0., 0.));
            println!("{},{:.2},{:.2},{:.2}", scan_position.name(), glcs.0, glcs.1, glcs.2);
        }
    } else if args.cmd_export_filters {
        let scan_position = if let Some(scan_position) = args.arg_scan_position {
            let project = Project::from_path(args.arg_project).unwrap();
            project.scan_position(&scan_position).unwrap().clone()
        } else {
            ScanPosition::from_path(args.arg_project).unwrap()
        };
        let mut filters = Vec::new();
        filters.push(filters_transformation(scan_position.sop()));
        filters.push(filters_transformation(scan_position.pop()));
        println!("{}", filters.to_json());
    }
}

fn filters_transformation(matrix: Matrix) -> Json {
    let mut filter = HashMap::new();
    filter.insert("type".to_string(), "filters.transformation".to_json());
    filter.insert("matrix".to_string(),
                  matrix.transpose()
                      .iter()
                      .map(|n| format!("{}", n))
                      .collect::<Vec<_>>()
                      .join(" ")
                      .to_json());
    filter.to_json()
}
<commit_msg>Redo coordiantes from scan positions<commit_after>extern crate docopt;
extern crate nalgebra;
extern crate riscan_pro;
extern crate rustc_serialize;

use docopt::Docopt;
use nalgebra::{Iterable, Transpose};
use riscan_pro::{Matrix, Project, ScanPosition};
use rustc_serialize::json::{Json, ToJson};
use std::collections::HashMap;

const USAGE: &'static str = "
RiSCAN PRO utilities.

Usage:
    riscan-pro export-filters <project> [<scan-position>]
    riscan-pro socs-to-glcs <project> [<scan-position>] [<x> <y> <z>]
    riscan-pro scan-positions <project>
    riscan-pro (-h | --help)

Options:
    -h --help                       Show this screen.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_export_filters: bool,
    cmd_socs_to_glcs: bool,
    cmd_scan_positions: bool,
    arg_project: String,
    arg_scan_position: Option<String>,
    arg_x: Option<f64>,
    arg_y: Option<f64>,
    arg_z: Option<f64>,
}

fn main() {
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());
    if args.cmd_socs_to_glcs {
        let scan_position = if let Some(scan_position) = args.arg_scan_position {
            let project = Project::from_path(args.arg_project).unwrap();
            project.scan_position(&scan_position).unwrap().clone()
        } else {
            ScanPosition::from_path(args.arg_project).unwrap()
        };
        let glcs = scan_position.socs_to_glcs((args.arg_x.unwrap_or(0.),
                                               args.arg_y.unwrap_or(0.),
                                               args.arg_z.unwrap_or(0.)));
        println!("{:.2}, {:.2}, {:.2}", glcs.0, glcs.1, glcs.2);
    } else if args.cmd_scan_positions {
        let project = Project::from_path(args.arg_project).unwrap();
        for scan_position in project.scan_positions() {
            let glcs = scan_position.socs_to_glcs((0., 0., 0.));
            println!("{:.2} {:.2}", glcs.0, glcs.1);
        }
    } else if args.cmd_export_filters {
        let scan_position = if let Some(scan_position) = args.arg_scan_position {
            let project = Project::from_path(args.arg_project).unwrap();
            project.scan_position(&scan_position).unwrap().clone()
        } else {
            ScanPosition::from_path(args.arg_project).unwrap()
        };
        let mut filters = Vec::new();
        filters.push(filters_transformation(scan_position.sop()));
        filters.push(filters_transformation(scan_position.pop()));
        println!("{}", filters.to_json());
    }
}

fn filters_transformation(matrix: Matrix) -> Json {
    let mut filter = HashMap::new();
    filter.insert("type".to_string(), "filters.transformation".to_json());
    filter.insert("matrix".to_string(),
                  matrix.transpose()
                      .iter()
                      .map(|n| format!("{}", n))
                      .collect::<Vec<_>>()
                      .join(" ")
                      .to_json());
    filter.to_json()
}
<|endoftext|>


<commit_before>#[macro_use] extern crate clap;
extern crate ini;
extern crate sha1;

use std::ffi::{OsStr, OsString};
use std::fmt;
use std::fs::{self, File};
use std::io::{self, Read, Write, BufWriter};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};

use ini::Ini;
use ini::ini::Error as IniError;

type Sha1DigestBytes = [u8; 20];
type ModList = Vec<String>;
type MediaSet = Vec<Asset>;

struct Asset {
	path: PathBuf,
	hash: Sha1DigestBytes,
}

impl Asset {
	pub fn new(pb: PathBuf, h: Sha1DigestBytes) -> Self {
		Asset {
			path: pb,
			hash: h,
		}
	}
}

impl PartialEq for Asset {
	fn eq(&self, other: &Self) -> bool {
		self.hash == other.hash
	}
}

enum Error {
	Io(io::Error),
	Ini(IniError),
}

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			Error::Io(ref e)  => write!(f, "IO error: {}", e),
			Error::Ini(ref e) => write!(f, "Settings file error: {}", e),
		}
	}
}

impl From<io::Error> for Error {
	fn from(e: io::Error) -> Self { Error::Io(e) }
}

impl From<IniError> for Error {
	fn from(e: IniError) -> Self { Error::Ini(e) }
}

enum AssetCopyMode {
	Symlink,
	Hardlink,
	Copy,
	None,
}

fn to_hex(input: &[u8]) -> String {
	String::from_iter(input.iter().map(|b| format!("{:02x}", b)))
}

fn make_absolute(path: &Path) -> PathBuf {
	if path.is_absolute() {
		path.to_path_buf()
	} else {
		std::env::current_dir()
			.and_then(|cd| Ok(cd.join(path)))
			.or_else(|_err| -> io::Result<_> {
				Ok(path.to_path_buf())
			})
			.unwrap()
	}
}

fn hash_file(path: &Path) -> io::Result<Sha1DigestBytes> {
	let mut buf = [0u8; 8192];
	let mut hash = sha1::Sha1::new();
	let mut file = File::open(&path)?;
	loop {
		match file.read(&mut buf) {
			Ok(0) => break,
			Ok(len) => hash.update(&buf[..len]),
			Err(e) => return Err(e),
		}
	}
	Ok(hash.digest().bytes())
}

fn search_media_dir(ms: &mut MediaSet, path: &Path) -> io::Result<()> {
	for entry in path.read_dir()? {
		let pb = entry?.path();
		if pb.is_file() {
			let h = hash_file(pb.as_path())?;
			ms.push(Asset::new(pb, h));
		}
	}
	Ok(())
}

fn search_mod_dir(ms: &mut MediaSet, path: &Path) -> io::Result<()> {
	static MEDIA_DIRS: &'static [&'static str] = &["textures", "models", "sounds"];
	for media_dir in MEDIA_DIRS {
		let media_pb = path.join(media_dir);
		if media_pb.is_dir() {
			search_media_dir(ms, media_pb.as_path())?;
		}
	}
	Ok(())
}

fn search_modpack_dir(ms: &mut MediaSet, path: &Path, mods: Option<&ModList>) -> io::Result<()> {
	for entry in path.read_dir()? {
		let entry_path = entry?.path();
		if !entry_path.is_dir() {
			continue;
		} else if entry_path.join("modpack.txt").exists() {
			search_modpack_dir(ms, entry_path.as_path(), mods)?;
		} else if entry_path.join("init.lua").exists() {
			if let Some(mod_list) = mods {
				let mod_name = &entry_path.file_name()
					.expect("Mod directory has no name!")
					.to_str()
					.expect("Mod directory name is not valid Unicode")
					.to_string();
				if !mod_list.contains(mod_name) {
					continue;
				}
			}
			search_mod_dir(ms, entry_path.as_path())?;
		}
		// Otherwise it's probably a VCS directory or something similar
	}
	Ok(())
}

fn write_index(ms: &MediaSet, path: &Path) -> io::Result<()> {
	let file = File::create(&path)?;
	let mut writer = BufWriter::new(file);
	writer.write_all(b"MTHS\x00\x01")?;
	for asset in ms {
		writer.write_all(&asset.hash)?;
	}
	Ok(())
}

fn copy_assets(ms: &MediaSet, path: &Path, mode: AssetCopyMode) -> io::Result<()> {
	fn copy_no_result<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		fs::copy(src, dst).map(|_| ())
	}

	#[cfg(unix)]
	fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		std::os::unix::fs::symlink(src, dst)
	}

	#[cfg(windows)]
	fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		std::os::windows::fs::symlink_file(src, dst)
	}

	#[cfg(not(any(unix, windows)))]
	fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		Err(io::Error::new(io::ErrorKind::Other,
				"Symlinking not supported on this platform!"))
	}

	let copy_func = match mode {
		AssetCopyMode::Symlink => symlink_file,
		AssetCopyMode::Hardlink => fs::hard_link,
		AssetCopyMode::Copy => copy_no_result,
		AssetCopyMode::None => return Ok(()),
	};

	for asset in ms {
		let to_path = path.join(to_hex(&asset.hash));
		if !to_path.exists() {
			copy_func(&asset.path, to_path)?;
		}
	}
	Ok(())
}

fn get_mod_list(path: &Path) -> Result<ModList, IniError> {
	let world_mt = Ini::load_from_file(path.join("world.mt"))?;
	let main_sec = world_mt.general_section();

	let mut list: ModList = vec![];
	for (key, value) in main_sec {
		if !key.starts_with("load_mod_") || value != "true" {
			continue;
		}
		let (_, mod_name) = key.split_at(9);
		list.push(mod_name.to_string());
	}
	Ok(list)
}

fn get_args<'a>() -> clap::ArgMatches<'a> {
	use clap::{App, Arg, ArgGroup};

	fn check_parent_dir(p: &Path) -> bool {
		if let Some(parent) = p.parent() {
			if parent.is_dir() {
				return true
			}
		}
		false
	}

	fn check_new_dir(s: &OsStr) -> Result<(), OsString> {
		let p = make_absolute(Path::new(&s));
		if p.is_dir() || check_parent_dir(&p) {
			Ok(())
		} else {
			Err("Invalid directory path.".into())
		}
	}

	fn check_existing_dir(s: &OsStr) -> Result<(), OsString> {
		if make_absolute(Path::new(&s)).is_dir() {
			Ok(())
		} else {
			Err("Invalid directory path.".into())
		}
	}

	fn check_new_file(s: &OsStr) -> Result<(), OsString> {
		let p = make_absolute(Path::new(&s));
		if p.is_file() || check_parent_dir(&p) {
			Ok(())
		} else {
			Err("Invalid file path.".into())
		}
	}

	let app = clap_app! { @app (app_from_crate!())
		(version_short: "v")

		(@arg mod_paths: [PATHS] ... validator_os(check_existing_dir) "Additional mod paths to search.")

		(@arg world: -w --world <PATH> validator_os(check_existing_dir) "Path to the world directory.")
		(@arg game:  -g --game  <PATH> validator_os(check_existing_dir) "Path to the game directory.")

		(@group output =>
			(@attributes +multiple +required)
			(@arg out: -o --out [PATH] validator_os(check_new_dir) display_order(1001)
				conflicts_with_all(&["media", "index"])
				"Directory to output media files and index. \
				Convenience for --index PATH/index.mth --media PATH.")
			(@arg media: -m --media [PATH] validator_os(check_new_dir) display_order(1001)
				requires("media_transfer")
				"Directory to output media files.")
			(@arg index: -i --index [PATH] validator_os(check_new_file) display_order(1001)
				"Path to the index file to output."))

		// Group these together with display_order
		(@arg copy: -c --copy display_order(1000) requires("media_out") "Copy assets to output folder.")
		// Symlink added below if applicable
		(@arg hardlink: -l --hardlink display_order(1000) requires("media_out") "Hard link assets to output folder.")
	};

	// Add symlink option if supported
	#[cfg(not(any(unix, windows)))]
	let add_symlink_arg = |app| app;

	#[cfg(any(unix, windows))]
	fn add_symlink_arg<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
		app.arg(Arg::with_name("symlink")
			.short("s")
			.long("symlink")
			.display_order(1000)
			.requires("media_out")
			.help("Symbolically link assets to output folder."))
	}

	let matches = add_symlink_arg(app)
		.group(ArgGroup::with_name("media_out")
			.args(&["out", "media"]))
		.group(ArgGroup::with_name("media_transfer")
			.args(&["copy", "symlink", "hardlink"]))
		.get_matches();

	matches
}

fn run(args: clap::ArgMatches) -> Result<(), Error> {
	// These unwraps are safe since the values are required
	// and clap will exit if the value is missing.
	let world_opt = args.value_of_os("world").unwrap();
	let world_path = Path::new(&world_opt);

	let game_opt = args.value_of_os("game").unwrap();
	let game_path = Path::new(&game_opt);

	let out_path = args.value_of_os("out").map(|s| PathBuf::from(s));

	let media_path = if let Some(media_opt) = args.value_of_os("media") {
			Some(PathBuf::from(media_opt))
		} else if let Some(ref out_path) = out_path {
			Some(out_path.clone())
		} else {
			None
		};

	let index_path = if let Some(index_opt) = args.value_of_os("index") {
			Some(PathBuf::from(index_opt))
		} else if let Some(ref out_path) = out_path {
			Some(out_path.join("index.mth"))
		} else {
			None
		};

	let copy_type = if args.is_present("copy") {
			AssetCopyMode::Copy
		} else if args.is_present("symlink") {
			AssetCopyMode::Symlink
		} else if args.is_present("hardlink") {
			AssetCopyMode::Hardlink
		} else {
			AssetCopyMode::None
		};

	let mut ms = MediaSet::new();
	let mods = get_mod_list(world_path)?;

	// Search world mods.
	let worldmods_path = world_path.join("worldmods");
	if worldmods_path.exists() {
		search_modpack_dir(&mut ms, worldmods_path.as_path(), Some(&mods))?;
	}

	// Search game mods.
	// Note: Game mods can not currently be disabled.
	search_modpack_dir(&mut ms, game_path.join("mods").as_path(), None)?;

	if let Some(mod_paths) = args.values_of_os("mod_paths") {
		for mod_path in mod_paths {
			search_modpack_dir(&mut ms,
					Path::new(&mod_path),
					Some(&mods))?;
		}
	}

	// Deduplicate list.  Otherwise linking will fail and the index will
	// be unnecessarily large.
	ms.sort_by(|a, b| a.hash.cmp(&b.hash));
	ms.dedup();

	if let Some(media_path) = media_path {
		if !media_path.exists() {
			fs::create_dir(media_path.as_path())?;
		}

		copy_assets(&ms, media_path.as_path(), copy_type)?;
	}

	if let Some(index_path) = index_path {
		write_index(&ms, index_path.as_path())?;
	}

	Ok(())
}

fn main() {
	match run(get_args()) {
		Ok(()) => return,
		Err(e) => {
			println!("{}", e);
			std::process::exit(1)
		}
	}
}
<commit_msg>Use _by_key variants of sort and dedup<commit_after>#[macro_use] extern crate clap;
extern crate ini;
extern crate sha1;

use std::ffi::{OsStr, OsString};
use std::fmt;
use std::fs::{self, File};
use std::io::{self, Read, Write, BufWriter};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};

use ini::Ini;
use ini::ini::Error as IniError;

type Sha1DigestBytes = [u8; 20];
type ModList = Vec<String>;
type MediaSet = Vec<Asset>;

struct Asset {
	path: PathBuf,
	hash: Sha1DigestBytes,
}

impl Asset {
	pub fn new(pb: PathBuf, h: Sha1DigestBytes) -> Self {
		Asset {
			path: pb,
			hash: h,
		}
	}
}

enum Error {
	Io(io::Error),
	Ini(IniError),
}

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			Error::Io(ref e)  => write!(f, "IO error: {}", e),
			Error::Ini(ref e) => write!(f, "Settings file error: {}", e),
		}
	}
}

impl From<io::Error> for Error {
	fn from(e: io::Error) -> Self { Error::Io(e) }
}

impl From<IniError> for Error {
	fn from(e: IniError) -> Self { Error::Ini(e) }
}

enum AssetCopyMode {
	Symlink,
	Hardlink,
	Copy,
	None,
}

fn to_hex(input: &[u8]) -> String {
	String::from_iter(input.iter().map(|b| format!("{:02x}", b)))
}

fn make_absolute(path: &Path) -> PathBuf {
	if path.is_absolute() {
		path.to_path_buf()
	} else {
		std::env::current_dir()
			.and_then(|cd| Ok(cd.join(path)))
			.or_else(|_err| -> io::Result<_> {
				Ok(path.to_path_buf())
			})
			.unwrap()
	}
}

fn hash_file(path: &Path) -> io::Result<Sha1DigestBytes> {
	let mut buf = [0u8; 8192];
	let mut hash = sha1::Sha1::new();
	let mut file = File::open(&path)?;
	loop {
		match file.read(&mut buf) {
			Ok(0) => break,
			Ok(len) => hash.update(&buf[..len]),
			Err(e) => return Err(e),
		}
	}
	Ok(hash.digest().bytes())
}

fn search_media_dir(ms: &mut MediaSet, path: &Path) -> io::Result<()> {
	for entry in path.read_dir()? {
		let pb = entry?.path();
		if pb.is_file() {
			let h = hash_file(pb.as_path())?;
			ms.push(Asset::new(pb, h));
		}
	}
	Ok(())
}

fn search_mod_dir(ms: &mut MediaSet, path: &Path) -> io::Result<()> {
	static MEDIA_DIRS: &'static [&'static str] = &["textures", "models", "sounds"];
	for media_dir in MEDIA_DIRS {
		let media_pb = path.join(media_dir);
		if media_pb.is_dir() {
			search_media_dir(ms, media_pb.as_path())?;
		}
	}
	Ok(())
}

fn search_modpack_dir(ms: &mut MediaSet, path: &Path, mods: Option<&ModList>) -> io::Result<()> {
	for entry in path.read_dir()? {
		let entry_path = entry?.path();
		if !entry_path.is_dir() {
			continue;
		} else if entry_path.join("modpack.txt").exists() {
			search_modpack_dir(ms, entry_path.as_path(), mods)?;
		} else if entry_path.join("init.lua").exists() {
			if let Some(mod_list) = mods {
				let mod_name = &entry_path.file_name()
					.expect("Mod directory has no name!")
					.to_str()
					.expect("Mod directory name is not valid Unicode")
					.to_string();
				if !mod_list.contains(mod_name) {
					continue;
				}
			}
			search_mod_dir(ms, entry_path.as_path())?;
		}
		// Otherwise it's probably a VCS directory or something similar
	}
	Ok(())
}

fn write_index(ms: &MediaSet, path: &Path) -> io::Result<()> {
	let file = File::create(&path)?;
	let mut writer = BufWriter::new(file);
	writer.write_all(b"MTHS\x00\x01")?;
	for asset in ms {
		writer.write_all(&asset.hash)?;
	}
	Ok(())
}

fn copy_assets(ms: &MediaSet, path: &Path, mode: AssetCopyMode) -> io::Result<()> {
	fn copy_no_result<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		fs::copy(src, dst).map(|_| ())
	}

	#[cfg(unix)]
	fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		std::os::unix::fs::symlink(src, dst)
	}

	#[cfg(windows)]
	fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		std::os::windows::fs::symlink_file(src, dst)
	}

	#[cfg(not(any(unix, windows)))]
	fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		Err(io::Error::new(io::ErrorKind::Other,
				"Symlinking not supported on this platform!"))
	}

	let copy_func = match mode {
		AssetCopyMode::Symlink => symlink_file,
		AssetCopyMode::Hardlink => fs::hard_link,
		AssetCopyMode::Copy => copy_no_result,
		AssetCopyMode::None => return Ok(()),
	};

	for asset in ms {
		let to_path = path.join(to_hex(&asset.hash));
		if !to_path.exists() {
			copy_func(&asset.path, to_path)?;
		}
	}
	Ok(())
}

fn get_mod_list(path: &Path) -> Result<ModList, IniError> {
	let world_mt = Ini::load_from_file(path.join("world.mt"))?;
	let main_sec = world_mt.general_section();

	let mut list: ModList = vec![];
	for (key, value) in main_sec {
		if !key.starts_with("load_mod_") || value != "true" {
			continue;
		}
		let (_, mod_name) = key.split_at(9);
		list.push(mod_name.to_string());
	}
	Ok(list)
}

fn get_args<'a>() -> clap::ArgMatches<'a> {
	use clap::{App, Arg, ArgGroup};

	fn check_parent_dir(p: &Path) -> bool {
		if let Some(parent) = p.parent() {
			if parent.is_dir() {
				return true
			}
		}
		false
	}

	fn check_new_dir(s: &OsStr) -> Result<(), OsString> {
		let p = make_absolute(Path::new(&s));
		if p.is_dir() || check_parent_dir(&p) {
			Ok(())
		} else {
			Err("Invalid directory path.".into())
		}
	}

	fn check_existing_dir(s: &OsStr) -> Result<(), OsString> {
		if make_absolute(Path::new(&s)).is_dir() {
			Ok(())
		} else {
			Err("Invalid directory path.".into())
		}
	}

	fn check_new_file(s: &OsStr) -> Result<(), OsString> {
		let p = make_absolute(Path::new(&s));
		if p.is_file() || check_parent_dir(&p) {
			Ok(())
		} else {
			Err("Invalid file path.".into())
		}
	}

	let app = clap_app! { @app (app_from_crate!())
		(version_short: "v")

		(@arg mod_paths: [PATHS] ... validator_os(check_existing_dir) "Additional mod paths to search.")

		(@arg world: -w --world <PATH> validator_os(check_existing_dir) "Path to the world directory.")
		(@arg game:  -g --game  <PATH> validator_os(check_existing_dir) "Path to the game directory.")

		(@group output =>
			(@attributes +multiple +required)
			(@arg out: -o --out [PATH] validator_os(check_new_dir) display_order(1001)
				conflicts_with_all(&["media", "index"])
				"Directory to output media files and index. \
				Convenience for --index PATH/index.mth --media PATH.")
			(@arg media: -m --media [PATH] validator_os(check_new_dir) display_order(1001)
				requires("media_transfer")
				"Directory to output media files.")
			(@arg index: -i --index [PATH] validator_os(check_new_file) display_order(1001)
				"Path to the index file to output."))

		// Group these together with display_order
		(@arg copy: -c --copy display_order(1000) requires("media_out") "Copy assets to output folder.")
		// Symlink added below if applicable
		(@arg hardlink: -l --hardlink display_order(1000) requires("media_out") "Hard link assets to output folder.")
	};

	// Add symlink option if supported
	#[cfg(not(any(unix, windows)))]
	let add_symlink_arg = |app| app;

	#[cfg(any(unix, windows))]
	fn add_symlink_arg<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
		app.arg(Arg::with_name("symlink")
			.short("s")
			.long("symlink")
			.display_order(1000)
			.requires("media_out")
			.help("Symbolically link assets to output folder."))
	}

	let matches = add_symlink_arg(app)
		.group(ArgGroup::with_name("media_out")
			.args(&["out", "media"]))
		.group(ArgGroup::with_name("media_transfer")
			.args(&["copy", "symlink", "hardlink"]))
		.get_matches();

	matches
}

fn run(args: clap::ArgMatches) -> Result<(), Error> {
	// These unwraps are safe since the values are required
	// and clap will exit if the value is missing.
	let world_opt = args.value_of_os("world").unwrap();
	let world_path = Path::new(&world_opt);

	let game_opt = args.value_of_os("game").unwrap();
	let game_path = Path::new(&game_opt);

	let out_path = args.value_of_os("out").map(|s| PathBuf::from(s));

	let media_path = if let Some(media_opt) = args.value_of_os("media") {
			Some(PathBuf::from(media_opt))
		} else if let Some(ref out_path) = out_path {
			Some(out_path.clone())
		} else {
			None
		};

	let index_path = if let Some(index_opt) = args.value_of_os("index") {
			Some(PathBuf::from(index_opt))
		} else if let Some(ref out_path) = out_path {
			Some(out_path.join("index.mth"))
		} else {
			None
		};

	let copy_type = if args.is_present("copy") {
			AssetCopyMode::Copy
		} else if args.is_present("symlink") {
			AssetCopyMode::Symlink
		} else if args.is_present("hardlink") {
			AssetCopyMode::Hardlink
		} else {
			AssetCopyMode::None
		};

	let mut ms = MediaSet::new();
	let mods = get_mod_list(world_path)?;

	// Search world mods.
	let worldmods_path = world_path.join("worldmods");
	if worldmods_path.exists() {
		search_modpack_dir(&mut ms, worldmods_path.as_path(), Some(&mods))?;
	}

	// Search game mods.
	// Note: Game mods can not currently be disabled.
	search_modpack_dir(&mut ms, game_path.join("mods").as_path(), None)?;

	if let Some(mod_paths) = args.values_of_os("mod_paths") {
		for mod_path in mod_paths {
			search_modpack_dir(&mut ms,
					Path::new(&mod_path),
					Some(&mods))?;
		}
	}

	// Deduplicate list.  Otherwise linking will fail and the index will
	// be unnecessarily large.
	ms.sort_by_key(|a| a.hash);
	ms.dedup_by_key(|a| a.hash);

	if let Some(media_path) = media_path {
		if !media_path.exists() {
			fs::create_dir(media_path.as_path())?;
		}

		copy_assets(&ms, media_path.as_path(), copy_type)?;
	}

	if let Some(index_path) = index_path {
		write_index(&ms, index_path.as_path())?;
	}

	Ok(())
}

fn main() {
	match run(get_args()) {
		Ok(()) => return,
		Err(e) => {
			println!("{}", e);
			std::process::exit(1)
		}
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017  Sebastian Wiesner <swiesner@lunaryorn.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#![deny(warnings)]

#[macro_use]
extern crate clap;
extern crate rand;

use clap::{App, AppSettings, Arg};

static EFF_WORDLIST: &'static str = include_str!(concat!(env!("OUT_DIR"), "/eff_wordlist.txt"));
static LICENSE: &'static str = {
    "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law."
};

fn builtin_words() -> Vec<&'static str> {
    EFF_WORDLIST.lines().collect()
}

fn main() {
    let parse_result = App::new("xkpwgen")
        .version(crate_version!())
        .about("Generate XKCD 936 passwords")
        .after_help(format!("Copyright (C) 2017 Sebastian Wiesner <swiesner@lunaryorn.com>\n\n{}",
                            LICENSE)
                            .as_str())
        .version_message("Print version information")
        .help_message("Print this message")
        .arg(Arg::with_name("number")
                 .short("n")
                 .long("number")
                 .default_value("5")
                 .help("The number of passwords to generate at once"))
        .arg(Arg::with_name("length")
                 .short("l")
                 .long("length")
                 .default_value("4")
                 .help("The number of words in each password"))
        .arg(Arg::with_name("words").long("words").help("Print the internal wordlist and exit"))
        .settings(&[AppSettings::ColoredHelp,
                    AppSettings::DontCollapseArgsInUsage,
                    // Don't put flags and options in separate --help groups
                    AppSettings::UnifiedHelpMessage])
        .get_matches_safe();

    match parse_result {
        Ok(matches) => {
            if matches.is_present("words") {
                for word in builtin_words() {
                    println!("{}", word);
                }
            } else {
                let words = builtin_words();
                let password_length = value_t_or_exit!(matches.value_of("length"), usize);
                let number_of_passwords = value_t_or_exit!(matches.value_of("number"), usize);
                for _ in 0..number_of_passwords {
                    println!("{}",
                             rand::sample(&mut rand::thread_rng(),
                                          words.iter().map(|s| *s),
                                          password_length)
                                     .join(" "));
                }
            }
        }
        Err(error @ clap::Error { kind: clap::ErrorKind::VersionDisplayed, .. }) => {
            let mut words = builtin_words();
            words.sort_by_key(|w| w.chars().count());
            print!("\n
EFF long wordlist July 2017: {} words (min length {}, max length {})

{}",
                   words.len(),
                   words[0].chars().count(),
                   words.last()
                       .unwrap()
                       .chars()
                       .count(),
                   LICENSE);
            error.exit();
        }
        Err(error) => error.exit(),
    }
}
<commit_msg>Build app from crate attributes<commit_after>/*
 * Copyright (C) 2017  Sebastian Wiesner <swiesner@lunaryorn.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#![deny(warnings)]

#[macro_use]
extern crate clap;
extern crate rand;

use clap::{AppSettings, Arg};

static EFF_WORDLIST: &'static str = include_str!(concat!(env!("OUT_DIR"), "/eff_wordlist.txt"));
static LICENSE: &'static str = {
    "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law."
};

fn builtin_words() -> Vec<&'static str> {
    EFF_WORDLIST.lines().collect()
}

fn main() {
    let parse_result = app_from_crate!()
        .after_help(format!("Copyright (C) 2017 Sebastian Wiesner <swiesner@lunaryorn.com>\n\n{}",
                            LICENSE)
                            .as_str())
        .version_message("Print version information")
        .help_message("Print this message")
        .arg(Arg::with_name("number")
                 .short("n")
                 .long("number")
                 .default_value("5")
                 .help("The number of passwords to generate at once"))
        .arg(Arg::with_name("length")
                 .short("l")
                 .long("length")
                 .default_value("4")
                 .help("The number of words in each password"))
        .arg(Arg::with_name("words").long("words").help("Print the internal wordlist and exit"))
        .settings(&[AppSettings::ColoredHelp,
                    AppSettings::DontCollapseArgsInUsage,
                    // Don't put flags and options in separate --help groups
                    AppSettings::UnifiedHelpMessage])
        .get_matches_safe();

    match parse_result {
        Ok(matches) => {
            if matches.is_present("words") {
                for word in builtin_words() {
                    println!("{}", word);
                }
            } else {
                let words = builtin_words();
                let password_length = value_t_or_exit!(matches.value_of("length"), usize);
                let number_of_passwords = value_t_or_exit!(matches.value_of("number"), usize);
                for _ in 0..number_of_passwords {
                    println!("{}",
                             rand::sample(&mut rand::thread_rng(),
                                          words.iter().map(|s| *s),
                                          password_length)
                                     .join(" "));
                }
            }
        }
        Err(error @ clap::Error { kind: clap::ErrorKind::VersionDisplayed, .. }) => {
            let mut words = builtin_words();
            words.sort_by_key(|w| w.chars().count());
            print!("\n
EFF long wordlist July 2017: {} words (min length {}, max length {})

{}",
                   words.len(),
                   words[0].chars().count(),
                   words.last()
                       .unwrap()
                       .chars()
                       .count(),
                   LICENSE);
            error.exit();
        }
        Err(error) => error.exit(),
    }
}
<|endoftext|>


<commit_before>use std::collections::LinkedList;

struct RowQuery<T>{
    map: LinkedList<T>,
}
impl<T> RowQuery<T>{
    fn new() -> RowQuery<T>{
        let mut d = LinkedList::<T>::new();
        RowQuery{
            map: d,
        }
    }
}
struct HashMap<T>{
    map: Vec<RowQuery<T>>,
}
impl<T> HashMap<T>{
    fn new() -> HashMap<T>{
        let mut d: Vec<RowQuery<T>> = vec![];
        HashMap{
            map: d,
        }
    }
}
fn main(){

}
<commit_msg>Update main.rs<commit_after>use std::collections::LinkedList;

trait Graph {
    type E;

    fn edges(&self) -> Vec<Self::E>;
}

struct MyGraph;

impl Graph for MyGraph {
    type E = i32;

    fn edges(&self) -> Vec<Self::E> {
        Vec::new()
    }
}
fn main(){
  let graph = MyGraph;
  let obj = Box::new(graph) as Box<Graph<E=i32>>;
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate numbat;

mod forza;
mod plugins;

use std::thread;
use std::collections::BTreeMap;
use forza::ForzaPlugin;

fn start_plugin<T: ForzaPlugin>(mut plugin: T) {
  plugin.start();
}

fn main() {
  let mut emitter = numbat::Emitter::new(BTreeMap::new(), "host");
  emitter.connect(&match std::env::var_os("METRICS") {
    Some(url) => url.into_string().expect("expected METRICS to be valid UTF-8"),
    None => String::from("tcp://127.0.0.1:1337")
  });

  emitter.emit_name("forza.start");

  let heartbeat = plugins::heartbeat::Heartbeat::new(emitter.clone());
  thread::spawn(|| {
    start_plugin(heartbeat);
  });

  let memory = plugins::memory::Memory::new(emitter.clone());
  thread::spawn(|| {
    start_plugin(memory);
  });

  let load_average = plugins::load_average::LoadAverage::new(emitter.clone());
  thread::spawn(|| {
    start_plugin(load_average);
  }).join();
}
<commit_msg>Use `numbat::Emitter::for_app`<commit_after>extern crate libc;
extern crate numbat;

mod forza;
mod plugins;

use std::thread;
use forza::ForzaPlugin;

fn start_plugin<T: ForzaPlugin>(mut plugin: T) {
  plugin.start();
}

fn main() {
  let mut emitter = numbat::Emitter::for_app("host");
  emitter.connect(&match std::env::var_os("METRICS") {
    Some(url) => url.into_string().expect("expected METRICS to be valid UTF-8"),
    None => String::from("tcp://127.0.0.1:1337")
  });

  emitter.emit_name("forza.start");

  let heartbeat = plugins::heartbeat::Heartbeat::new(emitter.clone());
  thread::spawn(|| {
    start_plugin(heartbeat);
  });

  let memory = plugins::memory::Memory::new(emitter.clone());
  thread::spawn(|| {
    start_plugin(memory);
  });

  let load_average = plugins::load_average::LoadAverage::new(emitter.clone());
  thread::spawn(|| {
    start_plugin(load_average);
  }).join();
}
<|endoftext|>