<commit_before>/* Stones esoteric programming language
 * (c) 2016 Zack Hixon - see LICENSE.txt */

/** NOTE: Hey there! This isn't even remotely started yet. I'm gonna need a
 * WHOLE lot of stuff to make this even *resemble* an interpreter. It also
 * isn't currently up-to-date with the "specification," so it features
 * misleading stuff like the Stone struct right below this, along with the
 * field vector.  Expect a lot of this stuff to change. */

#[derive(Debug)]
struct Stone {
    x: i32,
    y: i32,
    color: Color
}

impl Stone {
    fn new(x: i32, y: i32, color: Color) -> Stone {
        Stone {
            x: x,
            y: y,
            color: color
        }
    }

    /* only check stones with 0 <= x <= 9 and 0 <= y <= 9 */
    fn empty() -> Stone {
        Stone {
            x: -1,
            y: -1,
            color: Color::Invis
        }
    }
}

#[derive(Debug)]
enum Color {
    Red,
    Orange,
    Yellow,
    Green,
    Blue,
    Purple,
    Invis
}

fn main() {
    println!("test stone: (debug)");

    let mut test_stone = Stone {
        x: 0,
        y: 0,
        color: Color::Yellow
    };

    println!("{:?}", test_stone);

    test_stone.x = 1;
    test_stone.y = 1;
    test_stone.color = Color::Blue;

    println!("{:?}", test_stone);

    let mut field: Vec<Vec<Color>> = /* so much for 80 columns */
        vec![vec![Color::Blue,  Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Orange,Color::Invis, Color::Invis, Color::Invis, Color::Invis ],
             vec![Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis ],
             vec![Color::Invis, Color::Invis, Color::Red,   Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Green, Color::Invis, Color::Invis ],
             vec![Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis ],
             vec![Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Yellow,Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Purple],
             vec![Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis ]];

    for row in &field {
        for color in row {
            match color {
                &Color::Red => print!("{:?}... ", color),
                &Color::Orange => print!("{:?} ", color),
                &Color::Yellow => print!("{:?} ", color),
                &Color::Green => print!("{:?}. ", color),
                &Color::Blue => print!("{:?}.. ", color),
                &Color::Purple => print!("{:?} ", color),
                &Color::Invis => print!("...... "), /* oh. */
            }
        }
        println!("");
    }
}

<commit_msg>Remove stone field<commit_after>/* Stones esoteric programming language
 * (c) 2016 Zack Hixon - see LICENSE.txt */

#[derive(Debug)]
enum Color {
    Red,
    Orange,
    Yellow,
    Green,
    Blue,
    Purple,
    Invis
}

fn main() {
    let mut field: Vec<Vec<Color>> = /* so much for 80 columns */
        vec![vec![Color::Blue,  Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Orange,Color::Invis, Color::Invis, Color::Invis, Color::Invis ],
             vec![Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis ],
             vec![Color::Invis, Color::Invis, Color::Red,   Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Green, Color::Invis, Color::Invis ],
             vec![Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis ],
             vec![Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Yellow,Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Purple],
             vec![Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis ]];

    for row in &field {
        for color in row {
            match color {
                &Color::Red => print!("{:?}... ", color),
                &Color::Orange => print!("{:?} ", color),
                &Color::Yellow => print!("{:?} ", color),
                &Color::Green => print!("{:?}. ", color),
                &Color::Blue => print!("{:?}.. ", color),
                &Color::Purple => print!("{:?} ", color),
                &Color::Invis => print!("...... "), /* oh. */
            }
        }
        println!("");
    }
}

<|endoftext|>


<commit_before>//! emit_bosun -- Emits a single metric datum and corresponding metric meta data to [Bosun](http:////bosun.org).

extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate log;

extern crate bosun_emitter;

use clap::{Arg, ArgMatches, App};
use std::error::Error;
use std::path::Path;

use bosun_emitter::{BosunClient, Metadata, Datum, Tags, EmitterError, BosunConfig};

static VERSION: &'static str = env!("CARGO_PKG_VERSION");
static DEFAULT_CONFIG_FILE: &'static str = "/etc/bosun/scollector.conf";

#[derive(Debug)]
struct Config {
    host: String,
    hostname: String,
    metric: Option<String>,
    value: Option<String>,
    rate: Option<String>,
    unit: Option<String>,
    description: Option<String>,
    tags: Tags,
}

impl Config {
    pub fn default() -> Config {
        let bosun_config = BosunConfig::default();
        Config::from_bosun_config(bosun_config)
    }

    pub fn from_bosun_config(bosun_config: BosunConfig) -> Config {
        Config {
            host: bosun_config.Host,
            hostname: bosun_config.Hostname,
            metric: None,
            value: None,
            rate: None,
            unit: None,
            description: None,
            tags: bosun_config.Tags
        }
    }
}

fn main() {
    if env_logger::init().is_err() {
        exit_with_error("Could not initiliaze logger", -1);
    }

    let cli_args = App::new("Emit a Bosun")
                       .version(VERSION)
                       .after_help("Two modes are supported, i.e., sending a datum with meta \
                                    data or sending only meta data. The modes are controlled \
                                    whether a value `--value` is passed or not. Please mind that \
                                    in both cases the meta data is required.")
                       .arg(Arg::with_name("config")
                                .short("c")
                                .long("config")
                                .value_name("FILE")
                                .help("Sets a custom config file")
                                .takes_value(true))
                       .arg(Arg::with_name("host")
                                .long("host")
                                .value_name("HOST:PORT")
                                .help("Sets Bosun server connection parameters")
                                .takes_value(true))
                       .arg(Arg::with_name("hostname")
                                .long("hostname")
                                .value_name("HOSTNAME")
                                .help("Sets hostname")
                                .takes_value(true))
                       .arg(Arg::with_name("metric")
                                .short("m")
                                .long("metric")
                                .value_name("METRIC NAME")
                                .help("Sets metric name")
                                .takes_value(true))
                       .arg(Arg::with_name("value")
                                .requires("metric")
                                .short("v")
                                .long("value")
                                .value_name("VALUE")
                                .help("Sets metric value")
                                .takes_value(true))
                       .arg(Arg::with_name("rate")
                                .requires_all(&["metric", "rate", "unit", "description"])
                                .short("r")
                                .long("rate")
                                .value_name("RATE")
                                .possible_values(&["gauge", "counter", "rate"])
                                .help("Sets rate type")
                                .takes_value(true))
                       .arg(Arg::with_name("unit")
                                .requires_all(&["metric", "rate", "unit", "description"])
                                .short("u")
                                .long("unit")
                                .value_name("UNIT")
                                .help("Sets metric value unit")
                                .takes_value(true))
                       .arg(Arg::with_name("description")
                                .requires_all(&["metric", "rate", "unit", "description"])
                                .short("d")
                                .long("description")
                                .value_name("DESCRIPTION")
                                .help("Sets metric description")
                                .takes_value(true))
                       .arg(Arg::with_name("tags")
                                .use_delimiter(false)
                                .short("t")
                                .long("tags")
                                .value_name("KEY1=VALUE1,KEY2=VALUE2,...")
                                .help("Sets tags")
                                .takes_value(true))
                       .arg(Arg::with_name("show-config")
                                .long("show-config")
                                .help("Prints config"))
                       .arg(Arg::with_name("verbose")
                                .long("verbose")
                                .help("Enables verbose output"))
                       .arg(Arg::with_name("force")
                                .hidden(true)
                                .long("force")
                                .help("Forces metric datum to be send even without meta data"))
                       .get_matches();

    let force: bool = cli_args.is_present("force");
    let verbose: bool = cli_args.is_present("verbose");
    let config: Config = match parse_args(&cli_args) {
        Ok(config) => config,
        Err(err) => {
            exit_with_error(&format!("Failed to parse configuration, because {}.", err),
                            -2);
        }
    };
    if cli_args.is_present("show-config") {
        println!("config: {:?}", config);
    }

    let mode = match mode(&config, force) {
        Ok(mode) => mode,
        Err(ModeError::NoMetadata) => exit_with_error("Cannot send datum without meta data.", -11),
        Err(ModeError::NoValue) => exit_with_error("Cannot send datum without value.", -12),
        Err(ModeError::NoSuchMode) => {
            exit_with_error("Command line arguments combination does not make any sense.",
                            -13);
        }
    };

    let result = run(&config, mode, verbose);
    match result {
        Ok(_) => {}
        Err(EmitterError::JsonParseError(e)) => {
            exit_with_error(&format!("Failed to create JSON document, because {}.", e),
                            1)
        }
        Err(EmitterError::EmitError(e)) => {
            exit_with_error(&format!("Failed to send, because {}.", e), 2)
        }
        Err(EmitterError::ReceiveError(e)) => {
            exit_with_error(&format!("Failed to create resource, because {}.", e), 3)
        }
    }
}

fn parse_args(cli_args: &ArgMatches) -> Result<Config, Box<Error>> {
    let bosun_config_file_path = Path::new(cli_args.value_of("config").unwrap_or(DEFAULT_CONFIG_FILE));
    let mut config: Config = if bosun_config_file_path.exists() {
        let bosun_config: BosunConfig = try!(BosunConfig::load_from_scollector_config(&bosun_config_file_path));
        Config::from_bosun_config(bosun_config)
    } else {
        Config::default()
    };

    if cli_args.is_present("host") {
        config.host = cli_args.value_of("host").unwrap().to_string();
    }

    if cli_args.is_present("hostname") {
        config.hostname = cli_args.value_of("hostname").unwrap().to_string();
        config.tags.insert("host".to_string(), config.hostname.to_string());
    }

    if cli_args.is_present("metric") {
        config.metric = Some(cli_args.value_of("metric").unwrap().to_string());
    }

    if cli_args.is_present("value") {
        config.value = Some(cli_args.value_of("value").unwrap().to_string());
    }

    if cli_args.is_present("rate") {
        config.rate = Some(cli_args.value_of("rate").unwrap().to_string());
    }

    if cli_args.is_present("unit") {
        config.unit = Some(cli_args.value_of("unit").unwrap().to_string());
    }

    if cli_args.is_present("description") {
        config.description = Some(cli_args.value_of("description").unwrap().to_string());
    }

    if cli_args.is_present("tags") {
        let tags_string = cli_args.value_of("tags").unwrap().to_string();
        parse_tags(&mut config, &tags_string);
    }

    Ok(config)
}

fn parse_tags(config: &mut Config, tags_string: &str) {
    tags_string.split(',')
               .map(|kv| kv.split('=').collect::<Vec<&str>>())
               .map(|vec| {
                   assert_eq!(vec.len(), 2);
                   (vec[0].to_string(), vec[1].to_string())
               })
               .fold((), |_, (k, v)| {
                   config.tags.insert(k, v);
               });
}

enum Mode {
    Normal,
    MetadataOnly,
    DatumOnly,
}

enum ModeError {
    NoMetadata,
    NoValue,
    NoSuchMode,
}

fn run(config: &Config, mode: Mode, verbose: bool) -> bosun_emitter::EmitterResult {
    match mode {
        Mode::Normal => {
            msg("Sending meta data.", verbose);
            try!(emit_metadata(config));

            msg("Sending datum.", verbose);
            emit_datum(config)
        }
        Mode::MetadataOnly => {
            msg("Sending meta data.", verbose);
            emit_metadata(config)
        }
        Mode::DatumOnly => {
            msg("Sending datum.", verbose);
            emit_datum(config)
        }
    }
}

/// We support two modes officially and more mode unofficially.
/// 1. Send Datum with Metadata
/// 1. Send only Metadata
/// 1. Send Datum without Metadata -- only with `--force`
fn mode(config: &Config, force: bool) -> Result<Mode, ModeError> {
    let mode_config = (config.metric.is_some(),
                       config.value.is_some(),
                       config.rate.is_some(),
                       config.unit.is_some(),
                       config.description.is_some(),
                       force);
    match mode_config {
        (true, true, true, true, true, _) => Ok(Mode::Normal),
        (true, _, true, true, true, _) => Ok(Mode::MetadataOnly),
        (true, true, _, _, _, true) => Ok(Mode::DatumOnly),
        (true, true, _, _, _, false) => Err(ModeError::NoMetadata),
        (true, false, _, _, _, _) => Err(ModeError::NoValue),
        _ => Err(ModeError::NoSuchMode),
    }
}

fn msg(msg: &str, verbose: bool) {
    if verbose {
        println!("{}", msg);
    }
}

fn exit_with_error(msg: &str, exit_code: i32) -> ! {
    println!("{}", msg);
    std::process::exit(exit_code);
}

fn emit_datum(config: &Config) -> bosun_emitter::EmitterResult {
    // unwraps are safe, because mode analysis already checked these values are set
    let client = BosunClient::new(&config.host);
    let datum = Datum::now(config.metric.as_ref().unwrap(),
                           config.value.as_ref().unwrap(),
                           &config.tags);
    client.emit_datum(&datum)
}

fn emit_metadata(config: &Config) -> bosun_emitter::EmitterResult {
    // unwraps are safe, because mode analysis already checked these values are set
    let client = BosunClient::new(&config.host);
    let metadata = Metadata::new(config.metric.as_ref().unwrap(),
                                 config.rate.as_ref().unwrap(),
                                 config.unit.as_ref().unwrap(),
                                 config.description.as_ref().unwrap());
    client.emit_metadata(&metadata)
}
<commit_msg>Fixes missing host tag<commit_after>//! emit_bosun -- Emits a single metric datum and corresponding metric meta data to [Bosun](http:////bosun.org).

extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate log;

extern crate bosun_emitter;

use clap::{Arg, ArgMatches, App};
use std::error::Error;
use std::path::Path;

use bosun_emitter::{BosunClient, Metadata, Datum, Tags, EmitterError, BosunConfig};

static VERSION: &'static str = env!("CARGO_PKG_VERSION");
static DEFAULT_CONFIG_FILE: &'static str = "/etc/bosun/scollector.conf";

#[derive(Debug)]
struct Config {
    host: String,
    hostname: String,
    metric: Option<String>,
    value: Option<String>,
    rate: Option<String>,
    unit: Option<String>,
    description: Option<String>,
    tags: Tags,
}

impl Config {
    pub fn default() -> Config {
        let bosun_config = BosunConfig::default();
        Config::from_bosun_config(bosun_config)
    }

    pub fn from_bosun_config(bosun_config: BosunConfig) -> Config {
        Config {
            host: bosun_config.Host,
            hostname: bosun_config.Hostname,
            metric: None,
            value: None,
            rate: None,
            unit: None,
            description: None,
            tags: bosun_config.Tags
        }
    }
}

fn main() {
    if env_logger::init().is_err() {
        exit_with_error("Could not initiliaze logger", -1);
    }

    let cli_args = App::new("Emit a Bosun")
                       .version(VERSION)
                       .after_help("Two modes are supported, i.e., sending a datum with meta \
                                    data or sending only meta data. The modes are controlled \
                                    whether a value `--value` is passed or not. Please mind that \
                                    in both cases the meta data is required.")
                       .arg(Arg::with_name("config")
                                .short("c")
                                .long("config")
                                .value_name("FILE")
                                .help("Sets a custom config file")
                                .takes_value(true))
                       .arg(Arg::with_name("host")
                                .long("host")
                                .value_name("HOST:PORT")
                                .help("Sets Bosun server connection parameters")
                                .takes_value(true))
                       .arg(Arg::with_name("hostname")
                                .long("hostname")
                                .value_name("HOSTNAME")
                                .help("Sets hostname")
                                .takes_value(true))
                       .arg(Arg::with_name("metric")
                                .short("m")
                                .long("metric")
                                .value_name("METRIC NAME")
                                .help("Sets metric name")
                                .takes_value(true))
                       .arg(Arg::with_name("value")
                                .requires("metric")
                                .short("v")
                                .long("value")
                                .value_name("VALUE")
                                .help("Sets metric value")
                                .takes_value(true))
                       .arg(Arg::with_name("rate")
                                .requires_all(&["metric", "rate", "unit", "description"])
                                .short("r")
                                .long("rate")
                                .value_name("RATE")
                                .possible_values(&["gauge", "counter", "rate"])
                                .help("Sets rate type")
                                .takes_value(true))
                       .arg(Arg::with_name("unit")
                                .requires_all(&["metric", "rate", "unit", "description"])
                                .short("u")
                                .long("unit")
                                .value_name("UNIT")
                                .help("Sets metric value unit")
                                .takes_value(true))
                       .arg(Arg::with_name("description")
                                .requires_all(&["metric", "rate", "unit", "description"])
                                .short("d")
                                .long("description")
                                .value_name("DESCRIPTION")
                                .help("Sets metric description")
                                .takes_value(true))
                       .arg(Arg::with_name("tags")
                                .use_delimiter(false)
                                .short("t")
                                .long("tags")
                                .value_name("KEY1=VALUE1,KEY2=VALUE2,...")
                                .help("Sets tags")
                                .takes_value(true))
                       .arg(Arg::with_name("show-config")
                                .long("show-config")
                                .help("Prints config"))
                       .arg(Arg::with_name("verbose")
                                .long("verbose")
                                .help("Enables verbose output"))
                       .arg(Arg::with_name("force")
                                .hidden(true)
                                .long("force")
                                .help("Forces metric datum to be send even without meta data"))
                       .get_matches();

    let force: bool = cli_args.is_present("force");
    let verbose: bool = cli_args.is_present("verbose");
    let config: Config = match parse_args(&cli_args) {
        Ok(config) => config,
        Err(err) => {
            exit_with_error(&format!("Failed to parse configuration, because {}.", err),
                            -2);
        }
    };
    if cli_args.is_present("show-config") {
        println!("config: {:?}", config);
    }

    let mode = match mode(&config, force) {
        Ok(mode) => mode,
        Err(ModeError::NoMetadata) => exit_with_error("Cannot send datum without meta data.", -11),
        Err(ModeError::NoValue) => exit_with_error("Cannot send datum without value.", -12),
        Err(ModeError::NoSuchMode) => {
            exit_with_error("Command line arguments combination does not make any sense.",
                            -13);
        }
    };

    let result = run(&config, mode, verbose);
    match result {
        Ok(_) => {}
        Err(EmitterError::JsonParseError(e)) => {
            exit_with_error(&format!("Failed to create JSON document, because {}.", e),
                            1)
        }
        Err(EmitterError::EmitError(e)) => {
            exit_with_error(&format!("Failed to send, because {}.", e), 2)
        }
        Err(EmitterError::ReceiveError(e)) => {
            exit_with_error(&format!("Failed to create resource, because {}.", e), 3)
        }
    }
}

fn parse_args(cli_args: &ArgMatches) -> Result<Config, Box<Error>> {
    let bosun_config_file_path = Path::new(cli_args.value_of("config").unwrap_or(DEFAULT_CONFIG_FILE));
    let mut config: Config = if bosun_config_file_path.exists() {
        let bosun_config: BosunConfig = try!(BosunConfig::load_from_scollector_config(&bosun_config_file_path));
        Config::from_bosun_config(bosun_config)
    } else {
        Config::default()
    };

    if cli_args.is_present("host") {
        config.host = cli_args.value_of("host").unwrap().to_string();
    }

    config.tags.insert("host".to_string(), config.hostname.to_string());
    if cli_args.is_present("hostname") {
        config.hostname = cli_args.value_of("hostname").unwrap().to_string();
        config.tags.insert("host".to_string(), config.hostname.to_string());
    }

    if cli_args.is_present("metric") {
        config.metric = Some(cli_args.value_of("metric").unwrap().to_string());
    }

    if cli_args.is_present("value") {
        config.value = Some(cli_args.value_of("value").unwrap().to_string());
    }

    if cli_args.is_present("rate") {
        config.rate = Some(cli_args.value_of("rate").unwrap().to_string());
    }

    if cli_args.is_present("unit") {
        config.unit = Some(cli_args.value_of("unit").unwrap().to_string());
    }

    if cli_args.is_present("description") {
        config.description = Some(cli_args.value_of("description").unwrap().to_string());
    }

    if cli_args.is_present("tags") {
        let tags_string = cli_args.value_of("tags").unwrap().to_string();
        parse_tags(&mut config, &tags_string);
    }

    Ok(config)
}

fn parse_tags(config: &mut Config, tags_string: &str) {
    tags_string.split(',')
               .map(|kv| kv.split('=').collect::<Vec<&str>>())
               .map(|vec| {
                   assert_eq!(vec.len(), 2);
                   (vec[0].to_string(), vec[1].to_string())
               })
               .fold((), |_, (k, v)| {
                   config.tags.insert(k, v);
               });
}

enum Mode {
    Normal,
    MetadataOnly,
    DatumOnly,
}

enum ModeError {
    NoMetadata,
    NoValue,
    NoSuchMode,
}

fn run(config: &Config, mode: Mode, verbose: bool) -> bosun_emitter::EmitterResult {
    match mode {
        Mode::Normal => {
            msg("Sending meta data.", verbose);
            try!(emit_metadata(config));

            msg("Sending datum.", verbose);
            emit_datum(config)
        }
        Mode::MetadataOnly => {
            msg("Sending meta data.", verbose);
            emit_metadata(config)
        }
        Mode::DatumOnly => {
            msg("Sending datum.", verbose);
            emit_datum(config)
        }
    }
}

/// We support two modes officially and more mode unofficially.
/// 1. Send Datum with Metadata
/// 1. Send only Metadata
/// 1. Send Datum without Metadata -- only with `--force`
fn mode(config: &Config, force: bool) -> Result<Mode, ModeError> {
    let mode_config = (config.metric.is_some(),
                       config.value.is_some(),
                       config.rate.is_some(),
                       config.unit.is_some(),
                       config.description.is_some(),
                       force);
    match mode_config {
        (true, true, true, true, true, _) => Ok(Mode::Normal),
        (true, _, true, true, true, _) => Ok(Mode::MetadataOnly),
        (true, true, _, _, _, true) => Ok(Mode::DatumOnly),
        (true, true, _, _, _, false) => Err(ModeError::NoMetadata),
        (true, false, _, _, _, _) => Err(ModeError::NoValue),
        _ => Err(ModeError::NoSuchMode),
    }
}

fn msg(msg: &str, verbose: bool) {
    if verbose {
        println!("{}", msg);
    }
}

fn exit_with_error(msg: &str, exit_code: i32) -> ! {
    println!("{}", msg);
    std::process::exit(exit_code);
}

fn emit_datum(config: &Config) -> bosun_emitter::EmitterResult {
    // unwraps are safe, because mode analysis already checked these values are set
    let client = BosunClient::new(&config.host);
    let datum = Datum::now(config.metric.as_ref().unwrap(),
                           config.value.as_ref().unwrap(),
                           &config.tags);
    client.emit_datum(&datum)
}

fn emit_metadata(config: &Config) -> bosun_emitter::EmitterResult {
    // unwraps are safe, because mode analysis already checked these values are set
    let client = BosunClient::new(&config.host);
    let metadata = Metadata::new(config.metric.as_ref().unwrap(),
                                 config.rate.as_ref().unwrap(),
                                 config.unit.as_ref().unwrap(),
                                 config.description.as_ref().unwrap());
    client.emit_metadata(&metadata)
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate rustc_serialize;
extern crate gsdmm;

use gsdmm::GSDMM;
use docopt::Docopt;
use std::io::{BufRead,BufReader};
use std::fs::File;
use std::collections::HashSet;
use std::io::Write;
use std::cmp::Ordering;

const USAGE: &'static str ="
Gibbs sampling algorithm for a Dirichlet Mixture Model of Yin and Wang 2014.

Usage:
  gsdmm <datafile> <vocabfile> <outprefix> [-k <max_clusters>] [-a <alpha>] [-b <beta>] [-m <maxit>]
  gsdmm (-h | --help)
  gsdmm --version

Options:
  -h --help             Show this screen.
  --version             Show version.
  -k=<K>                Upper bound on the number of possible clusters. [default: 8]
  -a --alpha=<alpha>    Alpha controls the probability that a student will join a table that is currently empty
                        When alpha is 0, no one will join an empty table. [default: 0.1]
  -b --beta=<beta>      Beta controls the student's affinity for other students with similar interests. A low beta means
                        that students desire to sit with students of similar interests. A high beta means they are less
                        concerned with affinity and are more influenced by the popularity of a table. [default: 0.1]
  -m --maxit=<m>        Maximum number of iterations. [default: 30]

";

#[derive(Debug, RustcDecodable)]
struct Args {
    //    flag_mode: isize,
    arg_datafile: String,
    arg_vocabfile: String,
    arg_outprefix: String,
    flag_k: usize,
    flag_alpha: f64,
    flag_beta: f64,
    flag_maxit: isize
}

fn main() {

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    // get the data and vocabulary
    let vocab:HashSet<String> = lines_from_file(&args.arg_vocabfile).into_iter().collect();
    let docs:Vec<Vec<String>> = lines_from_file(&args.arg_datafile).into_iter().map(|line| {
        let mut term_vector = line.to_owned()
            .split_whitespace()
            .map(|s| s.to_owned())
            .filter(|s| (&vocab).contains(s))
            .collect::<Vec<String>>();

        // sort and dedupe: this implementation requires binary term counts
        term_vector.sort();
        term_vector.dedup();
        term_vector
    }).collect::<Vec<Vec<String>>>();

    let mut model = GSDMM::new(args.flag_alpha, args.flag_beta, args.flag_k, args.flag_maxit, vocab, docs);
    model.fit();

    // write the labels
    {
        let fname = (&args.arg_outprefix).clone() + "labels.csv";
        let error_msg = format ! ("Could not write file {}!", fname);
        let mut f = File::create( fname ).expect( & error_msg);
        let mut scored = Vec::<(String,String,String)>::new();

        // zip with the input data so we get clustered, raw input documents in the output set
        for (doc,txt) in (&model.docs).iter().zip(lines_from_file(&args.arg_datafile).iter()) {
            let p = model.score( & doc);
            let mut row = p.iter().enumerate().collect::<Vec<_>>();
            let mut defect_count = 0;
            row.sort_by(|a,b| a.1.partial_cmp(b.1).unwrap_or({
                if defect_count == 0 {
                    println!("Could not compare {:?} ? {:?} for document:\n {:?}", a, b, doc);
                    defect_count+=1;
                }
                match a.1.is_nan() {
                    true => Ordering::Less,
                    false => Ordering::Greater
                }
            }));
            let line = row.pop().unwrap();
            scored.push((line.0.to_string(), line.1.to_string(), txt.clone()));
        }
        scored.sort();
        for (label, score, txt) in scored {
            f.write((label + "," + &score + "," + &txt + "\n").as_bytes());
        }
    }

    // write the cluster descriptions
    {
        let fname = (&args.arg_outprefix).clone() + "cluster_descriptions.txt";
        let error_msg = format!("Could not write file {}!", fname);
        let mut f = File::create(fname).expect(&error_msg);
        for k in 0..args.flag_k {
            let ref word_dist = model.cluster_word_distributions[k];
            let mut line = k.to_string() + " ";
            let mut dist_counts:Vec<String> = word_dist.iter().map(|(a,b)| a.clone() + ":" + &b.clone().to_string() ).collect();
            dist_counts.sort();
            line += &dist_counts.join(" ");
            f.write((line+"\n").as_bytes());
        }
    }

    fn lines_from_file(filename: &str) -> Vec<String>
    {
        let error_msg = format!("Could not read file {}!", filename);
        let file = File::open(filename).expect(&error_msg);
        let buf = BufReader::new(file);
        buf.lines().map(|l| l.expect("Could not parse line!")).collect()
    }
}
<commit_msg>More handling for NaN<commit_after>extern crate docopt;
extern crate rustc_serialize;
extern crate gsdmm;

use gsdmm::GSDMM;
use docopt::Docopt;
use std::io::{BufRead,BufReader};
use std::fs::File;
use std::collections::HashSet;
use std::io::Write;
use std::cmp::Ordering;

const USAGE: &'static str ="
Gibbs sampling algorithm for a Dirichlet Mixture Model of Yin and Wang 2014.

Usage:
  gsdmm <datafile> <vocabfile> <outprefix> [-k <max_clusters>] [-a <alpha>] [-b <beta>] [-m <maxit>]
  gsdmm (-h | --help)
  gsdmm --version

Options:
  -h --help             Show this screen.
  --version             Show version.
  -k=<K>                Upper bound on the number of possible clusters. [default: 8]
  -a --alpha=<alpha>    Alpha controls the probability that a student will join a table that is currently empty
                        When alpha is 0, no one will join an empty table. [default: 0.1]
  -b --beta=<beta>      Beta controls the student's affinity for other students with similar interests. A low beta means
                        that students desire to sit with students of similar interests. A high beta means they are less
                        concerned with affinity and are more influenced by the popularity of a table. [default: 0.1]
  -m --maxit=<m>        Maximum number of iterations. [default: 30]

";

#[derive(Debug, RustcDecodable)]
struct Args {
    //    flag_mode: isize,
    arg_datafile: String,
    arg_vocabfile: String,
    arg_outprefix: String,
    flag_k: usize,
    flag_alpha: f64,
    flag_beta: f64,
    flag_maxit: isize
}

fn main() {

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    // get the data and vocabulary
    let vocab:HashSet<String> = lines_from_file(&args.arg_vocabfile).into_iter().collect();
    let docs:Vec<Vec<String>> = lines_from_file(&args.arg_datafile).into_iter().map(|line| {
        let mut term_vector = line.to_owned()
            .split_whitespace()
            .map(|s| s.to_owned())
            .filter(|s| (&vocab).contains(s))
            .collect::<Vec<String>>();

        // sort and dedupe: this implementation requires binary term counts
        term_vector.sort();
        term_vector.dedup();
        term_vector
    }).collect::<Vec<Vec<String>>>();

    let mut model = GSDMM::new(args.flag_alpha, args.flag_beta, args.flag_k, args.flag_maxit, vocab, docs);
    model.fit();

    // write the labels
    {
        let fname = (&args.arg_outprefix).clone() + "labels.csv";
        let error_msg = format ! ("Could not write file {}!", fname);
        let mut f = File::create( fname ).expect( & error_msg);
        let mut scored = Vec::<(String,String,String)>::new();

        // zip with the input data so we get clustered, raw input documents in the output set
        for (doc,txt) in (&model.docs).iter().zip(lines_from_file(&args.arg_datafile).iter()) {
            let p = model.score( & doc);
            let mut row = p.iter().enumerate().collect::<Vec<_>>();
            if row_has_nan(&row, &doc) {
                scored.push(("-1".to_string(), "0".to_string(), txt.clone()));
            } else {
                row.sort_by(|a, b| (a.1.partial_cmp(b.1)).unwrap());
                let line = row.pop().unwrap();
                scored.push((line.0.to_string(), line.1.to_string(), txt.clone()));
            }
        }
        scored.sort();
        for (label, score, txt) in scored {
            f.write((label + "," + &score + "," + &txt + "\n").as_bytes());
        }
    }

    // write the cluster descriptions
    {
        let fname = (&args.arg_outprefix).clone() + "cluster_descriptions.txt";
        let error_msg = format!("Could not write file {}!", fname);
        let mut f = File::create(fname).expect(&error_msg);
        for k in 0..args.flag_k {
            let ref word_dist = model.cluster_word_distributions[k];
            let mut line = k.to_string() + " ";
            let mut dist_counts:Vec<String> = word_dist.iter().map(|(a,b)| a.clone() + ":" + &b.clone().to_string() ).collect();
            dist_counts.sort();
            line += &dist_counts.join(" ");
            f.write((line+"\n").as_bytes());
        }
    }

    fn lines_from_file(filename: &str) -> Vec<String>
    {
        let error_msg = format!("Could not read file {}!", filename);
        let file = File::open(filename).expect(&error_msg);
        let buf = BufReader::new(file);
        buf.lines().map(|l| l.expect("Could not parse line!")).collect()
    }

    fn row_has_nan(row:&Vec<(usize, &f64)>, doc:&Vec<String>) -> bool {
        for entry in row {
            if entry.1.is_nan() {
                println!("Cluster: {:?} has NaN score for document {:?}", entry, doc);
                return true
            }
        }
        return false;
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate breezyvps;
extern crate simplelog;

use simplelog::{Config, TermLogger, WriteLogger, CombinedLogger, LogLevelFilter};
use std::fs::File;
use breezyvps::command;

fn sc_doctl(doctl_matches: &clap::ArgMatches) {
    if let Some(create_droplet_matches) = doctl_matches.subcommand_matches("create_droplet") {
        if let Some(name) = create_droplet_matches.value_of("name") {
            breezyvps::digitalocean::create_droplet_by_name(name);
        } else {
            println!("Missing required name parameter!");
        }
        return;
    }
    if let Some(destroy_droplet_matches) = doctl_matches.subcommand_matches("destroy_droplet") {
        if let Some(name) = destroy_droplet_matches.value_of("name") {
            breezyvps::digitalocean::destroy_droplet_by_name(name);
        } else {
            println!("Missing required name parameter!");
        }
        return;
    }
    if let Some(create_ssh_key_matches) = doctl_matches.subcommand_matches("create_sshkey") {
        if let Some(name) = create_ssh_key_matches.value_of("name") {
            breezyvps::digitalocean::create_sshkey(name);
        } else {
            println!("Missing required sshkey name parameter!");
        }
        return;
    }
}

fn sc_configure(configure_matches: &clap::ArgMatches) {
    if let Some(nginx_matches) = configure_matches.subcommand_matches("nginx") {
        if let Some(host) = nginx_matches.value_of("host") {
            // Default 8080
            let port = nginx_matches.value_of("port").unwrap_or("8080");
            breezyvps::configure::install_nginx(host);
            breezyvps::configure::add_nginx_host(host, port);
            breezyvps::configure::install_letsencrypt_cert(host);
        } else {
            println!("Missing required host parameter!");
        }
        return;
    }
}

fn main() {
    // Configure logging with simplelogger
    CombinedLogger::init(
        vec![
            TermLogger::new(LogLevelFilter::Info, Config::default()).unwrap(),
            WriteLogger::new(LogLevelFilter::Info, Config::default(), File::create("breezyvps.log").unwrap()),
        ]
    ).unwrap();

    let matches = clap_app!(myapp =>
        (version: "0.1.3")
        (author: "Michael Xu <michaeljxu11@gmail.com>")
        (about: "One stop shop for common command line goodness")
        (@arg verbose: -v ... "Enable verbose output")
        (@subcommand doctl =>
            (about: "Doctl wrapper")
            (author: "Michael Xu <michaeljxu11@gmail.com>")
            (@arg verbose: -v --verbose "Print test information verbosely")
            (@subcommand create_droplet =>
                (about: "Create a new droplet")
                (@arg name: +required "Name of the droplet, must be unique")
                (@arg config: -c "Which configuration to use [small|medium|large]")
            )
            (@subcommand destroy_droplet =>
                (about: "Destroy a droplet by name")
                (@arg name: +required "Name of the droplet to destroy completely")
            )
            (@subcommand create_sshkey =>
                (about: "Add an ssh key, which will be added upon instance creation")
                (@arg name: +required "Name of the new ssh keys")
            )
        )
        (@subcommand configure =>
            (about: "Configure droplets / nodes")
            (@subcommand nginx =>
                (about: "Install nginx and configure for host")
                (@arg host: +required "Host name of the droplet")
                (@arg port: "Port to run webapp from (default: 8080)")
            )
        )
    ).get_matches();

//    // Vary the output based on how many times the user used the "verbose" flag
//    // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v'
//    match matches.occurrences_of("v") {
//        0 => println!("No verbose info"),
//        1 => println!("Some verbose info"),
//        2 => println!("Tons of verbose info"),
//        3 | _ => println!("Don't be crazy"),
//    }

    // You can handle information about subcommands by requesting their matches by name
    // (as below), requesting just the name used, or both at the same time
    if let Some(matches) = matches.subcommand_matches("doctl") {
        sc_doctl(matches);
        return;
    }
    if let Some(matches) = matches.subcommand_matches("configure") {
        sc_configure(matches);
        return;
    }

    let mut x = breezyvps::chain::CommandChain::new();
    x.cmd("echo hello")
        .cmd("test2")
        .cmd("test3")
        .execute();

    breezyvps::chain::CommandChain::new()
        .cmd_nonfatal("echo hello")
        .cmd_nonfatal("restinpeace")
        .cmd("echo yo")
        .execute();

    let res = breezyvps::chain::CommandChain::new()
        .cmd("echo hello")
        .result_proc(&|res: &command::Result| -> command::Result {
            let mut extra_stdout = res.stdout.clone();
            extra_stdout.push_str(" + processing");

            command::Result {
                exit_code: res.exit_code,
                success: res.success,
                stdout: extra_stdout,
                stderr: res.stderr.clone()
            }
        })
        .execute();

    println!("{}", res.result.unwrap().stdout);
}
<commit_msg>one solution is to move closure to let<commit_after>#[macro_use]
extern crate clap;
extern crate breezyvps;
extern crate simplelog;

use simplelog::{Config, TermLogger, WriteLogger, CombinedLogger, LogLevelFilter};
use std::fs::File;
use breezyvps::command;

fn sc_doctl(doctl_matches: &clap::ArgMatches) {
    if let Some(create_droplet_matches) = doctl_matches.subcommand_matches("create_droplet") {
        if let Some(name) = create_droplet_matches.value_of("name") {
            breezyvps::digitalocean::create_droplet_by_name(name);
        } else {
            println!("Missing required name parameter!");
        }
        return;
    }
    if let Some(destroy_droplet_matches) = doctl_matches.subcommand_matches("destroy_droplet") {
        if let Some(name) = destroy_droplet_matches.value_of("name") {
            breezyvps::digitalocean::destroy_droplet_by_name(name);
        } else {
            println!("Missing required name parameter!");
        }
        return;
    }
    if let Some(create_ssh_key_matches) = doctl_matches.subcommand_matches("create_sshkey") {
        if let Some(name) = create_ssh_key_matches.value_of("name") {
            breezyvps::digitalocean::create_sshkey(name);
        } else {
            println!("Missing required sshkey name parameter!");
        }
        return;
    }
}

fn sc_configure(configure_matches: &clap::ArgMatches) {
    if let Some(nginx_matches) = configure_matches.subcommand_matches("nginx") {
        if let Some(host) = nginx_matches.value_of("host") {
            // Default 8080
            let port = nginx_matches.value_of("port").unwrap_or("8080");
            breezyvps::configure::install_nginx(host);
            breezyvps::configure::add_nginx_host(host, port);
            breezyvps::configure::install_letsencrypt_cert(host);
        } else {
            println!("Missing required host parameter!");
        }
        return;
    }
}

fn main() {
    // Configure logging with simplelogger
    CombinedLogger::init(
        vec![
            TermLogger::new(LogLevelFilter::Info, Config::default()).unwrap(),
            WriteLogger::new(LogLevelFilter::Info, Config::default(), File::create("breezyvps.log").unwrap()),
        ]
    ).unwrap();

    let matches = clap_app!(myapp =>
        (version: "0.1.3")
        (author: "Michael Xu <michaeljxu11@gmail.com>")
        (about: "One stop shop for common command line goodness")
        (@arg verbose: -v ... "Enable verbose output")
        (@subcommand doctl =>
            (about: "Doctl wrapper")
            (author: "Michael Xu <michaeljxu11@gmail.com>")
            (@arg verbose: -v --verbose "Print test information verbosely")
            (@subcommand create_droplet =>
                (about: "Create a new droplet")
                (@arg name: +required "Name of the droplet, must be unique")
                (@arg config: -c "Which configuration to use [small|medium|large]")
            )
            (@subcommand destroy_droplet =>
                (about: "Destroy a droplet by name")
                (@arg name: +required "Name of the droplet to destroy completely")
            )
            (@subcommand create_sshkey =>
                (about: "Add an ssh key, which will be added upon instance creation")
                (@arg name: +required "Name of the new ssh keys")
            )
        )
        (@subcommand configure =>
            (about: "Configure droplets / nodes")
            (@subcommand nginx =>
                (about: "Install nginx and configure for host")
                (@arg host: +required "Host name of the droplet")
                (@arg port: "Port to run webapp from (default: 8080)")
            )
        )
    ).get_matches();

//    // Vary the output based on how many times the user used the "verbose" flag
//    // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v'
//    match matches.occurrences_of("v") {
//        0 => println!("No verbose info"),
//        1 => println!("Some verbose info"),
//        2 => println!("Tons of verbose info"),
//        3 | _ => println!("Don't be crazy"),
//    }

    // You can handle information about subcommands by requesting their matches by name
    // (as below), requesting just the name used, or both at the same time
    if let Some(matches) = matches.subcommand_matches("doctl") {
        sc_doctl(matches);
        return;
    }
    if let Some(matches) = matches.subcommand_matches("configure") {
        sc_configure(matches);
        return;
    }

    let mut x = breezyvps::chain::CommandChain::new();
    x.cmd("echo hello")
        .cmd("test2")
        .cmd("test3")
        .execute();

    breezyvps::chain::CommandChain::new()
        .cmd_nonfatal("echo hello")
        .cmd_nonfatal("restinpeace")
        .cmd("echo yo")
        .execute();

    let processing_func = |res: &command::Result| -> command::Result {
        let mut extra_stdout = res.stdout.clone();
        extra_stdout.push_str(" + processing");

        command::Result {
            exit_code: res.exit_code,
            success: res.success,
            stdout: extra_stdout,
            stderr: res.stderr.clone()
        }
    };

    let res = breezyvps::chain::CommandChain::new()
        .cmd("echo hello")
        .result_proc(&processing_func)
        .execute();

    println!("{}", res.result.unwrap().stdout);
}
<|endoftext|>


<commit_before>extern crate rand;

#[derive(Debug, Clone, Copy)]
struct ConnectionGene{
    in_node_id: u32,
    out_node_id: u32,
    weight: f64,
    enabled: bool,
    innovation_id: u32,
}

impl Default for ConnectionGene{
    fn default () -> ConnectionGene {
        ConnectionGene { in_node_id: 1, out_node_id: 1, weight: 1_f64, enabled: true, innovation_id: 0 }
    }
}

struct Mutation {
    gen: ConnectionGene
}

impl Mutation {
    fn new (gen_orig: ConnectionGene) -> Mutation {
        Mutation { gen: gen_orig }
    }

    fn mutate_weight (&self) -> ConnectionGene {
        ConnectionGene { weight: rand::random::<f64>(), ..self.gen }
    }
}

#[derive(Debug)]
struct Genome{
    connection_genes: Vec<ConnectionGene>
}

impl Default for Genome{
    fn default () -> Genome {
        Genome { connection_genes: vec![Default::default(); 0]}
    }
}

fn main(){
    let genome = Genome {..Default::default()};
    println!("NEAT");
    println!("{:?}", genome);
    let mutation = Mutation::new(ConnectionGene {..Default::default()});
    println!("{:?}", mutation.mutate_weight());
}
<commit_msg>Adding mutation to genes<commit_after>extern crate rand;

#[derive(Debug, Clone, Copy)]
struct ConnectionGene{
    in_node_id: u32,
    out_node_id: u32,
    weight: f64,
    enabled: bool,
    innovation_id: u32,
}

impl ConnectionGene {
    fn generate_weight () -> f64 {
        rand::random::<f64>()
    }
}

impl Default for ConnectionGene{
    fn default () -> ConnectionGene {
        ConnectionGene { in_node_id: 1, out_node_id: 1, weight: ConnectionGene::generate_weight(), enabled: true, innovation_id: 0 }
    }
}

trait Mutation {
}

impl Mutation {
    fn connection_weight (gene: &mut ConnectionGene) {
        gene.weight = ConnectionGene::generate_weight()
    }

    fn add_connection (in_node_id: u32, out_node_id: u32) -> (ConnectionGene) {
        ConnectionGene { in_node_id: in_node_id, out_node_id: out_node_id, ..Default::default() }
    }

    fn add_node (gene: &mut ConnectionGene, new_node_id: u32) -> (ConnectionGene, ConnectionGene) {
        gene.enabled = false;

        (ConnectionGene {
            in_node_id: gene.in_node_id,
            out_node_id: new_node_id,
            weight: 1f64,
            ..Default::default()
        },
        ConnectionGene {
            in_node_id: new_node_id,
            out_node_id: gene.out_node_id,
            weight: gene.weight,
            ..Default::default()
        })
    }
}

#[derive(Debug)]
struct Genome{
    connection_genes: Vec<ConnectionGene>
}

impl Genome{
}

impl Default for Genome{
    fn default () -> Genome {
        Genome { connection_genes: vec![Default::default(); 0]}
    }
}

fn main(){
    let genome = Genome {..Default::default()};
    println!("NEAT");
    println!("{:?}", genome);

    let mut gene = ConnectionGene {..Default::default()};
    println!("{:?}", gene);
    Mutation::connection_weight(&mut gene);
    println!("{:?}", gene);
    println!("{:?}", Mutation::add_connection(1, 2));
    println!("{:?}", Mutation::add_node(&mut gene, 3));
    println!("{:?}", gene);
}

#[test]
fn mutation_connection_weight(){
    let mut gene = ConnectionGene {..Default::default()};
    let orig_gene = gene.clone();
    Mutation::connection_weight(&mut gene);

    assert!(gene.weight != orig_gene.weight);
}

#[test]
fn mutation_add_connection(){
    let new_gene = Mutation::add_connection(1, 2);

    assert!(new_gene.in_node_id == 1);
    assert!(new_gene.out_node_id == 2);
}

#[test]
fn mutation_add_node(){
    let mut gene = ConnectionGene {..Default::default()};
    let (new_gene1, new_gene2) = Mutation::add_node(&mut gene, 3);

    assert!(!gene.enabled);
    assert!(new_gene1.in_node_id == gene.in_node_id);
    assert!(new_gene1.out_node_id == 3);
    assert!(new_gene2.in_node_id == 3);
    assert!(new_gene2.out_node_id == gene.out_node_id);
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate chan;
extern crate crypto;
extern crate walkdir;

use self::crypto::digest::Digest;
use self::crypto::sha1::Sha1;
use std::env;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::io;
use walkdir::WalkDir;
use std::thread;
use std::sync::Arc;
use walkdir::DirEntry;

/// The purpose of this newtype is to hide the channel.
struct GatherIter<T>(chan::Iter<T>);
impl<T> Iterator for GatherIter<T> {
    type Item = T;
    fn next(&mut self) -> Option<T> {
        self.0.next()
    }
}

/// producer_ctor and xform_ctor is needed to allow construction
/// in the correct producer / worker thread.
/// TODO: Figure out how to simplify this trait mess :)
fn scatter_gather<PC, XC, P, X, J, R>(producer_ctor: PC, xform_ctor: XC) -> GatherIter<R>
    where PC: 'static + std::marker::Send + FnOnce() -> P,
          XC: 'static + std::marker::Send + std::marker::Sync + Fn() -> X,
          X: FnMut(J) -> R,
          J: 'static + std::marker::Send,
          R: 'static + std::marker::Send,
          P: IntoIterator<Item = J>
{
    let jobs_rx = {
        let (tx, rx) = chan::sync(0);
        thread::spawn(move || {
            for e in producer_ctor().into_iter() {
                tx.send(e);
            }
        });
        rx
    };
    let results_rx = {
        let (tx, rx) = chan::sync(0);
        let xform_ctor = Arc::new(xform_ctor); // TODO: Investigate why this is needed.
        for _ in 0..8 {
            let tx = tx.clone();
            let jobs_rx = jobs_rx.clone();
            let xform_ctor = xform_ctor.clone();
            thread::spawn(move || {
                let mut xform = xform_ctor();
                for e in jobs_rx {
                    tx.send(xform(e));
                }
            });
        }
        rx
    };
    GatherIter(results_rx.iter())
}

fn calc_hash(p: &Path, hasher: &mut Sha1, buf: &mut [u8]) -> io::Result<String> {
    hasher.reset();
    let mut f = File::open(p)?;
    loop {
        let num_read = f.read(buf)?;
        if num_read == 0 {
            break;
        }
        hasher.input(&buf[..num_read]);
    }
    Ok(hasher.result_str())
}

type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
enum Error {
    Io(io::Error),
    Ignored(DirEntry),
    WalkDir(walkdir::Error),
}

fn process_root(root: &Path) -> io::Result<()> {
    let pb = root.to_path_buf();
    let producer_ctor = || WalkDir::new(pb);
    let xform_ctor = || {
        let mut hasher = Sha1::new();
        let mut buf = [0; 1024 * 8];
        let f = move |e: walkdir::Result<DirEntry>| -> Result<String> {
            let e = e.map_err(Error::WalkDir)?;
            if !e.file_type().is_file() {
                return Err(Error::Ignored(e));
            }
            calc_hash(e.path(), &mut hasher, &mut buf).map_err(Error::Io)
        };
        f
    };
    let results = scatter_gather(producer_ctor, xform_ctor);
    for r in results {
        println!("{:?}", r);
    }
    Ok(())
}

fn main() {
    let root = env::args().nth(1).unwrap_or(".".to_string());
    let root = Path::new(root.as_str());
    process_root(root).expect("Hello error 2!");
}
<commit_msg>Added some comments.<commit_after>#![deny(warnings)]

extern crate chan;
extern crate crypto;
extern crate walkdir;

use self::crypto::digest::Digest;
use self::crypto::sha1::Sha1;
use std::env;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::io;
use walkdir::WalkDir;
use std::thread;
use std::sync::Arc;
use walkdir::DirEntry;

/// The purpose of this newtype is to hide the channel.
struct GatherIter<T>(chan::Iter<T>);
impl<T> Iterator for GatherIter<T> {
    type Item = T;
    fn next(&mut self) -> Option<T> {
        self.0.next()
    }
}

/// producer_ctor and xform_ctor is needed to allow construction
/// in the correct producer / worker thread.
/// TODO: Figure out how to simplify this trait mess :)
fn scatter_gather<PC, XC, P, X, J, R>(producer_ctor: PC, xform_ctor: XC) -> GatherIter<R>
    where PC: 'static + std::marker::Send + FnOnce() -> P,
          XC: 'static + std::marker::Send + std::marker::Sync + Fn() -> X,
          X: FnMut(J) -> R,
          J: 'static + std::marker::Send,
          R: 'static + std::marker::Send,
          P: IntoIterator<Item = J>
{
    let jobs_rx = {
        let (tx, rx) = chan::sync(0);
        thread::spawn(move || {
            for e in producer_ctor().into_iter() {
                tx.send(e);
            }
        });
        rx
    };
    let results_rx = {
        let (tx, rx) = chan::sync(0);
        let xform_ctor = Arc::new(xform_ctor); // TODO: Investigate why this is needed.
        // TODO: Find and use a num_cpu function.
        for _ in 0..8 {
            let tx = tx.clone();
            let jobs_rx = jobs_rx.clone();
            let xform_ctor = xform_ctor.clone();
            thread::spawn(move || {
                let mut xform = xform_ctor();
                for e in jobs_rx {
                    tx.send(xform(e));
                }
            });
        }
        rx
    };
    GatherIter(results_rx.iter())
}

fn calc_hash(p: &Path, hasher: &mut Sha1, buf: &mut [u8]) -> io::Result<String> {
    hasher.reset();
    let mut f = File::open(p)?;
    loop {
        let num_read = f.read(buf)?;
        if num_read == 0 {
            break;
        }
        hasher.input(&buf[..num_read]);
    }
    Ok(hasher.result_str())
}

type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
enum Error {
    Io(io::Error),
    Ignored(DirEntry),
    WalkDir(walkdir::Error),
}

fn process_root(root: &Path) -> io::Result<()> {
    let pb = root.to_path_buf();
    let producer_ctor = || WalkDir::new(pb);
    let xform_ctor = || {
        let mut hasher = Sha1::new();
        let mut buf = [0; 1024 * 8];
        let f = move |e: walkdir::Result<DirEntry>| -> Result<String> {
            let e = e.map_err(Error::WalkDir)?;
            if !e.file_type().is_file() {
                return Err(Error::Ignored(e));
            }
            calc_hash(e.path(), &mut hasher, &mut buf).map_err(Error::Io)
        };
        f
    };
    let results = scatter_gather(producer_ctor, xform_ctor);
    for r in results {
        println!("{:?}", r);
    }
    Ok(())
}

fn main() {
    let root = env::args().nth(1).unwrap_or(".".to_string());
    let root = Path::new(root.as_str());
    process_root(root).expect("Hello error 2!");
}
<|endoftext|>


<commit_before>#![recursion_limit = "128"]

extern crate ape;
extern crate app_dirs;
extern crate core;
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_codegen;
#[macro_use]
extern crate error_chain;
extern crate getopts;
extern crate hyper;
extern crate id3;
extern crate image;
extern crate iron;
extern crate lewton;
extern crate metaflac;
extern crate mount;
extern crate params;
extern crate rand;
extern crate reqwest;
extern crate regex;
extern crate ring;
extern crate router;
extern crate secure_session;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate staticfile;
extern crate toml;
extern crate typemap;
extern crate url;

#[cfg(windows)]
extern crate uuid;
#[cfg(windows)]
extern crate winapi;
#[cfg(windows)]
extern crate kernel32;
#[cfg(windows)]
extern crate shell32;
#[cfg(windows)]
extern crate user32;

#[cfg(unix)]
extern crate unix_daemonize;

#[cfg(unix)]
use unix_daemonize::{daemonize_redirect, ChdirMode};

use core::ops::Deref;
use errors::*;
use getopts::Options;
use iron::prelude::*;
use mount::Mount;
use staticfile::Static;
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::channel;

mod api;
mod config;
mod db;
mod ddns;
mod errors;
mod index;
mod metadata;
mod playlist;
mod ui;
mod user;
mod utils;
mod thumbnails;
mod vfs;

fn main() {
	if let Err(ref e) = run() {
		println!("Error: {}", e);

		for e in e.iter().skip(1) {
			println!("caused by: {}", e);
		}
		if let Some(backtrace) = e.backtrace() {
			println!("backtrace: {:?}", backtrace);
		}
		::std::process::exit(1);
	}
}

#[cfg(unix)]
fn daemonize() -> Result<()> {
	let mut log_file = utils::get_data_root()?;
	log_file.push("polaris.log");
	match daemonize_redirect(Some(&log_file), Some(&log_file), ChdirMode::NoChdir) {
		Ok(_) => Ok(()),
		Err(_) => bail!(ErrorKind::DaemonError),
	}
}

fn run() -> Result<()> {

	#[cfg(unix)]
	daemonize()?;

	// Parse CLI options
	let args: Vec<String> = std::env::args().collect();
	let mut options = Options::new();
	options.optopt("c", "config", "set the configuration file", "FILE");
	options.optopt("d", "database", "set the path to index database", "FILE");
	options.optopt("w", "web", "set the path to web client files", "DIRECTORY");
	let matches = options.parse(&args[1..])?;

	// Init DB
	println!("Starting up database");
	let db_path = matches.opt_str("d");
	let mut default_db_path = utils::get_data_root()?;
	default_db_path.push("db.sqlite");
	let db_path = db_path
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_db_path);
	let db = Arc::new(db::DB::new(&db_path)?);

	// Parse config
	let config_file_name = matches.opt_str("c");
	let config_file_path = config_file_name.map(|p| Path::new(p.as_str()).to_path_buf());
	if let Some(path) = config_file_path {
		let config = config::parse_toml_file(&path)?;
		config::overwrite(db.deref(), &config)?;
	}

	// Init index
	let (index_sender, index_receiver) = channel();
	let index_sender = Arc::new(Mutex::new(index_sender));
	let db_ref = db.clone();
	std::thread::spawn(move || {
		                   let db = db_ref.deref();
		                   index::update_loop(db, index_receiver);
		                  });

	// Trigger auto-indexing
	let db_ref = db.clone();
	let sender_ref = index_sender.clone();
	std::thread::spawn(move || { index::self_trigger(db_ref.deref(), sender_ref); });

	// Mount API
	println!("Mounting API");
	let mut mount = Mount::new();
	let handler = api::get_handler(db.clone(), index_sender)?;
	mount.mount("/api/", handler);

	// Mount static files
	println!("Mounting static files");
	let web_dir_name = matches.opt_str("w");
	let mut default_web_dir = utils::get_data_root()?;
	default_web_dir.push("web");
	let web_dir_path = web_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_web_dir);

	mount.mount("/", Static::new(web_dir_path));

	println!("Starting up server");
	let mut server = match Iron::new(mount).http(("0.0.0.0", 5050)) {
		Ok(s) => s,
		Err(e) => bail!("Error starting up server: {}", e),
	};

	// Start DDNS updates
	let db_ref = db.clone();
	std::thread::spawn(move || { ddns::run(db_ref.deref()); });

	// Run UI
	ui::run();

	println!("Shutting down server");
	if let Err(e) = server.close() {
		bail!("Error shutting down server: {}", e);
	}

	Ok(())
}
<commit_msg>- allow polaris to run in foreground - add cli help message<commit_after>#![recursion_limit = "128"]

extern crate ape;
extern crate app_dirs;
extern crate core;
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_codegen;
#[macro_use]
extern crate error_chain;
extern crate getopts;
extern crate hyper;
extern crate id3;
extern crate image;
extern crate iron;
extern crate lewton;
extern crate metaflac;
extern crate mount;
extern crate params;
extern crate rand;
extern crate reqwest;
extern crate regex;
extern crate ring;
extern crate router;
extern crate secure_session;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate staticfile;
extern crate toml;
extern crate typemap;
extern crate url;

#[cfg(windows)]
extern crate uuid;
#[cfg(windows)]
extern crate winapi;
#[cfg(windows)]
extern crate kernel32;
#[cfg(windows)]
extern crate shell32;
#[cfg(windows)]
extern crate user32;

#[cfg(unix)]
extern crate unix_daemonize;

#[cfg(unix)]
use unix_daemonize::{daemonize_redirect, ChdirMode};

use core::ops::Deref;
use errors::*;
use getopts::Options;
use iron::prelude::*;
use mount::Mount;
use staticfile::Static;
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::channel;

mod api;
mod config;
mod db;
mod ddns;
mod errors;
mod index;
mod metadata;
mod playlist;
mod ui;
mod user;
mod utils;
mod thumbnails;
mod vfs;

fn main() {
	if let Err(ref e) = run() {
		println!("Error: {}", e);

		for e in e.iter().skip(1) {
			println!("caused by: {}", e);
		}
		if let Some(backtrace) = e.backtrace() {
			println!("backtrace: {:?}", backtrace);
		}
		::std::process::exit(1);
	}
}

#[cfg(unix)]
fn daemonize() -> Result<()> {
	let mut log_file = utils::get_data_root()?;
	log_file.push("polaris.log");
	match daemonize_redirect(Some(&log_file), Some(&log_file), ChdirMode::NoChdir) {
		Ok(_) => Ok(()),
		Err(_) => bail!(ErrorKind::DaemonError),
	}
}

fn run() -> Result<()> {

	// Parse CLI options
	let args: Vec<String> = std::env::args().collect();
	let mut options = Options::new();
	options.optopt("c", "config", "set the configuration file", "FILE");
	options.optopt("d", "database", "set the path to index database", "FILE");
	options.optopt("w", "web", "set the path to web client files", "DIRECTORY");

	#[cfg(unix)]
	options.optflag("f", "foreground", "run polaris in the foreground instead of daemonizing");

	options.optflag("h", "help", "print this help menu");

	let matches = options.parse(&args[1..])?;

	if matches.opt_present("h") {
		let program = args[0].clone();
		let brief = format!("Usage: {} [options]", program);
		print!("{}", options.usage(&brief));
		return Ok(());
	}

	//attribute inside the if clause, because they are not yet allowed on `if` expressions
	if !matches.opt_present("f") {
		#[cfg(unix)]
		daemonize()?;
	}

	// Init DB
	println!("Starting up database");
	let db_path = matches.opt_str("d");
	let mut default_db_path = utils::get_data_root()?;
	default_db_path.push("db.sqlite");
	let db_path = db_path
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_db_path);
	let db = Arc::new(db::DB::new(&db_path)?);

	// Parse config
	let config_file_name = matches.opt_str("c");
	let config_file_path = config_file_name.map(|p| Path::new(p.as_str()).to_path_buf());
	if let Some(path) = config_file_path {
		let config = config::parse_toml_file(&path)?;
		config::overwrite(db.deref(), &config)?;
	}

	// Init index
	let (index_sender, index_receiver) = channel();
	let index_sender = Arc::new(Mutex::new(index_sender));
	let db_ref = db.clone();
	std::thread::spawn(move || {
		let db = db_ref.deref();
		index::update_loop(db, index_receiver);
	});

	// Trigger auto-indexing
	let db_ref = db.clone();
	let sender_ref = index_sender.clone();
	std::thread::spawn(move || { index::self_trigger(db_ref.deref(), sender_ref); });

	// Mount API
	println!("Mounting API");
	let mut mount = Mount::new();
	let handler = api::get_handler(db.clone(), index_sender)?;
	mount.mount("/api/", handler);

	// Mount static files
	println!("Mounting static files");
	let web_dir_name = matches.opt_str("w");
	let mut default_web_dir = utils::get_data_root()?;
	default_web_dir.push("web");
	let web_dir_path = web_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_web_dir);

	mount.mount("/", Static::new(web_dir_path));

	println!("Starting up server");
	let mut server = match Iron::new(mount).http(("0.0.0.0", 5050)) {
		Ok(s) => s,
		Err(e) => bail!("Error starting up server: {}", e),
	};

	// Start DDNS updates
	let db_ref = db.clone();
	std::thread::spawn(move || { ddns::run(db_ref.deref()); });

	// Run UI
	ui::run();

	println!("Shutting down server");
	if let Err(e) = server.close() {
		bail!("Error shutting down server: {}", e);
	}

	Ok(())
}
<|endoftext|>


<commit_before>use std::str;

extern crate base64;

fn main() {
    let res = base64::encode("Hello world".as_bytes());
    println!("{}", str::from_utf8(&res).unwrap());

    match base64::decode(&res) {
        Ok(data) => {
            println!("{}", str::from_utf8(&data).unwrap());
        },
        Err(err) => {
            println!("error: {:?}", err);
        }
    };
}
<commit_msg>encode from stdin<commit_after>use std::io;
use std::str;

extern crate base64;

fn encode(file: &mut io::Read) {
    let mut buf: [u8; 1024 * 4] = [0; 1024 * 4];

    loop {
        match file.read(&mut buf[..]) {
            Ok(count) => {
                if count == 0 {
                    print!("\n");
                    break;
                }
                let res = base64::encode(&buf);
                print!("{}", str::from_utf8(&res[..count + 1]).unwrap());
            },
            Err(err) => panic!(err),
        }
    }
}

fn main() {
    encode(&mut io::stdin());
}
<|endoftext|>


<commit_before>mod tiny_web_server;
fn main() {
    tiny_web_server::listener::listen("0.0.0.0:8423");
}
<commit_msg>:speaker: add startup message<commit_after>mod tiny_web_server;
fn main() {
    println!("start tiny web server: 0.0.0.0:8423");
    tiny_web_server::listener::listen("0.0.0.0:8423");
}
<|endoftext|>


<commit_before>extern crate txtpic_lib;
extern crate image;
extern crate clap;
use clap::{App, Arg};
use std::path::Path;
use txtpic_lib::character_set::CharacterSet;
use txtpic_lib::text_image::TextImage;

fn main() {
    let matches = App::new("txtpic")
                        .version(env!("CARGO_PKG_VERSION"))
                        .author("Jeremy Dormitzer <jeremy.dormitzer@gmail.com>")
                        .about("Generates text representations of images")
                        .arg(Arg::with_name("IMAGE")
                             .help("The input image")
                             .required(true)
                             .index(1))
                        .arg(Arg::with_name("width")
                             .short("w")
                             .long("width")
                             .takes_value(true)
                             .value_name("WIDTH")
                             .help("An approximate width value for the result")
                             .validator(|arg: String| {
                                 match arg.parse::<u32>() {
                                     Err(_) => Err("Width must be a positive number".to_string()),
                                     Ok(_) => Ok(())
                                 }
                             }))
                        .arg(Arg::with_name("char_set")
                             .short("c")
                             .long("character-set")
                             .use_delimiter(false)
                             .takes_value(true)
                             .value_name("CHARACTERS")
                             .help("An alternate character set to use"))
                        .arg(Arg::with_name("invert")
                             .short("i")
                             .long("invert")
                             .help("Invert the result to make it suitable for black text on a white background"))
                        .get_matches();

    let img_path = matches.value_of("IMAGE").unwrap();
    let img = match image::open(Path::new(img_path)) {
        Ok(img) => img,
        Err(e) => {
            println!("Unable to read image: {}", e);
            std::process::exit(1);
        }
    };

    let char_set = match matches.value_of("char_set") {
        Some(chars) => if matches.is_present("invert") {
            CharacterSet::from(&chars).invert()
        }
        else {
            CharacterSet::from(&chars)
        },
        None => if matches.is_present("invert") {
            CharacterSet::preset_small().invert()
        }
        else {
            CharacterSet::preset_small()
        }
    };

    let width = match matches.value_of("width") {
        Some(width) => width.parse::<u32>().unwrap(),
        None => 80 as u32
    };

    let txt_img = TextImage::from(img, char_set, width);
    println!("{}", txt_img);
}
<commit_msg>Add --preset option<commit_after>extern crate txtpic_lib;
extern crate image;
extern crate clap;
use clap::{App, Arg};
use std::path::Path;
use txtpic_lib::character_set::CharacterSet;
use txtpic_lib::text_image::TextImage;

fn main() {
    let matches = App::new("txtpic")
                        .version(env!("CARGO_PKG_VERSION"))
                        .author("Jeremy Dormitzer <jeremy.dormitzer@gmail.com>")
                        .about("Generates text representations of images")
                        .arg(Arg::with_name("IMAGE")
                             .help("The input image")
                             .required(true)
                             .index(1))
                        .arg(Arg::with_name("width")
                             .short("w")
                             .long("width")
                             .takes_value(true)
                             .value_name("WIDTH")
                             .default_value("80")
                             .help("An approximate width value for the result")
                             .validator(|arg: String| {
                                 match arg.parse::<u32>() {
                                     Err(_) => Err("Width must be a positive number".to_string()),
                                     Ok(_) => Ok(())
                                 }
                             }))
                        .arg(Arg::with_name("char_set")
                             .short("c")
                             .long("character-set")
                             .use_delimiter(false)
                             .takes_value(true)
                             .value_name("CHARACTERS")
                             .help("An alternate character set to use"))
                        .arg(Arg::with_name("invert")
                             .short("i")
                             .long("invert")
                             .help("Invert the result to make it suitable for black text on a white background"))
                        .arg(Arg::with_name("preset")
                             .short("p")
                             .long("preset")
                             .value_name("PRESET NAME")
                             .conflicts_with("char_set")
                             .possible_values(&["small", "medium", "large"])
                             .default_value("small")
                             .help("A preset character set to use"))
                        .get_matches();

    let img_path = matches.value_of("IMAGE").unwrap();
    let img = match image::open(Path::new(img_path)) {
        Ok(img) => img,
        Err(e) => {
            println!("Unable to read image: {}", e);
            std::process::exit(1);
        }
    };

    let mut char_set = match matches.value_of("char_set") {
        Some(chars) => CharacterSet::from(&chars),
        None => match matches.value_of("preset").unwrap() {
            "small" => CharacterSet::preset_small(),
            "medium" => CharacterSet::preset_medium(),
            "large" => CharacterSet::preset_large(),
            &_ => panic!("Unknown preset: {}", matches.value_of("preset").unwrap())
        }
    };

    if matches.is_present("invert") { char_set = char_set.invert(); };

    let width = matches.value_of("width").unwrap().parse::<u32>().unwrap();

    let txt_img = TextImage::from(img, char_set, width);
    println!("{}", txt_img);
}
<|endoftext|>


<commit_before>use std::fs;
use std::env;
use std::fs::File;
use std::collections::HashMap;
use std::os::unix::fs::MetadataExt;
use std::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
use std::io::Read;

#[derive(Debug)]
struct FileEntry {
    inode: u64,
    dev:  u64,
    path : String,
}

fn collect_files(dir: &String, h: &mut HashMap<u64, Vec<FileEntry>>) {
    if let Ok(entries) = fs::read_dir(dir) {
        for entry in entries {
            if let Ok(entry) = entry {
                let path = entry.path();
                if let Some(path_str) = path.to_str() {
                    if let Ok(metadata) = path.symlink_metadata() {
                        let ft = metadata.file_type();
                        if !ft.is_symlink() {
                            if ft.is_file() {
                                let file_size = metadata.len();
                                if file_size == 0 {
                                    continue;
                                }
                                h.entry(file_size).or_insert_with(Vec::new)
                                    .push(
                                     FileEntry{ inode : metadata.ino(),
                                         dev   : metadata.dev(),
                                         path  : String::from(path_str),
                                     });
                            } else if ft.is_dir() {
                                collect_files(&(String::from(path_str)), h);
                            }
                        }
                    }
                }
            }
        }
    } else {
        println!("{}: invalid directory", dir);
    }
}

fn find_duplicates(duplicates: &mut HashMap<u64, Vec<FileEntry>>,
                   vec: &Vec<FileEntry> ) {
    for file_entry in vec {
        if let Ok(mut file) = File::open(&file_entry.path) {
            let mut buf: [u8; 1024] = [0; 1024];
            if let Ok(nbytes) = file.read(&mut buf) {
                let mut hasher = DefaultHasher::new();
                hasher.write(&buf[..nbytes as usize]);
                let k = hasher.finish();
                duplicates.entry(k).or_insert_with(Vec::new)
                    .push(
                        FileEntry{ inode : file_entry.inode,
                            dev  : file_entry.dev,
                            path : file_entry.path.to_string(),
                        });
            }
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();

    // Print out usage if no directories are given.
    if args.len() == 1 {
        println!("Usage: {} <dir1> [dir2 [dir3 ...]]", args[0]);
        ::std::process::exit(0);
    }

    let mut hmap: HashMap<u64, Vec<FileEntry> > = HashMap::new();

    for dir in &args[1..] {
        collect_files(dir, &mut hmap);
    }

    // Get rid of all the single entries.
    hmap.retain(|_, v| v.len() >= 2);

    let mut cluster = 1;

    for (key, val) in hmap.iter() {
        let mut duplicates: HashMap<u64, Vec<FileEntry> > = HashMap::new();
        find_duplicates(&mut duplicates, &val);

        for (hash, vec) in duplicates {
            if vec.len() >= 2 {
                println!("{} files in cluster {} (size: {}, digest: {})",
                         vec.len(), cluster, key, hash);
                for file_entry in vec {
                    println!("{}", file_entry.path);
                }
                cluster += 1;
            }
        }
    }
}
<commit_msg>Some more idiomatic changes<commit_after>use std::fs;
use std::env;
use std::fs::File;
use std::io::Read;
use std::hash::Hasher;
use std::collections::HashMap;
use std::os::unix::fs::MetadataExt;
use std::collections::hash_map::DefaultHasher;

#[derive(Debug)]
struct FileEntry {
    inode: u64,
    dev:  u64,
    path : String,
}

fn collect_files(dir: &String, h: &mut HashMap<u64, Vec<FileEntry>>) {
    if let Ok(entries) = fs::read_dir(dir) {
        for entry in entries {
            if let Ok(entry) = entry {
                let path = entry.path();
                if let Some(path_str) = path.to_str() {
                    if let Ok(metadata) = path.symlink_metadata() {
                        let ft = metadata.file_type();
                        if ft.is_symlink() {
                            continue;
                        } else if ft.is_file() {
                                match metadata.len() {
                                    0 => continue,
                                    i => h.entry(i).or_insert_with(Vec::new)
                                          .push(
                                           FileEntry{ inode : metadata.ino(),
                                               dev   : metadata.dev(),
                                               path  : String::from(path_str),
                                           }),
                                };
                        } else if ft.is_dir() {
                            collect_files(&(String::from(path_str)), h);
                        }
                    }
                }
            }
        }
    } else {
        println!("{}: invalid directory", dir);
    }
}

fn find_duplicates(duplicates: &mut HashMap<u64, Vec<FileEntry>>,
                   vec: &Vec<FileEntry> ) {
    for file_entry in vec {
        if let Ok(mut file) = File::open(&file_entry.path) {
            let mut buf: [u8; 1024] = [0; 1024];
            if let Ok(nbytes) = file.read(&mut buf) {
                let mut hasher = DefaultHasher::new();
                hasher.write(&buf[..nbytes as usize]);
                let k = hasher.finish();
                duplicates.entry(k).or_insert_with(Vec::new)
                    .push(
                        FileEntry{ inode : file_entry.inode,
                            dev  : file_entry.dev,
                            path : file_entry.path.to_string(),
                        });
            }
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();

    // Print out usage if no directories are given.
    if args.len() == 1 {
        println!("Usage: {} <dir1> [dir2 [dir3 ...]]", args[0]);
        ::std::process::exit(0);
    }

    let mut hmap: HashMap<u64, Vec<FileEntry> > = HashMap::new();

    for dir in &args[1..] {
        collect_files(dir, &mut hmap);
    }

    // Get rid of all the single entries.
    hmap.retain(|_, v| v.len() >= 2);

    let mut cluster = 1;

    for (key, val) in hmap.iter() {
        let mut duplicates: HashMap<u64, Vec<FileEntry> > = HashMap::new();
        find_duplicates(&mut duplicates, &val);

        for (hash, vec) in duplicates {
            if vec.len() >= 2 {
                println!("{} files in cluster {} (size: {}, digest: {})",
                         vec.len(), cluster, key, hash);
                for file_entry in vec {
                    println!("{}", file_entry.path);
                }
                cluster += 1;
            }
        }
    }
}
<|endoftext|>