<commit_before>#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

mod logger;
mod toml_file;
mod git;
mod changelog;
mod commit_analyzer;
mod cargo;
mod error;
mod github;
mod config;
mod utils;

extern crate rustc_serialize;
extern crate toml;
extern crate regex;
extern crate semver;
extern crate docopt;
extern crate git2;
extern crate clog;
extern crate hyper;
extern crate hubcaps;
extern crate url;
extern crate travis_after_all;
extern crate env_logger;

use docopt::Docopt;
use commit_analyzer::CommitType;
use config::ConfigBuilder;
use std::process;
use semver::Version;
use std::{env,fs};
use std::path::Path;
use std::error::Error;
use std::thread;
use std::time::Duration;
use travis_after_all::Build;
use utils::user_repo_from_url;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USERAGENT: &'static str = concat!("semantic-rs/", env!("CARGO_PKG_VERSION"));
const USAGE: &'static str = "
semantic.rs 🚀

Usage:
  semantic-rs [options]
  semantic-rs --version

Options:
  -h --help              Show this screen.
  --version              Show version.
  -p PATH, --path=PATH   Specifies the repository path. [default: .]
  -w W, --write=W        Write changes to files (default: yes if CI is set, otherwise no).
  -r R, --release=R      Create release on GitHub and publish on crates.io (only in write mode) [default: yes].
  -b B, --branch=B       The branch on which releases should happen. [default: master].
";

const COMMITTER_ERROR_MESSAGE: &'static str = r"
A release commit needs a committer name and email address.
We tried fetching it from different locations, but couldn't find one.

Committer information is taken from the following environment variables, if set:

GIT_COMMITTER_NAME
GIT_COMMITTER_EMAIL

If none is set the normal git config is tried in the following order:

Local repository config
User config
Global config";

macro_rules! print_exit {
    ($fmt:expr) => {{
        logger::stderr($fmt);
        process::exit(1);
    }};
    ($fmt:expr, $($arg:tt)*) => {{
        logger::stderr(format!($fmt, $($arg)*));
        process::exit(1);
    }};
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_path: String,
    flag_write: Option<String>,
    flag_version: bool,
    flag_release: String,
    flag_branch: String,
}

fn string_to_bool(answer: &str) -> bool {
    match &answer.to_lowercase()[..] {
        "yes" | "true" | "1" => true,
        _ => false
    }
}

fn version_bump(version: &Version, bump: CommitType) -> Option<Version> {
    let mut version = version.clone();
    match bump {
        CommitType::Unknown => return None,
        CommitType::Patch => version.increment_patch(),
        CommitType::Minor => version.increment_minor(),
        CommitType::Major => version.increment_major(),
    }

    Some(version)
}

fn ci_env_set() -> bool {
    env::var("CI").is_ok()
}

fn current_branch(repo: &git2::Repository) -> Option<String> {
    if let Ok(branch) = env::var("TRAVIS_BRANCH") {
        return Some(branch)
    }

    let head = repo.head().expect("No HEAD found for repository");

    if head.is_branch() {
        let short = head.shorthand().expect("No branch name found");
        return Some(short.into());
    }

    None
}

fn is_release_branch(current: &str, release: &str) -> bool {
    if let Ok(pr) = env::var("TRAVIS_PULL_REQUEST") {
        if pr != "false" {
            return false;
        }
    }

    current == release
}

fn push_to_github(config: &config::Config, tag_name: &str) {
    logger::stdout("Pushing new commit and tag");
    git::push(&config, &tag_name)
        .unwrap_or_else(|err| print_exit!("Failed to push git: {:?}", err));

    logger::stdout("Waiting a tiny bit, so GitHub can store the git tag");
    thread::sleep(Duration::from_secs(1));
}

fn release_on_github(config: &config::Config, tag_message: &str, tag_name: &str) {
    if github::can_release(&config) {
        logger::stdout("Creating GitHub release");
        github::release(&config, &tag_name, &tag_message)
            .unwrap_or_else(|err| print_exit!("Failed to create GitHub release: {:?}", err));
    } else {
        logger::stdout("Project not hosted on GitHub. Skipping release step");
    }
}

fn release_on_cratesio(config: &config::Config) {
    logger::stdout("Publishing crate on crates.io");
    if !cargo::publish(&config.repository_path, &config.cargo_token.as_ref().unwrap()) {
        print_exit!("Failed to publish on crates.io");
    }
}

fn generate_changelog(repository_path: &str, version: &Version, new_version: &String) -> String {
    logger::stdout(format!("New version would be: {}", new_version));
    logger::stdout("Would write the following Changelog:");
    match changelog::generate(repository_path, &version.to_string(), new_version) {
        Ok(log) => log,
        Err(err) => {
            logger::stderr(format!("Generating Changelog failed: {:?}", err));
            process::exit(1)
        }
    }
}

fn write_changelog(repository_path: &str, version: &Version, new_version: &str) {
    logger::stdout("Writing Changelog");
    changelog::write(repository_path, &version.to_string(), &new_version)
        .unwrap_or_else(|err| print_exit!("Writing Changelog failed: {:?}", err));
}

fn print_changelog(changelog: &str) {
    logger::stdout("====================================");
    logger::stdout(changelog);
    logger::stdout("====================================");
    logger::stdout("Would create annotated git tag");
}

fn package_crate(config: &config::Config, repository_path: &str, new_version: &str) {
    if config.release_mode {
        logger::stdout("Updating lockfile");
        if !cargo::update_lockfile(repository_path) {
            print_exit!("`cargo fetch` failed. See above for the cargo error message.");
        }
    }

    git::commit_files(&config, &new_version)
        .unwrap_or_else(|err| print_exit!("Committing files failed: {:?}", err));

    logger::stdout("Package crate");
    if !cargo::package(repository_path) {
        print_exit!("`cargo package` failed. See above for the cargo error message.");
    }
}

fn main() {
    env_logger::init().expect("Can't instantiate env logger");

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

    let mut config_builder = ConfigBuilder::new();

    if args.flag_version {
        println!("semantic.rs 🚀 -- v{}", VERSION);
        process::exit(0);
    }

    // If write mode is requested OR denied,
    // adhere to the user's wish,
    // otherwise we decide based on whether we are running in CI.
    let write_mode = match args.flag_write {
        None => ci_env_set(),
        Some(ref flag) => string_to_bool(flag)
    };

    // We can only release, if we are allowed to write
    let release_mode = write_mode && string_to_bool(&args.flag_release);

    config_builder.write(write_mode);
    config_builder.release(release_mode);
    config_builder.branch(args.flag_branch);

    println!("semantic.rs 🚀");

    logger::stdout("Analyzing your repository");
    let path = Path::new(&args.flag_path);
    let path = fs::canonicalize(path)
        .unwrap_or_else(|_| print_exit!("Path does not exist or a component is not a directory"));
    let repository_path = path.to_str()
        .unwrap_or_else(|| print_exit!("Path is not valid unicode"));

    let repo = match git2::Repository::open(repository_path) {
        Ok(repo) => repo,
        Err(e) => {
            logger::stderr(format!("Could not open the git repository: {:?}", e));
            process::exit(1);
        }
    };

    config_builder.repository_path(repository_path.to_owned());

    // extra scope scope to make sure borrow of `repo` is dropped
    {
        let signature = match git::get_signature(&repo) {
            Ok(sig) => sig,
            Err(e) => {
                logger::stderr(format!("Failed to get the committer's name and email address: {}", e.description()));
                logger::stderr(COMMITTER_ERROR_MESSAGE);
                process::exit(1);
            }
        };

        config_builder.signature(signature.to_owned());
    }

    // In case we are in write-mode AND release mode,
    // we will make sure we got all configuration settings
    if write_mode && release_mode {
        let remote_or_none = repo.find_remote("origin");
        match remote_or_none {
            Ok(remote) => {
                let url = remote.url().expect("Remote URL is not valid UTF-8").to_owned();
                let (user, repo_name) = user_repo_from_url(&url)
                    .unwrap_or_else(|e| print_exit!("Could not extract user and repository name from URL: {:?}", e));
                config_builder.user(user);
                config_builder.repository_name(repo_name);

                if github::is_github_url(&url) {
                    let gh_token = env::var("GH_TOKEN")
                        .unwrap_or_else(|err| print_exit!("GH_TOKEN not set: {:?}", err));
                    config_builder.gh_token(gh_token);
                }

                let cargo_token = env::var("CARGO_TOKEN")
                    .unwrap_or_else(|err| print_exit!("CARGO_TOKEN not set: {:?}", err));

                config_builder.cargo_token(cargo_token);
            },
            Err(err) => {
                logger::warn(format!("Could not determine the origin remote url: {:?}", err));
                logger::warn("semantic-rs can't push changes or create a release on GitHub");
            }
        }
    }

    config_builder.repository(repo);
    let config = config_builder.build();

    let branch = current_branch(&config.repository)
        .unwrap_or_else(|| print_exit!("Could not determine current branch."));

    if !is_release_branch(&branch, &config.branch) {
        println!("Current branch is '{}', releases are only done from branch '{}'", branch, config.branch);
        println!("No release done from a pull request either.");
        process::exit(0);
    }

    if config.release_mode && ci_env_set() {
        let build_run = Build::from_env()
            .unwrap_or_else(|e| print_exit!("CI mode, but can't check other builds. Error: {:?}", e));

        if !build_run.is_leader() {
            println!("Not the build leader. Nothing to do. Bye.");
            process::exit(0);
        }

        println!("I am the build leader. Waiting for other jobs to finish.");
        match build_run.wait_for_others() {
            Ok(()) => println!("Other jobs finished and succeeded. Doing my work now."),
            Err(travis_after_all::Error::FailedBuilds) => {
                print_exit!("Some builds failed. Stopping here.");
            },
            Err(e) => print_exit!("Waiting for other builds failed Reason: {:?}", e),
        }
    }

    let version = toml_file::read_from_file(&config.repository_path)
        .unwrap_or_else(|err| print_exit!("Reading `Cargo.toml` failed: {:?}", err));

    let version = Version::parse(&version).expect("Not a valid version");
    logger::stdout(format!("Current version: {}", version.to_string()));

    logger::stdout("Analyzing commits");

    let bump = git::version_bump_since_latest(&config.repository);
    if write_mode {
        logger::stdout(format!("Commits analyzed. Bump will be {:?}", bump));
    } else {
        logger::stdout(format!("Commits analyzed. Bump would be {:?}", bump));
    }
    let new_version = match version_bump(&version, bump) {
        Some(new_version) => new_version.to_string(),
        None => {
            logger::stdout("No version bump. Nothing to do.");
            process::exit(0);
        }
    };

    if !config.write_mode {
        let changelog = generate_changelog(repository_path, &version, &new_version);
        print_changelog(&changelog);
    } else {
        logger::stdout(format!("New version: {}", new_version));

        toml_file::write_new_version(repository_path, &new_version)
            .unwrap_or_else(|err| print_exit!("Writing `Cargo.toml` failed: {:?}", err));

        write_changelog(&repository_path, &version, &new_version);
        package_crate(&config, &repository_path, &new_version);

        logger::stdout("Creating annotated git tag");
        let tag_message = changelog::generate(repository_path, &version.to_string(), &new_version)
            .unwrap_or_else(|err| print_exit!("Can't generate changelog: {:?}", err));

        let tag_name = format!("v{}", new_version);
        git::tag(&config, &tag_name, &tag_message)
            .unwrap_or_else(|err| print_exit!("Failed to create git tag: {:?}", err));

        if config.release_mode && config.can_push() {
            push_to_github(&config, &tag_name);
            release_on_github(&config, &tag_message, &tag_name);
            release_on_cratesio(&config);
            println!("{} v{} is released. 🚀🚀🚀", config.repository_name.unwrap(), new_version);
        }
    }
}
<commit_msg>refactor: remove old main function up to config builder initialisation<commit_after>#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

mod logger;
mod toml_file;
mod git;
mod changelog;
mod commit_analyzer;
mod cargo;
mod error;
mod github;
mod config;
mod utils;

extern crate rustc_serialize;
extern crate toml;
extern crate regex;
extern crate semver;
extern crate docopt;
extern crate git2;
extern crate clog;
extern crate hyper;
extern crate hubcaps;
extern crate url;
extern crate travis_after_all;
extern crate env_logger;

use docopt::Docopt;
use commit_analyzer::CommitType;
use config::ConfigBuilder;
use std::process;
use semver::Version;
use std::{env,fs};
use std::path::Path;
use std::error::Error;
use std::thread;
use std::time::Duration;
use travis_after_all::Build;
use utils::user_repo_from_url;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USERAGENT: &'static str = concat!("semantic-rs/", env!("CARGO_PKG_VERSION"));
const USAGE: &'static str = "
semantic.rs 🚀

Usage:
  semantic-rs [options]
  semantic-rs --version

Options:
  -h --help              Show this screen.
  --version              Show version.
  -p PATH, --path=PATH   Specifies the repository path. [default: .]
  -w W, --write=W        Write changes to files (default: yes if CI is set, otherwise no).
  -r R, --release=R      Create release on GitHub and publish on crates.io (only in write mode) [default: yes].
  -b B, --branch=B       The branch on which releases should happen. [default: master].
";

const COMMITTER_ERROR_MESSAGE: &'static str = r"
A release commit needs a committer name and email address.
We tried fetching it from different locations, but couldn't find one.

Committer information is taken from the following environment variables, if set:

GIT_COMMITTER_NAME
GIT_COMMITTER_EMAIL

If none is set the normal git config is tried in the following order:

Local repository config
User config
Global config";

macro_rules! print_exit {
    ($fmt:expr) => {{
        logger::stderr($fmt);
        process::exit(1);
    }};
    ($fmt:expr, $($arg:tt)*) => {{
        logger::stderr(format!($fmt, $($arg)*));
        process::exit(1);
    }};
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_path: String,
    flag_write: Option<String>,
    flag_version: bool,
    flag_release: String,
    flag_branch: String,
}

fn string_to_bool(answer: &str) -> bool {
    match &answer.to_lowercase()[..] {
        "yes" | "true" | "1" => true,
        _ => false
    }
}

fn version_bump(version: &Version, bump: CommitType) -> Option<Version> {
    let mut version = version.clone();
    match bump {
        CommitType::Unknown => return None,
        CommitType::Patch => version.increment_patch(),
        CommitType::Minor => version.increment_minor(),
        CommitType::Major => version.increment_major(),
    }

    Some(version)
}

fn ci_env_set() -> bool {
    env::var("CI").is_ok()
}

fn current_branch(repo: &git2::Repository) -> Option<String> {
    if let Ok(branch) = env::var("TRAVIS_BRANCH") {
        return Some(branch)
    }

    let head = repo.head().expect("No HEAD found for repository");

    if head.is_branch() {
        let short = head.shorthand().expect("No branch name found");
        return Some(short.into());
    }

    None
}

fn is_release_branch(current: &str, release: &str) -> bool {
    if let Ok(pr) = env::var("TRAVIS_PULL_REQUEST") {
        if pr != "false" {
            return false;
        }
    }

    current == release
}

fn push_to_github(config: &config::Config, tag_name: &str) {
    logger::stdout("Pushing new commit and tag");
    git::push(&config, &tag_name)
        .unwrap_or_else(|err| print_exit!("Failed to push git: {:?}", err));

    logger::stdout("Waiting a tiny bit, so GitHub can store the git tag");
    thread::sleep(Duration::from_secs(1));
}

fn release_on_github(config: &config::Config, tag_message: &str, tag_name: &str) {
    if github::can_release(&config) {
        logger::stdout("Creating GitHub release");
        github::release(&config, &tag_name, &tag_message)
            .unwrap_or_else(|err| print_exit!("Failed to create GitHub release: {:?}", err));
    } else {
        logger::stdout("Project not hosted on GitHub. Skipping release step");
    }
}

fn release_on_cratesio(config: &config::Config) {
    logger::stdout("Publishing crate on crates.io");
    if !cargo::publish(&config.repository_path, &config.cargo_token.as_ref().unwrap()) {
        print_exit!("Failed to publish on crates.io");
    }
}

fn generate_changelog(repository_path: &str, version: &Version, new_version: &String) -> String {
    logger::stdout(format!("New version would be: {}", new_version));
    logger::stdout("Would write the following Changelog:");
    match changelog::generate(repository_path, &version.to_string(), new_version) {
        Ok(log) => log,
        Err(err) => {
            logger::stderr(format!("Generating Changelog failed: {:?}", err));
            process::exit(1)
        }
    }
}

fn write_changelog(repository_path: &str, version: &Version, new_version: &str) {
    logger::stdout("Writing Changelog");
    changelog::write(repository_path, &version.to_string(), &new_version)
        .unwrap_or_else(|err| print_exit!("Writing Changelog failed: {:?}", err));
}

fn print_changelog(changelog: &str) {
    logger::stdout("====================================");
    logger::stdout(changelog);
    logger::stdout("====================================");
    logger::stdout("Would create annotated git tag");
}

fn package_crate(config: &config::Config, repository_path: &str, new_version: &str) {
    if config.release_mode {
        logger::stdout("Updating lockfile");
        if !cargo::update_lockfile(repository_path) {
            print_exit!("`cargo fetch` failed. See above for the cargo error message.");
        }
    }

    git::commit_files(&config, &new_version)
        .unwrap_or_else(|err| print_exit!("Committing files failed: {:?}", err));

    logger::stdout("Package crate");
    if !cargo::package(repository_path) {
        print_exit!("`cargo package` failed. See above for the cargo error message.");
    }
}

fn main() {
    env_logger::init().expect("Can't instantiate env logger");
    println!("semantic.rs 🚀");

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

    let mut config_builder = ConfigBuilder::new();

    if args.flag_version {
        println!("semantic.rs 🚀 -- v{}", VERSION);
        process::exit(0);
    }

    // If write mode is requested OR denied,
    // adhere to the user's wish,
    // otherwise we decide based on whether we are running in CI.
    let write_mode = match args.flag_write {
        None => ci_env_set(),
        Some(ref flag) => string_to_bool(flag)
    };

    // We can only release, if we are allowed to write
    let release_mode = write_mode && string_to_bool(&args.flag_release);

    config_builder.write(write_mode);
    config_builder.release(release_mode);
    config_builder.branch(args.flag_branch);

}
<|endoftext|>


<commit_before>extern crate dive;

extern crate getopts;

use std::env;
use std::process;
use getopts::Options;

const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} path ... [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("a", "all", "Show files whose names begin with a dot (.)");
    opts.optflag("h", "help", "Print this help menu");
    opts.optflag("V", "version", "Print version info and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }
    if matches.opt_present("V") {
        println!("{} version {}", program, VERSION.unwrap_or("unknown"));
        return;
    }

    let config = dive::Config::new(&matches);

    let start_paths = if !matches.free.is_empty() {
        matches.free.clone()
    } else {
        vec![".".to_string()]
    };

    if let Err(e) = dive::run(start_paths, config) {
        println!("ERROR: {}", e);
        process::exit(1);
    }
}

<commit_msg>Stripping path info from --help/--version response<commit_after>extern crate dive;

extern crate getopts;

use std::env;
use std::path::Path;
use std::process;
use getopts::Options;

const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} path ... [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = Path::new(&args[0])
        .file_name()
        .and_then(|o| o.to_str())
        .unwrap();

    let mut opts = Options::new();
    opts.optflag("a", "all", "Show files whose names begin with a dot (.)");
    opts.optflag("h", "help", "Print this help menu");
    opts.optflag("V", "version", "Print version info and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    if matches.opt_present("V") {
        println!("{} version {}", program, VERSION.unwrap_or("unknown"));
        return;
    }

    let config = dive::Config::new(&matches);

    let start_paths = if !matches.free.is_empty() {
        matches.free.clone()
    } else {
        vec![".".to_string()]
    };

    if let Err(e) = dive::run(start_paths, config) {
        println!("ERROR: {}", e);
        process::exit(1);
    }
}

<|endoftext|>


<commit_before>extern crate regex;
use std::{env, fs, io};
use std::collections::HashMap;
use std::io::prelude::*;

macro_rules! regex { ($re:expr) => { ::regex::Regex::new($re).unwrap() } }

fn replace_var(line: String, keys: &HashMap<String, String>, result: &mut Vec<String>) {
    let re = regex!(r"(?P<full>\$\{\s*(?P<var>\S*)\s*\})");
    let mut str_line: String = line.clone();

    for cap in re.captures_iter(&*str_line.clone()) {
        cap.name("var").map(|v| {
            env_or_prop(v, keys).map(|v2|{
                str_line = re.replace(&*str_line, &*v2);
            });
        });
    }

    result.push(str_line.to_string());
}

fn env_or_prop(key: &str, keys: &HashMap<String, String>) -> Option<String> {
    env::var_os(key).or(
        keys.get(key).map(|v2| {
            std::ffi::OsString::from(v2 as &String)
        })
        ).and_then(|v| v.into_string().ok())
}

fn process(file: fs::File, dict: &HashMap<String, String>) -> Vec<String> {
    let buf_reader = io::BufReader::new(&file);
    let mut result: Vec<String> = vec!();

    println!("Skriver ut: ");
    for line in buf_reader.lines() {
        replace_var(line.unwrap(), &dict, &mut result);
    }

    result
}

fn extract_keys(file: fs::File) -> HashMap<String, String>{
    let key_regex = regex!(r"^\s*(?P<key>\S*)\s*=\s*(?P<val>.*)");
    let buf_reader = io::BufReader::new(&file);
    let mut key_map = HashMap::new();

    for line in buf_reader.lines().enumerate() {
        for cap in key_regex.captures_iter(&*line.1.ok().expect("Could not read line")) {
            let key = cap.name("key").unwrap_or("???");
            let val = cap.name("val").unwrap_or("???");
            key_map.insert(key.to_string(), val.to_string());
            println!("{}: key({}), val({})", line.0, key, val);
        }
    }

    key_map
}

fn open_file(filename: &str) -> fs::File {
    fs::File::open(filename)
        .ok().expect(&*format!("Could not open: {}", filename))
}

fn map_args(args: &Vec<String>) -> HashMap<ValidArgs, Option<String>> {
    let mut arg_map = HashMap::new();
    for i in args {
        arg_map.insert(ValidArgs::PropertyFilename, None /*Some("val1".to_string())*/);
    }
    arg_map
}

fn validate_args<'a>(args: &'a HashMap<ValidArgs, Option<String>>) -> Result<&'a HashMap<ValidArgs, Option<String>>, &str> {
    match args.len() != 4 {
        true => Ok(args),
        false => Err("There needs to be 4 args"),
    }
}

static help_txt: &'static str = "Usage: proper [OPTIONS] <property-file> <result-file>";

#[derive(Eq)]
#[derive(Hash)]
enum ValidArgs {
    PropertyFilename,
    KeysFilename,
    ResultFilename,
}

impl PartialEq for ValidArgs {
    fn eq(&self, other: &ValidArgs) -> bool {
        self == other
    }
    fn ne(&self, other: &ValidArgs) -> bool {
        self != other
    }
}

#[allow(dead_code)]
fn main() {
  /*  let mut cmd_args = env::args();
    let application_name = cmd_args.next().unwrap();
    let args = &map_args(&cmd_args.collect());
    let valid_args = validate_args(&args).unwrap_or_else(|v| {
        println!("ERROR: {}", v);
        println!("{}", help_txt);
        std::process::exit(1);
    });

    let prop_maybe = valid_args.get(&ValidArgs::PropertyFilename);
    let prop_maybe2 = prop_maybe.unwrap();
    let prop_filename = prop_maybe2.unwrap();
    let key_filename = args.get(&ValidArgs::KeysFilename).unwrap().unwrap();
    let result_filename = args.get(&ValidArgs::ResultFilename).unwrap().unwrap();
    let prop_file = open_file(&*prop_filename);
    let key_file = open_file(&*key_filename);

    let mut result_file = fs::File::create(result_filename).unwrap();
    for line in process(prop_file, &extract_keys(key_file)).iter().enumerate() {
        println!("{}: {}", line.0, line.1);
        result_file.write_all(&format!("{}\n", line.1).as_bytes()).unwrap();
    }*/
}
<commit_msg>Reworking the args-management and validation for the tool.<commit_after>extern crate regex;
use std::{env, fs, io};
use std::collections::HashMap;
use std::io::prelude::*;

macro_rules! regex { ($re:expr) => { ::regex::Regex::new($re).unwrap() } }

fn replace_var(line: String, keys: &HashMap<String, String>, result: &mut Vec<String>) {
    let re = regex!(r"(?P<full>\$\{\s*(?P<var>\S*)\s*\})");
    let mut str_line: String = line.clone();

    for cap in re.captures_iter(&*str_line.clone()) {
        cap.name("var").map(|v| {
            env_or_prop(v, keys).map(|v2|{
                str_line = re.replace(&*str_line, &*v2);
            });
        });
    }

    result.push(str_line.to_string());
}

fn env_or_prop(key: &str, keys: &HashMap<String, String>) -> Option<String> {
    env::var_os(key).or(
        keys.get(key).map(|v2| {
            std::ffi::OsString::from(v2 as &String)
        })
        ).and_then(|v| v.into_string().ok())
}

fn process(file: fs::File, dict: &HashMap<String, String>) -> Vec<String> {
    let buf_reader = io::BufReader::new(&file);
    let mut result: Vec<String> = vec!();

    println!("Skriver ut: ");
    for line in buf_reader.lines() {
        replace_var(line.unwrap(), &dict, &mut result);
    }

    result
}

fn extract_keys(file: fs::File) -> HashMap<String, String>{
    let key_regex = regex!(r"^\s*(?P<key>\S*)\s*=\s*(?P<val>.*)");
    let buf_reader = io::BufReader::new(&file);
    let mut key_map = HashMap::new();

    for line in buf_reader.lines().enumerate() {
        for cap in key_regex.captures_iter(&*line.1.ok().expect("Could not read line")) {
            let key = cap.name("key").unwrap_or("???");
            let val = cap.name("val").unwrap_or("???");
            key_map.insert(key.to_string(), val.to_string());
            println!("{}: key({}), val({})", line.0, key, val);
        }
    }

    key_map
}

fn open_file(filename: &str) -> fs::File {
    fs::File::open(filename)
        .ok().expect(&*format!("Could not open: {}", filename))
}

fn map_args(args: &Vec<String>) -> Box<HashMap<ValidArgs, Option<String>>> {
    let mut arg_map = Box::new(HashMap::new());
    println!("len: {}", args.len());
    for i in args.iter().enumerate() {
        println!("{}: {}", i.0, i.1);
        //(*arg_map).insert(ValidArgs::PropertyFilename, /*Some(i.to_string()*/None);
    }
    arg_map
}

fn validate_args<'a>(args: &'a HashMap<ValidArgs, Option<String>>) -> Result<&'a HashMap<ValidArgs, Option<String>>, &str> {
    match args.len() != 4 {
        true => Ok(args),
        false => Err("There needs to be 4 args"),
    }
}

static HELP_TXT: &'static str = "Usage: proper [OPTIONS] <property-file> <result-file>";

#[derive(Eq)]
#[derive(Hash)]
enum ValidArgs {
    PropertyFilename,
    KeysFilename,
    ResultFilename,
}

impl PartialEq for ValidArgs {
    fn eq(&self, other: &ValidArgs) -> bool {
        self == other
    }
    fn ne(&self, other: &ValidArgs) -> bool {
        self != other
    }
}

#[allow(dead_code)]
fn main() {
    let mut cmd_args = env::args();
    let application_name = cmd_args.next().unwrap();

    let args = map_args(&cmd_args.collect());
    let valid_args = validate_args(&args).unwrap_or_else(|v| {
        println!("ERROR: {}", v);
        println!("{}", HELP_TXT);
        std::process::exit(1);
    });

    let prop_filename = valid_args.get(&ValidArgs::PropertyFilename).unwrap_or_else(|| {
        println!("ERROR: {}", "Could not find property-file");
        println!("{}", HELP_TXT);
        std::process::exit(1);
    }).as_ref().unwrap();
    let key_filename = valid_args.get(&ValidArgs::KeysFilename).unwrap_or_else(|| {
        println!("ERROR: {}", "Could not find key-file");
        println!("{}", HELP_TXT);
        std::process::exit(1);
    }).as_ref().unwrap();
    let result_filename = valid_args.get(&ValidArgs::ResultFilename).unwrap_or_else(|| {
        println!("ERROR: {}", "Could not find result-file");
        println!("{}", HELP_TXT);
        std::process::exit(1);
    }).as_ref().unwrap();
//    let prop_file = open_file(&prop_filename);
//    let key_file = open_file(&key_filename);

    let mut result_file = fs::File::create(result_filename).unwrap();
  /*  for line in process(prop_file, &extract_keys(key_file)).iter().enumerate() {
        println!("{}: {}", line.0, line.1);
        result_file.write_all(&format!("{}\n", line.1).as_bytes()).unwrap();
    }*/
}
<|endoftext|>


<commit_before>#![allow(unstable, dead_code)]

extern crate libc;

mod args;
mod ansi;
mod matching;
mod screen;

use std::os;
use std::io;
use std::cmp::min;
use screen::Screen;
use screen::Key::*;

fn main() {
  let args = match args::parse_args() {
    Some(args) => args,
    None => {
      os::set_exit_status(1);
      return;
    },
  };

  if args.help { return; }

  let choices = read_choices();

  let mut screen = Screen::open_screen();
  let mut index = 0;

  let visible_choices = min(20, screen.height - 1);

  let mut search = args.initial_search.clone();
  let start_line = screen.height - visible_choices - 1;
  loop {
    screen.hide_cursor();
    screen.blank_screen(start_line);
    screen.move_cursor(start_line, 0);
    let matches = matching::compute_matches(&choices, search.as_slice());
    let mut i = 1;
    screen.write(format!("> {} ({} choices)\n", search.as_slice(), choices.len()).as_slice());
    for choice in matches.iter() {
      if i == index + 1 {
        screen.write_inverted(choice.as_slice());
      } else {
        screen.write(choice.as_slice());
      }
      if i >= visible_choices as usize {
        break;
      } else {
        screen.write("\n");
      }
      i += 1;
    }

    screen.move_cursor(start_line, 2 + search.len() as u16);
    screen.show_cursor();

    match screen.tty.getchar() {
      Char(x) => search.push(x),
      Backspace => { search.pop(); }
      Control('h') => { search.pop(); }
      Control('u') => { search.clear(); }
      Control('c') => { return; }
      Control('n') => { index = min(index + 1, matches.len() - 1); }
      Control('p') => { index = if index == 0 { 0 } else { index - 1 }; }
      Enter => {
        screen.move_cursor(start_line + visible_choices, 0);
        screen.write("\n");
        println!("{}", matches[index]);
        break;
      }
      _ => panic!("Unexpected input"),
    }
  }
}

fn read_choices() -> Vec<String> {
  let mut stdin = io::stdio::stdin();
  let mut lines = Vec::new();

  loop {
    match stdin.read_line() {
      Ok(x) => lines.push(String::from_str(x.as_slice().trim())),
      Err(_) => break,
    }
  }

  lines
}
<commit_msg>Fix index upper bound<commit_after>#![allow(unstable, dead_code)]

extern crate libc;

mod args;
mod ansi;
mod matching;
mod screen;

use std::os;
use std::io;
use std::cmp::min;
use screen::Screen;
use screen::Key::*;

fn main() {
  let args = match args::parse_args() {
    Some(args) => args,
    None => {
      os::set_exit_status(1);
      return;
    },
  };

  if args.help { return; }

  let choices = read_choices();

  let mut screen = Screen::open_screen();
  let mut index = 0;

  let visible_choices = min(20, screen.height - 1);

  let mut search = args.initial_search.clone();
  let start_line = screen.height - visible_choices - 1;
  loop {
    screen.hide_cursor();
    screen.blank_screen(start_line);
    screen.move_cursor(start_line, 0);
    let matches = matching::compute_matches(&choices, search.as_slice());
    let mut i = 1;
    screen.write(format!("> {} ({} choices)\n", search.as_slice(), choices.len()).as_slice());
    for choice in matches.iter() {
      if i == index + 1 {
        screen.write_inverted(choice.as_slice());
      } else {
        screen.write(choice.as_slice());
      }
      if i >= visible_choices as usize {
        break;
      } else {
        screen.write("\n");
      }
      i += 1;
    }

    screen.move_cursor(start_line, 2 + search.len() as u16);
    screen.show_cursor();

    match screen.tty.getchar() {
      Char(x) => {
        search.push(x);
        index = 0;
      }
      Backspace => { search.pop(); }
      Control('h') => { search.pop(); }
      Control('u') => { search.clear(); }
      Control('c') => { return; }
      Control('n') => { index = min(index + 1, min(visible_choices as usize - 1, matches.len() - 1)); }
      Control('p') => { index = if index == 0 { 0 } else { index - 1 }; }
      Enter => {
        screen.move_cursor(start_line + visible_choices, 0);
        screen.write("\n");
        println!("{}", matches[index]);
        break;
      }
      _ => panic!("Unexpected input"),
    }
  }
}

fn read_choices() -> Vec<String> {
  let mut stdin = io::stdio::stdin();
  let mut lines = Vec::new();

  loop {
    match stdin.read_line() {
      Ok(x) => lines.push(String::from_str(x.as_slice().trim())),
      Err(_) => break,
    }
  }

  lines
}
<|endoftext|>


<commit_before>use std::net::TcpStream;
use std::io;
use std::io::prelude::*;
use std::thread;
use std::str;

const COMMAND_BUF_SIZE: usize = 4096;

struct IrcMessage {
	msg: [u8; COMMAND_BUF_SIZE],
	length: usize,
}

struct IrcReader {
	stream: TcpStream,

}

impl IrcReader {
	pub fn new(base_stream: &TcpStream) -> io::Result<IrcReader> {
		let stream = try!(base_stream.try_clone());
		Ok(IrcReader {
			stream: stream,
		})
	}
}

impl Iterator for IrcReader {
	type Item = IrcMessage;
	fn next(&mut self) -> Option<IrcMessage> {
		let mut command_buf: [u8; COMMAND_BUF_SIZE] = [0; COMMAND_BUF_SIZE];
		let mut buf_ind = 0;
		let mut command_end = false;
		let stream = &self.stream;
		let bytes = stream.bytes();
		for x in bytes {
			if x.is_err() {
				return None;
			}
			let next_char = x.unwrap();
			command_buf[buf_ind] = next_char;
			buf_ind = buf_ind + 1;
			if command_end && next_char == 10 {
				return Some(IrcMessage { msg: command_buf, length: buf_ind - 2 });
			} else if next_char == 13 {
				command_end = true;
			} else {
				command_end = false;
			}

			if buf_ind >= COMMAND_BUF_SIZE {
				buf_ind = 0;
			}
		}
		None
	}
}

struct IrcWriter {
	stream: TcpStream,
}

impl IrcWriter {
	pub fn new(base_stream: &TcpStream) -> io::Result<IrcWriter> {
		let stream = try!(base_stream.try_clone());
		Ok(IrcWriter {
			stream: stream,
		})
	}

	pub fn write(&mut self, bytes: &[u8]) {
		let _ = &self.stream.write(&bytes);
	}
}

fn main() {
	let connection_result = TcpStream::connect("127.0.0.1:6667");
	if connection_result.is_err() {
		return;
	}

	let connection = connection_result.unwrap();
	let reader = IrcReader::new(&connection).unwrap();
	let mut writer = IrcWriter::new(&connection).unwrap();

	thread::spawn(move || {
		let stdin = io::stdin();
		let stdin_lock = stdin.lock();
		for in_line in stdin_lock.lines() {
			let _ = in_line.and_then(|x| {
				writer.write(x.as_bytes());
				writer.write(b"\n");
				Ok(x)
			});
		}
	});

	for irc_msg in reader {
		parse_command(&irc_msg.msg[0..irc_msg.length]);
	}
}

fn parse_command(command: &[u8]) {
	let command_str = str::from_utf8(command);
	if command_str.is_err() {
		return;
	}
	println!("{}", command_str.unwrap());
}
<commit_msg>Add parser for IRC messages<commit_after>use std::net::TcpStream;
use std::io;
use std::io::prelude::*;
use std::thread;
use std::str;

const COMMAND_BUF_SIZE: usize = 4096;

struct IrcMessage {
	message: [u8; COMMAND_BUF_SIZE],
	length: usize,
    has_prefix: bool,
    command_index: usize,
    param_index: usize,
    trail_index: usize,
}

impl IrcMessage {
    pub fn new(message: [u8; COMMAND_BUF_SIZE], length: usize) -> IrcMessage {
        let has_prefix = message[0] == b':';

        let mut command_index = 0;
        if has_prefix {
            for x in 1 .. length {
                if message[x] == b' ' {
                    command_index = x + 1;
                    break;
                }
            }
        }

        let mut param_index = 0;
        for x in command_index .. length {
            if message[x] == b' ' {
                param_index = x + 1;
                break;
            }
        }

        let mut trail_index = 0;
        for x in param_index .. length {
            if message[x] == b':' {
                trail_index = x + 1;
                break;
            }
        }

        let new_message = IrcMessage {
            message: message,
            length: length,
            has_prefix: has_prefix,
            command_index: command_index,
            param_index: param_index,
            trail_index: trail_index,
        };

        new_message
    }

    pub fn prefix(&self) -> Option<&[u8]> {
        if self.has_prefix {
            return Some(&self.message[1..self.command_index - 1]);
        }
        None
    }

    pub fn command(&self) -> &[u8] {
        &self.message[self.command_index..self.param_index - 1]
    }

    pub fn param_at(&self, index: u32) -> Option<&[u8]> {
        if self.param_index == 0 {
            return None;
        }

        let mut last_param_index = self.param_index;
        let mut param_count = 0;
        let mut x = last_param_index;
        while x < self.length && (self.trail_index == 0 || x < self.trail_index) {
            if self.message[x] == b' '  {
                if param_count == index {
                    return Some(&self.message[last_param_index..x]);
                }

                param_count = param_count + 1;
                last_param_index = x + 1;
            }
            x = x + 1;
        }
        None
    }

    pub fn trailing(&self) -> Option<&[u8]> {
        if self.trail_index == 0 {
            return None;
        }
        Some(&self.message[self.trail_index..self.length])
    }
}

#[cfg(test)]
mod tests {
    const COMMAND_BUF_SIZE: usize = 4096;
    use std::str;
    #[test]
    fn parse_message() {
        let msg = super::IrcMessage::new(load_message(b":syrk!kalt@millennium.stealth.net QUIT :Gone to have lunch"), 58);
        assert_eq!("syrk!kalt@millennium.stealth.net", str::from_utf8(msg.prefix().unwrap()).unwrap());
        assert_eq!("QUIT", str::from_utf8(msg.command()).unwrap());
        assert_eq!(None, msg.param_at(0));
        assert_eq!(None, msg.param_at(1));
        assert_eq!("Gone to have lunch", str::from_utf8(msg.trailing().unwrap()).unwrap());

        let msg_two = super::IrcMessage::new(load_message(b"SERVICE dict * *.fr 0 0 :French Dictionary"),
            "SERVICE dict * *.fr 0 0 :French Dictionary".len());
        assert_eq!(None, msg_two.prefix());
        assert_eq!("SERVICE", str::from_utf8(msg_two.command()).unwrap());
        assert_eq!("dict", str::from_utf8(msg_two.param_at(0).unwrap()).unwrap());
        assert_eq!("*", str::from_utf8(msg_two.param_at(1).unwrap()).unwrap());
        assert_eq!("*.fr", str::from_utf8(msg_two.param_at(2).unwrap()).unwrap());
        assert_eq!("0", str::from_utf8(msg_two.param_at(3).unwrap()).unwrap());
        assert_eq!("0", str::from_utf8(msg_two.param_at(4).unwrap()).unwrap());
        assert_eq!(None, msg_two.param_at(5));
        assert_eq!("French Dictionary", str::from_utf8(msg_two.trailing().unwrap()).unwrap());
    }

    fn load_message(msg_str: &[u8]) -> [u8; COMMAND_BUF_SIZE] {
        let mut buf: [u8; COMMAND_BUF_SIZE] = [0; COMMAND_BUF_SIZE];

        for x in 0 .. msg_str.len() {
            buf[x] = msg_str[x];
        }

        buf
    }
}

struct IrcReader {
	stream: TcpStream,

}

impl IrcReader {
	pub fn new(base_stream: &TcpStream) -> io::Result<IrcReader> {
		let stream = try!(base_stream.try_clone());
		Ok(IrcReader {
			stream: stream,
		})
	}
}

impl Iterator for IrcReader {
	type Item = IrcMessage;
	fn next(&mut self) -> Option<IrcMessage> {
		let mut command_buf: [u8; COMMAND_BUF_SIZE] = [0; COMMAND_BUF_SIZE];
		let mut buf_ind = 0;
		let mut command_end = false;
		let stream = &self.stream;
		let bytes = stream.bytes();
		for x in bytes {
			if x.is_err() {
				return None;
			}
			let next_char = x.unwrap();
			command_buf[buf_ind] = next_char;
			buf_ind = buf_ind + 1;
			if command_end && next_char == 10 {
				return Some(IrcMessage::new(command_buf, buf_ind - 2));
			} else if next_char == 13 {
				command_end = true;
			} else {
				command_end = false;
			}

			if buf_ind >= COMMAND_BUF_SIZE {
				buf_ind = 0;
			}
		}
		None
	}
}

struct IrcWriter {
	stream: TcpStream,
}

impl IrcWriter {
	pub fn new(base_stream: &TcpStream) -> io::Result<IrcWriter> {
		let stream = try!(base_stream.try_clone());
		Ok(IrcWriter {
			stream: stream,
		})
	}

	pub fn write(&mut self, bytes: &[u8]) {
		let _ = &self.stream.write(&bytes);
	}
}

fn main() {
	let connection_result = TcpStream::connect("127.0.0.1:6667");
	if connection_result.is_err() {
		return;
	}

	let connection = connection_result.unwrap();
	let reader = IrcReader::new(&connection).unwrap();
	let mut writer = IrcWriter::new(&connection).unwrap();

	thread::spawn(move || {
		let stdin = io::stdin();
		let stdin_lock = stdin.lock();
		for in_line in stdin_lock.lines() {
			let _ = in_line.and_then(|x| {
				writer.write(x.as_bytes());
				writer.write(b"\n");
				Ok(x)
			});
		}
	});

	for irc_msg in reader {
		parse_command(&irc_msg.message[0..irc_msg.length]);
	}
}

fn parse_command(command: &[u8]) {
	let command_str = str::from_utf8(command);
	if command_str.is_err() {
		return;
	}
	println!("{}", command_str.unwrap());
}
<|endoftext|>


<commit_before>#[macro_use] extern crate lazy_static;
extern crate regex;
extern crate json;

use std::env;
use std::io;
use std::io::*;
use std::process;

const ANSI_RESET: &'static str = "\x1b[0m";
const ANSI_RED: &'static str = "\x1b[31m";
const ANSI_GREEN: &'static str = "\x1b[32m";
const ANSI_YELLOW: &'static str = "\x1b[33m";
const ANSI_MAGENTA: &'static str = "\x1b[35m";
const ANSI_CYAN: &'static str = "\x1b[36m";
const ANSI_BRIGHT_WHITE: &'static str = "\x1b[97m";

mod dictionary;

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

    let action = env::args().nth(1);

    let include_ids = arguments.contains(&"--id".to_string());
    let tag_per_line = arguments.contains(&"--tag-per-line".to_string());
    let color = arguments.contains(&"--color".to_string());

    match action.as_ref().map(String::as_ref) {
        Some("decode") => process_stdin(include_ids, tag_per_line, color),
        Some(a) => die(&format!("unsupported action '{}'", &a)),
        None => die("no action specified"),
    }
}

fn process_stdin(include_ids: bool, tag_per_line: bool, color: bool) {
    let stdin = io::stdin();
    let in_reader = BufReader::new(stdin);
    let mut stdout = io::stdout();

    for line in in_reader.lines() {
        let translation = match line.as_ref().map(String::as_ref) {
                              Ok(text) => decode_line(text, include_ids, tag_per_line, color).to_string(),
                              Err(error) => error.to_string(),
                          };

        write!(stdout, "{}\n", translation).unwrap();
    }
}

fn enquote(text: &str) -> String {
    return if text == "" || text.contains(' ') { format!("'{}'", text) } else { text.to_string() };
}

fn decode_line(line: &str, include_ids: bool, tag_per_line: bool, color: bool) -> String {
    lazy_static! {
        static ref PATTERN: regex::Regex = regex::Regex::new(r"8=FIX\.\d+\.\d+\1.*?10=\d{3}\1").unwrap();
    }

    if !PATTERN.is_match(line) { return line.to_string(); }

    let mut translation = String::new();

    for field in line.split("\x01") {
        let pair: Vec<&str> = field.splitn(2, "=").collect();
        if pair.len() < 2 { continue; }

        let tag = pair[0];
        let value = pair[1];

        let decoded_tag = decode_tag(tag);
        let decoded_value = decode_value(tag, value);

        if include_ids
        {
            translation.push_str(&colorize(tag, &ANSI_CYAN, color));
            translation.push(':');
        }

        translation.push_str(&colorize(&decoded_tag, &ANSI_BRIGHT_WHITE, color));

        translation.push_str("=");

        if include_ids && value != decoded_value
        {
            translation.push_str(&colorize(value, &ANSI_YELLOW, color));
            translation.push(':');
        }

        translation.push_str(&enquote(&colorize_by_type(value, &decoded_value, color)));

        translation.push(if tag_per_line { '\n' } else {' '});
    }

    if tag_per_line
    {
        translation.push_str("-\n");
    }

    translation.pop();

    return translation;
}

fn colorize(text: &str, ansi_color_code: &str, use_color: bool) -> String {
    let mut result = String::new();

    if use_color { result.push_str(ansi_color_code); }
    result.push_str(text);
    if use_color { result.push_str(&ANSI_RESET); }

    return result;
}

fn colorize_by_type(value: &str, decoded: &str, use_color: bool) -> String {
    lazy_static! {
        static ref DATETIME_PATTERN: regex::Regex = regex::Regex::new(r"\d{8}-\d{2}:\d{2}:\d{2}(.\d{3})?").unwrap();
    }

    let is_decoded = decoded != value;
    let is_number = value.chars().all(|c| char::is_numeric(c) || c == '.');
    let is_date = DATETIME_PATTERN.is_match(value);

    let color_code = if is_decoded { ANSI_RED }
                             else if is_number { ANSI_CYAN }
                             else if is_date { ANSI_MAGENTA }
                             else { ANSI_GREEN };

    return colorize(decoded, color_code, use_color);
}

fn decode_tag(tag: &str) -> String {
     let name = &dictionary::DICTIONARY["tags"][tag];

    return if !name.is_null() { name.to_string() } else { tag.to_string() };
}

fn decode_value<'a>(tag: &'a str, value: &'a str) -> String {
    let enumeration = &dictionary::DICTIONARY["enums"][tag];
    return if !enumeration.is_null() { enumeration[value].to_string() } else { value.to_string() };
}

fn die(message: &str) {
    println!("{}", message);
    process::exit(1);
}
<commit_msg>Changed the colours.<commit_after>#[macro_use] extern crate lazy_static;
extern crate regex;
extern crate json;

use std::env;
use std::io;
use std::io::*;
use std::process;

const ANSI_RESET: &'static str = "\x1b[0m";
const ANSI_RED: &'static str = "\x1b[31m";
const ANSI_GREEN: &'static str = "\x1b[32m";
const ANSI_YELLOW: &'static str = "\x1b[33m";
const ANSI_BLUE: &'static str = "\x1b[34m";
const ANSI_MAGENTA: &'static str = "\x1b[35m";
const ANSI_WHITE: &'static str = "\x1b[37m";
const ANSI_GREY: &'static str = "\x1b[90m";
const ANSI_CYAN: &'static str = "\x1b[36m";
const ANSI_BRIGHT_WHITE: &'static str = "\x1b[97m";

mod dictionary;

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

    let action = env::args().nth(1);

    let include_ids = arguments.contains(&"--id".to_string());
    let tag_per_line = arguments.contains(&"--tag-per-line".to_string());
    let color = arguments.contains(&"--color".to_string());

    match action.as_ref().map(String::as_ref) {
        Some("decode") => process_stdin(include_ids, tag_per_line, color),
        Some(a) => die(&format!("unsupported action '{}'", &a)),
        None => die("no action specified"),
    }
}

fn process_stdin(include_ids: bool, tag_per_line: bool, color: bool) {
    let stdin = io::stdin();
    let in_reader = BufReader::new(stdin);
    let mut stdout = io::stdout();

    for line in in_reader.lines() {
        let translation = match line.as_ref().map(String::as_ref) {
                              Ok(text) => decode_line(text, include_ids, tag_per_line, color).to_string(),
                              Err(error) => error.to_string(),
                          };

        write!(stdout, "{}\n", translation).unwrap();
    }
}

fn enquote(text: &str) -> String {
    return if text == "" || text.contains(' ') { format!("'{}'", text) } else { text.to_string() };
}

fn decode_line(line: &str, include_ids: bool, tag_per_line: bool, color: bool) -> String {
    lazy_static! {
        static ref PATTERN: regex::Regex = regex::Regex::new(r"8=FIX\.\d+\.\d+\1.*?10=\d{3}\1").unwrap();
    }

    if !PATTERN.is_match(line) { return line.to_string(); }

    let mut translation = String::new();

    for field in line.split("\x01") {
        let pair: Vec<&str> = field.splitn(2, "=").collect();
        if pair.len() < 2 { continue; }

        let tag = pair[0];
        let value = pair[1];

        let decoded_tag = decode_tag(tag);
        let decoded_value = decode_value(tag, value);

        if include_ids
        {
            translation.push_str(&colorize(tag, &ANSI_RED, color));
            translation.push(':');
        }

        translation.push_str(&colorize(&decoded_tag, &ANSI_BRIGHT_WHITE, color));

        translation.push_str("=");

        if include_ids && value != decoded_value
        {
            translation.push_str(&colorize(value, &ANSI_YELLOW, color));
            translation.push(':');
        }

        translation.push_str(&enquote(&colorize_by_type(value, &decoded_value, color)));

        translation.push(if tag_per_line { '\n' } else {' '});
    }

    if tag_per_line
    {
        translation.push_str("-\n");
    }

    translation.pop();

    return translation;
}

fn colorize(text: &str, ansi_color_code: &str, use_color: bool) -> String {
    let mut result = String::new();

    if use_color { result.push_str(ansi_color_code); }
    result.push_str(text);
    if use_color { result.push_str(&ANSI_RESET); }

    return result;
}

fn colorize_by_type(value: &str, decoded: &str, use_color: bool) -> String {
    lazy_static! {
        static ref DATETIME_PATTERN: regex::Regex = regex::Regex::new(r"\d{8}-\d{2}:\d{2}:\d{2}(.\d{3})?").unwrap();
    }

    let is_decoded = decoded != value;
    let is_number = value.chars().all(|c| char::is_numeric(c) || c == '.');
    let is_date = DATETIME_PATTERN.is_match(value);

    let color_code = if is_decoded { ANSI_YELLOW }
                             else if is_number { ANSI_CYAN }
                             else if is_date { ANSI_MAGENTA }
                             else { ANSI_GREEN };

    return colorize(decoded, color_code, use_color);
}

fn decode_tag(tag: &str) -> String {
     let name = &dictionary::DICTIONARY["tags"][tag];

    return if !name.is_null() { name.to_string() } else { tag.to_string() };
}

fn decode_value<'a>(tag: &'a str, value: &'a str) -> String {
    let enumeration = &dictionary::DICTIONARY["enums"][tag];
    return if !enumeration.is_null() { enumeration[value].to_string() } else { value.to_string() };
}

fn die(message: &str) {
    println!("{}", message);
    process::exit(1);
}
<|endoftext|>


<commit_before>extern crate identicon;
extern crate openssl;
extern crate png;

use std::io;
use std::os;

use openssl::crypto::hash::{Hasher, HashType};
use png::store_png;

use identicon::Identicon;

fn main() {
    match output() {
        Some(path) => {
            match hash() {
                Some(bytes) => generate(bytes, &path),
                None => os::set_exit_status(2),
            }
        },
        None => {
            println!("Usage: identicon FILENAME INPUT");
            os::set_exit_status(1);
        }
    }
}

fn output() -> Option<Path> {
    if os::args().len() == 2 {
        let name = os::args()[1].clone();
        Some(Path::new(name))
    } else {
        None
    }
}

fn generate(input: Vec<u8>, path: &Path) {
    let identicon = Identicon::new(input);
    let mut image = identicon.image();
    let result = store_png(&mut image, path);
    match result {
        Ok(_) => {},
        Err(e) => {
            println!("{}", e);
            os::set_exit_status(2);
        },
    };
}

fn hash() -> Option<Vec<u8>> {
    let mut hash = Hasher::new(HashType::MD5);
    for result in io::stdin().lines() {
        match result {
            Ok(line) => {
                hash.update(line.as_bytes());
            },
            Err(e) => {
                println!("{}", e);
                return None
            },
        }
    }
    Some(hash.finalize())
}
<commit_msg>Write png to stdout.<commit_after>extern crate identicon;
extern crate openssl;
extern crate png;

use std::io;
use std::os;

use openssl::crypto::hash::{Hasher, HashType};
use png::write_png;

use identicon::Identicon;

fn main() {
    match hash() {
        Some(bytes) => {
            match generate(bytes) {
                Ok(_) => (),
                Err(e) => {
                    println!("{}", e);
                    os::set_exit_status(2);
                },
            }
        },
        None => os::set_exit_status(1),
    }
}

fn generate(input: Vec<u8>) -> Result<(), String> {
    let identicon = Identicon::new(input);
    let mut image = identicon.image();
    write_png(&mut image, &mut io::stdout())
}

fn hash() -> Option<Vec<u8>> {
    let mut hash = Hasher::new(HashType::MD5);
    for result in io::stdin().lines() {
        match result {
            Ok(line) => {
                hash.update(line.as_bytes());
            },
            Err(e) => {
                println!("{}", e);
                return None
            },
        }
    }
    Some(hash.finalize())
}
<|endoftext|>


<commit_before>extern crate chrono;
#[macro_use]
extern crate clap;
extern crate env_logger;
extern crate error_chain;
#[macro_use]
extern crate log;
extern crate mdbook;
extern crate open;

use chrono::Local;
use clap::{App, AppSettings, ArgMatches};
use env_logger::Builder;
use log::LevelFilter;
use mdbook::utils;
use std::env;
use std::ffi::OsStr;
use std::io::Write;
use std::path::{Path, PathBuf};

mod cmd;

const NAME: &str = "mdBook";
const VERSION: &str = concat!("v", crate_version!());

fn main() {
    init_logger();

    // Create a list of valid arguments and sub-commands
    let app = App::new(NAME)
        .about("Creates a book from markdown files")
        .author("Mathieu David <mathieudavid@mathieudavid.org>")
        .version(VERSION)
        .setting(AppSettings::GlobalVersion)
        .setting(AppSettings::ArgRequiredElseHelp)
        .after_help(
            "For more information about a specific command, try `mdbook <command> --help`\n\
             The source code for mdBook is available at: https://github.com/rust-lang-nursery/mdBook",
        )
        .subcommand(cmd::init::make_subcommand())
        .subcommand(cmd::build::make_subcommand())
        .subcommand(cmd::test::make_subcommand())
        .subcommand(cmd::clean::make_subcommand());

    #[cfg(feature = "watch")]
    let app = app.subcommand(cmd::watch::make_subcommand());
    #[cfg(feature = "serve")]
    let app = app.subcommand(cmd::serve::make_subcommand());

    // Check which subcomamnd the user ran...
    let res = match app.get_matches().subcommand() {
        ("init", Some(sub_matches)) => cmd::init::execute(sub_matches),
        ("build", Some(sub_matches)) => cmd::build::execute(sub_matches),
        ("clean", Some(sub_matches)) => cmd::clean::execute(sub_matches),
        #[cfg(feature = "watch")]
        ("watch", Some(sub_matches)) => cmd::watch::execute(sub_matches),
        #[cfg(feature = "serve")]
        ("serve", Some(sub_matches)) => cmd::serve::execute(sub_matches),
        ("test", Some(sub_matches)) => cmd::test::execute(sub_matches),
        (_, _) => unreachable!(),
    };

    if let Err(e) = res {
        utils::log_backtrace(&e);

        ::std::process::exit(101);
    }
}

fn init_logger() {
    let mut builder = Builder::new();

    builder.format(|formatter, record| {
        writeln!(
            formatter,
            "{} [{}] ({}): {}",
            Local::now().format("%Y-%m-%d %H:%M:%S"),
            record.level(),
            record.target(),
            record.args()
        )
    });

    if let Ok(var) = env::var("RUST_LOG") {
        builder.parse(&var);
    } else {
        // if no RUST_LOG provided, default to logging at the Info level
        builder.filter(None, LevelFilter::Info);
        // Filter extraneous html5ever not-implemented messages
        builder.filter(Some("html5ever"), LevelFilter::Error);
    }

    builder.init();
}

fn get_book_dir(args: &ArgMatches) -> PathBuf {
    if let Some(dir) = args.value_of("dir") {
        // Check if path is relative from current dir, or absolute...
        let p = Path::new(dir);
        if p.is_relative() {
            env::current_dir().unwrap().join(dir)
        } else {
            p.to_path_buf()
        }
    } else {
        env::current_dir().expect("Unable to determine the current directory")
    }
}

fn open<P: AsRef<OsStr>>(path: P) {
    if let Err(e) = open::that(path) {
        error!("Error opening web browser: {}", e);
    }
}
<commit_msg>Fix duplication with Cargo.toml<commit_after>extern crate chrono;
#[macro_use]
extern crate clap;
extern crate env_logger;
extern crate error_chain;
#[macro_use]
extern crate log;
extern crate mdbook;
extern crate open;

use chrono::Local;
use clap::{App, AppSettings, ArgMatches};
use env_logger::Builder;
use log::LevelFilter;
use mdbook::utils;
use std::env;
use std::ffi::OsStr;
use std::io::Write;
use std::path::{Path, PathBuf};

mod cmd;

const VERSION: &str = concat!("v", crate_version!());

fn main() {
    init_logger();

    // Create a list of valid arguments and sub-commands
    let app = App::new(crate_name!())
        .about(crate_description!())
        .author("Mathieu David <mathieudavid@mathieudavid.org>")
        .version(VERSION)
        .setting(AppSettings::GlobalVersion)
        .setting(AppSettings::ArgRequiredElseHelp)
        .after_help(
            "For more information about a specific command, try `mdbook <command> --help`\n\
             The source code for mdBook is available at: https://github.com/rust-lang-nursery/mdBook",
        )
        .subcommand(cmd::init::make_subcommand())
        .subcommand(cmd::build::make_subcommand())
        .subcommand(cmd::test::make_subcommand())
        .subcommand(cmd::clean::make_subcommand());

    #[cfg(feature = "watch")]
    let app = app.subcommand(cmd::watch::make_subcommand());
    #[cfg(feature = "serve")]
    let app = app.subcommand(cmd::serve::make_subcommand());

    // Check which subcomamnd the user ran...
    let res = match app.get_matches().subcommand() {
        ("init", Some(sub_matches)) => cmd::init::execute(sub_matches),
        ("build", Some(sub_matches)) => cmd::build::execute(sub_matches),
        ("clean", Some(sub_matches)) => cmd::clean::execute(sub_matches),
        #[cfg(feature = "watch")]
        ("watch", Some(sub_matches)) => cmd::watch::execute(sub_matches),
        #[cfg(feature = "serve")]
        ("serve", Some(sub_matches)) => cmd::serve::execute(sub_matches),
        ("test", Some(sub_matches)) => cmd::test::execute(sub_matches),
        (_, _) => unreachable!(),
    };

    if let Err(e) = res {
        utils::log_backtrace(&e);

        ::std::process::exit(101);
    }
}

fn init_logger() {
    let mut builder = Builder::new();

    builder.format(|formatter, record| {
        writeln!(
            formatter,
            "{} [{}] ({}): {}",
            Local::now().format("%Y-%m-%d %H:%M:%S"),
            record.level(),
            record.target(),
            record.args()
        )
    });

    if let Ok(var) = env::var("RUST_LOG") {
        builder.parse(&var);
    } else {
        // if no RUST_LOG provided, default to logging at the Info level
        builder.filter(None, LevelFilter::Info);
        // Filter extraneous html5ever not-implemented messages
        builder.filter(Some("html5ever"), LevelFilter::Error);
    }

    builder.init();
}

fn get_book_dir(args: &ArgMatches) -> PathBuf {
    if let Some(dir) = args.value_of("dir") {
        // Check if path is relative from current dir, or absolute...
        let p = Path::new(dir);
        if p.is_relative() {
            env::current_dir().unwrap().join(dir)
        } else {
            p.to_path_buf()
        }
    } else {
        env::current_dir().expect("Unable to determine the current directory")
    }
}

fn open<P: AsRef<OsStr>>(path: P) {
    if let Err(e) = open::that(path) {
        error!("Error opening web browser: {}", e);
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

extern crate clap;
extern crate rayon;
extern crate reqwest;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use std::env;
use std::env::VarError;
use std::io::prelude::*;
use std::fs::File;
use rayon::prelude::*;
use clap::{App, Arg};

mod github;

static GITHUB_TOKEN: &'static str = "RP_GITHUBTOKEN";

fn main() {
    let matches = App::new("release-party-br")
        .version("0.2.0")
        .author("Matthew Mayer <matthewkmayer@gmail.com>")
        .about("Release party automation")
        .arg(
            Arg::with_name("ORG")
                .short("o")
                .long("org")
                .value_name("github org")
                .help("Github org")
                .takes_value(true)
                .required(true),
        )
        .arg(
            Arg::with_name("DRYRUN")
                .short("d")
                .long("dry-run")
                .help("dry-run - don't actually create PRs"),
        )
        .get_matches();

    let org = matches
        .value_of("ORG")
        .expect("Please specify a github org");
    let org_url = format!("https://api.github.com/orgs/{}/repos", org);
    let dryrun = if matches.is_present("DRYRUN") {
        true
    } else {
        false
    };

    let token = match get_github_token() {
        Ok(gh_token) => gh_token,
        Err(e) => panic!(format!("Couldn't find {}: {}", GITHUB_TOKEN, e)),
    };
    let reqwest_client = match reqwest::Client::new() {
        Ok(new_client) => new_client,
        Err(e) => panic!("Couldn't create new reqwest client: {}", e),
    };

    let repos = get_repos_we_care_about(&token, &org_url, &reqwest_client);

    let mut pr_links: Vec<Option<String>> = repos
        .into_par_iter()
        .map(|repo| match get_release_pr_for(&repo, &token, &reqwest_client, dryrun) {
            Some(pr_url) => Some(pr_url),
            None => None,
        })
        .collect();
    // only keep the Some(PR_URL) items:
    pr_links.retain(|maybe_pr_link| maybe_pr_link.is_some());

    print_party_links(pr_links);
}

fn get_repos_we_care_about(token: &str, github_org_url: &str, reqwest_client: &reqwest::Client) -> Vec<github::GithubRepo> {
    let mut repos = match github::get_repos_at(&github_org_url, token, reqwest_client) {
        Ok(repos) => repos,
        Err(e) => panic!(format!("Couldn't get repos from github: {}", e)),
    };
    let repos_to_ignore = ignored_repos();

    // remove repos we don't care about:
    repos.retain(|repo| !repos_to_ignore.contains(&repo.name));

    repos
}

fn get_release_pr_for(repo: &github::GithubRepo, token: &str, client: &reqwest::Client, dryrun: bool) -> Option<String> {
    println!("looking for release PR for {}", repo.name);
    match github::existing_release_pr_location(repo, token, client) {
        Some(url) => Some(url),
        None => if !github::is_release_up_to_date_with_master(&repo.url, token, client) {
            if dryrun {
                Some(format!("Dry run: {} would get a release PR.", repo.url))
            } else {
                match github::create_release_pull_request(repo, token, client) {
                    Ok(pr_url) => Some(pr_url),
                    Err(_) => None,
                }
            }
        } else {
            None
        },
    }
}

fn print_party_links(pr_links: Vec<Option<String>>) {
    if !pr_links.is_empty() {
        println!("\nIt's a release party!  PRs to review and approve:");
        for link in pr_links {
            match link {
                Some(pr_link) => println!("{}", pr_link),
                None => println!("Party link is None: this shouldn't happen."),
            }
        }
    } else {
        println!("\nNo party today, all releases are done.");
    }
}

#[derive(Deserialize, Debug)]
struct IgnoredRepo {
    ignore: Option<Vec<String>>,
}

fn ignored_repos() -> Vec<String> {
    let mut f = match File::open("ignoredrepos.toml") {
        Ok(file) => file,
        Err(e) => {
            println!("Couldn't load ignoredrepos.toml, not ignoring any repos. Reason: {}", e);
            return Vec::new();
        }
    };
    let mut buffer = String::new();
    match f.read_to_string(&mut buffer) {
        Ok(_) => (),
        Err(e) => {
            println!("Couldn't read from ignoredrepos.toml, not ignoring any repos. Reason: {}", e);
            return Vec::new();
        }
    }

    let ignored: IgnoredRepo = match toml::from_str(&buffer) {
        Ok(ignored_repos) => ignored_repos,
        Err(e) => {
            println!(
                "Couldn't parse toml from ignoredrepos.toml, not ignoring any repos. Reason: {}",
                e
            );
            return Vec::new();
        }
    };
    match ignored.ignore {
        Some(repos_to_ignore) => repos_to_ignore,
        None => Vec::new(),
    }
}

fn get_github_token() -> Result<String, VarError> {
    env::var(GITHUB_TOKEN)
}
<commit_msg>release-party 0.3.0.<commit_after>#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

extern crate clap;
extern crate rayon;
extern crate reqwest;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use std::env;
use std::env::VarError;
use std::io::prelude::*;
use std::fs::File;
use rayon::prelude::*;
use clap::{App, Arg};

mod github;

static GITHUB_TOKEN: &'static str = "RP_GITHUBTOKEN";

fn main() {
    let matches = App::new("release-party-br")
        .version("0.3.0")
        .author("Matthew Mayer <matthewkmayer@gmail.com>")
        .about("Release party automation")
        .arg(
            Arg::with_name("ORG")
                .short("o")
                .long("org")
                .value_name("github org")
                .help("Github org")
                .takes_value(true)
                .required(true),
        )
        .arg(
            Arg::with_name("DRYRUN")
                .short("d")
                .long("dry-run")
                .help("dry-run - don't actually create PRs"),
        )
        .get_matches();

    let org = matches
        .value_of("ORG")
        .expect("Please specify a github org");
    let org_url = format!("https://api.github.com/orgs/{}/repos", org);
    let dryrun = if matches.is_present("DRYRUN") {
        true
    } else {
        false
    };

    let token = match get_github_token() {
        Ok(gh_token) => gh_token,
        Err(e) => panic!(format!("Couldn't find {}: {}", GITHUB_TOKEN, e)),
    };
    let reqwest_client = match reqwest::Client::new() {
        Ok(new_client) => new_client,
        Err(e) => panic!("Couldn't create new reqwest client: {}", e),
    };

    let repos = get_repos_we_care_about(&token, &org_url, &reqwest_client);

    let mut pr_links: Vec<Option<String>> = repos
        .into_par_iter()
        .map(|repo| match get_release_pr_for(&repo, &token, &reqwest_client, dryrun) {
            Some(pr_url) => Some(pr_url),
            None => None,
        })
        .collect();
    // only keep the Some(PR_URL) items:
    pr_links.retain(|maybe_pr_link| maybe_pr_link.is_some());

    print_party_links(pr_links);
}

fn get_repos_we_care_about(token: &str, github_org_url: &str, reqwest_client: &reqwest::Client) -> Vec<github::GithubRepo> {
    let mut repos = match github::get_repos_at(&github_org_url, token, reqwest_client) {
        Ok(repos) => repos,
        Err(e) => panic!(format!("Couldn't get repos from github: {}", e)),
    };
    let repos_to_ignore = ignored_repos();

    // remove repos we don't care about:
    repos.retain(|repo| !repos_to_ignore.contains(&repo.name));

    repos
}

fn get_release_pr_for(repo: &github::GithubRepo, token: &str, client: &reqwest::Client, dryrun: bool) -> Option<String> {
    println!("looking for release PR for {}", repo.name);
    match github::existing_release_pr_location(repo, token, client) {
        Some(url) => Some(url),
        None => if !github::is_release_up_to_date_with_master(&repo.url, token, client) {
            if dryrun {
                Some(format!("Dry run: {} would get a release PR.", repo.url))
            } else {
                match github::create_release_pull_request(repo, token, client) {
                    Ok(pr_url) => Some(pr_url),
                    Err(_) => None,
                }
            }
        } else {
            None
        },
    }
}

fn print_party_links(pr_links: Vec<Option<String>>) {
    if !pr_links.is_empty() {
        println!("\nIt's a release party!  PRs to review and approve:");
        for link in pr_links {
            match link {
                Some(pr_link) => println!("{}", pr_link),
                None => println!("Party link is None: this shouldn't happen."),
            }
        }
    } else {
        println!("\nNo party today, all releases are done.");
    }
}

#[derive(Deserialize, Debug)]
struct IgnoredRepo {
    ignore: Option<Vec<String>>,
}

fn ignored_repos() -> Vec<String> {
    let mut f = match File::open("ignoredrepos.toml") {
        Ok(file) => file,
        Err(e) => {
            println!("Couldn't load ignoredrepos.toml, not ignoring any repos. Reason: {}", e);
            return Vec::new();
        }
    };
    let mut buffer = String::new();
    match f.read_to_string(&mut buffer) {
        Ok(_) => (),
        Err(e) => {
            println!("Couldn't read from ignoredrepos.toml, not ignoring any repos. Reason: {}", e);
            return Vec::new();
        }
    }

    let ignored: IgnoredRepo = match toml::from_str(&buffer) {
        Ok(ignored_repos) => ignored_repos,
        Err(e) => {
            println!(
                "Couldn't parse toml from ignoredrepos.toml, not ignoring any repos. Reason: {}",
                e
            );
            return Vec::new();
        }
    };
    match ignored.ignore {
        Some(repos_to_ignore) => repos_to_ignore,
        None => Vec::new(),
    }
}

fn get_github_token() -> Result<String, VarError> {
    env::var(GITHUB_TOKEN)
}
<|endoftext|>


<commit_before>/* main.rs - Main source file for mymdb
 * (c) 2016 Zack Hixon under MIT license.
 * See LICENSE.txt for more details. */
//extern crate argparse;
extern crate rusqlite;
extern crate time;
extern crate regex;

//use argparse::{ArgumentParser, StoreTrue, Store};
use time::Timespec;
use rusqlite::Connection;
use std::io;
use std::path::PathBuf;
use std::env;
use regex::Regex;

static VERSION: &'static str = "0.4.3";

// movie struct
#[derive(Debug)]
struct Movie {
    id: i32,
    name: String,
    time_created: Timespec,
    opinion: String,
    rating: i32
}

// movie impl: possibly add search functions
impl Movie {
    // create new movie
    fn new(id: i32, name: String, time_created: Timespec, opinion: String, rating: i32) -> Movie {
        Movie {
            id: id,
            name: name,
            time_created: time_created,
            opinion: opinion,
            rating: rating,
        }
    }
}

fn main() {
    // open ~/.movies.db, uses platform-independant home directory
    let mut path_buf = PathBuf::new();
    path_buf.push(env::home_dir().expect("Could not find home dir!"));
    path_buf.push(".movies.db");
    let path = path_buf.as_path();
    let conn = Connection::open(path).expect("connection fucked");

    // create a table in movies database that maps to a movie struct
    conn.execute("CREATE TABLE IF NOT EXISTS movies (
        id INTEGER PRIMARY KEY,
        name TEXT NOT NULL,
        time_created TEXT NOT NULL,
        opinion TEXT NOT NULL,
        rating INTEGER)", &[]).expect("create table fucked");

    // get args
    let args: Vec<String> = env::args().collect();
    let length = args.len();

    if length == 1 {
        println!("for help, use \"mymdb help\"");
    }
    else if length == 2 {
        for i in &args {
            if i == "help" { print_help(); }
            else if i == "version" || i == "-v" {
                println!("mymdb version {}", VERSION);
            }
            else if i == "add" {
                // prompt user for new movie
                let new_movie = new_movie();

                // insert new movie into database
                conn.execute("INSERT INTO movies (name, time_created, opinion, rating) VALUES ($1, $2, $3, $4)",
                    &[&new_movie.name, &new_movie.time_created,
                    &new_movie.opinion, &new_movie.rating]).unwrap();

                println!("\"{}\" has been added.", new_movie.name.trim());
            }
            else if i == "remove" {
                // get movie id
                println!("ID of movie to be removed: (number)");
                let id: i32 = number_input();

                // find movie by id: TODO: make more efficient
                let mut stmt = conn.prepare("SELECT * FROM movies WHERE id=$1").unwrap();
                let movie_iter = stmt.query_map(&[&id,], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                // get last movie with id because shitty API or I don't know how to use it
                // probably the latter honestly
                let mut q = Movie::new(0, String::new(), time::get_time(), String::new(), 0);
                for i in movie_iter {
                    q = i.unwrap();
                }

                if q.name.is_empty() {
                    println!("Cannot find movie with ID of {}", id);
                    return
                }

                println!("Are you sure you want to remove {}?", q.name.trim());

                // get_input() does not last long enough and I don't know how
                // to extend lifetimes so yeah
                let resp_upper = get_input();
                let resp_trim = resp_upper.to_lowercase();
                let resp = resp_trim.trim();

                // remove from database
                if resp == String::from("yes") {
                    conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                    println!("{} has been removed from the database.", q.name.trim());
                } else if resp == String::from("y") {
                    conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                    println!("{} has been removed from the database.", q.name.trim());
                } else {
                    println!("Movie will not be removed.");
                }
            }
            // show movies in database
            else if i == "show" {
                // select all movies, conver to iterator
                let mut stmt = conn.prepare("SELECT * FROM movies").expect("prepare fucked");
                let movie_iter = stmt.query_map(&[], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).expect("hey it fucked up");

                // convert list of movies to vector
                let mut count = 0;
                let mut movies: Vec<Movie> = vec![];
                for movie in movie_iter {
                    movies.push(movie.expect("push fucked"));
                    count = count + 1;
                }

                println!("Found {} movie(s)", count);

                // print movies
                for z in movies {
                    println!("Name:    {}\nOpinion: {}\nRating:  {}\nID:      {}\nTime:    {}\n",
                             z.name.trim(),
                             z.opinion.trim(),
                             z.rating,
                             z.id,
                             time(z.time_created));
                }
            }
            else {
                // TODO: make this not ridiculous
                let re = Regex::new(r"mymdb").unwrap();
                if !re.is_match(&i) {
                    println!("Not an option: {}", i);
                } else {
                    continue;
                }
            }
        }
    }
    else {
        // TODO: get argparse or something like that
        let mut arg3: &String = &String::from("");
        let mut arg4: &String = &String::from("");
        let mut arg5: i32 = 0;
        if length >= 3 {
            arg3 = &args[2];
        }
        if length == 5 {
            arg4 = &args[3];
            arg5 = args[4].trim().parse().expect("3rd arg must be a number");
        }
        for i in &args {
            if i == "-a" {
                // add movie
                conn.execute("INSERT INTO movies (name, time_created, opinion, rating) VALUES ($1, $2, $3, $4)",
                    &[arg3, &time::get_time(),
                    arg4, &arg5]).unwrap();
                println!("\"{}\" has been added.", arg3);
            }
            else if i == "-r" {
                // remove movie
                let id: i32 = arg3.trim().parse().expect("arg must be a number");

                let mut stmt = conn.prepare("SELECT * FROM movies WHERE id=$1").unwrap();
                let movie_iter = stmt.query_map(&[&id,], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                let mut q = Movie::new(0, String::new(), time::get_time(), String::new(), 0);
                for i in movie_iter {
                    q = i.unwrap();
                }

                if q.name.is_empty() {
                    println!("Cannot find movie with ID of {}", id);
                    return
                }

                conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                println!("{} has been removed from the database.", q.name.trim());
            }
        }
    }
}

// create new movie struct using input
fn new_movie() -> Movie {
    println!("Name of movie:");
    let name: String = get_input().trim().to_string();

    println!("Thoughts:");
    let opinion: String = get_input().trim().to_string();

    println!("Rating: (number)");
    let rating: i32 = number_input();

    // TODO: non-retarded ID numbers, like autoincrement
    Movie::new(0, name,
        time::get_time(), opinion, rating)
}

// return time as string
fn time(t: Timespec) -> String {
    let real_time = time::at(t);
    String::from(format!("{}-{}-{} {}:{}", (real_time.tm_year + 1900), real_time.tm_mon,
                 real_time.tm_mday, real_time.tm_hour, real_time.tm_min))
}

fn print_help() {
    println!("mymdb - personal movie database");
    println!("usage:");
    println!("mymdb <command> [options]");
    println!("commands:");
    println!("\tshow - lists movies in database");
    println!("\tadd - adds movie to database (interactively)");
    println!("\tremove - removes movie from database (interactively)");
    println!("options:");
    println!("\t-r <movie ID> - removes movie from database");
    println!("\t-a <movie name> <opinion> <rating>");
    println!("mymdb creates a movie database that the program is run in.");
    println!("It looks for a sqlite file called .movies.db, and if it does");
    println!("not exist, it is created automatically.");
}

// get input as number
fn number_input() -> i32 {
    let n = match get_input().trim().parse::<i32>() {
        Ok(n) => n,
        Err(e) => { println!("Not a number"); 0 },
    };

    n
}

// get input as string
fn get_input() -> String {
    let mut i = String::new();
    let handle = io::stdin();

    match handle.read_line(&mut i) {
        Ok(n) => {},
        Err(e) => println!("What's your problem?")
    }

    i
}
<commit_msg>remove vulgar error messages<commit_after>/* main.rs - Main source file for mymdb
 * (c) 2016 Zack Hixon under MIT license.
 * See LICENSE.txt for more details. */
//extern crate argparse;
extern crate rusqlite;
extern crate time;
extern crate regex;

//use argparse::{ArgumentParser, StoreTrue, Store};
use time::Timespec;
use rusqlite::Connection;
use std::io;
use std::path::PathBuf;
use std::env;
use regex::Regex;

static VERSION: &'static str = "0.4.3";

// movie struct
#[derive(Debug)]
struct Movie {
    id: i32,
    name: String,
    time_created: Timespec,
    opinion: String,
    rating: i32
}

// movie impl: possibly add search functions
impl Movie {
    // create new movie
    fn new(id: i32, name: String, time_created: Timespec, opinion: String, rating: i32) -> Movie {
        Movie {
            id: id,
            name: name,
            time_created: time_created,
            opinion: opinion,
            rating: rating,
        }
    }
}

fn main() {
    // open ~/.movies.db, uses platform-independant home directory
    let mut path_buf = PathBuf::new();
    path_buf.push(env::home_dir().expect("Could not find home dir!"));
    path_buf.push(".movies.db");
    let path = path_buf.as_path();
    let conn = Connection::open(path).expect("Could not open database!");

    // create a table in movies database that maps to a movie struct
    conn.execute("CREATE TABLE IF NOT EXISTS movies (
        id INTEGER PRIMARY KEY,
        name TEXT NOT NULL,
        time_created TEXT NOT NULL,
        opinion TEXT NOT NULL,
        rating INTEGER)", &[]).expect("Could not create table!");

    // get args
    let args: Vec<String> = env::args().collect();
    let length = args.len();

    if length == 1 {
        println!("for help, use \"mymdb help\"");
    }
    else if length == 2 {
        for i in &args {
            if i == "help" { print_help(); }
            else if i == "version" || i == "-v" {
                println!("mymdb version {}", VERSION);
            }
            else if i == "add" {
                // prompt user for new movie
                let new_movie = new_movie();

                // insert new movie into database
                conn.execute("INSERT INTO movies (name, time_created, opinion, rating) VALUES ($1, $2, $3, $4)",
                    &[&new_movie.name, &new_movie.time_created,
                    &new_movie.opinion, &new_movie.rating]).unwrap();

                println!("\"{}\" has been added.", new_movie.name.trim());
            }
            else if i == "remove" {
                // get movie id
                println!("ID of movie to be removed: (number)");
                let id: i32 = number_input();

                // find movie by id: TODO: make more efficient
                let mut stmt = conn.prepare("SELECT * FROM movies WHERE id=$1").unwrap();
                let movie_iter = stmt.query_map(&[&id,], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                // get last movie with id because shitty API or I don't know how to use it
                // probably the latter honestly
                let mut q = Movie::new(0, String::new(), time::get_time(), String::new(), 0);
                for i in movie_iter {
                    q = i.unwrap();
                }

                if q.name.is_empty() {
                    println!("Cannot find movie with ID of {}", id);
                    return
                }

                println!("Are you sure you want to remove {}?", q.name.trim());

                // get_input() does not last long enough and I don't know how
                // to extend lifetimes so yeah
                let resp_upper = get_input();
                let resp_trim = resp_upper.to_lowercase();
                let resp = resp_trim.trim();

                // remove from database
                if resp == String::from("yes") {
                    conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                    println!("{} has been removed from the database.", q.name.trim());
                } else if resp == String::from("y") {
                    conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                    println!("{} has been removed from the database.", q.name.trim());
                } else {
                    println!("Movie will not be removed.");
                }
            }
            // show movies in database
            else if i == "show" {
                // select all movies, conver to iterator
                let mut stmt = conn.prepare("SELECT * FROM movies").expect("Could not prepare statement!");
                let movie_iter = stmt.query_map(&[], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).expect("Could not iterate movies!");

                // convert list of movies to vector
                let mut count = 0;
                let mut movies: Vec<Movie> = vec![];
                for movie in movie_iter {
                    movies.push(movie.expect("Could not unwrap movie!"));
                    count = count + 1;
                }

                println!("Found {} movie(s)", count);

                // print movies
                for z in movies {
                    println!("Name:    {}\nOpinion: {}\nRating:  {}\nID:      {}\nTime:    {}\n",
                             z.name.trim(),
                             z.opinion.trim(),
                             z.rating,
                             z.id,
                             time(z.time_created));
                }
            }
            else {
                // TODO: make this not ridiculous
                let re = Regex::new(r"mymdb").unwrap();
                if !re.is_match(&i) {
                    println!("Not an option: {}", i);
                } else {
                    continue;
                }
            }
        }
    }
    else {
        // TODO: get argparse or something like that
        let mut arg3: &String = &String::from("");
        let mut arg4: &String = &String::from("");
        let mut arg5: i32 = 0;
        if length >= 3 {
            arg3 = &args[2];
        }
        if length == 5 {
            arg4 = &args[3];
            arg5 = args[4].trim().parse().expect("3rd arg must be a number");
        }
        for i in &args {
            if i == "-a" {
                // add movie
                conn.execute("INSERT INTO movies (name, time_created, opinion, rating) VALUES ($1, $2, $3, $4)",
                    &[arg3, &time::get_time(),
                    arg4, &arg5]).unwrap();
                println!("\"{}\" has been added.", arg3);
            }
            else if i == "-r" {
                // remove movie
                let id: i32 = arg3.trim().parse().expect("arg must be a number");

                let mut stmt = conn.prepare("SELECT * FROM movies WHERE id=$1").unwrap();
                let movie_iter = stmt.query_map(&[&id,], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                let mut q = Movie::new(0, String::new(), time::get_time(), String::new(), 0);
                for i in movie_iter {
                    q = i.unwrap();
                }

                if q.name.is_empty() {
                    println!("Cannot find movie with ID of {}", id);
                    return
                }

                conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                println!("{} has been removed from the database.", q.name.trim());
            }
        }
    }
}

// create new movie struct using input
fn new_movie() -> Movie {
    println!("Name of movie:");
    let name: String = get_input().trim().to_string();

    println!("Thoughts:");
    let opinion: String = get_input().trim().to_string();

    println!("Rating: (number)");
    let rating: i32 = number_input();

    // TODO: non-retarded ID numbers, like autoincrement
    Movie::new(0, name,
        time::get_time(), opinion, rating)
}

// return time as string
fn time(t: Timespec) -> String {
    let real_time = time::at(t);
    String::from(format!("{}-{}-{} {}:{}", (real_time.tm_year + 1900), real_time.tm_mon,
                 real_time.tm_mday, real_time.tm_hour, real_time.tm_min))
}

fn print_help() {
    println!("mymdb - personal movie database");
    println!("usage:");
    println!("mymdb <command> [options]");
    println!("commands:");
    println!("\tshow - lists movies in database");
    println!("\tadd - adds movie to database (interactively)");
    println!("\tremove - removes movie from database (interactively)");
    println!("options:");
    println!("\t-r <movie ID> - removes movie from database");
    println!("\t-a <movie name> <opinion> <rating>");
    println!("mymdb creates a movie database that the program is run in.");
    println!("It looks for a sqlite file called .movies.db, and if it does");
    println!("not exist, it is created automatically.");
}

// get input as number
fn number_input() -> i32 {
    let n = match get_input().trim().parse::<i32>() {
        Ok(n) => n,
        Err(e) => { println!("Not a number"); 0 },
    };

    n
}

// get input as string
fn get_input() -> String {
    let mut i = String::new();
    let handle = io::stdin();

    match handle.read_line(&mut i) {
        Ok(n) => {},
        Err(e) => println!("What's your problem?")
    }

    i
}
<|endoftext|>


<commit_before>extern crate image;

use std::env;
use std::process;

use image::open;
use display::Display;
use parse_args::ArgParser;
use parse_args::Error as ParseError;

mod display;
mod braille;
mod parse_args;

fn main() {
    let args = match ArgParser::new(env::args().skip(1).collect()) {
        Err(ParseError::TooFewArgs) =>
            complain("Too few arguments!"),
        Err(ParseError::CantParseSize) =>
            complain("Couldn't parse size!"),
        Err(ParseError::BadArgs) =>
            complain("Bad arguments!"),
        Ok(args) => args
    };

    let img = match image::open(args.path()) {
        Ok(image) => image.to_luma(),
        Err(_) => complain("Couldn't open image!")
    };

    let (width, height) = args.size().unwrap_or({
        let (width, height) = img.dimensions();
        (width/10, height/10)
    });

    let display = Display::new(img, width, height);

    println!("{}", display.render());
}

fn complain(error: &str) -> ! {
    let usage = "braillify image [size]\n\
                 \timage: Any image (example: image.png)\n\
                 \tsize: The desired output size. (example: 50x25)\n\
                 \t\tIf a size isn't given, it'll be guessed automatically.";

    println!("{}\n\n{}", error, usage);
    process::exit(1);
}
<commit_msg>Moved the usage text to a const and cleaned it up<commit_after>extern crate image;

use std::env;
use std::process;

use image::open;
use display::Display;
use parse_args::ArgParser;
use parse_args::Error as ParseError;

mod display;
mod braille;
mod parse_args;

const USAGE_TEXT: &'static str = "\
braillify image [size]
    image: Any image (ex: image.png)
    size: The desired output size in characters. (ex: 50x25)
        If a size isn't given, it'll be guessed from the image's dimensions.";

fn main() {
    let args = match ArgParser::new(env::args().skip(1).collect()) {
        Err(ParseError::TooFewArgs) =>
            complain("Too few arguments!"),
        Err(ParseError::CantParseSize) =>
            complain("Couldn't parse size!"),
        Err(ParseError::BadArgs) =>
            complain("Bad arguments!"),
        Ok(args) => args
    };

    let img = match image::open(args.path()) {
        Ok(image) => image.to_luma(),
        Err(_) => complain("Couldn't open image!")
    };

    let (width, height) = args.size().unwrap_or({
        let (width, height) = img.dimensions();
        (width/10, height/10)
    });

    let display = Display::new(img, width, height);

    println!("{}", display.render());
}

fn complain(error: &str) -> ! {
    println!("{}\n\n{}", error, USAGE_TEXT);
    process::exit(1);
}
<|endoftext|>