<commit_before>#![feature(libc, fs_ext, path_ext, convert, fs, exit_status)]
#![allow(dead_code)]

extern crate crypto;
extern crate libc;

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

use crypto::sha2::Sha512;
use crypto::digest::Digest;
use libc::{getgid, getuid};
use std::env;
use std::path::Path;
use std::os::unix::fs::PermissionsExt;
use std::io;
use std::io::{Read, Write};
use std::fs::{File, Permissions, create_dir_all,
              set_permissions, PathExt};
use std::process::{Command, Stdio};

const ALL_PERMISSIONS: usize = 0777;
const OTHER_EXECUTE: usize = 0001;
const OTHER_READ: usize = 0004;
const OTHER_RWX: usize = 0007;
const GROUP_EXECUTE: usize = 0010;
const GROUP_READ: usize = 0040;
const GROUP_RWX: usize = 0070;
const USER_EXECUTE: usize = 0100;
const USER_READ: usize = 0400;
const USER_RWX: usize = 0700;

trait PermExt2 {
    fn contains(&self, mask: usize) -> bool;
}

impl PermExt2 for Permissions {
    fn contains(&self, mask: usize) -> bool {
        self.mode() & (mask as i32) != 0
    }
}

const CACHE_SUBPATH: &'static str = "pexe-runner-cache";
// TODO: support overriding cache location.
const CACHE_BASE: &'static str = "/tmp";

const RUST_PNACL_TRANS: &'static str = "rust_pnacl_trans";

fn mkdir<P: AsRef<Path>>(p: P, mode: usize) -> io::Result<()> {
    try!(create_dir_all(&p));
    chmod(p, mode)
}
fn chmod<P: AsRef<Path>>(p: P, mode: usize) -> io::Result<()> {
    let p = p.as_ref();
    let md = try!(p.metadata());
    let mut perms = md.permissions();
    perms.set_mode(mode as i32);
    set_permissions(p, perms)
}

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

    let args: Vec<String> = env::args()
        .collect();
    if args.len() != 2 { return; }
    let pexe_path = Path::new(&(args[1])[..]);

    let cache = Path::new(CACHE_BASE).join(CACHE_SUBPATH);
    if !cache.exists() {
        mkdir(&cache, ALL_PERMISSIONS).unwrap();
    }

    // if the binary is rx by the world, don't use a user prefix when caching.

    let pexe = File::open(&pexe_path);
    if pexe.is_err() {
        panic!("could not open Pexe file!");
    }
    let mut pexe = pexe.unwrap();

    let pexe_filename = Path::new(pexe_path.file_name().unwrap());

    let pexe_stat = pexe.metadata().unwrap();
    let (cache_dir, perms) = if pexe_stat.permissions().contains(OTHER_EXECUTE | OTHER_READ) {
        let c = cache.join("other");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        (c, ALL_PERMISSIONS)
    } else if pexe_stat.permissions().contains(GROUP_EXECUTE | GROUP_READ) {
        let c = cache.join("group");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let gid = unsafe { getgid() };
        let c = c.join(format!("{}", gid));
        if !c.exists() {
            mkdir(&c, GROUP_RWX | USER_RWX).unwrap();
        }
        (c, GROUP_RWX | USER_RWX)
    } else if pexe_stat.permissions().contains(USER_EXECUTE) {
        let c = cache.join("user");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let uid = unsafe { getuid() };
        let c = c.join(format!("{}", uid));
        if !c.exists() {
            mkdir(&c, USER_RWX).unwrap();
        }
        (c, USER_RWX)
    } else {
        panic!("cann't execute: permissing denied");
    };
    let mut pexe_bin = Vec::new();
    pexe.read_to_end(&mut pexe_bin)
        .unwrap();

    let mut hasher = Sha512::new();
    hasher.input(pexe_bin.as_slice());
    let cache_dir = cache_dir.join(hasher.result_str());
    if !cache_dir.exists() {
        mkdir(&cache_dir, perms).unwrap();
    }
    let nexe_path = cache_dir
        .join(pexe_filename.with_extension("nexe"));

    let nacl_sdk_root = env!("NACL_SDK_ROOT");

    if !nexe_path.exists() {
        let mut cmd = Command::new(RUST_PNACL_TRANS);
        cmd.arg("--cross-path");
        cmd.arg(nacl_sdk_root);
        cmd.arg(pexe_path.display().to_string());
        cmd.arg("-o");
        cmd.arg(nexe_path.display().to_string());
        cmd.arg("--opt-level=2");
        debug!("trans cmd line: `{:?}`", cmd);
        let trans = cmd.spawn().unwrap();

        let output = trans.wait_with_output().unwrap();
        let status = output.status;
        match status {
            _ if status.success() => {
                chmod(&nexe_path, perms).unwrap();
            }
            _ => {
                let mut stderr = ::std::io::stderr();
                let mut stdout = ::std::io::stdout();
                (writeln!(&mut stderr, "`{:?}` failed:", cmd)).unwrap();
                stdout.write(output.stdout.as_slice()).unwrap();
                stderr.write(output.stderr.as_slice()).unwrap();
                env::set_exit_status(status.code().unwrap_or(1));
                return;
            }
        }
    }

    let nacl_sdk_root = Path::new(nacl_sdk_root);
    let tools = nacl_sdk_root.join("tools");
    let nacl_helper_bootstrap = tools.join("nacl_helper_bootstrap_x86_64");
    let sel_ldr_bin = tools.join("sel_ldr_x86_64");
    let irt_core = tools.join("irt_core_x86_64.nexe");

    let mut sel_ldr_args = vec!(sel_ldr_bin.display().to_string(),
                                "--r_debug=0xXXXXXXXXXXXXXXXX".to_string(),
                                "--reserved_at_zero=0xXXXXXXXXXXXXXXXX".to_string(),
                                //"-a".to_string(),
                                "-B".to_string(),
                                irt_core.display().to_string(),
                                "-l".to_string(), "/dev/null".to_string());
    sel_ldr_args.push("--".to_string());
    sel_ldr_args.push(nexe_path.display().to_string());
    for arg in &args[2..] {
        sel_ldr_args.push(arg.clone());
    }

    let mut cmd = Command::new(nacl_helper_bootstrap);
    cmd.args(sel_ldr_args.as_slice());
    cmd.stdout(Stdio::inherit());
    cmd.stderr(Stdio::inherit());
    debug!("sel_ldr cmd line: `{:?}`", cmd);
    match cmd.spawn() {
        Ok(mut process) => {
            match process.wait() {
                Ok(status) => {
                    env::set_exit_status(status.code().unwrap_or(1));
                },
                Err(e) => {
                    panic!("couldn't wait on sel_ldr: {}", e);
                }
            }
        }
        Err(e) => {
            panic!("couldn't spawn sel_ldr: {}", e);
        }
    }
}
<commit_msg>Accept more than two arguments. Not sure when this was added..<commit_after>#![feature(libc, fs_ext, path_ext, convert, fs, exit_status)]
#![allow(dead_code)]

extern crate crypto;
extern crate libc;

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

use crypto::sha2::Sha512;
use crypto::digest::Digest;
use libc::{getgid, getuid};
use std::env;
use std::path::Path;
use std::os::unix::fs::PermissionsExt;
use std::io;
use std::io::{Read, Write};
use std::fs::{File, Permissions, create_dir_all,
              set_permissions, PathExt};
use std::process::{Command, Stdio};

const ALL_PERMISSIONS: usize = 0777;
const OTHER_EXECUTE: usize = 0001;
const OTHER_READ: usize = 0004;
const OTHER_RWX: usize = 0007;
const GROUP_EXECUTE: usize = 0010;
const GROUP_READ: usize = 0040;
const GROUP_RWX: usize = 0070;
const USER_EXECUTE: usize = 0100;
const USER_READ: usize = 0400;
const USER_RWX: usize = 0700;

trait PermExt2 {
    fn contains(&self, mask: usize) -> bool;
}

impl PermExt2 for Permissions {
    fn contains(&self, mask: usize) -> bool {
        self.mode() & (mask as i32) != 0
    }
}

const CACHE_SUBPATH: &'static str = "pexe-runner-cache";
// TODO: support overriding cache location.
const CACHE_BASE: &'static str = "/tmp";

const RUST_PNACL_TRANS: &'static str = "rust_pnacl_trans";

fn mkdir<P: AsRef<Path>>(p: P, mode: usize) -> io::Result<()> {
    try!(create_dir_all(&p));
    chmod(p, mode)
}
fn chmod<P: AsRef<Path>>(p: P, mode: usize) -> io::Result<()> {
    let p = p.as_ref();
    let md = try!(p.metadata());
    let mut perms = md.permissions();
    perms.set_mode(mode as i32);
    set_permissions(p, perms)
}

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

    let args: Vec<String> = env::args()
        .collect();
    let pexe_path = Path::new(&(args[1])[..]);

    let cache = Path::new(CACHE_BASE).join(CACHE_SUBPATH);
    if !cache.exists() {
        mkdir(&cache, ALL_PERMISSIONS).unwrap();
    }

    // if the binary is rx by the world, don't use a user prefix when caching.

    let pexe = File::open(&pexe_path);
    if pexe.is_err() {
        panic!("could not open Pexe file!");
    }
    let mut pexe = pexe.unwrap();

    let pexe_filename = Path::new(pexe_path.file_name().unwrap());

    let pexe_stat = pexe.metadata().unwrap();
    let (cache_dir, perms) = if pexe_stat.permissions().contains(OTHER_EXECUTE | OTHER_READ) {
        let c = cache.join("other");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        (c, ALL_PERMISSIONS)
    } else if pexe_stat.permissions().contains(GROUP_EXECUTE | GROUP_READ) {
        let c = cache.join("group");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let gid = unsafe { getgid() };
        let c = c.join(format!("{}", gid));
        if !c.exists() {
            mkdir(&c, GROUP_RWX | USER_RWX).unwrap();
        }
        (c, GROUP_RWX | USER_RWX)
    } else if pexe_stat.permissions().contains(USER_EXECUTE) {
        let c = cache.join("user");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let uid = unsafe { getuid() };
        let c = c.join(format!("{}", uid));
        if !c.exists() {
            mkdir(&c, USER_RWX).unwrap();
        }
        (c, USER_RWX)
    } else {
        panic!("cann't execute: permissing denied");
    };
    let mut pexe_bin = Vec::new();
    pexe.read_to_end(&mut pexe_bin)
        .unwrap();

    let mut hasher = Sha512::new();
    hasher.input(pexe_bin.as_slice());
    let cache_dir = cache_dir.join(hasher.result_str());
    if !cache_dir.exists() {
        mkdir(&cache_dir, perms).unwrap();
    }
    let nexe_path = cache_dir
        .join(pexe_filename.with_extension("nexe"));

    let nacl_sdk_root = env!("NACL_SDK_ROOT");

    if !nexe_path.exists() {
        let mut cmd = Command::new(RUST_PNACL_TRANS);
        cmd.arg("--cross-path");
        cmd.arg(nacl_sdk_root);
        cmd.arg(pexe_path.display().to_string());
        cmd.arg("-o");
        cmd.arg(nexe_path.display().to_string());
        cmd.arg("--opt-level=2");
        debug!("trans cmd line: `{:?}`", cmd);
        let trans = cmd.spawn().unwrap();

        let output = trans.wait_with_output().unwrap();
        let status = output.status;
        match status {
            _ if status.success() => {
                chmod(&nexe_path, perms).unwrap();
            }
            _ => {
                let mut stderr = ::std::io::stderr();
                let mut stdout = ::std::io::stdout();
                (writeln!(&mut stderr, "`{:?}` failed:", cmd)).unwrap();
                stdout.write(output.stdout.as_slice()).unwrap();
                stderr.write(output.stderr.as_slice()).unwrap();
                env::set_exit_status(status.code().unwrap_or(1));
                return;
            }
        }
    }

    let nacl_sdk_root = Path::new(nacl_sdk_root);
    let tools = nacl_sdk_root.join("tools");
    let nacl_helper_bootstrap = tools.join("nacl_helper_bootstrap_x86_64");
    let sel_ldr_bin = tools.join("sel_ldr_x86_64");
    let irt_core = tools.join("irt_core_x86_64.nexe");

    let mut sel_ldr_args = vec!(sel_ldr_bin.display().to_string(),
                                "--r_debug=0xXXXXXXXXXXXXXXXX".to_string(),
                                "--reserved_at_zero=0xXXXXXXXXXXXXXXXX".to_string(),
                                //"-a".to_string(),
                                "-B".to_string(),
                                irt_core.display().to_string(),
                                "-l".to_string(), "/dev/null".to_string());
    sel_ldr_args.push("--".to_string());
    sel_ldr_args.push(nexe_path.display().to_string());
    for arg in &args[2..] {
        sel_ldr_args.push(arg.clone());
    }

    let mut cmd = Command::new(nacl_helper_bootstrap);
    cmd.args(sel_ldr_args.as_slice());
    cmd.stdout(Stdio::inherit());
    cmd.stderr(Stdio::inherit());
    debug!("sel_ldr cmd line: `{:?}`", cmd);
    match cmd.spawn() {
        Ok(mut process) => {
            match process.wait() {
                Ok(status) => {
                    env::set_exit_status(status.code().unwrap_or(1));
                },
                Err(e) => {
                    panic!("couldn't wait on sel_ldr: {}", e);
                }
            }
        }
        Err(e) => {
            panic!("couldn't spawn sel_ldr: {}", e);
        }
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#![allow(dead_code)] // only temporary, until more stuff is filled in

extern crate devicemapper;
#[macro_use]
extern crate clap;
#[macro_use]
extern crate nix;
extern crate crc;
extern crate bidir_map;
extern crate byteorder;
extern crate uuid;
extern crate time;
extern crate bytesize;
extern crate dbus;
extern crate term;
extern crate rand;

#[macro_use]
extern crate custom_derive;
#[macro_use]
extern crate newtype_derive;
#[macro_use]
extern crate enum_derive;

pub static mut debug: bool = false;

macro_rules! dbgp {
    ($($arg:tt)*) => (
        unsafe {
            if ::debug {
                println!($($arg)*)
            }
        })
}

mod types;
mod consts;
mod dbus_consts;
mod stratis;
mod dbus_api;
mod engine;
mod sim_engine;

use std::io::Write;
use std::error::Error;
use std::process::exit;
use std::rc::Rc;
use std::cell::RefCell;

use types::{StratisResult, StratisError};

use sim_engine::SimEngine;

fn write_err(err: StratisError) -> StratisResult<()> {
    let mut out = term::stderr().expect("could not get stderr");

    try!(out.fg(term::color::RED));
    try!(writeln!(out, "{}", err.description()));
    try!(out.reset());
    Ok(())
}

fn main() {

    let engine = Rc::new(RefCell::new(SimEngine::new()));
    // TODO: add cmdline option to specify engine
    //  let context = Rc::new(RefCell::new(Context::new()));

    let r = dbus_api::run(engine);

    if let Err(r) = r {
        if let Err(e) = write_err(r) {
            panic!("Unable to write to stderr: {}", e)
        }

        exit(1);
    }
}
<commit_msg>Use clap to parse cmdline arguments<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#![allow(dead_code)] // only temporary, until more stuff is filled in

extern crate devicemapper;
#[macro_use]
extern crate clap;
#[macro_use]
extern crate nix;
extern crate crc;
extern crate bidir_map;
extern crate byteorder;
extern crate uuid;
extern crate time;
extern crate bytesize;
extern crate dbus;
extern crate term;
extern crate rand;

#[macro_use]
extern crate custom_derive;
#[macro_use]
extern crate newtype_derive;
#[macro_use]
extern crate enum_derive;

pub static mut debug: bool = false;

macro_rules! dbgp {
    ($($arg:tt)*) => (
        unsafe {
            if ::debug {
                println!($($arg)*)
            }
        })
}

mod types;
mod consts;
mod dbus_consts;
mod stratis;
mod dbus_api;
mod engine;
mod sim_engine;

use std::io::Write;
use std::error::Error;
use std::process::exit;
use std::rc::Rc;
use std::cell::RefCell;

use types::{StratisResult, StratisError};

use clap::{App, Arg};
use sim_engine::SimEngine;

fn write_err(err: StratisError) -> StratisResult<()> {
    let mut out = term::stderr().expect("could not get stderr");

    try!(out.fg(term::color::RED));
    try!(writeln!(out, "{}", err.description()));
    try!(out.reset());
    Ok(())
}

fn main() {
    let matches = App::new("stratis")
        .version(&crate_version!())
        .about("Stratis storage management")
        .arg(Arg::with_name("debug")
            .short("d")
            .long("debug")
            .help("Print additional output for debugging"))
        .get_matches();

    if matches.is_present("debug") {
        unsafe { debug = true }
    };

    let engine = Rc::new(RefCell::new(SimEngine::new()));
    // TODO: add cmdline option to specify engine
    //  let context = Rc::new(RefCell::new(Context::new()));

    let r = dbus_api::run(engine);

    if let Err(r) = r {
        if let Err(e) = write_err(r) {
            panic!("Unable to write to stderr: {}", e)
        }

        exit(1);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;
extern crate toml;
extern crate getopts;
use std::io;
use std::result;
use std::env;
use getopts::Options;
use getopts::ParsingStyle;

#[allow(dead_code)]
#[derive(Deserialize)]
struct Config {
    version: toml::Value,
    tools: Vec<Tools>,
}

#[allow(dead_code)]
#[derive(Deserialize)]
struct Tools {
    command: toml::Value,
    extentions: toml::value::Array,
}

pub type Result<T> = result::Result<T, io::Error>;

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

fn main() {
    let exit_code = run();
    std::process::exit(exit_code);
}

fn run() -> i32 {
    let args: Vec<String> = env::args().collect();
    let ref program = &args[0];

    let mut opts = Options::new();
    opts.parsing_style(ParsingStyle::FloatingFrees);
    opts.optopt("c", "config", "specify configure file name", "CONFIG");
    opts.optflag("h", "help", "print this help menu");

    let matches = opts.parse(&args[1..]).unwrap();

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

    let filename = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, &opts);
        return 1;
    };

    println!("{:?}", matches.free);
    0
}

#[test]
fn test_decode_toml() {
    let toml_config_str = r#"
    version = 0.0

    [[tools]]
    command = "apvlv"
    extentions = [ "pdf" ]

    [[tools]]
    command = "mirage"
    extentions = [ "jpg", "png", "gif" ]

    [[tools]]
    command = "vlc"
    extentions = [ "mp4", "mov", "avi" ]

    [[tools]]
    command = "vim -R"
    extentions = [ "conf" ]
    "#;

    let config: Config = toml::from_str(toml_config_str).unwrap();
    assert_eq!(config.version, toml::Value::Float(0.0));

    assert_eq!(config.tools[0].command, toml::Value::String("apvlv".to_string()));
    assert_eq!(config.tools[0].extentions[0], toml::Value::String("pdf".to_string()));

    assert_eq!(config.tools[1].command, toml::Value::String("mirage".to_string()));
    assert_eq!(config.tools[1].extentions[0], toml::Value::String("jpg".to_string()));
    assert_eq!(config.tools[1].extentions[1], toml::Value::String("png".to_string()));
    assert_eq!(config.tools[1].extentions[2], toml::Value::String("gif".to_string()));

    assert_eq!(config.tools[2].command, toml::Value::String("vlc".to_string()));
    assert_eq!(config.tools[2].extentions[0], toml::Value::String("mp4".to_string()));
    assert_eq!(config.tools[2].extentions[1], toml::Value::String("mov".to_string()));
    assert_eq!(config.tools[2].extentions[2], toml::Value::String("avi".to_string()));

    assert_eq!(config.tools[3].command, toml::Value::String("vim -R".to_string()));
    assert_eq!(config.tools[3].extentions[0], toml::Value::String("conf".to_string()));
}
<commit_msg>apply rustfmt<commit_after>#[macro_use]
extern crate serde_derive;
extern crate toml;
extern crate getopts;
use std::io;
use std::result;
use std::env;
use getopts::Options;
use getopts::ParsingStyle;

#[allow(dead_code)]
#[derive(Deserialize)]
struct Config {
    version: toml::Value,
    tools: Vec<Tools>,
}

#[allow(dead_code)]
#[derive(Deserialize)]
struct Tools {
    command: toml::Value,
    extentions: toml::value::Array,
}

pub type Result<T> = result::Result<T, io::Error>;

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

fn main() {
    let exit_code = run();
    std::process::exit(exit_code);
}

fn run() -> i32 {
    let args: Vec<String> = env::args().collect();
    let ref program = &args[0];

    let mut opts = Options::new();
    opts.parsing_style(ParsingStyle::FloatingFrees);
    opts.optopt("c", "config", "specify configure file name", "CONFIG");
    opts.optflag("h", "help", "print this help menu");

    let matches = opts.parse(&args[1..]).unwrap();

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

    let filename = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, &opts);
        return 1;
    };

    println!("{:?}", matches.free);
    0
}

#[test]
fn test_decode_toml() {
    let toml_config_str = r#"
    version = 0.0

    [[tools]]
    command = "apvlv"
    extentions = [ "pdf" ]

    [[tools]]
    command = "mirage"
    extentions = [ "jpg", "png", "gif" ]

    [[tools]]
    command = "vlc"
    extentions = [ "mp4", "mov", "avi" ]

    [[tools]]
    command = "vim -R"
    extentions = [ "conf" ]
    "#;

    let config: Config = toml::from_str(toml_config_str).unwrap();
    assert_eq!(config.version, toml::Value::Float(0.0));

    assert_eq!(config.tools[0].command,
               toml::Value::String("apvlv".to_string()));
    assert_eq!(config.tools[0].extentions[0],
               toml::Value::String("pdf".to_string()));

    assert_eq!(config.tools[1].command,
               toml::Value::String("mirage".to_string()));
    assert_eq!(config.tools[1].extentions[0],
               toml::Value::String("jpg".to_string()));
    assert_eq!(config.tools[1].extentions[1],
               toml::Value::String("png".to_string()));
    assert_eq!(config.tools[1].extentions[2],
               toml::Value::String("gif".to_string()));

    assert_eq!(config.tools[2].command,
               toml::Value::String("vlc".to_string()));
    assert_eq!(config.tools[2].extentions[0],
               toml::Value::String("mp4".to_string()));
    assert_eq!(config.tools[2].extentions[1],
               toml::Value::String("mov".to_string()));
    assert_eq!(config.tools[2].extentions[2],
               toml::Value::String("avi".to_string()));

    assert_eq!(config.tools[3].command,
               toml::Value::String("vim -R".to_string()));
    assert_eq!(config.tools[3].extentions[0],
               toml::Value::String("conf".to_string()));
}
<|endoftext|>


<commit_before>use elsa::FrozenMap;
use fluent::{FluentBundle, FluentResource};
use fluent_fallback::Localization;
use fluent_langneg::{accepted_languages, negotiate_languages, NegotiationStrategy};
use git2::Repository;
use regex::Regex;
use std::env;
use std::fs;
use std::io;
use std::io::prelude::*;
use std::io::{Error, ErrorKind};
use std::iter;
use std::path;
use std::str;
use std::vec;
use structopt::clap::AppSettings;
use structopt::StructOpt;
use unic_langid::LanguageIdentifier;

static L10N_RESOURCES: &[&str] = &["cli.ftl"];

fn main() -> io::Result<()> {
    /// The command line interface to the CaSILE toolkit, a book publishing
    /// workflow employing SILE and other wizardry
    #[derive(StructOpt)]
    #[structopt(version = env!("VERGEN_SEMVER"))]
    #[structopt(setting = AppSettings::InferSubcommands)]
    struct Cli {
        /// Activate debug mode
        #[structopt(short, long, env = "DEBUG")]
        debug: bool,

        /// Set language
        #[structopt(short, long, env = "LANG")]
        language: String,

        /// Outputs verbose feedback where possible
        #[structopt(short, long)]
        verbose: bool,

        #[structopt(subcommand)]
        subcommand: Subcommand,
    }

    #[derive(StructOpt)]
    enum Subcommand {
        /// Executes a make target
        Make {
            /// Target as defined in CaSILE makefile
            target: Vec<String>,
        },

        /// Configure a book repository
        Setup {
            /// Path to project repository
            #[structopt(parse(from_os_str), default_value = "./")]
            path: path::PathBuf,
        },

        /// Pass through other commands to shell
        #[structopt(external_subcommand)]
        Other(Vec<String>),
    }

    let args = Cli::from_args();

    if args.debug {
        println!("User requested debug mode")
    }

    if args.verbose {
        println!("User requested verbose output")
    }

    let available = get_available_locales().expect("Could not find valid BCP47 resource files.");
    let re = Regex::new(r"\..*$").unwrap();
    let input = re.replace(&args.language, "");
    let requested = accepted_languages::parse(&input);
    let default: LanguageIdentifier = "en-US".parse().unwrap();
    let resolved_locales = negotiate_languages(
        &requested,
        &available,
        Some(&default),
        NegotiationStrategy::Filtering,
    );

    let resources: FrozenMap<String, Box<FluentResource>> = FrozenMap::new();
    let mut res_path_scheme = env::current_dir().expect("Failed to retireve current dir.");
    res_path_scheme.push("resources");
    res_path_scheme.push("{locale}");
    res_path_scheme.push("{res_id}");
    let res_path_scheme = res_path_scheme.to_str().unwrap();
    let generate_messages = |res_ids: &[String]| {
        let mut locales = resolved_locales.iter();
        let res_mgr = &resources;
        let res_ids = res_ids.to_vec();

        iter::from_fn(move || {
            locales.next().map(|locale| {
                let mut bundle = FluentBundle::new(vec![locale.clone()]);
                let res_path = res_path_scheme.replace("{locale}", &locale.to_string());

                for res_id in &res_ids {
                    let path = res_path.replace("{res_id}", res_id);
                    let res = res_mgr.get(&path).unwrap_or_else(|| {
                        let source = read_file(&path).unwrap();
                        let res = FluentResource::try_new(source).unwrap();
                        res_mgr.insert(path.to_string(), Box::new(res))
                    });
                    bundle.add_resource(res).unwrap();
                }
                bundle
            })
        })
    };
    let loc = Localization::new(
        L10N_RESOURCES.iter().map(|s| s.to_string()).collect(),
        generate_messages,
    );

    let value = loc.format_value("debug-shell", None);
    println!("Message is: {}", value);

    match args.subcommand {
        Subcommand::Make { target } => make(target),
        Subcommand::Setup { path } => setup(path),
        _a => shell(),
    }
}

fn make(_target: vec::Vec<String>) -> io::Result<()> {
    println!("Make make make sense or I’ll make you make makefiles.");
    Ok(())
}

fn setup(path: path::PathBuf) -> io::Result<()> {
    let metadata = fs::metadata(&path)?;
    match metadata.is_dir() {
        true => match Repository::open(path) {
            Ok(_repo) => Ok(println!(
                "Run setup, “They said you were this great colossus!”"
            )),
            Err(_error) => Err(Error::new(ErrorKind::InvalidInput, "Not a git repo!")),
        },
        false => Err(Error::new(ErrorKind::InvalidInput, "Not a dir, Frank!")),
    }
}

fn shell() -> io::Result<()> {
    println!("Ship all this off to the shell, maybe they can handle it.");
    Ok(())
}

// https://github.com/projectfluent/fluent-rs/blob/c9e45651/fluent-fallback/examples/simple-fallback.rs#L38
fn read_file(path: &str) -> Result<String, io::Error> {
    let mut f = fs::File::open(path)?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

// TODO: Move to build.rs?
// https://github.com/projectfluent/fluent-rs/blob/c9e45651/fluent-resmgr/examples/simple-resmgr.rs#L35
fn get_available_locales() -> Result<Vec<LanguageIdentifier>, io::Error> {
    let mut locales = vec![];
    let res_dir = fs::read_dir("./resources/")?;
    for entry in res_dir {
        if let Ok(entry) = entry {
            let path = entry.path();
            if path.is_dir() {
                if let Some(name) = path.file_name() {
                    if let Some(name) = name.to_str() {
                        let langid: LanguageIdentifier =
                            name.parse().expect("Could not parse BCP47 language tag.");
                        locales.push(langid);
                    }
                }
            }
        }
    }
    return Ok(locales);
}
<commit_msg>feat(cli): Generate Bash, Fish, & ZSH completions<commit_after>use elsa::FrozenMap;
use fluent::{FluentBundle, FluentResource};
use fluent_fallback::Localization;
use fluent_langneg::{accepted_languages, negotiate_languages, NegotiationStrategy};
use git2::Repository;
use regex::Regex;
use std::env;
use std::fs;
use std::io;
use std::io::prelude::*;
use std::io::{Error, ErrorKind};
use std::iter;
use std::path;
use std::str;
use std::vec;
use structopt::StructOpt;
use structopt::clap::AppSettings;
use structopt::clap::Shell;
use unic_langid::LanguageIdentifier;

static L10N_RESOURCES: &[&str] = &["cli.ftl"];

fn main() -> io::Result<()> {
    /// The command line interface to the CaSILE toolkit, a book publishing
    /// workflow employing SILE and other wizardry
    #[derive(StructOpt)]
    #[structopt(version = env!("VERGEN_SEMVER"))]
    #[structopt(setting = AppSettings::InferSubcommands)]
    struct Cli {
        /// Activate debug mode
        #[structopt(short, long, env = "DEBUG")]
        debug: bool,

        /// Set language
        #[structopt(short, long, env = "LANG")]
        language: String,

        /// Outputs verbose feedback where possible
        #[structopt(short, long)]
        verbose: bool,

        #[structopt(subcommand)]
        subcommand: Subcommand,
    }

    #[derive(StructOpt)]
    enum Subcommand {
        /// Executes a make target
        Make {
            /// Target as defined in CaSILE makefile
            target: Vec<String>,
        },

        /// Configure a book repository
        Setup {
            /// Path to project repository
            #[structopt(parse(from_os_str), default_value = "./")]
            path: path::PathBuf,
        },

        /// Pass through other commands to shell
        #[structopt(external_subcommand)]
        Other(Vec<String>),
    }

    Cli::clap().gen_completions(env!("CARGO_PKG_NAME"), Shell::Bash, "target");
    Cli::clap().gen_completions(env!("CARGO_PKG_NAME"), Shell::Fish, "target");
    Cli::clap().gen_completions(env!("CARGO_PKG_NAME"), Shell::Zsh, "target");

    let args = Cli::from_args();

    if args.debug {
        println!("User requested debug mode")
    }

    if args.verbose {
        println!("User requested verbose output")
    }

    let available = get_available_locales().expect("Could not find valid BCP47 resource files.");
    let re = Regex::new(r"\..*$").unwrap();
    let input = re.replace(&args.language, "");
    let requested = accepted_languages::parse(&input);
    let default: LanguageIdentifier = "en-US".parse().unwrap();
    let resolved_locales = negotiate_languages(
        &requested,
        &available,
        Some(&default),
        NegotiationStrategy::Filtering,
    );

    let resources: FrozenMap<String, Box<FluentResource>> = FrozenMap::new();
    let mut res_path_scheme = env::current_dir().expect("Failed to retireve current dir.");
    res_path_scheme.push("resources");
    res_path_scheme.push("{locale}");
    res_path_scheme.push("{res_id}");
    let res_path_scheme = res_path_scheme.to_str().unwrap();
    let generate_messages = |res_ids: &[String]| {
        let mut locales = resolved_locales.iter();
        let res_mgr = &resources;
        let res_ids = res_ids.to_vec();

        iter::from_fn(move || {
            locales.next().map(|locale| {
                let mut bundle = FluentBundle::new(vec![locale.clone()]);
                let res_path = res_path_scheme.replace("{locale}", &locale.to_string());

                for res_id in &res_ids {
                    let path = res_path.replace("{res_id}", res_id);
                    let res = res_mgr.get(&path).unwrap_or_else(|| {
                        let source = read_file(&path).unwrap();
                        let res = FluentResource::try_new(source).unwrap();
                        res_mgr.insert(path.to_string(), Box::new(res))
                    });
                    bundle.add_resource(res).unwrap();
                }
                bundle
            })
        })
    };
    let loc = Localization::new(
        L10N_RESOURCES.iter().map(|s| s.to_string()).collect(),
        generate_messages,
    );

    let value = loc.format_value("debug-shell", None);
    println!("Message is: {}", value);

    match args.subcommand {
        Subcommand::Make { target } => make(target),
        Subcommand::Setup { path } => setup(path),
        _a => shell(),
    }
}

fn make(_target: vec::Vec<String>) -> io::Result<()> {
    println!("Make make make sense or I’ll make you make makefiles.");
    Ok(())
}

fn setup(path: path::PathBuf) -> io::Result<()> {
    let metadata = fs::metadata(&path)?;
    match metadata.is_dir() {
        true => match Repository::open(path) {
            Ok(_repo) => Ok(println!(
                "Run setup, “They said you were this great colossus!”"
            )),
            Err(_error) => Err(Error::new(ErrorKind::InvalidInput, "Not a git repo!")),
        },
        false => Err(Error::new(ErrorKind::InvalidInput, "Not a dir, Frank!")),
    }
}

fn shell() -> io::Result<()> {
    println!("Ship all this off to the shell, maybe they can handle it.");
    Ok(())
}

// https://github.com/projectfluent/fluent-rs/blob/c9e45651/fluent-fallback/examples/simple-fallback.rs#L38
fn read_file(path: &str) -> Result<String, io::Error> {
    let mut f = fs::File::open(path)?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

// TODO: Move to build.rs?
// https://github.com/projectfluent/fluent-rs/blob/c9e45651/fluent-resmgr/examples/simple-resmgr.rs#L35
fn get_available_locales() -> Result<Vec<LanguageIdentifier>, io::Error> {
    let mut locales = vec![];
    let res_dir = fs::read_dir("./resources/")?;
    for entry in res_dir {
        if let Ok(entry) = entry {
            let path = entry.path();
            if path.is_dir() {
                if let Some(name) = path.file_name() {
                    if let Some(name) = name.to_str() {
                        let langid: LanguageIdentifier =
                            name.parse().expect("Could not parse BCP47 language tag.");
                        locales.push(langid);
                    }
                }
            }
        }
    }
    return Ok(locales);
}
<|endoftext|>


<commit_before>// Copyright 2015 Robert Helmer <rhelmer@rhelmer.org>. See the LICENSE
// file at the top-level directory of this distribution.

/**
  * Symbolapi - a microservice which accepts lists of symbol+addresses, and returns
  * a list of symbolicated functions.
  *
  * The goal is to take an HTTP JSON request such as:
  * {"stacks":[
  *   [
  *     [0,11723767],
  *     [1, 65802]
  *    ]
  *  ],
  *  "memoryMap":[
  *    ["xul.pdb","44E4EC8C2F41492B9369D6B9A059577C2"],
  *    ["wntdll.pdb","D74F79EB1F8D4A45ABCD2F476CCABACC2"]
  *  ],
  *  "version":4
  * }
  *
  * The symbolapi service then downloads the corresponding symbol files (e.g. from S3), and returns
  * the function names for the corresponding addresses (in the "stacks" array) and returns JSON
  * such as:
  * {"symbolicatedStacks": [
  *   [
  *     "XREMain::XRE_mainRun() (in xul.pdb)",
  *     "KiUserCallbackDispatcher (in wntdll.pdb)"]
  *   ],
  *   "knownModules": [true, true]
  * }
  */

extern crate breakpad_symbols;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate rustc_serialize;
extern crate toml;

use std::collections::HashMap;
use std::fs::{File, create_dir_all};
use std::io::{Read, Write};
use std::path::{PathBuf};
use std::thread;

use breakpad_symbols::{Symbolizer, SimpleSymbolSupplier};
use hyper::Client;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use rustc_serialize::json;

/**
  * Incoming JSON request format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcDecodable)]
pub struct SymbolRequest {
    memoryMap: Vec<(String,String)>,
    // index, offset
    stacks: Vec<Vec<(i8,u64)>>,
    version: u8,
}

/**
  * Outgoing JSON response format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcEncodable)]
pub struct SymbolResponse {
    symbolicatedStacks: Vec<Vec<String>>,
    knownModules: Vec<bool>,
}

fn main() {
    log4rs::init_file("config/log.toml", Default::default()).unwrap();

    let address = "0.0.0.0:5000";

    info!("Listening on {}", address);
    Server::http(address).unwrap().handle(server).unwrap();
}

/**
  * Receives single HTTP requests and demuxes to symbols file fetches from S3 bucket.
  */
fn server(mut req: Request, mut res: Response) {
    info!("incoming connection from {}", req.remote_addr);

    match req.method {
        hyper::Post => {
            let mut res = res.start().unwrap();

            let mut buffer = String::new();
            req.read_to_string(&mut buffer).unwrap();
            debug!("raw POST: {:?}", &buffer);

            let decoded: SymbolRequest = json::decode(&buffer).unwrap();

            debug!("decoded memoryMap: {:?}", decoded.memoryMap);
            debug!("decoded stacks: {:?}", decoded.stacks);
            debug!("decoded version: {}", decoded.version);

            let symbol_url = get_config("symbol_urls.public");

            // stacks come in as an array, turn into hashmap
            let mut stack_map: HashMap<i8, Vec<u64>> = HashMap::new();

            debug!("decoded.stacks: {:?}", decoded.stacks);

            let stacks = decoded.stacks[0].clone();
            for stack in &stacks {
                let (index, offset) = *stack;

                let mut offsets = vec!();
                if stack_map.contains_key(&index) {
                    offsets = stack_map.get(&index).unwrap().clone();
                }
                offsets.push(offset);
                stack_map.insert(index, offsets);
            }

            debug!("stack_map: {:?}", stack_map);

            // FIXME limit the number of possible threads
            // TODO maybe push these into a queue and have a thread pool service the queue?
            let symbol_response = client(symbol_url, decoded.memoryMap, stack_map.clone());
            res.write_all(symbol_response.as_bytes()).unwrap();

            res.end().unwrap();
        },
        hyper::Get => {
            let mut res = res.start().unwrap();
            res.write_all("symbolapi, see github.com/rhelmer/symbolapi".as_bytes()).unwrap();
        },
        _ => { *res.status_mut() = StatusCode::MethodNotAllowed },
    }

    debug!("finished serving request");
}

/**
  * Creates multiple client connections and aggregates result.
  */
fn client(url: String, memory_map: Vec<(String,String)>, stack_map: HashMap<i8, Vec<u64>>) -> String {
    let mut handles = vec![];
    let mut counter: i8 = 0;
    for (debug_file, debug_id) in memory_map {
        let debug_file_name = debug_file.clone();
        let pdb = debug_file.find(".pdb").unwrap();
        let (symbol_name, _) = debug_file.split_at(pdb);
        let symbol_file = format!("{}.sym", symbol_name);
        let this_url = format!("{}/{}/{}/{}", url, debug_file, debug_id, symbol_file);

        let mut symbol_path = PathBuf::new();
        // TODO get from config
        symbol_path.push("testdata/symbols");

        let mut full_symbol_path = symbol_path.clone();
        full_symbol_path.push(&debug_file);
        full_symbol_path.push(&debug_id);
        full_symbol_path.push(&symbol_file);

        let stack_map_copy = stack_map.clone();

        create_dir_all(&full_symbol_path.parent().unwrap()).unwrap();

        let supplier = SimpleSymbolSupplier::new(vec!(symbol_path.clone()));

        // TODO most of the time is probably spent waiting on I/O, maybe async would be more appropriate?
        // TODO decide min/max possible threads, possibly based on number of cores?
        handles.push(thread::spawn(move || {

            let symbolizer = Symbolizer::new(supplier);
            // FIXME use Arc<Mutex<File>> to prevent concurrent writes
            // TODO only write contents if server version newer
            if !&full_symbol_path.exists() {

                let mut body = String::new();
                let c = Client::new();
                let mut res = c.get(&this_url).send().unwrap();
                res.read_to_string(&mut body).unwrap();

                let mut f = File::create(&full_symbol_path).unwrap();
                f.write_all(body.as_bytes()).unwrap();
            }

            debug!("symbol_path: {:?}", &symbol_path);
            // FIXME this is having problems with CRLF

            let mut symbols = vec!();
            for stacks in stack_map_copy.get(&counter) {
                for address in stacks {
                    debug!("attempt to symbolicate: {} for: {:?}", *address, &symbol_path);
                    match symbolizer.get_symbol_at_address(&debug_file_name, &debug_id, *address) {
                        Some(x) => symbols.push(x),
                        // return the address rather than function name if symbol not found
                        None => symbols.push(format!("0x{:x}", address)),
                    }
                }
            }
            debug!("debug_file_name: {:?}, symbols: {:?}", debug_file_name, symbols);

            (debug_file_name, symbols)
        }));

        counter += 1;
    }

    let mut result = SymbolResponse {
        symbolicatedStacks: vec!(),
        knownModules: vec!(),
    };

    let mut symbolicated_stacks = vec!();

    for handle in handles {
        let (debug_file_name, symbols) = handle.join().unwrap();

        for symbol in symbols {
            symbolicated_stacks.push(
                format!("{} (in {})", symbol, debug_file_name)
            );
        }
        result.knownModules.push(true);
    }

    // the required result format requires this to be a vec-of-vecs
    result.symbolicatedStacks.push(symbolicated_stacks);

    json::encode(&result).unwrap()
}

/**
  * Returns individual values from the configuration file.
  */
fn get_config(value_name: &str) -> String {
    // TODO move to actual file, static str for the moment
    let toml: &'static str = r#"
        [symbol_urls]
        public = "https://s3-us-west-2.amazonaws.com/org.mozilla.crash-stats.symbols-public/v1"
    "#;
    // TODO support multiple URLs
    let value: toml::Value = toml.parse().unwrap();

    value.lookup(value_name).unwrap().as_str().unwrap().to_string()
}
<commit_msg>handle the -1s<commit_after>// Copyright 2015 Robert Helmer <rhelmer@rhelmer.org>. See the LICENSE
// file at the top-level directory of this distribution.

/**
  * Symbolapi - a microservice which accepts lists of symbol+addresses, and returns
  * a list of symbolicated functions.
  *
  * The goal is to take an HTTP JSON request such as:
  * {"stacks":[
  *   [
  *     [0,11723767],
  *     [1, 65802]
  *    ]
  *  ],
  *  "memoryMap":[
  *    ["xul.pdb","44E4EC8C2F41492B9369D6B9A059577C2"],
  *    ["wntdll.pdb","D74F79EB1F8D4A45ABCD2F476CCABACC2"]
  *  ],
  *  "version":4
  * }
  *
  * The symbolapi service then downloads the corresponding symbol files (e.g. from S3), and returns
  * the function names for the corresponding addresses (in the "stacks" array) and returns JSON
  * such as:
  * {"symbolicatedStacks": [
  *   [
  *     "XREMain::XRE_mainRun() (in xul.pdb)",
  *     "KiUserCallbackDispatcher (in wntdll.pdb)"]
  *   ],
  *   "knownModules": [true, true]
  * }
  */

extern crate breakpad_symbols;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate rustc_serialize;
extern crate toml;

use std::collections::HashMap;
use std::fs::{File, create_dir_all};
use std::io::{Read, Write};
use std::path::{PathBuf};
use std::thread;

use breakpad_symbols::{Symbolizer, SimpleSymbolSupplier};
use hyper::Client;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use rustc_serialize::json;

/**
  * Incoming JSON request format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcDecodable)]
pub struct SymbolRequest {
    memoryMap: Vec<(String,String)>,
    // index, offset
    stacks: Vec<Vec<(i8,u64)>>,
    version: u8,
}

/**
  * Outgoing JSON response format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcEncodable)]
pub struct SymbolResponse {
    symbolicatedStacks: Vec<Vec<String>>,
    knownModules: Vec<bool>,
}

fn main() {
    log4rs::init_file("config/log.toml", Default::default()).unwrap();

    let address = "0.0.0.0:5000";

    info!("Listening on {}", address);
    Server::http(address).unwrap().handle(server).unwrap();
}

/**
  * Receives single HTTP requests and demuxes to symbols file fetches from S3 bucket.
  */
fn server(mut req: Request, mut res: Response) {
    info!("incoming connection from {}", req.remote_addr);

    match req.method {
        hyper::Post => {
            let mut res = res.start().unwrap();

            let mut buffer = String::new();
            req.read_to_string(&mut buffer).unwrap();
            debug!("raw POST: {:?}", &buffer);

            let decoded: SymbolRequest = json::decode(&buffer).unwrap();

            debug!("decoded memoryMap: {:?}", decoded.memoryMap);
            debug!("decoded stacks: {:?}", decoded.stacks);
            debug!("decoded version: {}", decoded.version);

            let symbol_url = get_config("symbol_urls.public");

            // stacks come in as an array, turn into hashmap
            let mut stack_map: HashMap<i8, Vec<u64>> = HashMap::new();

            debug!("decoded.stacks: {:?}", decoded.stacks);

            let stacks = decoded.stacks[0].clone();
            for stack in &stacks {
                let (index, offset) = *stack;

                let mut offsets = vec!();
                if stack_map.contains_key(&index) {
                    offsets = stack_map.get(&index).unwrap().clone();
                }
                offsets.push(offset);
                stack_map.insert(index, offsets);
            }

            debug!("stack_map: {:?}", stack_map);

            // FIXME limit the number of possible threads
            // TODO maybe push these into a queue and have a thread pool service the queue?
            let symbol_response = client(symbol_url, decoded.memoryMap, stack_map.clone());
            res.write_all(symbol_response.as_bytes()).unwrap();

            res.end().unwrap();
        },
        hyper::Get => {
            let mut res = res.start().unwrap();
            res.write_all("symbolapi, see github.com/rhelmer/symbolapi".as_bytes()).unwrap();
        },
        _ => { *res.status_mut() = StatusCode::MethodNotAllowed },
    }

    debug!("finished serving request");
}

/**
  * Creates multiple client connections and aggregates result.
  */
fn client(url: String, memory_map: Vec<(String,String)>, stack_map: HashMap<i8, Vec<u64>>) -> String {
    let mut handles = vec![];
    let mut counter: i8 = 0;
    for (debug_file, debug_id) in memory_map {
        let debug_file_name = debug_file.clone();
        let pdb = debug_file.find(".pdb").unwrap();
        let (symbol_name, _) = debug_file.split_at(pdb);
        let symbol_file = format!("{}.sym", symbol_name);
        let this_url = format!("{}/{}/{}/{}", url, debug_file, debug_id, symbol_file);

        let mut symbol_path = PathBuf::new();
        // TODO get from config
        symbol_path.push("testdata/symbols");

        let mut full_symbol_path = symbol_path.clone();
        full_symbol_path.push(&debug_file);
        full_symbol_path.push(&debug_id);
        full_symbol_path.push(&symbol_file);

        let stack_map_copy = stack_map.clone();

        create_dir_all(&full_symbol_path.parent().unwrap()).unwrap();

        let supplier = SimpleSymbolSupplier::new(vec!(symbol_path.clone()));

        // TODO most of the time is probably spent waiting on I/O, maybe async would be more appropriate?
        // TODO decide min/max possible threads, possibly based on number of cores?
        handles.push(thread::spawn(move || {

            let symbolizer = Symbolizer::new(supplier);
            // FIXME use Arc<Mutex<File>> to prevent concurrent writes
            // TODO only write contents if server version newer
            if !&full_symbol_path.exists() {

                let mut body = String::new();
                let c = Client::new();
                let mut res = c.get(&this_url).send().unwrap();
                res.read_to_string(&mut body).unwrap();

                let mut f = File::create(&full_symbol_path).unwrap();
                f.write_all(body.as_bytes()).unwrap();
            }

            debug!("symbol_path: {:?}", &symbol_path);
            // FIXME this is having problems with CRLF

            let mut symbols = vec!();
            for stacks in stack_map_copy.get(&counter) {
                for address in stacks {
                    debug!("attempt to symbolicate: {} for: {:?}", *address, &symbol_path);
                    match symbolizer.get_symbol_at_address(&debug_file_name, &debug_id, *address) {
                        Some(x) => symbols.push(x),
                        // return the address rather than function name if symbol not found
                        None => symbols.push(format!("0x{:x}", address)),
                    }
                }
            }
            debug!("debug_file_name: {:?}, symbols: {:?}", debug_file_name, symbols);

            (debug_file_name, symbols)
        }));

        counter += 1;
    }

    let mut result = SymbolResponse {
        symbolicatedStacks: vec!(),
        knownModules: vec!(),
    };

    let mut symbolicated_stacks = vec!();

    // pass anything with index -1 through
    for stacks in stack_map.get(&-1) {
        for address in stacks {
            symbolicated_stacks.push(
                format!("0x{:x}", address)
            );
        }
    }

    for handle in handles {
        let (debug_file_name, symbols) = handle.join().unwrap();

        for symbol in symbols {
            symbolicated_stacks.push(
                format!("{} (in {})", symbol, debug_file_name)
            );
        }
        result.knownModules.push(true);
    }

    // the required result format requires this to be a vec-of-vecs
    result.symbolicatedStacks.push(symbolicated_stacks);

    json::encode(&result).unwrap()
}

/**
  * Returns individual values from the configuration file.
  */
fn get_config(value_name: &str) -> String {
    // TODO move to actual file, static str for the moment
    let toml: &'static str = r#"
        [symbol_urls]
        public = "https://s3-us-west-2.amazonaws.com/org.mozilla.crash-stats.symbols-public/v1"
    "#;
    // TODO support multiple URLs
    let value: toml::Value = toml.parse().unwrap();

    value.lookup(value_name).unwrap().as_str().unwrap().to_string()
}
<|endoftext|>


<commit_before>use std::process::{ Child, Command, Stdio, ExitStatus };
use std::io::{ BufRead, BufReader, BufWriter, Read,  Write };
use std::path::{ Path, PathBuf };
use std::net::{ TcpListener, TcpStream };
use std::thread;
use std::fs::File;

extern crate argparse;
extern crate rand;

use argparse::{ ArgumentParser };
use rand::distributions::{IndependentSample, Range};

struct ListenerData {
    listener: TcpListener,
    port: u16,
}

fn create_listener() -> Result<ListenerData, &'static str>
{
    let possible_port_values = Range::new( 1024, 65535 );
    let mut rng = rand::thread_rng();
    for _ in 1..5 {
        let try_port = possible_port_values.ind_sample( &mut rng );

        let result = TcpListener::bind( ( "127.0.0.1", try_port ) );
        if result.is_ok() {
            return Ok( ListenerData{ listener: result.unwrap(), port: try_port } )
        }
    }

    Err( &"Failed to bind port" )
}

struct Credentials {
    username: String,
    user_token: String,
}

fn parse_credentials( credentials_file: &Path ) -> Result<Credentials, &str>
{
    let f = File::open( credentials_file ).unwrap();
    let mut reader = BufReader::new( f );

    let mut credentials_version = String::new();
    reader.read_line( &mut credentials_version ).unwrap();
    match credentials_version.trim().as_ref() {
        "0.1.0" |
        "0.2.0" |
        "0.2.1" => {
            let mut username = String::new();
            let mut token = String::new();
            reader.read_line( &mut username ).unwrap();
            reader.read_line( &mut token ).unwrap();
            Ok( Credentials{ username: username.trim().to_string(), user_token: token.trim().to_string() } )
        },
        _ => Err( "Unknown version" ),
    }
}

fn main()
{
    let mut wrapper_id = String::new();
    let mut pid_path = String::new();
    let mut package_path = String::new();
    let mut game_path = String::new();
    let mut game_args: Vec<String> = std::vec::Vec::new();

    {
        let mut ap: ArgumentParser = ArgumentParser::new();
        ap.refer( &mut wrapper_id ).add_argument( "wrapper-id", argparse::Store, "A unique identifier for the wrapper" ).required();
        ap.refer( &mut pid_path ).add_argument( "pid-path", argparse::Store, "Path to the pid directory" ).required();
        ap.refer( &mut package_path ).add_argument( "package-path", argparse::Store, "Path to the package installation directory" ).required();
        ap.refer( &mut game_path ).add_argument( "game-path", argparse::Store, "Path to the game file relative to the package installation directory" ).required();
        ap.refer( &mut game_args ).add_argument( "game-args", argparse::Collect, "Additional arguments to the game file" );
        ap.parse_args_or_exit();
    }

    let listener_data = create_listener().unwrap();
    let listener = listener_data.listener;

    let task_wrapper_id = wrapper_id.clone();
    let task_package_path = package_path.clone();
    let task_game_path = game_path.clone();
    let task_game_args = game_args.clone();
    thread::spawn( move || {

        for stream in listener.incoming() {
            let mut stream: TcpStream = stream.unwrap_or_else( |e| panic!( "Could not get incoming connection stream: {}", e ) );
            let out_str = String::from( "v0.2.1:Game Wrapper:" ) + &task_wrapper_id + ":" + &task_package_path + ":" + &task_game_path + ":\"" + &task_game_args.join( &"\",\"" ) + "\"";
            stream.write( out_str.as_bytes() ).unwrap_or_else( |e| panic!( "Could not send reply to the new connection: {}", e ) );
        }
    } );

    let mut pid_path = PathBuf::from( pid_path );
    pid_path.push( wrapper_id );

    match File::create( &pid_path ) {
        Ok( f ) => {
            let mut writer = BufWriter::new( f );
            writer.write( listener_data.port.to_string().as_bytes() )
                .expect( "Failed to write pid file" );
            writer.flush()
                .expect( "Failed to flush pid file" );
            drop( writer );
        },
        Err( e ) => println!( "Failed to write pid file: {}", e ),
    };

    // Get the full game file path.
    let mut game_file = PathBuf::from( package_path.clone() );
    game_file.push( game_path );

    // Current working directory is the directory of the game executable
    let cwd: &Path = game_file.parent()
        .expect( "Could not get parent dir from path" );

    let mut package_credentials: PathBuf = PathBuf::from( &package_path );
    package_credentials.push( ".gj-credentials" );

    let mut game_file_credentials: PathBuf = PathBuf::from( cwd );
    game_file_credentials.push( ".gj-credentials" );

    // Copy over the credential file from the package directory to the game executable's directory.
    let mut supports_game_api = package_credentials == game_file_credentials || std::fs::copy( package_credentials.as_path(), game_file_credentials.as_path() ).is_ok();

    let mut credentials: Credentials = Credentials{ username: String::new(), user_token: String::new() };
    if supports_game_api {
        let get_credentials = parse_credentials( game_file_credentials.as_path() );
        supports_game_api = get_credentials.is_ok();
        credentials = get_credentials.unwrap();
    }

    if supports_game_api {
        game_args.push( String::from( "gjapi_username" ) );
        game_args.push( credentials.username.to_string() );
        game_args.push( String::from( "gjapi_token" ) );
        game_args.push( credentials.user_token.to_string() );
    }

    let mut game_handle: Child = Command::new( &game_file )
        .current_dir( cwd )
        .args( game_args.as_slice() )
        .stderr( Stdio::piped() )
        .spawn()
        .unwrap_or_else( |e| panic!( "Couldn't launch game: {}", e ) );

    let result: ExitStatus = game_handle.wait().unwrap_or_else( |e| panic!( "Couldn't wait for game to launch/finish {}", e ) );

    if std::fs::remove_file( &pid_path ).is_err() {
        println!( "Failed to remove pid file: {}", pid_path.display() );
    }

    println!( "Game exited with exit code {}", result.code().expect( "Could not discern wrapped game exit code" ) );

    if !result.success() {
        let mut err_str = String::new();
        match game_handle.stderr.expect( "Could not get err stream" ).read_to_string( &mut err_str )  {
            Err(e) => panic!( "Could not read err stream {}", e ),
            Ok(_) => println!( "Stderr: {}", err_str ),
        }
    }
}
<commit_msg>Dont pass api credentials as command line arguments<commit_after>use std::process::{ Child, Command, Stdio, ExitStatus };
use std::io::{ BufWriter, Read,  Write };
use std::path::{ Path, PathBuf };
use std::net::{ TcpListener, TcpStream };
use std::thread;
use std::fs::File;

extern crate argparse;
extern crate rand;

use argparse::{ ArgumentParser };
use rand::distributions::{IndependentSample, Range};

struct ListenerData {
    listener: TcpListener,
    port: u16,
}

fn create_listener() -> Result<ListenerData, &'static str>
{
    let possible_port_values = Range::new( 1024, 65535 );
    let mut rng = rand::thread_rng();
    for _ in 1..5 {
        let try_port = possible_port_values.ind_sample( &mut rng );

        let result = TcpListener::bind( ( "127.0.0.1", try_port ) );
        if result.is_ok() {
            return Ok( ListenerData{ listener: result.unwrap(), port: try_port } )
        }
    }

    Err( &"Failed to bind port" )
}

fn main()
{
    let mut wrapper_id = String::new();
    let mut pid_path = String::new();
    let mut package_path = String::new();
    let mut game_path = String::new();
    let mut game_args: Vec<String> = std::vec::Vec::new();

    {
        let mut ap: ArgumentParser = ArgumentParser::new();
        ap.refer( &mut wrapper_id ).add_argument( "wrapper-id", argparse::Store, "A unique identifier for the wrapper" ).required();
        ap.refer( &mut pid_path ).add_argument( "pid-path", argparse::Store, "Path to the pid directory" ).required();
        ap.refer( &mut package_path ).add_argument( "package-path", argparse::Store, "Path to the package installation directory" ).required();
        ap.refer( &mut game_path ).add_argument( "game-path", argparse::Store, "Path to the game file relative to the package installation directory" ).required();
        ap.refer( &mut game_args ).add_argument( "game-args", argparse::Collect, "Additional arguments to the game file" );
        ap.parse_args_or_exit();
    }

    let listener_data = create_listener().unwrap();
    let listener = listener_data.listener;

    let task_wrapper_id = wrapper_id.clone();
    let task_package_path = package_path.clone();
    let task_game_path = game_path.clone();
    let task_game_args = game_args.clone();
    thread::spawn( move || {

        for stream in listener.incoming() {
            let mut stream: TcpStream = stream.unwrap_or_else( |e| panic!( "Could not get incoming connection stream: {}", e ) );
            let out_str = String::from( "v0.2.1:Game Wrapper:" ) + &task_wrapper_id + ":" + &task_package_path + ":" + &task_game_path + ":\"" + &task_game_args.join( &"\",\"" ) + "\"";
            stream.write( out_str.as_bytes() ).unwrap_or_else( |e| panic!( "Could not send reply to the new connection: {}", e ) );
        }
    } );

    let mut pid_path = PathBuf::from( pid_path );
    pid_path.push( wrapper_id );

    match File::create( &pid_path ) {
        Ok( f ) => {
            let mut writer = BufWriter::new( f );
            writer.write( listener_data.port.to_string().as_bytes() )
                .expect( "Failed to write pid file" );
            writer.flush()
                .expect( "Failed to flush pid file" );
            drop( writer );
        },
        Err( e ) => println!( "Failed to write pid file: {}", e ),
    };

    // Get the full game file path.
    let mut game_file = PathBuf::from( package_path.clone() );
    game_file.push( game_path );

    // Current working directory is the directory of the game executable
    let cwd: &Path = game_file.parent()
        .expect( "Could not get parent dir from path" );

    let mut package_credentials: PathBuf = PathBuf::from( &package_path );
    package_credentials.push( ".gj-credentials" );

    let mut game_file_credentials: PathBuf = PathBuf::from( cwd );
    game_file_credentials.push( ".gj-credentials" );

    // Copy over the credential file from the package directory to the game executable's directory.
    if package_credentials != game_file_credentials {
        std::fs::copy( package_credentials.as_path(), game_file_credentials.as_path() ).unwrap();
    }

    let mut game_handle: Child = Command::new( &game_file )
        .current_dir( cwd )
        .args( game_args.as_slice() )
        .stderr( Stdio::piped() )
        .spawn()
        .unwrap_or_else( |e| panic!( "Couldn't launch game: {}", e ) );

    let result: ExitStatus = game_handle.wait().unwrap_or_else( |e| panic!( "Couldn't wait for game to launch/finish {}", e ) );

    if std::fs::remove_file( &pid_path ).is_err() {
        println!( "Failed to remove pid file: {}", pid_path.display() );
    }

    println!( "Game exited with exit code {}", result.code().expect( "Could not discern wrapped game exit code" ) );

    if !result.success() {
        let mut err_str = String::new();
        match game_handle.stderr.expect( "Could not get err stream" ).read_to_string( &mut err_str )  {
            Err(e) => panic!( "Could not read err stream {}", e ),
            Ok(_) => println!( "Stderr: {}", err_str ),
        }
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Bytes;

#[derive(Debug)]
enum Mnemonic {
    Add, Call, Cls, Drw,
    Jp, Ld, Or, Ret,
    Rnd, Se, Shl, Shr,
    Sknp, Skp, Sne, Sub,
    Subn, Sys, Xor,
}

#[derive(Debug)]
enum Register {
    V0, V1, V2, V3,
    V4, V5, V6, V7,
    V8, V9, Va, Vb,
    Vc, Vd, Ve, Vf,
    Sp, Pc, I, St, Dt, IVal,
}

#[derive(Debug)]
enum Token {
    Opcode(Mnemonic),
    Reg(Register),
    ImmConst(u16),
}

struct Stream {
    input: Bytes<File>,
}

impl Stream {
    fn new(input: Bytes<File>) -> Stream {
        Stream {
            input: input,
        }
    }

    fn next_token(&mut self) -> Option<Token> {
        let mut buffer: Vec<u8> = vec![];

        loop {
            let bs = self.input.next().map_or(None, |bm| match bm {
                Ok(b) => Some(b),
                _ => None
            });

            match bs {
                Some(b) => {
                    if Stream::is_separator(b) {
                        return Stream::create_token(buffer);
                    }
                    buffer.push(b);
                },
                None => {
                    return Stream::create_token(buffer);
                }
            }
        }
    }

    fn create_token(input: Vec<u8>) -> Option<Token> {
        let token_str: String = String::from_utf8(input).unwrap_or_else(|err| {
            println!("Error: {:?}", err);
            "".to_owned()
        }).to_lowercase();

        let (numeric, radix) = Stream::is_numeric(&token_str);
        if numeric {
            return match radix {
                // base 10
                0 => Some(Token::ImmConst(token_str.parse::<u16>().unwrap())),
                // base 16
                1 => Some(Token::ImmConst(u16::from_str_radix(&token_str, 16).unwrap())),
                _ => None,
            }

        }

        if Stream::is_register(&token_str) {
            return match token_str.as_str() {
                "v0"   => Some(Token::Reg(Register::V0)),
                "v1"   => Some(Token::Reg(Register::V1)),
                "v2"   => Some(Token::Reg(Register::V2)),
                "v3"   => Some(Token::Reg(Register::V3)),
                "v4"   => Some(Token::Reg(Register::V4)),
                "v5"   => Some(Token::Reg(Register::V5)),
                "v6"   => Some(Token::Reg(Register::V6)),
                "v7"   => Some(Token::Reg(Register::V7)),
                "v8"   => Some(Token::Reg(Register::V8)),
                "v9"   => Some(Token::Reg(Register::V9)),
                "va"   => Some(Token::Reg(Register::Va)),
                "vb"   => Some(Token::Reg(Register::Vb)),
                "vc"   => Some(Token::Reg(Register::Vc)),
                "vd"   => Some(Token::Reg(Register::Vd)),
                "ve"   => Some(Token::Reg(Register::Ve)),
                "vf"   => Some(Token::Reg(Register::Vf)),
                "sp"   => Some(Token::Reg(Register::Sp)),
                "st"   => Some(Token::Reg(Register::St)),
                "dt"   => Some(Token::Reg(Register::Dt)),
                "pc"   => Some(Token::Reg(Register::Pc)),
                "i"    => Some(Token::Reg(Register::I)),
                "[i]"  => Some(Token::Reg(Register::IVal)),
                _      => None
            }
        }

        match token_str.as_str() {
            "add"   => Some(Token::Opcode(Mnemonic::Add)),
            "call"  => Some(Token::Opcode(Mnemonic::Call)),
            "cls"   => Some(Token::Opcode(Mnemonic::Cls)),
            "drw"   => Some(Token::Opcode(Mnemonic::Drw)),
            "jp"    => Some(Token::Opcode(Mnemonic::Jp)),
            "ld"    => Some(Token::Opcode(Mnemonic::Ld)),
            "or"    => Some(Token::Opcode(Mnemonic::Or)),
            "ret"   => Some(Token::Opcode(Mnemonic::Ret)),
            "rnd"   => Some(Token::Opcode(Mnemonic::Rnd)),
            "se"    => Some(Token::Opcode(Mnemonic::Se)),
            "shl"   => Some(Token::Opcode(Mnemonic::Shl)),
            "shr"   => Some(Token::Opcode(Mnemonic::Shr)),
            "sknp"  => Some(Token::Opcode(Mnemonic::Sknp)),
            "skp"   => Some(Token::Opcode(Mnemonic::Skp)),
            "sne"   => Some(Token::Opcode(Mnemonic::Sne)),
            "sub"   => Some(Token::Opcode(Mnemonic::Sub)),
            "subn"  => Some(Token::Opcode(Mnemonic::Subn)),
            "sys"   => Some(Token::Opcode(Mnemonic::Sys)),
            "xor"   => Some(Token::Opcode(Mnemonic::Xor)),
            _       => None
        }
    }

    fn is_separator(b: u8) -> bool {
        match b as char {
            ','|' '|'\n' => { true }
            _ => { false }
        }
    }

    fn is_register(input: &str) -> bool {
        input == "v0" || input == "v1" || input == "v2" ||
        input == "v3" || input == "v4" || input == "v5" ||
        input == "v6" || input == "v7" || input == "v8" ||
        input == "v9" || input == "va" || input == "vb" ||
        input == "vc" || input == "vd" || input == "ve" ||
        input == "vf" || input == "sp" || input == "st" ||
        input == "dt" || input == "pc" || input == "i" ||
        input == "[i]"
    }

    // Returns a tuple of boolean and integer
    // The input is numeric if the boolean component of the result is true
    // Integer component of result:
    //   0 => base 10
    //   1 => base 16
    fn is_numeric(input: &str) -> (bool, u8) {
        if input.len() < 1 {
            return (false, std::u8::MAX);
        }

        let in_bytes = input.as_bytes();
        if !Stream::is_ascii_numeric(in_bytes[0]) {
            return (false, std::u8::MAX);
        }

        // hex
        if input.starts_with("0x") {
            for i in 2..(in_bytes.len()) {
                if !Stream::is_ascii_hex(in_bytes[i]) {
                    return (false, std::u8::MAX);
                }
                return (true, 1);
            }
        } else {
            for b in in_bytes {
                if !Stream::is_ascii_numeric(*b) {
                    return (false, std::u8::MAX);
                }
                return (true, 0);
            }
        }
        return (false, std::u8::MAX);
    }

    fn is_ascii_numeric(input: u8) -> bool {
        input >= 48 && input <= 57
    }

    fn is_ascii_hex(input: u8) -> bool {
        (input >= 48 && input <= 57) || ((input >= 97 && input <= 102) || (input >= 65 && input <= 70))
    }
}

fn main() {
}
<commit_msg>Minor correction for converting hex string to u16<commit_after>use std::fs::File;
use std::io::Bytes;

#[derive(Debug)]
enum Mnemonic {
    Add, Call, Cls, Drw,
    Jp, Ld, Or, Ret,
    Rnd, Se, Shl, Shr,
    Sknp, Skp, Sne, Sub,
    Subn, Sys, Xor,
}

#[derive(Debug)]
enum Register {
    V0, V1, V2, V3,
    V4, V5, V6, V7,
    V8, V9, Va, Vb,
    Vc, Vd, Ve, Vf,
    Sp, Pc, I, St, Dt, IVal,
}

#[derive(Debug)]
enum Token {
    Opcode(Mnemonic),
    Reg(Register),
    ImmConst(u16),
}

struct Stream {
    input: Bytes<File>,
}

impl Stream {
    fn new(input: Bytes<File>) -> Stream {
        Stream {
            input: input,
        }
    }

    fn next_token(&mut self) -> Option<Token> {
        let mut buffer: Vec<u8> = vec![];

        loop {
            let bs = self.input.next().map_or(None, |bm| match bm {
                Ok(b) => Some(b),
                _ => None
            });

            match bs {
                Some(b) => {
                    if Stream::is_separator(b) {
                        return Stream::create_token(buffer);
                    }
                    buffer.push(b);
                },
                None => {
                    return Stream::create_token(buffer);
                }
            }
        }
    }

    fn create_token(input: Vec<u8>) -> Option<Token> {
        let token_str: String = String::from_utf8(input).unwrap_or_else(|err| {
            println!("Error: {:?}", err);
            "".to_owned()
        }).to_lowercase();

        let (numeric, radix) = Stream::is_numeric(&token_str);
        if numeric {
            return match radix {
                // base 10
                0 => Some(Token::ImmConst(token_str.parse::<u16>().unwrap())),
                // base 16
                1 => Some(Token::ImmConst(u16::from_str_radix(&token_str[2..], 16).unwrap())),
                _ => None,
            }

        }

        if Stream::is_register(&token_str) {
            return match token_str.as_str() {
                "v0"   => Some(Token::Reg(Register::V0)),
                "v1"   => Some(Token::Reg(Register::V1)),
                "v2"   => Some(Token::Reg(Register::V2)),
                "v3"   => Some(Token::Reg(Register::V3)),
                "v4"   => Some(Token::Reg(Register::V4)),
                "v5"   => Some(Token::Reg(Register::V5)),
                "v6"   => Some(Token::Reg(Register::V6)),
                "v7"   => Some(Token::Reg(Register::V7)),
                "v8"   => Some(Token::Reg(Register::V8)),
                "v9"   => Some(Token::Reg(Register::V9)),
                "va"   => Some(Token::Reg(Register::Va)),
                "vb"   => Some(Token::Reg(Register::Vb)),
                "vc"   => Some(Token::Reg(Register::Vc)),
                "vd"   => Some(Token::Reg(Register::Vd)),
                "ve"   => Some(Token::Reg(Register::Ve)),
                "vf"   => Some(Token::Reg(Register::Vf)),
                "sp"   => Some(Token::Reg(Register::Sp)),
                "st"   => Some(Token::Reg(Register::St)),
                "dt"   => Some(Token::Reg(Register::Dt)),
                "pc"   => Some(Token::Reg(Register::Pc)),
                "i"    => Some(Token::Reg(Register::I)),
                "[i]"  => Some(Token::Reg(Register::IVal)),
                _      => None
            }
        }

        match token_str.as_str() {
            "add"   => Some(Token::Opcode(Mnemonic::Add)),
            "call"  => Some(Token::Opcode(Mnemonic::Call)),
            "cls"   => Some(Token::Opcode(Mnemonic::Cls)),
            "drw"   => Some(Token::Opcode(Mnemonic::Drw)),
            "jp"    => Some(Token::Opcode(Mnemonic::Jp)),
            "ld"    => Some(Token::Opcode(Mnemonic::Ld)),
            "or"    => Some(Token::Opcode(Mnemonic::Or)),
            "ret"   => Some(Token::Opcode(Mnemonic::Ret)),
            "rnd"   => Some(Token::Opcode(Mnemonic::Rnd)),
            "se"    => Some(Token::Opcode(Mnemonic::Se)),
            "shl"   => Some(Token::Opcode(Mnemonic::Shl)),
            "shr"   => Some(Token::Opcode(Mnemonic::Shr)),
            "sknp"  => Some(Token::Opcode(Mnemonic::Sknp)),
            "skp"   => Some(Token::Opcode(Mnemonic::Skp)),
            "sne"   => Some(Token::Opcode(Mnemonic::Sne)),
            "sub"   => Some(Token::Opcode(Mnemonic::Sub)),
            "subn"  => Some(Token::Opcode(Mnemonic::Subn)),
            "sys"   => Some(Token::Opcode(Mnemonic::Sys)),
            "xor"   => Some(Token::Opcode(Mnemonic::Xor)),
            _       => None
        }
    }

    fn is_separator(b: u8) -> bool {
        match b as char {
            ','|' '|'\n' => { true }
            _ => { false }
        }
    }

    fn is_register(input: &str) -> bool {
        input == "v0" || input == "v1" || input == "v2" ||
        input == "v3" || input == "v4" || input == "v5" ||
        input == "v6" || input == "v7" || input == "v8" ||
        input == "v9" || input == "va" || input == "vb" ||
        input == "vc" || input == "vd" || input == "ve" ||
        input == "vf" || input == "sp" || input == "st" ||
        input == "dt" || input == "pc" || input == "i" ||
        input == "[i]"
    }

    // Returns a tuple of boolean and integer
    // The input is numeric if the boolean component of the result is true
    // Integer component of result:
    //   0 => base 10
    //   1 => base 16
    fn is_numeric(input: &str) -> (bool, u8) {
        if input.len() < 1 {
            return (false, std::u8::MAX);
        }

        let in_bytes = input.as_bytes();
        if !Stream::is_ascii_numeric(in_bytes[0]) {
            return (false, std::u8::MAX);
        }

        // hex
        if input.starts_with("0x") {
            for i in 2..(in_bytes.len()) {
                if !Stream::is_ascii_hex(in_bytes[i]) {
                    return (false, std::u8::MAX);
                }
                return (true, 1);
            }
        } else {
            for b in in_bytes {
                if !Stream::is_ascii_numeric(*b) {
                    return (false, std::u8::MAX);
                }
                return (true, 0);
            }
        }
        return (false, std::u8::MAX);
    }

    fn is_ascii_numeric(input: u8) -> bool {
        input >= 48 && input <= 57
    }

    fn is_ascii_hex(input: u8) -> bool {
        (input >= 48 && input <= 57) || ((input >= 97 && input <= 102) || (input >= 65 && input <= 70))
    }
}

fn main() {
}
<|endoftext|>


<commit_before>#[macro_use]
mod game;

use std::cell::{RefCell, RefMut};

extern crate gfx_device_gl;
extern crate piston_window;

use game::{Config, ConfigBuilder, Menu, MenuResult, Game, GameOver, GameWindow, Scene, SceneResult};

fn main() {
    let mut window = GameWindow::new(450, 600, "TetRS");
    let config = ConfigBuilder::new()
        .grid_size((10, 22))
        .grid_offset(10.0)
        .tile_size(29.0)
        .shadow(false)
        .ui_color([1.0; 4])
        .build();

    let main_menu = RefCell::new(create_main_menu(config, &window));
    let pause_menu = RefCell::new(create_pause_menu(config, &window));

    let game = RefCell::new(Game::new(config, window.piston_window.factory.clone()));
    let gameover = RefCell::new(GameOver::new(config, window.piston_window.factory.clone()));

    let mut scene: RefMut<Scene> = main_menu.borrow_mut();

    while let Some(e) = window.next() {
        match scene.process(&e) {
            SceneResult::MainMenu => {
                scene = main_menu.borrow_mut();
            }
            SceneResult::NewGame => {
                game.borrow_mut().reset();
                scene = game.borrow_mut();
            }
            SceneResult::PauseGame => {
                scene = pause_menu.borrow_mut();
            }
            SceneResult::ResumeGame => {
                game.borrow_mut().unpause();
                scene = game.borrow_mut();
            }
            SceneResult::GameOver => {
                scene = gameover.borrow_mut();
            }
            SceneResult::Quit => break,
            _ => (),
        };

        scene.render(&mut window, &e);
    }
}

fn create_main_menu(config: Config, window: &GameWindow) -> Menu {
    menu![
        (config, window.piston_window.factory.clone()),
        "New Game" => MenuResult::NewGame,
        "Quit" => MenuResult::Quit
    ]
}

fn create_pause_menu(config: Config, window: &GameWindow) -> Menu {
    menu![
        (config, window.piston_window.factory.clone()),
        "Resume" => MenuResult::ResumeGame,
        "New Game" => MenuResult::NewGame,
        "Main Manu" => MenuResult::MainMenu
    ]
}<commit_msg>--shadow-enabled toggle<commit_after>#[macro_use]
mod game;

use std::cell::{RefCell, RefMut};

extern crate gfx_device_gl;
extern crate piston_window;

use game::{Config, ConfigBuilder, Menu, MenuResult, Game, GameOver, GameWindow, Scene, SceneResult};

fn main() {
    let shadow_arg = std::env::args().nth(1);
    let shadow_enabled = shadow_arg.is_some() && shadow_arg.unwrap() == "--shadow-enabled";

    let mut window = GameWindow::new(450, 600, "TetRS");
    let config = ConfigBuilder::new()
        .grid_size((10, 22))
        .grid_offset(10.0)
        .tile_size(29.0)
        .shadow(shadow_enabled)
        .ui_color([1.0; 4])
        .build();

    let main_menu = RefCell::new(create_main_menu(config, &window));
    let pause_menu = RefCell::new(create_pause_menu(config, &window));

    let game = RefCell::new(Game::new(config, window.piston_window.factory.clone()));
    let gameover = RefCell::new(GameOver::new(config, window.piston_window.factory.clone()));

    let mut scene: RefMut<Scene> = main_menu.borrow_mut();

    while let Some(e) = window.next() {
        match scene.process(&e) {
            SceneResult::MainMenu => {
                scene = main_menu.borrow_mut();
            }
            SceneResult::NewGame => {
                game.borrow_mut().reset();
                scene = game.borrow_mut();
            }
            SceneResult::PauseGame => {
                scene = pause_menu.borrow_mut();
            }
            SceneResult::ResumeGame => {
                game.borrow_mut().unpause();
                scene = game.borrow_mut();
            }
            SceneResult::GameOver => {
                scene = gameover.borrow_mut();
            }
            SceneResult::Quit => break,
            _ => (),
        };

        scene.render(&mut window, &e);
    }
}

fn create_main_menu(config: Config, window: &GameWindow) -> Menu {
    menu![
        (config, window.piston_window.factory.clone()),
        "New Game" => MenuResult::NewGame,
        "Quit" => MenuResult::Quit
    ]
}

fn create_pause_menu(config: Config, window: &GameWindow) -> Menu {
    menu![
        (config, window.piston_window.factory.clone()),
        "Resume" => MenuResult::ResumeGame,
        "New Game" => MenuResult::NewGame,
        "Main Manu" => MenuResult::MainMenu
    ]
}<|endoftext|>


<commit_before>#![feature(macro_rules)]

extern crate getopts;
use getopts::{optflag,optopt,getopts,usage};
use std::os;
use std::collections::HashMap;
use std::collections::hashmap::{Occupied, Vacant};
use std::io;
use std::io::fs::PathExtensions;

fn get_env() -> HashMap<String, String> {
    let mut env = HashMap::new();
    env.extend(os::env().into_iter().filter(|&(ref key, ref value)| {
        key.as_slice().starts_with("MATES_")
    }));
    env
}

fn from_env<'a>(env: &'a HashMap<String, String>, key: &str) -> Option<&'a String> {
    env.find_equiv(&key)
}

fn expect_env<'a>(env: &'a HashMap<String, String>, key: &str) -> &'a String {
    from_env(env, key).expect(
        format!("The {} environment variable must be set.", key).as_slice()
    )
}

macro_rules! expect_or_this(
    ($iterator:expr, $this: expr) => (
        match $iterator {
            Some(x) => x,
            None => $this
        }
    )
)

fn build_index(outfile: &Path, dir: &Path) {
    if !dir.is_dir() {
        fail!("MATES_DIR must be a directory.");
    };

    let mut outf = io::File::create(outfile);
    let entries = match io::fs::readdir(dir) {
        Ok(x) => x,
        Err(f) => { fail!(f.desc) }
    };
    for entry in entries.iter() {
        if !entry.is_file() {
            continue;
        }
        let itemstr = match io::File::open(entry).read_to_string() {
            Ok(x) => x,
            Err(f) => { fail!(format!("Failed to open {}: {}", entry.display(), f.desc)) }
        };
        let item = parse_item(&itemstr);
        let name = item.fullname();
        match item.emails() {
            Some(emails) => {
                for email in emails.iter() {
                    outf.write_str(format!("{}\t{}\n", email.value, name).as_slice());
                };
            },
            None => ()
        };
    };
}

struct PropertyValue {
    params: String,
    value: String,
}

struct Item {
    props: HashMap<String, Vec<PropertyValue>>
}

impl Item {
    fn single_value(&self, key: &String) -> Option<String> {
        match self.props.find(key) {
            Some(x) => { if x.len() > 0 { Some(x[0].value.clone()) } else { None } },
            None => { None }
        }
    }
    fn fullname(&self) -> String {
        match self.single_value(&"FN".into_string()) {
            Some(x) => { x }
            None => { "".into_string() }
        }
    }

    fn emails(&self) -> Option<&Vec<PropertyValue>> {
        self.props.find(&"EMAIL".into_string())
    }
}

fn parse_item(s: &String) -> Item {
    let mut linebuffer = String::new();
    let mut line: String;
    let mut is_continuation: bool;
    let mut rv = Item {
        props: HashMap::new()
    };

    for strline in s.as_slice().split('\n') {
        line = strline.into_string();
        is_continuation = false;
        while line.as_slice().char_at(0).is_whitespace() {
            is_continuation = true;
            line.remove(0);
        };

        if !is_continuation && linebuffer.len() > 0 {
            let (propkey, propvalue) = parse_line(&linebuffer);
            match rv.props.entry(propkey) {
                Occupied(values) => { values.into_mut().push(propvalue); },
                Vacant(values) => { values.set(vec![propvalue]); }
            };
            linebuffer.clear();
        };

        linebuffer.push_str(line.as_slice());
    };
    rv
}

fn parse_line(s: &String) -> (String, PropertyValue) {
    let mut kv_splitresult = s.as_slice().splitn(1, ':');
    let key_and_params = kv_splitresult.next().expect("");
    let value = expect_or_this!(kv_splitresult.next(), "");

    let mut kp_splitresult = key_and_params.splitn(1, ';');
    let key = kp_splitresult.next().expect("");
    let params = expect_or_this!(kp_splitresult.next(), "");

    (key.into_string(), PropertyValue {
        value: value.into_string(),
        params: params.into_string()
    })
}

fn main() {
    let args = os::args();

    let program = args[0].as_slice();
    let opts = [
        optflag("i", "index", "Create index."),
        optflag("h", "help", "Print help."),
        optopt("m", "mutt-search", "Search in index, for mutt search.", "")
    ];

    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    let env = get_env();

    let print_usage = || {
        println!("{}", usage(program, opts));
        println!("Environment variables:");
        println!("- MATES_INDEX: Path to index file, which is basically a cache of all");
        println!("               contacts.");
        println!("- MATES_DIR:   The vdir to use.");
        println!("- MATES_GREP:  The grep executable to use.");
    };

    if matches.opt_present("h") {
        print_usage();
    } else if matches.opt_present("index") {
        let index_file = expect_env(&env, "MATES_INDEX");
        let mates_dir = expect_env(&env, "MATES_DIR");
        println!("Rebuilding index file \"{}\"...", index_file);
        build_index(
            &Path::new(index_file.as_slice()),
            &Path::new(mates_dir.as_slice())
        );
    } else if matches.opt_present("mutt-search") {
        let index_file = expect_env(&env, "MATES_INDEX");
        let default_grep = "grep".into_string();
        let grep_cmd = expect_or_this!(from_env(&env, "MATES_GREP"), &default_grep);

        // FIXME: Better way to write this? We already checked for presence of mutt-search before
        let query = matches.opt_str("mutt-search").expect("This should never happen and yet it did.");
        match match io::Command::new(grep_cmd.as_slice())
            .arg(query.as_slice())
            .arg(index_file.as_slice())
            .stdout(io::process::InheritFd(1))
            .stderr(io::process::InheritFd(2))
            .spawn() {
                Ok(child) => child,
                Err(e) => fail!("Failed to execute grep command: {}", e),
            }.wait() {
                Ok(code) => {
                    std::os::set_exit_status(match code {
                        io::process::ExitStatus(x) => x,
                        io::process::ExitSignal(x) => x,
                    });
                },
                Err(e) => fail!("Failed to execute grep command: {}", e),
            };
    } else {
        print_usage();
    };
}
<commit_msg>Add more FIXMEs<commit_after>#![feature(macro_rules)]

extern crate getopts;
use getopts::{optflag,optopt,getopts,usage};
use std::os;
use std::collections::HashMap;
use std::collections::hashmap::{Occupied, Vacant};
use std::io;
use std::io::fs::PathExtensions;

fn get_env() -> HashMap<String, String> {
    let mut env = HashMap::new();
    env.extend(os::env().into_iter().filter(|&(ref key, ref value)| {
        key.as_slice().starts_with("MATES_")
    }));
    env
}

fn from_env<'a>(env: &'a HashMap<String, String>, key: &str) -> Option<&'a String> {
    env.find_equiv(&key)
}

fn expect_env<'a>(env: &'a HashMap<String, String>, key: &str) -> &'a String {
    from_env(env, key).expect(
        format!("The {} environment variable must be set.", key).as_slice()
    )
}

macro_rules! expect_or_this(
    ($iterator:expr, $this: expr) => (
        match $iterator {
            Some(x) => x,
            None => $this
        }
    )
)

fn build_index(outfile: &Path, dir: &Path) {
    if !dir.is_dir() {
        fail!("MATES_DIR must be a directory.");
    };

    let mut outf = io::File::create(outfile);
    let entries = match io::fs::readdir(dir) {
        Ok(x) => x,
        Err(f) => { fail!(f.desc) }
    };
    for entry in entries.iter() {
        if !entry.is_file() {
            continue;
        }
        let itemstr = match io::File::open(entry).read_to_string() {
            Ok(x) => x,
            Err(f) => { fail!(format!("Failed to open {}: {}", entry.display(), f.desc)) }
        };
        let item = parse_item(&itemstr);
        let name = item.fullname();
        match item.emails() {
            Some(emails) => {
                for email in emails.iter() {
                    outf.write_str(format!("{}\t{}\n", email.value, name).as_slice());
                };
            },
            None => ()
        };
    };
}

struct PropertyValue {
    params: String,
    value: String,
}

struct Item {
    props: HashMap<String, Vec<PropertyValue>>
}

impl Item {
    fn single_value(&self, key: &String) -> Option<String> {
        match self.props.find(key) {
            Some(x) => { if x.len() > 0 { Some(x[0].value.clone()) } else { None } },
            None => { None }
        }
    }
    fn fullname(&self) -> String {
        match self.single_value(&"FN".into_string()) {
            Some(x) => { x }
            None => { "".into_string() }
        }
    }

    fn emails(&self) -> Option<&Vec<PropertyValue>> {
        self.props.find(&"EMAIL".into_string())
    }
}

fn parse_item(s: &String) -> Item {
    let mut linebuffer = String::new();
    let mut line: String;
    let mut is_continuation: bool;
    let mut rv = Item {
        props: HashMap::new()
    };

    for strline in s.as_slice().split('\n') {
        line = strline.into_string();
        is_continuation = false;
        while line.as_slice().char_at(0).is_whitespace() {
            is_continuation = true;
            line.remove(0);
        };

        if !is_continuation && linebuffer.len() > 0 {
            let (propkey, propvalue) = parse_line(&linebuffer);
            match rv.props.entry(propkey) {
                Occupied(values) => { values.into_mut().push(propvalue); },
                Vacant(values) => { values.set(vec![propvalue]); }
            };
            linebuffer.clear();
        };

        linebuffer.push_str(line.as_slice());
    };
    rv
}

fn parse_line(s: &String) -> (String, PropertyValue) {
    // FIXME: Better way to write this without expect?
    let mut kv_splitresult = s.as_slice().splitn(1, ':');
    let key_and_params = kv_splitresult.next().expect("");
    let value = expect_or_this!(kv_splitresult.next(), "");

    // FIXME: Better way to write this without expect?
    let mut kp_splitresult = key_and_params.splitn(1, ';');
    let key = kp_splitresult.next().expect("");
    let params = expect_or_this!(kp_splitresult.next(), "");

    (key.into_string(), PropertyValue {
        value: value.into_string(),
        params: params.into_string()
    })
}

fn main() {
    let args = os::args();

    let program = args[0].as_slice();
    let opts = [
        optflag("i", "index", "Create index."),
        optflag("h", "help", "Print help."),
        optopt("m", "mutt-search", "Search in index, for mutt search.", "")
    ];

    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    let env = get_env();

    let print_usage = || {
        println!("{}", usage(program, opts));
        println!("Environment variables:");
        println!("- MATES_INDEX: Path to index file, which is basically a cache of all");
        println!("               contacts.");
        println!("- MATES_DIR:   The vdir to use.");
        println!("- MATES_GREP:  The grep executable to use.");
    };

    if matches.opt_present("h") {
        print_usage();
    } else if matches.opt_present("index") {
        let index_file = expect_env(&env, "MATES_INDEX");
        let mates_dir = expect_env(&env, "MATES_DIR");
        println!("Rebuilding index file \"{}\"...", index_file);
        build_index(
            &Path::new(index_file.as_slice()),
            &Path::new(mates_dir.as_slice())
        );
    } else if matches.opt_present("mutt-search") {
        let index_file = expect_env(&env, "MATES_INDEX");
        let default_grep = "grep".into_string();
        let grep_cmd = expect_or_this!(from_env(&env, "MATES_GREP"), &default_grep);

        // FIXME: Better way to write this? We already checked for presence of mutt-search before
        let query = matches.opt_str("mutt-search").expect("This should never happen and yet it did.");
        match match io::Command::new(grep_cmd.as_slice())
            .arg(query.as_slice())
            .arg(index_file.as_slice())
            .stdout(io::process::InheritFd(1))
            .stderr(io::process::InheritFd(2))
            .spawn() {
                Ok(child) => child,
                Err(e) => fail!("Failed to execute grep command: {}", e),
            }.wait() {
                Ok(code) => {
                    std::os::set_exit_status(match code {
                        io::process::ExitStatus(x) => x,
                        io::process::ExitSignal(x) => x,
                    });
                },
                Err(e) => fail!("Failed to execute grep command: {}", e),
            };
    } else {
        print_usage();
    };
}
<|endoftext|>