<commit_before>extern crate cargo;
extern crate url;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use std::collections::BTreeSet;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

use cargo::core::shell::{Verbosity, ColorConfig};
use cargo::util::{self, CliResult, lev_distance, Config, human, CargoResult};
use cargo::util::CliError;

#[derive(RustcDecodable)]
pub struct Flags {
    flag_list: bool,
    flag_version: bool,
    flag_verbose: u32,
    flag_quiet: Option<bool>,
    flag_color: Option<String>,
    flag_explain: Option<String>,
    arg_command: String,
    arg_args: Vec<String>,
    flag_locked: bool,
    flag_frozen: bool,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --list              List installed commands
    --explain CODE      Run `rustc --explain CODE`
    -v, --verbose ...   Use verbose output (-vv very verbose/build.rs output)
    -q, --quiet         No output printed to stdout
    --color WHEN        Coloring: auto, always, never
    --frozen            Require Cargo.lock and cache are up to date
    --locked            Require Cargo.lock is up to date

Some common cargo commands are (see all commands with --list):
    build       Compile the current project
    check       Analyze the current project and report errors, but don't build object files
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    init        Create a new cargo project in an existing directory
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this project to the registry
    install     Install a Rust binary

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();

    let config = match Config::default() {
        Ok(cfg) => cfg,
        Err(e) => {
            let mut shell = cargo::shell(Verbosity::Verbose, ColorConfig::Auto);
            cargo::exit_with_error(e.into(), &mut shell)
        }
    };

    let result = (|| {
        let args: Vec<_> = try!(env::args_os()
            .map(|s| {
                s.into_string().map_err(|s| human(format!("invalid unicode in argument: {:?}", s)))
            })
            .collect());
        let rest = &args;
        cargo::call_main_without_stdin(execute, &config, USAGE, rest, true)
    })();

    match result {
        Err(e) => cargo::exit_with_error(e, &mut *config.shell()),
        Ok(()) => {}
    }
}

macro_rules! each_subcommand{
    ($mac:ident) => {
        $mac!(bench);
        $mac!(build);
        $mac!(check);
        $mac!(clean);
        $mac!(doc);
        $mac!(fetch);
        $mac!(generate_lockfile);
        $mac!(git_checkout);
        $mac!(help);
        $mac!(init);
        $mac!(install);
        $mac!(locate_project);
        $mac!(login);
        $mac!(metadata);
        $mac!(new);
        $mac!(owner);
        $mac!(package);
        $mac!(pkgid);
        $mac!(publish);
        $mac!(read_manifest);
        $mac!(run);
        $mac!(rustc);
        $mac!(rustdoc);
        $mac!(search);
        $mac!(test);
        $mac!(uninstall);
        $mac!(update);
        $mac!(verify_project);
        $mac!(version);
        $mac!(yank);
    }
}

macro_rules! declare_mod {
    ($name:ident) => ( pub mod $name; )
}
each_subcommand!(declare_mod);

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult {
    config.configure(flags.flag_verbose,
                   flags.flag_quiet,
                   &flags.flag_color,
                   flags.flag_frozen,
                   flags.flag_locked)?;

    init_git_transports(config);
    let _token = cargo::util::job::setup();

    if flags.flag_version {
        let version = cargo::version();
        println!("{}", version);
        if flags.flag_verbose > 0 {
            println!("release: {}.{}.{}",
                     version.major,
                     version.minor,
                     version.patch);
            if let Some(ref cfg) = version.cfg_info {
                if let Some(ref ci) = cfg.commit_info {
                    println!("commit-hash: {}", ci.commit_hash);
                    println!("commit-date: {}", ci.commit_date);
                }
            }
        }
        return Ok(());
    }

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands(config) {
            println!("    {}", command);
        }
        return Ok(());
    }

    if let Some(ref code) = flags.flag_explain {
        let mut procss = config.rustc()?.process();
        procss.arg("--explain").arg(code).exec().map_err(human)?;
        return Ok(());
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbosity(Verbosity::Verbose);
            let args = &["cargo".to_string(), "-h".to_string()];
            return cargo::call_main_without_stdin(execute, config, USAGE, args, false);
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" || flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => vec!["cargo".to_string(), flags.arg_args[0].clone(), "-h".to_string()],

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => {
            let mut default_alias = HashMap::new();
            default_alias.insert("b", "build".to_string());
            default_alias.insert("t", "test".to_string());
            default_alias.insert("r", "run".to_string());
            let mut args: Vec<String> = env::args().collect();
            if let Some(new_command) = default_alias.get(&args[1][..]) {
                args[1] = new_command.clone();
            }
            args
        }
    };

    if let Some(r) = try_execute_builtin_command(&config, &args) {
        return r;
    }

    let alias_list = aliased_command(&config, &args[1])?;
    let args = match alias_list {
        Some(alias_command) => {
            let chain = args.iter()
                .take(1)
                .chain(alias_command.iter())
                .chain(args.iter().skip(2))
                .map(|s| s.to_string())
                .collect::<Vec<_>>();
            if let Some(r) = try_execute_builtin_command(&config, &chain) {
                return r;
            } else {
                chain
            }
        }
        None => args,
    };

    execute_external_subcommand(config, &args[1], &args)
}

fn try_execute_builtin_command(config: &Config, args: &[String]) -> Option<CliResult> {
    macro_rules! cmd {
        ($name:ident) => (if args[1] == stringify!($name).replace("_", "-") {
            config.shell().set_verbosity(Verbosity::Verbose);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            return Some(r);
        })
    }
    each_subcommand!(cmd);

    None
}

fn aliased_command(config: &Config, command: &String) -> CargoResult<Option<Vec<String>>> {
    let alias_name = format!("alias.{}", command);
    let mut result = Ok(None);
    match config.get_string(&alias_name) {
        Ok(value) => {
            if let Some(record) = value {
                let alias_commands = record.val
                    .split_whitespace()
                    .map(|s| s.to_string())
                    .collect();
                result = Ok(Some(alias_commands));
            }
        }
        Err(_) => {
            let value = config.get_list(&alias_name)?;
            if let Some(record) = value {
                let alias_commands: Vec<String> = record.val
                    .iter()
                    .map(|s| s.0.to_string())
                    .collect();
                result = Ok(Some(alias_commands));
            }
        }
    }
    result
}

fn find_closest(config: &Config, cmd: &str) -> Option<String> {
    let cmds = list_commands(config);
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter()
        .map(|c| (lev_distance(&c, cmd), c))
        .filter(|&(d, _)| d < 4)
        .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));
    filtered.get(0).map(|slot| slot.1.clone())
}

fn execute_external_subcommand(config: &Config, cmd: &str, args: &[String]) -> CliResult {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = search_directories(config)
        .iter()
        .map(|dir| dir.join(&command_exe))
        .find(|file| is_executable(file));
    let command = match path {
        Some(command) => command,
        None => {
            return Err(human(match find_closest(config, cmd) {
                    Some(closest) => {
                        format!("no such subcommand: `{}`\n\n\tDid you mean `{}`?\n",
                                cmd,
                                closest)
                    }
                    None => format!("no such subcommand: `{}`", cmd),
                })
                .into())
        }
    };

    let cargo_exe = config.cargo_exe()?;
    let err = match util::process(&command)
        .env(cargo::CARGO_ENV, cargo_exe)
        .args(&args[1..])
        .exec() {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if let Some(code) = err.exit.as_ref().and_then(|c| c.code()) {
        Err(CliError::code(code))
    } else {
        Err(CliError::new(Box::new(err), 101))
    }
}

/// List all runnable commands
fn list_commands(config: &Config) -> BTreeSet<String> {
    let prefix = "cargo-";
    let suffix = env::consts::EXE_SUFFIX;
    let mut commands = BTreeSet::new();
    for dir in search_directories(config) {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue,
        };
        for entry in entries.filter_map(|e| e.ok()) {
            let path = entry.path();
            let filename = match path.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue,
            };
            if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
                continue;
            }
            if is_executable(entry.path()) {
                let end = filename.len() - suffix.len();
                commands.insert(filename[prefix.len()..end].to_string());
            }
        }
    }

    macro_rules! add_cmd {
        ($cmd:ident) => ({ commands.insert(stringify!($cmd).replace("_", "-")); })
    }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path)
        .map(|metadata| metadata.is_file() && metadata.permissions().mode() & 0o111 != 0)
        .unwrap_or(false)
}
#[cfg(windows)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).map(|metadata| metadata.is_file()).unwrap_or(false)
}

fn search_directories(config: &Config) -> Vec<PathBuf> {
    let mut dirs = vec![config.home().clone().into_path_unlocked().join("bin")];
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return,
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>exec (replace the current process) external subommands instead of running them as child processes.<commit_after>extern crate cargo;
extern crate url;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use std::collections::BTreeSet;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

use cargo::core::shell::{Verbosity, ColorConfig};
use cargo::util::{self, CliResult, lev_distance, Config, human, CargoResult};
use cargo::util::CliError;

#[derive(RustcDecodable)]
pub struct Flags {
    flag_list: bool,
    flag_version: bool,
    flag_verbose: u32,
    flag_quiet: Option<bool>,
    flag_color: Option<String>,
    flag_explain: Option<String>,
    arg_command: String,
    arg_args: Vec<String>,
    flag_locked: bool,
    flag_frozen: bool,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --list              List installed commands
    --explain CODE      Run `rustc --explain CODE`
    -v, --verbose ...   Use verbose output (-vv very verbose/build.rs output)
    -q, --quiet         No output printed to stdout
    --color WHEN        Coloring: auto, always, never
    --frozen            Require Cargo.lock and cache are up to date
    --locked            Require Cargo.lock is up to date

Some common cargo commands are (see all commands with --list):
    build       Compile the current project
    check       Analyze the current project and report errors, but don't build object files
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    init        Create a new cargo project in an existing directory
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this project to the registry
    install     Install a Rust binary

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();

    let config = match Config::default() {
        Ok(cfg) => cfg,
        Err(e) => {
            let mut shell = cargo::shell(Verbosity::Verbose, ColorConfig::Auto);
            cargo::exit_with_error(e.into(), &mut shell)
        }
    };

    let result = (|| {
        let args: Vec<_> = try!(env::args_os()
            .map(|s| {
                s.into_string().map_err(|s| human(format!("invalid unicode in argument: {:?}", s)))
            })
            .collect());
        let rest = &args;
        cargo::call_main_without_stdin(execute, &config, USAGE, rest, true)
    })();

    match result {
        Err(e) => cargo::exit_with_error(e, &mut *config.shell()),
        Ok(()) => {}
    }
}

macro_rules! each_subcommand{
    ($mac:ident) => {
        $mac!(bench);
        $mac!(build);
        $mac!(check);
        $mac!(clean);
        $mac!(doc);
        $mac!(fetch);
        $mac!(generate_lockfile);
        $mac!(git_checkout);
        $mac!(help);
        $mac!(init);
        $mac!(install);
        $mac!(locate_project);
        $mac!(login);
        $mac!(metadata);
        $mac!(new);
        $mac!(owner);
        $mac!(package);
        $mac!(pkgid);
        $mac!(publish);
        $mac!(read_manifest);
        $mac!(run);
        $mac!(rustc);
        $mac!(rustdoc);
        $mac!(search);
        $mac!(test);
        $mac!(uninstall);
        $mac!(update);
        $mac!(verify_project);
        $mac!(version);
        $mac!(yank);
    }
}

macro_rules! declare_mod {
    ($name:ident) => ( pub mod $name; )
}
each_subcommand!(declare_mod);

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult {
    config.configure(flags.flag_verbose,
                   flags.flag_quiet,
                   &flags.flag_color,
                   flags.flag_frozen,
                   flags.flag_locked)?;

    init_git_transports(config);
    let _token = cargo::util::job::setup();

    if flags.flag_version {
        let version = cargo::version();
        println!("{}", version);
        if flags.flag_verbose > 0 {
            println!("release: {}.{}.{}",
                     version.major,
                     version.minor,
                     version.patch);
            if let Some(ref cfg) = version.cfg_info {
                if let Some(ref ci) = cfg.commit_info {
                    println!("commit-hash: {}", ci.commit_hash);
                    println!("commit-date: {}", ci.commit_date);
                }
            }
        }
        return Ok(());
    }

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands(config) {
            println!("    {}", command);
        }
        return Ok(());
    }

    if let Some(ref code) = flags.flag_explain {
        let mut procss = config.rustc()?.process();
        procss.arg("--explain").arg(code).exec().map_err(human)?;
        return Ok(());
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbosity(Verbosity::Verbose);
            let args = &["cargo".to_string(), "-h".to_string()];
            return cargo::call_main_without_stdin(execute, config, USAGE, args, false);
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" || flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => vec!["cargo".to_string(), flags.arg_args[0].clone(), "-h".to_string()],

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => {
            let mut default_alias = HashMap::new();
            default_alias.insert("b", "build".to_string());
            default_alias.insert("t", "test".to_string());
            default_alias.insert("r", "run".to_string());
            let mut args: Vec<String> = env::args().collect();
            if let Some(new_command) = default_alias.get(&args[1][..]) {
                args[1] = new_command.clone();
            }
            args
        }
    };

    if let Some(r) = try_execute_builtin_command(&config, &args) {
        return r;
    }

    let alias_list = aliased_command(&config, &args[1])?;
    let args = match alias_list {
        Some(alias_command) => {
            let chain = args.iter()
                .take(1)
                .chain(alias_command.iter())
                .chain(args.iter().skip(2))
                .map(|s| s.to_string())
                .collect::<Vec<_>>();
            if let Some(r) = try_execute_builtin_command(&config, &chain) {
                return r;
            } else {
                chain
            }
        }
        None => args,
    };

    execute_external_subcommand(config, &args[1], &args)
}

fn try_execute_builtin_command(config: &Config, args: &[String]) -> Option<CliResult> {
    macro_rules! cmd {
        ($name:ident) => (if args[1] == stringify!($name).replace("_", "-") {
            config.shell().set_verbosity(Verbosity::Verbose);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            return Some(r);
        })
    }
    each_subcommand!(cmd);

    None
}

fn aliased_command(config: &Config, command: &String) -> CargoResult<Option<Vec<String>>> {
    let alias_name = format!("alias.{}", command);
    let mut result = Ok(None);
    match config.get_string(&alias_name) {
        Ok(value) => {
            if let Some(record) = value {
                let alias_commands = record.val
                    .split_whitespace()
                    .map(|s| s.to_string())
                    .collect();
                result = Ok(Some(alias_commands));
            }
        }
        Err(_) => {
            let value = config.get_list(&alias_name)?;
            if let Some(record) = value {
                let alias_commands: Vec<String> = record.val
                    .iter()
                    .map(|s| s.0.to_string())
                    .collect();
                result = Ok(Some(alias_commands));
            }
        }
    }
    result
}

fn find_closest(config: &Config, cmd: &str) -> Option<String> {
    let cmds = list_commands(config);
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter()
        .map(|c| (lev_distance(&c, cmd), c))
        .filter(|&(d, _)| d < 4)
        .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));
    filtered.get(0).map(|slot| slot.1.clone())
}

fn execute_external_subcommand(config: &Config, cmd: &str, args: &[String]) -> CliResult {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = search_directories(config)
        .iter()
        .map(|dir| dir.join(&command_exe))
        .find(|file| is_executable(file));
    let command = match path {
        Some(command) => command,
        None => {
            return Err(human(match find_closest(config, cmd) {
                    Some(closest) => {
                        format!("no such subcommand: `{}`\n\n\tDid you mean `{}`?\n",
                                cmd,
                                closest)
                    }
                    None => format!("no such subcommand: `{}`", cmd),
                })
                .into())
        }
    };

    let cargo_exe = config.cargo_exe()?;
    let err = match util::process(&command)
        .env(cargo::CARGO_ENV, cargo_exe)
        .args(&args[1..])
        .exec_replace() {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if let Some(code) = err.exit.as_ref().and_then(|c| c.code()) {
        Err(CliError::code(code))
    } else {
        Err(CliError::new(Box::new(err), 101))
    }
}

/// List all runnable commands
fn list_commands(config: &Config) -> BTreeSet<String> {
    let prefix = "cargo-";
    let suffix = env::consts::EXE_SUFFIX;
    let mut commands = BTreeSet::new();
    for dir in search_directories(config) {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue,
        };
        for entry in entries.filter_map(|e| e.ok()) {
            let path = entry.path();
            let filename = match path.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue,
            };
            if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
                continue;
            }
            if is_executable(entry.path()) {
                let end = filename.len() - suffix.len();
                commands.insert(filename[prefix.len()..end].to_string());
            }
        }
    }

    macro_rules! add_cmd {
        ($cmd:ident) => ({ commands.insert(stringify!($cmd).replace("_", "-")); })
    }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path)
        .map(|metadata| metadata.is_file() && metadata.permissions().mode() & 0o111 != 0)
        .unwrap_or(false)
}
#[cfg(windows)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).map(|metadata| metadata.is_file()).unwrap_or(false)
}

fn search_directories(config: &Config) -> Vec<PathBuf> {
    let mut dirs = vec![config.home().clone().into_path_unlocked().join("bin")];
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return,
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<|endoftext|>


<commit_before>extern crate cargo;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::path::PathBuf;

use cargo::execute_main_without_stdin;
use cargo::util::{self, CliResult, lev_distance, Config, human, CargoResult, ChainError};

#[derive(RustcDecodable)]
pub struct Flags {
    flag_list: bool,
    flag_version: bool,
    flag_verbose: Option<bool>,
    flag_quiet: Option<bool>,
    flag_color: Option<String>,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --list              List installed commands
    -v, --verbose       Use verbose output
    -q, --quiet         No output printed to stdout
    --color WHEN        Coloring: auto, always, never

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    init        Create a new cargo project in an existing directory
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this project to the registry
    install     Install a Rust binary

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{
    ($mac:ident) => {
        $mac!(bench);
        $mac!(build);
        $mac!(clean);
        $mac!(doc);
        $mac!(fetch);
        $mac!(generate_lockfile);
        $mac!(git_checkout);
        $mac!(help);
        $mac!(init);
        $mac!(install);
        $mac!(locate_project);
        $mac!(login);
        $mac!(metadata);
        $mac!(new);
        $mac!(owner);
        $mac!(package);
        $mac!(pkgid);
        $mac!(publish);
        $mac!(read_manifest);
        $mac!(run);
        $mac!(rustc);
        $mac!(rustdoc);
        $mac!(search);
        $mac!(test);
        $mac!(uninstall);
        $mac!(update);
        $mac!(verify_project);
        $mac!(version);
        $mac!(yank);
    }
}

mod subcommands {
    macro_rules! declare_mod {
        ($name:ident) => ( pub mod $name; )
    }
    each_subcommand!(declare_mod);
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    try!(config.configure_shell(flags.flag_verbose,
                                flags.flag_quiet,
                                &flags.flag_color));

    init_git_transports(config);
    cargo::util::job::setup();

    if flags.flag_version {
        println!("{}", cargo::version());
        return Ok(None)
    }

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands(config) {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbose(true);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => vec!["cargo".to_string(), flags.arg_args[0].clone(),
                       "-h".to_string()],

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => env::args().collect(),
    };

    macro_rules! cmd{
        ($name:ident) => (if args[1] == stringify!($name).replace("_", "-") {
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin(subcommands::$name::execute, config,
                                                   subcommands::$name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        })
    }
    each_subcommand!(cmd);

    try!(execute_subcommand(config, &args[1], &args));
    Ok(None)
}

fn find_closest(config: &Config, cmd: &str) -> Option<String> {
    let cmds = list_commands(config);
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));
    filtered.get(0).map(|slot| slot.1.clone())
}

fn execute_subcommand(config: &Config,
                      cmd: &str,
                      args: &[String]) -> CargoResult<()> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = search_directories(config)
                    .iter()
                    .map(|dir| dir.join(&command_exe))
                    .filter_map(|dir| fs::metadata(&dir).ok().map(|m| (dir, m)))
                    .find(|&(_, ref meta)| is_executable(meta));
    let command = match path {
        Some((command, _)) => command,
        None => {
            return Err(human(match find_closest(config, cmd) {
                Some(closest) => format!("no such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "no such subcommand".to_string()
            }))
        }
    };
    try!(util::process(&command).args(&args[1..]).exec().chain_error(|| {
        human(format!("third party subcommand `{}` exited unsuccessfully", command_exe))
    }));
    Ok(())
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands(config: &Config) -> BTreeSet<String> {
    let prefix = "cargo-";
    let suffix = env::consts::EXE_SUFFIX;
    let mut commands = BTreeSet::new();
    for dir in search_directories(config) {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.filter_map(|e| e.ok()) {
            let path = entry.path();
            let filename = match path.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
                continue
            }
            if let Ok(meta) = entry.metadata() {
                if is_executable(&meta) {
                    let end = filename.len() - suffix.len();
                    commands.insert(filename[prefix.len()..end].to_string());
                }
            }
        }
    }

    macro_rules! add_cmd {
        ($cmd:ident) => ({ commands.insert(stringify!($cmd).replace("_", "-")); })
    }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable(metadata: &fs::Metadata) -> bool {
    use std::os::unix::prelude::*;
    metadata.is_file() && metadata.permissions().mode() & 0o111 != 0
}
#[cfg(windows)]
fn is_executable(metadata: &fs::Metadata) -> bool {
    metadata.is_file()
}

fn search_directories(config: &Config) -> Vec<PathBuf> {
    let mut dirs = vec![config.home().join("bin")];
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>Ensure future compatibility with fixed module search paths (see rust PR #32006)<commit_after>extern crate cargo;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::path::PathBuf;

use cargo::execute_main_without_stdin;
use cargo::util::{self, CliResult, lev_distance, Config, human, CargoResult, ChainError};

#[derive(RustcDecodable)]
pub struct Flags {
    flag_list: bool,
    flag_version: bool,
    flag_verbose: Option<bool>,
    flag_quiet: Option<bool>,
    flag_color: Option<String>,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --list              List installed commands
    -v, --verbose       Use verbose output
    -q, --quiet         No output printed to stdout
    --color WHEN        Coloring: auto, always, never

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    init        Create a new cargo project in an existing directory
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this project to the registry
    install     Install a Rust binary

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{
    ($mac:ident) => {
        $mac!(bench);
        $mac!(build);
        $mac!(clean);
        $mac!(doc);
        $mac!(fetch);
        $mac!(generate_lockfile);
        $mac!(git_checkout);
        $mac!(help);
        $mac!(init);
        $mac!(install);
        $mac!(locate_project);
        $mac!(login);
        $mac!(metadata);
        $mac!(new);
        $mac!(owner);
        $mac!(package);
        $mac!(pkgid);
        $mac!(publish);
        $mac!(read_manifest);
        $mac!(run);
        $mac!(rustc);
        $mac!(rustdoc);
        $mac!(search);
        $mac!(test);
        $mac!(uninstall);
        $mac!(update);
        $mac!(verify_project);
        $mac!(version);
        $mac!(yank);
    }
}

macro_rules! declare_mod {
    ($name:ident) => ( pub mod $name; )
}
each_subcommand!(declare_mod);

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    try!(config.configure_shell(flags.flag_verbose,
                                flags.flag_quiet,
                                &flags.flag_color));

    init_git_transports(config);
    cargo::util::job::setup();

    if flags.flag_version {
        println!("{}", cargo::version());
        return Ok(None)
    }

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands(config) {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbose(true);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => vec!["cargo".to_string(), flags.arg_args[0].clone(),
                       "-h".to_string()],

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => env::args().collect(),
    };

    macro_rules! cmd{
        ($name:ident) => (if args[1] == stringify!($name).replace("_", "-") {
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        })
    }
    each_subcommand!(cmd);

    try!(execute_subcommand(config, &args[1], &args));
    Ok(None)
}

fn find_closest(config: &Config, cmd: &str) -> Option<String> {
    let cmds = list_commands(config);
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));
    filtered.get(0).map(|slot| slot.1.clone())
}

fn execute_subcommand(config: &Config,
                      cmd: &str,
                      args: &[String]) -> CargoResult<()> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = search_directories(config)
                    .iter()
                    .map(|dir| dir.join(&command_exe))
                    .filter_map(|dir| fs::metadata(&dir).ok().map(|m| (dir, m)))
                    .find(|&(_, ref meta)| is_executable(meta));
    let command = match path {
        Some((command, _)) => command,
        None => {
            return Err(human(match find_closest(config, cmd) {
                Some(closest) => format!("no such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "no such subcommand".to_string()
            }))
        }
    };
    try!(util::process(&command).args(&args[1..]).exec().chain_error(|| {
        human(format!("third party subcommand `{}` exited unsuccessfully", command_exe))
    }));
    Ok(())
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands(config: &Config) -> BTreeSet<String> {
    let prefix = "cargo-";
    let suffix = env::consts::EXE_SUFFIX;
    let mut commands = BTreeSet::new();
    for dir in search_directories(config) {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.filter_map(|e| e.ok()) {
            let path = entry.path();
            let filename = match path.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
                continue
            }
            if let Ok(meta) = entry.metadata() {
                if is_executable(&meta) {
                    let end = filename.len() - suffix.len();
                    commands.insert(filename[prefix.len()..end].to_string());
                }
            }
        }
    }

    macro_rules! add_cmd {
        ($cmd:ident) => ({ commands.insert(stringify!($cmd).replace("_", "-")); })
    }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable(metadata: &fs::Metadata) -> bool {
    use std::os::unix::prelude::*;
    metadata.is_file() && metadata.permissions().mode() & 0o111 != 0
}
#[cfg(windows)]
fn is_executable(metadata: &fs::Metadata) -> bool {
    metadata.is_file()
}

fn search_directories(config: &Config) -> Vec<PathBuf> {
    let mut dirs = vec![config.home().join("bin")];
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<|endoftext|>


<commit_before>use parse_args;
use std::io::{BufRead, BufReader};
use std::fs::File;
use std::collections::HashSet;

use filter::sv_locus_identifiers as sv_locus_identifiers;

const USAGE: &'static str = "
Usage:
  breakfast blacklist [options] <sv_files>...

Options:
  --freq-above=FREQ     Minimum samples to consider [default: 0]
";

pub fn main() {

    let args = parse_args(USAGE);
    let min_frequency: f32 = args.get_str("--freq-above").parse().unwrap();
	let sv_files = args.get_vec("<sv_files>").to_vec();
    let mut sample_variants: Vec<HashSet<String>> = Vec::new();

    for (s, sv_file) in sv_files.iter().enumerate() {

        let sv = BufReader::new(File::open(&sv_file).unwrap());
        let mut tmp: HashSet<String> = HashSet::new();

        for l in sv.lines() {
            let line = l.unwrap();
            if !line.starts_with("chr") { continue; }

            let tokens: Vec<&str> = line.split('\t').collect();
            let chrom = tokens[0];
            let pos: usize = tokens[2].parse().unwrap();
            let tmp1: HashSet<_> = sv_locus_identifiers(chrom, pos, 5000).into_iter().collect();

            let chrom = tokens[5];
            let pos: usize = tokens[7].parse().unwrap();
            let tmp2: HashSet<_> = sv_locus_identifiers(chrom, pos, 5000).into_iter().collect();

            tmp = tmp1.union(&tmp2).cloned().collect();
        }
        sample_variants.push(tmp);
    }

     let variants_cp = sample_variants.to_vec();
     let mut blacklist: HashSet<String> = HashSet::new();
     for loci in variants_cp {
        for l in loci {
         blacklist.insert(l);
        }
     }
     blacklist = natural_sorted(blacklist);

     let mut frequency: Vec<f32> = vec![0.0; blacklist.len()];
     for (k, bad_variant) in blacklist.iter().enumerate() {
        let mut bad_in_sample: Vec<usize> = vec![0; sample_variants.len()];
        for (n, loci) in sample_variants.iter().enumerate() {
            if loci.contains(bad_variant) {
                bad_in_sample[n] = 1;
                }
            }
        let sum: usize = bad_in_sample.iter().sum();
        let freq: f32  = sum as f32 / bad_in_sample.len() as f32;
        frequency[k]   = freq;
    }

    for (x, loci) in blacklist.iter().enumerate() {
        if frequency[x] >= min_frequency{
            println!("{}", loci);
        }
    }
}

pub fn natural_sorted(blacklist: HashSet<String>) -> HashSet<String> {
    let mut v: Vec<String> = blacklist.into_iter().collect();
    v.sort_by(|a, b| a.cmp(b));
    let out: HashSet<_> = v.into_iter().collect();
    out
}
<commit_msg>	modified:   src/blacklist.rs<commit_after>use parse_args;
use std::io::{BufRead, BufReader};
use std::fs::File;
use std::collections::HashSet;

use filter::sv_locus_identifiers as sv_locus_identifiers;

const USAGE: &'static str = "
Usage:
  breakfast blacklist [options] <sv_files>...

Options:
  --freq-above=FREQ     Minimum samples(0.0 - 1.0) to consider [default: 0.0]
";

pub fn main() {

    let args = parse_args(USAGE);
    let min_frequency: f32 = args.get_str("--freq-above").parse()
        .expect("\tERROR: *** Invalid frequency! *** \n");
	let sv_files = args.get_vec("<sv_files>").to_vec();
    let mut sample_variants: Vec<HashSet<String>> = Vec::new();

    for (s, sv_file) in sv_files.iter().enumerate() {

        let sv = BufReader::new(File::open(&sv_file).unwrap());
        let mut tmp: HashSet<String> = HashSet::new();

        for l in sv.lines() {
            let line = l.unwrap();
            if !line.starts_with("chr") { continue; }

            let tokens: Vec<&str> = line.split('\t').collect();
            let chrom = tokens[0];
            let pos: usize = tokens[2].parse().unwrap();
            let tmp1: HashSet<_> = sv_locus_identifiers(chrom, pos, 5000).into_iter().collect();

            let chrom = tokens[5];
            let pos: usize = tokens[7].parse().unwrap();
            let tmp2: HashSet<_> = sv_locus_identifiers(chrom, pos, 5000).into_iter().collect();

            tmp = tmp1.union(&tmp2).cloned().collect();
        }
        sample_variants.push(tmp);
    }

     let variants_cp = sample_variants.to_vec();
     let mut blacklist: HashSet<String> = HashSet::new();
     for loci in variants_cp {
        for l in loci {
         blacklist.insert(l);
        }
     }
     blacklist = natural_sorted(blacklist);

     let mut frequency: Vec<f32> = vec![0.0; blacklist.len()];
     for (k, bad_variant) in blacklist.iter().enumerate() {
        let mut bad_in_sample: Vec<usize> = vec![0; sample_variants.len()];
        for (n, loci) in sample_variants.iter().enumerate() {
            if loci.contains(bad_variant) {
                bad_in_sample[n] = 1;
                }
            }
        let sum: usize = bad_in_sample.iter().sum();
        let freq: f32  = sum as f32 / bad_in_sample.len() as f32;
        frequency[k]   = freq;
    }

    for (x, loci) in blacklist.iter().enumerate() {
        if frequency[x] >= min_frequency {
            println!("{}", loci);
        }
    }
}

pub fn natural_sorted(blacklist: HashSet<String>) -> HashSet<String> {
    let mut v: Vec<String> = blacklist.into_iter().collect();
    v.sort_by(|a, b| a.cmp(b));
    let out: HashSet<_> = v.into_iter().collect();
    out
}
<|endoftext|>


<commit_before>use std::ops::{Mul, Div, BitXor as Pow};

use smallvec::SmallVec;

use ast::{UnitExpr, UnitName, Span};
use unit_graph::{UnitGraph, UnitID};
use display_string::DisplayString;

#[derive(Debug, Clone)]
pub struct UndeclaredUnit<'a> {
    pub name: UnitName<'a>,
    pub span: Span<'a>,
}

/// We assume that most compound units won't involve more than this many units. This allows us to
/// store most unit representations entirely on the stack while "spilling" over to the heap if our
/// assumption turns out to be false. This constant can be changed over time based on experience.
/// The value of this constant affects the memory overhead of the compiler significantly if most
/// units are much smaller than this constant and it affects the compiler's performance
/// significantly if most units are larger than this constant.
const MAX_ASSUMED_UNIT_SIZE: usize = 8;

/// A CanonicalUnit is a unit expression in canonical form
///
/// e.g. 'a^x 'b^y 'c^z
///      where 'a, 'b, 'c are units and x, y, z are integers
///
/// The elements are guaranteed to be sorted by UnitID (ascending) and not have any duplicate
/// UnitIDs. No exponent will be zero.
///
/// The number of terms in a CanonicalUnit can be zero. In that case, the CanonicalUnit represents
/// a "unitless" quantity (denoted '_)
#[derive(Debug, Clone, Default, Hash, PartialEq, Eq)]
pub struct CanonicalUnit(SmallVec<[(UnitID, i64); MAX_ASSUMED_UNIT_SIZE]>);

/// Ensure that the terms are sorted and without duplicates
fn ensure_unit_invariants(terms: &[(UnitID, i64)]) {
    let mut last = None;
    for (term, x) in terms {
        if *x == 0 {
            panic!("bug: exponent in canonical unit was zero: {:?}",
                CanonicalUnit(SmallVec::from_slice(terms)));
        }
        if let Some(last) = last {
            if term == last {
                panic!("bug: duplicate unit in canonical representation: {:?}",
                    CanonicalUnit(SmallVec::from_slice(terms)));
            }
            else if term < last {
                panic!("bug: unsorted unit in canonical representation: {:?}",
                    CanonicalUnit(SmallVec::from_slice(terms)));
            }
        }
        else {
            last = Some(term);
        }
    }
}

macro_rules! unit_invariants_debug {
    ($name:ident) => {
        #[cfg(debug)]
        ensure_unit_invariants(&$name);
    };
}

impl CanonicalUnit {
    /// Returns the canonical unit that represents unitless
    pub fn unitless() -> Self {
        CanonicalUnit(SmallVec::new())
    }

    /// Canonicalizes a unit
    pub fn from_unit_expr<'a>(expr: &UnitExpr<'a>, units: &UnitGraph) -> Result<Self, UndeclaredUnit<'a>> {
        use self::UnitExpr::*;
        //TODO: Make sure unit is sorted
        Ok(match expr {
            Unit(name, _) if name.is_unitless() => CanonicalUnit::unitless(),
            Unit(name, span) => units.unit_id(name).map(Self::from).map_err(|_| UndeclaredUnit {
                name: name.clone(),
                span: span.clone(),
            })?,
            Mul(lhs, rhs, _) => {
                let lhs = CanonicalUnit::from_unit_expr(lhs, units)?;
                let rhs = CanonicalUnit::from_unit_expr(rhs, units)?;
                lhs * rhs
            },
            Div(lhs, rhs, _) => {
                let lhs = CanonicalUnit::from_unit_expr(lhs, units)?;
                let rhs = CanonicalUnit::from_unit_expr(rhs, units)?;
                lhs / rhs
            },
            Pow(lhs, exp, _) => {
                let lhs = CanonicalUnit::from_unit_expr(lhs, units)?;
                lhs ^ *exp
            },
        })
    }

    /// Returns true if this represents having no unit
    pub fn is_unitless(&self) -> bool {
        // "Unitless" means has no units
        self.0.is_empty()
    }

    /// Iterator over the unit names and exponents
    pub fn iter_unit_names<'a>(&'a self, units: &'a UnitGraph<'a>) -> impl Iterator<Item=(&UnitName<'a>, i64)> {
        self.0.iter().map(move |&(id, exp)| (units.unit_name(id), exp))
    }
}

impl From<UnitID> for CanonicalUnit {
    fn from(id: UnitID) -> Self {
        CanonicalUnit(smallvec![(id, 1)])
    }
}

impl DisplayString for CanonicalUnit {
    fn display<'a>(&self, units: &UnitGraph<'a>) -> String {
        if self.is_unitless() {
            return "'_".to_string();
        }

        fn print_unit<'b>(unit_name: &UnitName<'b>, exp: i64) -> String {
            if exp != 1 {
                format!("{}^{}", unit_name, exp)
            }
            else {
                format!("{}", unit_name)
            }
        }

        let mut names = self.iter_unit_names(units);

        let mut out = String::new();
        if let Some((unit_name, exp)) = names.next() {
            out += &print_unit(unit_name, exp);
        }
        for (unit_name, exp) in names {
            out += " ";
            out += &print_unit(unit_name, exp);
        }

        out
    }
}

// Maybe not a good idea to do this, but we're using Bitwise XOR ^ for exponentiation
impl Pow<i64> for CanonicalUnit {
    type Output = CanonicalUnit;

    fn bitxor(self, rhs: i64) -> Self::Output {
        &self ^ rhs
    }
}

impl<'a> Pow<i64> for &'a CanonicalUnit {
    type Output = CanonicalUnit;

    fn bitxor(self, rhs: i64) -> Self::Output {
        CanonicalUnit(self.0.iter()
            .map(|&(x, e)| (x, e * rhs))
            .filter(|&(_, e)| e != 0).collect())
    }
}

impl<'a> Mul<CanonicalUnit> for &'a CanonicalUnit {
    type Output = CanonicalUnit;

    fn mul(self, other: CanonicalUnit) -> Self::Output {
        self * &other
    }
}

impl Mul<CanonicalUnit> for CanonicalUnit {
    type Output = CanonicalUnit;

    fn mul(self, other: CanonicalUnit) -> Self::Output {
        &self * &other
    }
}

impl<'a> Mul<&'a CanonicalUnit> for &'a CanonicalUnit {
    type Output = CanonicalUnit;

    fn mul<'b>(self, other: &'b CanonicalUnit) -> Self::Output {
        let mut terms = smallvec![];

        let CanonicalUnit(lhs) = self;
        let CanonicalUnit(rhs) = other;
        unit_invariants_debug!(lhs);
        unit_invariants_debug!(rhs);
        let mut lhs_i = 0;
        let mut rhs_i = 0;
        while lhs_i < lhs.len() && rhs_i < rhs.len() {
            let (left, x) = lhs[lhs_i];
            let (right, y) = rhs[rhs_i];
            // Left must go after right in the sorted order
            if left > right {
                terms.push((right, y));
                rhs_i += 1;
            }
            // Right must go after left in the sorted order
            else if right > left {
                terms.push((left, x));
                lhs_i += 1;
            }
            // Both are equal and their counts must be added because 'a^x * 'a^y = 'a^(x+y)
            else {
                debug_assert!(left == right);
                let exponent = x + y;
                if exponent != 0 {
                    terms.push((left, exponent));
                }
                lhs_i += 1;
                rhs_i += 1;
            }
        }
        // Only up to one of these loops will run
        while lhs_i < lhs.len() {
            let (left, x) = lhs[lhs_i];
            terms.push((left, x));
            lhs_i += 1;
        }
        while rhs_i < rhs.len() {
            let (right, y) = rhs[rhs_i];
            terms.push((right, y));
            rhs_i += 1;
        }

        ensure_unit_invariants(&terms);
        CanonicalUnit(terms)
    }
}

impl<'a> Div<CanonicalUnit> for &'a CanonicalUnit {
    type Output = CanonicalUnit;

    fn div(self, other: CanonicalUnit) -> Self::Output {
        self / &other
    }
}

impl Div<CanonicalUnit> for CanonicalUnit {
    type Output = CanonicalUnit;

    fn div(self, other: CanonicalUnit) -> Self::Output {
        &self / &other
    }
}

//FIXME: Implement Mul and invert and then make Div = left * invert(right)
impl<'a> Div<&'a CanonicalUnit> for &'a CanonicalUnit {
    type Output = CanonicalUnit;

    fn div<'b>(self, other: &'b CanonicalUnit) -> Self::Output {
        // self / other == self * other^-1
        self * (other ^ -1)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    /// Generate variables for some UnitIDs
    ///
    /// unit_ids!(a, b, c) generates:
    ///
    ///    let a: UnitID = 0;
    ///    let b: UnitID = 1;
    ///    let c: UnitID = 2;
    macro_rules! unit_ids {
        // Use default counter
        ($name:ident, $($rest:tt)*) => {
            unit_ids!(0, $name, $($rest)*);
        };
        // Need to make the comma optional
        ($name:ident) => {
            unit_ids!(0, $name);
        };
        // Increment a given counter
        ($count:expr, $name:ident, $($rest:tt)*) => {
            unit_ids!($count, $name);
            unit_ids!($count + 1, $($rest)*);
        };
        // Need to make the comma optional
        ($count:expr, $name:ident) => {
            let $name: UnitID = $count;
        };
        // Base case
        ($count:expr) => ();
    }

    macro_rules! unit {
        ($($unit_name:ident ^ $exp:expr)*) => {
            {
                let mut terms = smallvec![$(($unit_name, $exp)),*];
                terms.sort_unstable_by(|&(a, _): &(UnitID, i64), &(b, _): &(UnitID, i64)| a.cmp(&b));
                ensure_unit_invariants(&terms);
                CanonicalUnit(terms)
            }
        };
    }

    #[test]
    fn pow() {
        // These are intentionally out of order so that we can test if the unit is sorted properly
        unit_ids!(a, c, b);
        let unit1 = &unit!(a^3 b^2 c^-2);
        // Should multiply the exponents
        assert_eq!(unit1 ^ 2, unit!(a^6 b^4 c^-4));
        assert_eq!(unit1 ^ -1, unit!(a^-3 b^-2 c^2));
        assert_eq!(unit1 ^ -2, unit!(a^-6 b^-4 c^4));
        assert_eq!(unit1 ^ 0, CanonicalUnit::unitless());
    }

    #[test]
    fn multiplication() {
        // These are intentionally out of order so that we can test if the unit is sorted properly
        unit_ids!(a, c, d, b);
        let unit1 = unit!(a^3 b^2 c^-2);
        let unit2 = unit!(b^-1 c^2 d^3);
        let expected = unit!(a^3 b^1 d^3);
        assert_eq!(unit1 * unit2, expected);
    }

    #[test]
    fn division() {
        // These are intentionally out of order so that we can test if the unit is sorted properly
        unit_ids!(b, c, a);
        let unit1 = unit!(a^1 b^1);
        let unit2 = unit!(a^1 b^2 c^3);
        let expected = unit!(b^-1 c^-3);
        assert_eq!(unit1 / unit2, expected);
    }
}
<commit_msg>Removed FIXME comment that has been resolved<commit_after>use std::ops::{Mul, Div, BitXor as Pow};

use smallvec::SmallVec;

use ast::{UnitExpr, UnitName, Span};
use unit_graph::{UnitGraph, UnitID};
use display_string::DisplayString;

#[derive(Debug, Clone)]
pub struct UndeclaredUnit<'a> {
    pub name: UnitName<'a>,
    pub span: Span<'a>,
}

/// We assume that most compound units won't involve more than this many units. This allows us to
/// store most unit representations entirely on the stack while "spilling" over to the heap if our
/// assumption turns out to be false. This constant can be changed over time based on experience.
/// The value of this constant affects the memory overhead of the compiler significantly if most
/// units are much smaller than this constant and it affects the compiler's performance
/// significantly if most units are larger than this constant.
const MAX_ASSUMED_UNIT_SIZE: usize = 8;

/// A CanonicalUnit is a unit expression in canonical form
///
/// e.g. 'a^x 'b^y 'c^z
///      where 'a, 'b, 'c are units and x, y, z are integers
///
/// The elements are guaranteed to be sorted by UnitID (ascending) and not have any duplicate
/// UnitIDs. No exponent will be zero.
///
/// The number of terms in a CanonicalUnit can be zero. In that case, the CanonicalUnit represents
/// a "unitless" quantity (denoted '_)
#[derive(Debug, Clone, Default, Hash, PartialEq, Eq)]
pub struct CanonicalUnit(SmallVec<[(UnitID, i64); MAX_ASSUMED_UNIT_SIZE]>);

/// Ensure that the terms are sorted and without duplicates
fn ensure_unit_invariants(terms: &[(UnitID, i64)]) {
    let mut last = None;
    for (term, x) in terms {
        if *x == 0 {
            panic!("bug: exponent in canonical unit was zero: {:?}",
                CanonicalUnit(SmallVec::from_slice(terms)));
        }
        if let Some(last) = last {
            if term == last {
                panic!("bug: duplicate unit in canonical representation: {:?}",
                    CanonicalUnit(SmallVec::from_slice(terms)));
            }
            else if term < last {
                panic!("bug: unsorted unit in canonical representation: {:?}",
                    CanonicalUnit(SmallVec::from_slice(terms)));
            }
        }
        else {
            last = Some(term);
        }
    }
}

macro_rules! unit_invariants_debug {
    ($name:ident) => {
        #[cfg(debug)]
        ensure_unit_invariants(&$name);
    };
}

impl CanonicalUnit {
    /// Returns the canonical unit that represents unitless
    pub fn unitless() -> Self {
        CanonicalUnit(SmallVec::new())
    }

    /// Canonicalizes a unit
    pub fn from_unit_expr<'a>(expr: &UnitExpr<'a>, units: &UnitGraph) -> Result<Self, UndeclaredUnit<'a>> {
        use self::UnitExpr::*;
        //TODO: Make sure unit is sorted
        Ok(match expr {
            Unit(name, _) if name.is_unitless() => CanonicalUnit::unitless(),
            Unit(name, span) => units.unit_id(name).map(Self::from).map_err(|_| UndeclaredUnit {
                name: name.clone(),
                span: span.clone(),
            })?,
            Mul(lhs, rhs, _) => {
                let lhs = CanonicalUnit::from_unit_expr(lhs, units)?;
                let rhs = CanonicalUnit::from_unit_expr(rhs, units)?;
                lhs * rhs
            },
            Div(lhs, rhs, _) => {
                let lhs = CanonicalUnit::from_unit_expr(lhs, units)?;
                let rhs = CanonicalUnit::from_unit_expr(rhs, units)?;
                lhs / rhs
            },
            Pow(lhs, exp, _) => {
                let lhs = CanonicalUnit::from_unit_expr(lhs, units)?;
                lhs ^ *exp
            },
        })
    }

    /// Returns true if this represents having no unit
    pub fn is_unitless(&self) -> bool {
        // "Unitless" means has no units
        self.0.is_empty()
    }

    /// Iterator over the unit names and exponents
    pub fn iter_unit_names<'a>(&'a self, units: &'a UnitGraph<'a>) -> impl Iterator<Item=(&UnitName<'a>, i64)> {
        self.0.iter().map(move |&(id, exp)| (units.unit_name(id), exp))
    }
}

impl From<UnitID> for CanonicalUnit {
    fn from(id: UnitID) -> Self {
        CanonicalUnit(smallvec![(id, 1)])
    }
}

impl DisplayString for CanonicalUnit {
    fn display<'a>(&self, units: &UnitGraph<'a>) -> String {
        if self.is_unitless() {
            return "'_".to_string();
        }

        fn print_unit<'b>(unit_name: &UnitName<'b>, exp: i64) -> String {
            if exp != 1 {
                format!("{}^{}", unit_name, exp)
            }
            else {
                format!("{}", unit_name)
            }
        }

        let mut names = self.iter_unit_names(units);

        let mut out = String::new();
        if let Some((unit_name, exp)) = names.next() {
            out += &print_unit(unit_name, exp);
        }
        for (unit_name, exp) in names {
            out += " ";
            out += &print_unit(unit_name, exp);
        }

        out
    }
}

// Maybe not a good idea to do this, but we're using Bitwise XOR ^ for exponentiation
impl Pow<i64> for CanonicalUnit {
    type Output = CanonicalUnit;

    fn bitxor(self, rhs: i64) -> Self::Output {
        &self ^ rhs
    }
}

impl<'a> Pow<i64> for &'a CanonicalUnit {
    type Output = CanonicalUnit;

    fn bitxor(self, rhs: i64) -> Self::Output {
        CanonicalUnit(self.0.iter()
            .map(|&(x, e)| (x, e * rhs))
            .filter(|&(_, e)| e != 0).collect())
    }
}

impl<'a> Mul<CanonicalUnit> for &'a CanonicalUnit {
    type Output = CanonicalUnit;

    fn mul(self, other: CanonicalUnit) -> Self::Output {
        self * &other
    }
}

impl Mul<CanonicalUnit> for CanonicalUnit {
    type Output = CanonicalUnit;

    fn mul(self, other: CanonicalUnit) -> Self::Output {
        &self * &other
    }
}

impl<'a> Mul<&'a CanonicalUnit> for &'a CanonicalUnit {
    type Output = CanonicalUnit;

    fn mul<'b>(self, other: &'b CanonicalUnit) -> Self::Output {
        let mut terms = smallvec![];

        let CanonicalUnit(lhs) = self;
        let CanonicalUnit(rhs) = other;
        unit_invariants_debug!(lhs);
        unit_invariants_debug!(rhs);
        let mut lhs_i = 0;
        let mut rhs_i = 0;
        while lhs_i < lhs.len() && rhs_i < rhs.len() {
            let (left, x) = lhs[lhs_i];
            let (right, y) = rhs[rhs_i];
            // Left must go after right in the sorted order
            if left > right {
                terms.push((right, y));
                rhs_i += 1;
            }
            // Right must go after left in the sorted order
            else if right > left {
                terms.push((left, x));
                lhs_i += 1;
            }
            // Both are equal and their counts must be added because 'a^x * 'a^y = 'a^(x+y)
            else {
                debug_assert!(left == right);
                let exponent = x + y;
                if exponent != 0 {
                    terms.push((left, exponent));
                }
                lhs_i += 1;
                rhs_i += 1;
            }
        }
        // Only up to one of these loops will run
        while lhs_i < lhs.len() {
            let (left, x) = lhs[lhs_i];
            terms.push((left, x));
            lhs_i += 1;
        }
        while rhs_i < rhs.len() {
            let (right, y) = rhs[rhs_i];
            terms.push((right, y));
            rhs_i += 1;
        }

        ensure_unit_invariants(&terms);
        CanonicalUnit(terms)
    }
}

impl<'a> Div<CanonicalUnit> for &'a CanonicalUnit {
    type Output = CanonicalUnit;

    fn div(self, other: CanonicalUnit) -> Self::Output {
        self / &other
    }
}

impl Div<CanonicalUnit> for CanonicalUnit {
    type Output = CanonicalUnit;

    fn div(self, other: CanonicalUnit) -> Self::Output {
        &self / &other
    }
}

impl<'a> Div<&'a CanonicalUnit> for &'a CanonicalUnit {
    type Output = CanonicalUnit;

    fn div<'b>(self, other: &'b CanonicalUnit) -> Self::Output {
        // self / other == self * other^-1
        self * (other ^ -1)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    /// Generate variables for some UnitIDs
    ///
    /// unit_ids!(a, b, c) generates:
    ///
    ///    let a: UnitID = 0;
    ///    let b: UnitID = 1;
    ///    let c: UnitID = 2;
    macro_rules! unit_ids {
        // Use default counter
        ($name:ident, $($rest:tt)*) => {
            unit_ids!(0, $name, $($rest)*);
        };
        // Need to make the comma optional
        ($name:ident) => {
            unit_ids!(0, $name);
        };
        // Increment a given counter
        ($count:expr, $name:ident, $($rest:tt)*) => {
            unit_ids!($count, $name);
            unit_ids!($count + 1, $($rest)*);
        };
        // Need to make the comma optional
        ($count:expr, $name:ident) => {
            let $name: UnitID = $count;
        };
        // Base case
        ($count:expr) => ();
    }

    macro_rules! unit {
        ($($unit_name:ident ^ $exp:expr)*) => {
            {
                let mut terms = smallvec![$(($unit_name, $exp)),*];
                terms.sort_unstable_by(|&(a, _): &(UnitID, i64), &(b, _): &(UnitID, i64)| a.cmp(&b));
                ensure_unit_invariants(&terms);
                CanonicalUnit(terms)
            }
        };
    }

    #[test]
    fn pow() {
        // These are intentionally out of order so that we can test if the unit is sorted properly
        unit_ids!(a, c, b);
        let unit1 = &unit!(a^3 b^2 c^-2);
        // Should multiply the exponents
        assert_eq!(unit1 ^ 2, unit!(a^6 b^4 c^-4));
        assert_eq!(unit1 ^ -1, unit!(a^-3 b^-2 c^2));
        assert_eq!(unit1 ^ -2, unit!(a^-6 b^-4 c^4));
        assert_eq!(unit1 ^ 0, CanonicalUnit::unitless());
    }

    #[test]
    fn multiplication() {
        // These are intentionally out of order so that we can test if the unit is sorted properly
        unit_ids!(a, c, d, b);
        let unit1 = unit!(a^3 b^2 c^-2);
        let unit2 = unit!(b^-1 c^2 d^3);
        let expected = unit!(a^3 b^1 d^3);
        assert_eq!(unit1 * unit2, expected);
    }

    #[test]
    fn division() {
        // These are intentionally out of order so that we can test if the unit is sorted properly
        unit_ids!(b, c, a);
        let unit1 = unit!(a^1 b^1);
        let unit2 = unit!(a^1 b^2 c^3);
        let expected = unit!(b^-1 c^-3);
        assert_eq!(unit1 / unit2, expected);
    }
}
<|endoftext|>


<commit_before>#![crate_id="cargo"]
#![crate_type="rlib"]

#![feature(macro_rules, phase)]

extern crate debug;
extern crate term;
extern crate url;
extern crate serialize;
extern crate semver;
extern crate toml;

#[phase(plugin, link)]
extern crate hammer;

#[phase(plugin, link)]
extern crate log;

#[cfg(test)]
extern crate hamcrest;

use serialize::{Decoder, Encoder, Decodable, Encodable, json};
use std::io;
use std::io::{stdout, stderr};
use std::io::stdio::{stdout_raw, stderr_raw};
use hammer::{Flags, decode_args, usage};

use core::{Shell, MultiShell, ShellConfig};
use term::color::{BLACK};

pub use util::{CargoError, CliError, CliResult, human};

macro_rules! some(
    ($e:expr) => (
        match $e {
            Some(e) => e,
            None => return None
        }
    )
)

// Added so that the try! macro below can refer to cargo::util, while
// other external importers of this macro can use it as well.
//
// "Hygiene strikes again" - @acrichton
mod cargo {
    pub use super::util;
}

#[macro_export]
macro_rules! try (
    ($expr:expr) => ({
        use cargo::util::FromError;
        match $expr.map_err(FromError::from_error) {
            Ok(val) => val,
            Err(err) => return Err(err)
        }
    })
)

macro_rules! raw_try (
    ($expr:expr) => ({
        match $expr {
            Ok(val) => val,
            Err(err) => return Err(err)
        }
    })
)

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

trait RepresentsJSON : Decodable<json::Decoder, json::DecoderError> {}
impl<T: Decodable<json::Decoder, json::DecoderError>> RepresentsJSON for T {}

#[deriving(Decodable)]
pub struct NoFlags;

hammer_config!(NoFlags)

#[deriving(Decodable)]
pub struct GlobalFlags {
    verbose: bool,
    help: bool,
    rest: Vec<String>
}

hammer_config!(GlobalFlags |c| {
    c.short("verbose", 'v').short("help", 'h')
})

pub fn execute_main<'a,
                    T: Flags,
                    U: RepresentsJSON,
                    V: Encodable<json::Encoder<'a>, io::IoError>>(
                        exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>)
{
    fn call<'a,
            T: Flags,
            U: RepresentsJSON,
            V: Encodable<json::Encoder<'a>, io::IoError>>(
                exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
                shell: &mut MultiShell,
                args: &[String])
        -> CliResult<Option<V>>
    {
        let flags = try!(flags_from_args::<T>(args));
        let json = try!(json_from_stdin::<U>());

        exec(flags, json, shell)
    }

    process::<T, V>(|rest, shell| call(exec, shell, rest));
}

pub fn execute_main_without_stdin<'a,
                                  T: Flags,
                                  V: Encodable<json::Encoder<'a>, io::IoError>>(
                                      exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>)
{
    fn call<'a,
            T: Flags,
            V: Encodable<json::Encoder<'a>, io::IoError>>(
                exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
                shell: &mut MultiShell,
                args: &[String])
        -> CliResult<Option<V>>
    {
        let flags = try!(flags_from_args::<T>(args));
        exec(flags, shell)
    }

    process::<T, V>(|rest, shell| call(exec, shell, rest));
}

fn process<'a,
           T: Flags,
           V: Encodable<json::Encoder<'a>, io::IoError>>(
               callback: |&[String], &mut MultiShell| -> CliResult<Option<V>>) {

    match global_flags() {
        Err(e) => handle_error(e, &mut shell(false)),
        Ok(val) => {
            let mut shell = shell(val.verbose);

            if val.help {
                let (desc, options) = usage::<T>(true);

                desc.map(|d| println!("{}\n", d));

                println!("Options:\n");

                print!("{}", options);

                let (_, options) = usage::<GlobalFlags>(false);
                print!("{}", options);
            } else {
                process_executed(callback(val.rest.as_slice(), &mut shell), &mut shell)
            }
        }
    }
}

pub fn process_executed<'a,
                        T: Encodable<json::Encoder<'a>, io::IoError>>(
                            result: CliResult<Option<T>>,
                            shell: &mut MultiShell)
{
    match result {
        Err(e) => handle_error(e, shell),
        Ok(encodable) => {
            encodable.map(|encodable| {
                let encoded = json::Encoder::str_encode(&encodable);
                println!("{}", encoded);
            });
        }
    }
}

pub fn shell(verbose: bool) -> MultiShell {
    let tty = stderr_raw().isatty();
    let stderr = box stderr() as Box<Writer>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let err = Shell::create(stderr, config);

    let tty = stdout_raw().isatty();
    let stdout = box stdout() as Box<Writer>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let out = Shell::create(stdout, config);

    MultiShell::new(out, err, verbose)
}

pub fn handle_error(err: CliError, shell: &mut MultiShell) {
    log!(4, "handle_error; err={}", err);

    let CliError { error, exit_code, unknown, .. } = err;

    if unknown {
        let _ = shell.error("An unknown error occurred");
    } else {
        let _ = shell.error(error.to_str());
    }

    if error.cause().is_some() {
        let _ = shell.concise(|shell| {
            shell.err().say("\nTo learn more, run the command again with --verbose.", BLACK)
        });
    }

    let _ = shell.verbose(|shell| {
        let _ = handle_cause(error, shell);
        Ok(())
      });

    std::os::set_exit_status(exit_code as int);
}

fn handle_cause(err: &CargoError, shell: &mut MultiShell) {
    let _ = shell.err().say("\nCaused by:", BLACK);
    let _ = shell.err().say(format!("  {}", err.description()), BLACK);

    err.cause().map(|e| handle_cause(e, shell));
}

fn args() -> Vec<String> {
    std::os::args()
}

fn flags_from_args<T: Flags>(args: &[String]) -> CliResult<T> {
    decode_args(args).map_err(|e| {
        CliError::new(e.message, 1)
    })
}

fn global_flags() -> CliResult<GlobalFlags> {
    decode_args(args().tail()).map_err(|e| {
        CliError::new(e.message, 1)
    })
}

fn json_from_stdin<T: RepresentsJSON>() -> CliResult<T> {
    let mut reader = io::stdin();
    let input = try!(reader.read_to_str().map_err(|_| {
        CliError::new("Standard in did not exist or was not UTF-8", 1)
    }));

    let json = try!(json::from_str(input.as_slice()).map_err(|_| {
        CliError::new("Could not parse standard in as JSON", 1)
    }));
    let mut decoder = json::Decoder::new(json);

    Decodable::decode(&mut decoder).map_err(|_| {
        CliError::new("Could not process standard in as input", 1)
    })
}
<commit_msg>auto merge of #109 : steveklabnik/cargo/json, r=alexcrichton<commit_after>#![crate_id="cargo"]
#![crate_type="rlib"]

#![feature(macro_rules, phase)]

extern crate debug;
extern crate term;
extern crate url;
extern crate serialize;
extern crate semver;
extern crate toml;

#[phase(plugin, link)]
extern crate hammer;

#[phase(plugin, link)]
extern crate log;

#[cfg(test)]
extern crate hamcrest;

use serialize::{Decoder, Encoder, Decodable, Encodable, json};
use std::io;
use std::io::{stdout, stderr};
use std::io::stdio::{stdout_raw, stderr_raw};
use hammer::{Flags, decode_args, usage};

use core::{Shell, MultiShell, ShellConfig};
use term::color::{BLACK};

pub use util::{CargoError, CliError, CliResult, human};

macro_rules! some(
    ($e:expr) => (
        match $e {
            Some(e) => e,
            None => return None
        }
    )
)

// Added so that the try! macro below can refer to cargo::util, while
// other external importers of this macro can use it as well.
//
// "Hygiene strikes again" - @acrichton
mod cargo {
    pub use super::util;
}

#[macro_export]
macro_rules! try (
    ($expr:expr) => ({
        use cargo::util::FromError;
        match $expr.map_err(FromError::from_error) {
            Ok(val) => val,
            Err(err) => return Err(err)
        }
    })
)

macro_rules! raw_try (
    ($expr:expr) => ({
        match $expr {
            Ok(val) => val,
            Err(err) => return Err(err)
        }
    })
)

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

trait RepresentsJSON : Decodable<json::Decoder, json::DecoderError> {}
impl<T: Decodable<json::Decoder, json::DecoderError>> RepresentsJSON for T {}

#[deriving(Decodable)]
pub struct NoFlags;

hammer_config!(NoFlags)

#[deriving(Decodable)]
pub struct GlobalFlags {
    verbose: bool,
    help: bool,
    rest: Vec<String>
}

hammer_config!(GlobalFlags |c| {
    c.short("verbose", 'v').short("help", 'h')
})

pub fn execute_main<'a,
                    T: Flags,
                    U: RepresentsJSON,
                    V: Encodable<json::Encoder<'a>, io::IoError>>(
                        exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>)
{
    fn call<'a,
            T: Flags,
            U: RepresentsJSON,
            V: Encodable<json::Encoder<'a>, io::IoError>>(
                exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
                shell: &mut MultiShell,
                args: &[String])
        -> CliResult<Option<V>>
    {
        let flags = try!(flags_from_args::<T>(args));
        let json = try!(json_from_stdin::<U>());

        exec(flags, json, shell)
    }

    process::<T, V>(|rest, shell| call(exec, shell, rest));
}

pub fn execute_main_without_stdin<'a,
                                  T: Flags,
                                  V: Encodable<json::Encoder<'a>, io::IoError>>(
                                      exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>)
{
    fn call<'a,
            T: Flags,
            V: Encodable<json::Encoder<'a>, io::IoError>>(
                exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
                shell: &mut MultiShell,
                args: &[String])
        -> CliResult<Option<V>>
    {
        let flags = try!(flags_from_args::<T>(args));
        exec(flags, shell)
    }

    process::<T, V>(|rest, shell| call(exec, shell, rest));
}

fn process<'a,
           T: Flags,
           V: Encodable<json::Encoder<'a>, io::IoError>>(
               callback: |&[String], &mut MultiShell| -> CliResult<Option<V>>) {

    match global_flags() {
        Err(e) => handle_error(e, &mut shell(false)),
        Ok(val) => {
            let mut shell = shell(val.verbose);

            if val.help {
                let (desc, options) = usage::<T>(true);

                desc.map(|d| println!("{}\n", d));

                println!("Options:\n");

                print!("{}", options);

                let (_, options) = usage::<GlobalFlags>(false);
                print!("{}", options);
            } else {
                process_executed(callback(val.rest.as_slice(), &mut shell), &mut shell)
            }
        }
    }
}

pub fn process_executed<'a,
                        T: Encodable<json::Encoder<'a>, io::IoError>>(
                            result: CliResult<Option<T>>,
                            shell: &mut MultiShell)
{
    match result {
        Err(e) => handle_error(e, shell),
        Ok(encodable) => {
            encodable.map(|encodable| {
                let encoded = json::encode(&encodable);
                println!("{}", encoded);
            });
        }
    }
}

pub fn shell(verbose: bool) -> MultiShell {
    let tty = stderr_raw().isatty();
    let stderr = box stderr() as Box<Writer>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let err = Shell::create(stderr, config);

    let tty = stdout_raw().isatty();
    let stdout = box stdout() as Box<Writer>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let out = Shell::create(stdout, config);

    MultiShell::new(out, err, verbose)
}

pub fn handle_error(err: CliError, shell: &mut MultiShell) {
    log!(4, "handle_error; err={}", err);

    let CliError { error, exit_code, unknown, .. } = err;

    if unknown {
        let _ = shell.error("An unknown error occurred");
    } else {
        let _ = shell.error(error.to_str());
    }

    if error.cause().is_some() {
        let _ = shell.concise(|shell| {
            shell.err().say("\nTo learn more, run the command again with --verbose.", BLACK)
        });
    }

    let _ = shell.verbose(|shell| {
        let _ = handle_cause(error, shell);
        Ok(())
      });

    std::os::set_exit_status(exit_code as int);
}

fn handle_cause(err: &CargoError, shell: &mut MultiShell) {
    let _ = shell.err().say("\nCaused by:", BLACK);
    let _ = shell.err().say(format!("  {}", err.description()), BLACK);

    err.cause().map(|e| handle_cause(e, shell));
}

fn args() -> Vec<String> {
    std::os::args()
}

fn flags_from_args<T: Flags>(args: &[String]) -> CliResult<T> {
    decode_args(args).map_err(|e| {
        CliError::new(e.message, 1)
    })
}

fn global_flags() -> CliResult<GlobalFlags> {
    decode_args(args().tail()).map_err(|e| {
        CliError::new(e.message, 1)
    })
}

fn json_from_stdin<T: RepresentsJSON>() -> CliResult<T> {
    let mut reader = io::stdin();
    let input = try!(reader.read_to_str().map_err(|_| {
        CliError::new("Standard in did not exist or was not UTF-8", 1)
    }));

    let json = try!(json::from_str(input.as_slice()).map_err(|_| {
        CliError::new("Could not parse standard in as JSON", 1)
    }));
    let mut decoder = json::Decoder::new(json);

    Decodable::decode(&mut decoder).map_err(|_| {
        CliError::new("Could not process standard in as input", 1)
    })
}
<|endoftext|>


<commit_before>use csv;
use std::result;
use std::str;
use std::process;
use curl::http;
use rustc_serialize::json;

pub fn run(owner: &str,
           repo: &str,
           oauth_token: String,
           labels: Vec<String>) {
    let url = format!("https://api.github.com/repos/{}/{}/issues", owner, repo);
    let auth_header = format!("token {}", oauth_token);

    // println!("{:?}, {:?}", owner, repo);
    // println!("{:?}", url);
    // println!("{:?}", labels);

    let res = http::handle()
                   .get(url)
                   .header("Authorization", &auth_header)
                   .header("User-Agent", "Github-Issues-CLI")
                   .header("Accept", "application/vnd.github.v3+json")
                   .exec()
                   .unwrap_or_else(|e| process::exit(1));

    let body = match str::from_utf8(res.get_body()) {
        Ok(b) => b,
        Err(..) => "Unable to parse"
    };

    let issues_result: result::Result<Vec<Issue>,_> = json::decode(body);
    let issues = issues_result.unwrap();
    // println!("{:?}", issues);

    println!("{:?}", res.get_headers().get("Link"));
    // println!("code={}; headers={:?}",
    //          res.get_code(),
    //          res.get_headers());

    // let mut wtr = csv::Writer::from_memory();
    let mut wtr = csv::Writer::from_file("foo.csv").unwrap();
    let headers = ("number",
                   "title",
                   "state",
                   "created_at",
                   "closed_at",
                   "user",
                   "labels",
                   "body");
    wtr.encode(headers);

    for issue in issues {
        let labels = issue.labels.iter()
                                 .map(|x| x.name.clone())
                                 .collect::<Vec<String>>()
                                 .join(",");

        let row = (issue.number,
                   issue.title,
                   issue.state,
                   issue.created_at,
                   issue.closed_at,
                   issue.user.login,
                   labels,
                   issue.body);

        // println!("{:?}", row);
        // let result = wtr.encode(row);
        // println!("{:?}", result.is_ok());
        wtr.encode(row);
    }

    // println!("{:?}", wtr.as_string());
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Issue {
    body: Option<String>,
    created_at: Option<String>,
    closed_at: Option<String>,
    labels: Vec<Label>,
    number: u32,
    state: Option<String>,
    title: Option<String>,
    user: User,
}

type Labels = Vec<Label>;

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Label {
    color: String,
    name: String,
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct User {
    login: String,
}
<commit_msg>Extract get_page()<commit_after>use csv;
use std::result::Result;
use std::str;
use std::process;
use curl::http;
use rustc_serialize::json;

// fn get_page(url: String, token: String) -> Result<Vec<Issue>, json::DecoderError> {
//     let auth_header = format!("token {}", token);
//     let res = http::handle()
//                    .get(url)
//                    .header("Authorization", &auth_header)
//                    .header("User-Agent", "Github-Issues-CLI")
//                    .header("Accept", "application/vnd.github.v3+json")
//                    .exec()
//                    .unwrap_or_else(|e| process::exit(1));

//     let body = match str::from_utf8(res.get_body()) {
//         Ok(b) => b,
//         Err(..) => "Unable to parse"
//     };

//     // let issues_result: Result<Vec<Issue>,_> = json::decode(body);
//     // issues_result
//     json::decode(body)
// }

fn get_page(owner: &str,
            repo: &str,
            page: u16,
            labels: Vec<String>,
            token: String) -> http::Response {

    let url = format!("https://api.github.com/repos/{}/{}/issues?state=all&page={}",
                      owner, repo, page);
    let auth_header = format!("token {}", token);
    let res = http::handle()
                   .get(url)
                   .header("Authorization", &auth_header)
                   .header("User-Agent", "Github-Issues-CLI")
                   .header("Accept", "application/vnd.github.v3+json")
                   .exec()
                   .unwrap_or_else(|e| process::exit(1));

    res
}

pub fn run(owner: &str,
           repo: &str,
           oauth_token: String,
           labels: Vec<String>) {

    let page = 1;
    let res = get_page(owner, repo, page, labels, oauth_token);
    let body = match str::from_utf8(res.get_body()) {
        Ok(b) => b,
        Err(..) => "Unable to parse"
    };

    let issues_result: Result<Vec<Issue>,_> = json::decode(body);
    let issues = issues_result.unwrap();
    // println!("{:?}", issues);

    println!("{:?}", res.get_headers().get("link"));
    for (k, v) in res.get_headers() {
        println!("{:?}: {:?}", k, v);
    }
    // println!("code={}; headers={:?}",
    //          res.get_code(),
    //          res.get_headers());

    // let mut wtr = csv::Writer::from_memory();
    let mut wtr = csv::Writer::from_file("foo.csv").unwrap();
    let headers = ("number",
                   "title",
                   "state",
                   "created_at",
                   "closed_at",
                   "user",
                   "labels",
                   "body");
    wtr.encode(headers);

    println!("{:?}", issues.len());

    for issue in issues {
        let labels = issue.labels.iter()
                                 .map(|x| x.name.clone())
                                 .collect::<Vec<String>>()
                                 .join(",");

        let row = (issue.number,
                   issue.title,
                   issue.state,
                   issue.created_at,
                   issue.closed_at,
                   issue.user.login,
                   labels,
                   issue.body);

        // println!("{:?}", row);
        // let result = wtr.encode(row);
        // println!("{:?}", result.is_ok());
        wtr.encode(row);
    }

    // println!("{:?}", wtr.as_string());
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Issue {
    body: Option<String>,
    created_at: Option<String>,
    closed_at: Option<String>,
    labels: Vec<Label>,
    number: u32,
    state: Option<String>,
    title: Option<String>,
    user: User,
}

type Labels = Vec<Label>;

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Label {
    color: String,
    name: String,
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct User {
    login: String,
}
<|endoftext|>


<commit_before>extern crate gcc;

fn main()
{
    gcc::Config::new().cpp(true)
        .file("wrapper/wrapper.cpp")
        .file("pugixml/src/pugixml.cpp")
        .include("pugixml/src")
        .flag("-std=c++1y")
        .compile("libpugixml.a")
}
<commit_msg>Fixing std c++1y to c++11 for travis CI<commit_after>extern crate gcc;

fn main()
{
    gcc::Config::new().cpp(true)
        .file("wrapper/wrapper.cpp")
        .file("pugixml/src/pugixml.cpp")
        .include("pugixml/src")
        .flag("-std=c++11")
        .compile("libpugixml.a")
}
<|endoftext|>


<commit_before>use std::str;
use std::path::Path;
use std::process::{self, Command};

extern crate capnpc;

fn main() {

    // CAPNP_INCLUDE_DIR=$(shell dirname $(shell which capnp))/../include

    let prefix = {
        let output = Command::new("which")
                             .arg("capnp")
                             .output()
                             .expect("Failed to run `which capnp`");

        if !output.status.success() {
            println!("Failed to find `capnp` executable");
            process::exit(1);
        }

        let path = Path::new(str::from_utf8(&output.stdout).unwrap());
        let mut path1 = path.parent().unwrap().parent().unwrap().to_path_buf();
        path1.push("include/capnp");
        path1
    };

    capnpc::compile(&prefix,
                    &[&prefix.clone().join("rpc.capnp"),
                      &prefix.join("rpc-twoparty.capnp")]).unwrap();
}
<commit_msg>Update to modern Path api<commit_after>use std::str;
use std::path::Path;
use std::process::{self, Command};

extern crate capnpc;

fn main() {

    // CAPNP_INCLUDE_DIR=$(shell dirname $(shell which capnp))/../include

    let prefix = {
        let output = Command::new("which")
                             .arg("capnp")
                             .output()
                             .expect("Failed to run `which capnp`");

        if !output.status.success() {
            println!("Failed to find `capnp` executable");
            process::exit(1);
        }

        let path = Path::new(str::from_utf8(&output.stdout).unwrap());
        path.join("../../include/capnp")
    };

    capnpc::compile(&prefix,
                    &[prefix.join("rpc.capnp"),
                      prefix.join("rpc-twoparty.capnp")]).unwrap();
}
<|endoftext|>