<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/. */

// Needed to derive `Serialize` on ServiceProperties
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]
// For Docopt macro
#![plugin(docopt_macros)]

// Needed for IntoIter in controller.rs
#![feature(collections)]

// Make linter fail for every warning
#![plugin(clippy)]
#![deny(clippy)]

#![cfg_attr(test, feature(const_fn))] // Dependency of stainless
#![cfg_attr(test, plugin(stainless))] // Test runner

#![feature(reflect_marker)]

#![feature(associated_consts)]

extern crate chrono;
extern crate core;
extern crate docopt;
extern crate env_logger;
extern crate foxbox_adapters;
extern crate foxbox_taxonomy;
extern crate foxbox_users;
extern crate hyper;
#[macro_use]
extern crate iron;
extern crate iron_cors;
#[cfg(test)]
extern crate iron_test;
extern crate libc;
#[macro_use]
extern crate log;
extern crate mio;
extern crate mount;
extern crate nix;
extern crate openssl;
extern crate openssl_sys;
extern crate router;
extern crate rustc_serialize;
extern crate serde;
extern crate serde_json;
extern crate staticfile;
extern crate time;
extern crate timer;
extern crate transformable_channels;
extern crate unicase;
extern crate uuid;
extern crate ws;
extern crate multicast_dns;
extern crate xml;

#[cfg(test)]
extern crate regex;

// Need to be declared first so to let the macros be visible from other modules.
#[macro_use]
mod utils;
mod adapters;
mod config_store;
mod controller;
mod http_server;
mod managed_process;
mod profile_service;
mod registration;
mod service;
mod upnp;
mod service_router;
mod stable_uuid;
mod static_router;
mod tls;
mod tunnel_controller;
mod ws_server;

#[cfg(test)]
mod stubs {
    #![allow(dead_code)]
    #![allow(unused_variables)]
    #![allow(boxed_local)]
    pub mod service;
    pub mod controller;
}

use controller::{ Controller, FoxBox };
use env_logger::LogBuilder;
use tunnel_controller:: { TunnelConfig, Tunnel };
use libc::SIGINT;
use log::{ LogRecord, LogLevelFilter };

use multicast_dns::host::HostManager;
use std::env;
use std::mem;
use std::sync::atomic::{ AtomicBool, Ordering, ATOMIC_BOOL_INIT };
use tls::TlsOption;

docopt!(Args derive Debug, "
Usage: foxbox [-v] [-h] [-l <hostname>] [-p <port>] [-w <wsport>] [-r <url>] [-i <iface>] [-t <tunnel>] [-s <secret>] [--disable-tls] [-u <hostname>] [-c <namespace;key;value>]...

Options:
    -v, --verbose            Toggle verbose output.
    -l, --local-name <hostname>    Set local hostname. Linux only. Requires to be a member of the netdev group.
    -p, --port <port>        Set port to listen on for http connections. [default: 3000]
    -w, --wsport <wsport>    Set port to listen on for websocket. [default: 4000]
    -r, --register <url>     Change the url of the registration endpoint. [default: http://localhost:4242/register]
    -i, --iface <iface>      Specify the local IP interface.
    -t, --tunnel <tunnel>    Set the tunnel endpoint's hostname. If omitted, the tunnel is disabled.
    -s, --tunnel-secret <secret>    Set the tunnel shared secret. [default: secret]
        --disable-tls               Run as a plain HTTP server, disabling encryption.
        --remote-name <hostname>    Set remote hostname. This the URL to access the box through the bridge. If omitted, the tunnel is disabled
    -c, --config <namespace;key;value>  Set configuration override
    -h, --help               Print this help menu.
",
        flag_local_name: Option<String>,
        flag_port: u16,
        flag_wsport: u16,
        flag_register: String,
        flag_iface: Option<String>,
        flag_tunnel: Option<String>,
        flag_tunnel_secret: String,
        flag_disable_tls: bool,
        flag_remote_name: Option<String>,
        flag_config: Option<Vec<String>>);

/// Updates local host name with the provided host name string. If requested host name
/// is not available (used by anyone else on the same network) then collision
/// resolution logic is triggered and alternative name is chosen automatically
/// (host name plus "-2", "-3" and etc. postfix). This function blocks until host name
/// is updated and returns actual host name.
///
/// # Panics
///
/// Panics if provided host name is not valid non-FQDN host name.
///
/// # Arguments
///
/// * `hostname` - host name name we'd like to set (should be a valid non-FQDN host name).
fn update_hostname(hostname: String) -> Option<String> {
    let host_manager = HostManager::new();

    if !host_manager.is_valid_name(&hostname) {
        panic!("Host name `{}` is not a valid host name!", &hostname);
    }

    Some(host_manager.set_name(&hostname))
}

// Handle SIGINT (Ctrl-C) for manual shutdown.
// Signal handlers must not do anything substantial. To trigger shutdown, we atomically
// flip this flag; the event loop checks the flag and exits accordingly.
static SHUTDOWN_FLAG: AtomicBool = ATOMIC_BOOL_INIT;
unsafe fn handle_sigint(_:i32) {
    SHUTDOWN_FLAG.store(true, Ordering::Release);
}

#[cfg(any(target_os = "linux", target_os = "android"))]
#[inline]
fn tid_str() -> String {
    // gettid only exists for the linux and android variants of nix
    format!("({}) ", nix::unistd::gettid())
}

#[cfg(not(any(target_os = "linux", target_os = "android")))]
#[inline]
fn tid_str() -> &'static str {
    ""
}

fn main() {
    unsafe {
        libc::signal(SIGINT, mem::transmute(handle_sigint));
    }

    let format = |record: &LogRecord| {
        let t = time::now();
        format!("{}.{:03}: {}{:5} {}",
            time::strftime("%Y-%m-%d %H:%M:%S", &t).unwrap(),
            t.tm_nsec / 1000_000,
            tid_str(),
            record.level(),
            record.args()
        )
    };
    let mut builder = LogBuilder::new();
    builder.format(format).filter(None, LogLevelFilter::Info);

    if env::var("RUST_LOG").is_ok() {
       builder.parse(&env::var("RUST_LOG").unwrap());
    }
    builder.init().unwrap();

    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

    // Start the tunnel.
    let mut tunnel: Option<Tunnel> = None;
    if let Some(tunnel_url) = args.flag_tunnel {
        if let Some(remote_name) = args.flag_remote_name {
            tunnel = Some(Tunnel::new(TunnelConfig::new(tunnel_url,
                                                        args.flag_tunnel_secret,
                                                        args.flag_port,
                                                        args.flag_wsport,
                                                        remote_name)));
            tunnel.as_mut().unwrap().start().unwrap();
        }
    }

    // Register with the nUPNP server.
    let registrar = registration::Registrar::new();
    registrar.start(args.flag_register, args.flag_iface, &tunnel);

    let mut controller = FoxBox::new(
        args.flag_verbose, args.flag_local_name.map_or(None, update_hostname), args.flag_port,
        args.flag_wsport,
        if args.flag_disable_tls { TlsOption::Disabled } else { TlsOption::Enabled });

    // Override config values
    {
        if let Some(flags) = args.flag_config {
            for flag in flags {
                let items: Vec<String> = utils::split_escaped(&flag, ';');
                if items.len() >= 3 {
                    let namespace = items[0].clone();
                    let key = items[1].clone();
                    let value = items[2..].join(";");
                    warn!("Setting config override: {}::{}->{}", namespace, key, value);
                    controller.config.set_override(&namespace, &key, &value);
                } else {
                    error!("Config override requires three fields: {}", flag)
                }
            }
        }
    }

    controller.run(&SHUTDOWN_FLAG);

    if let Some(mut tunnel) = tunnel {
        tunnel.stop().unwrap();
    }
}

#[cfg(test)]
describe! main {
    describe! args {
        it "should have default values" {
            let argv = || vec!["foxbox"];
            let args: super::super::Args = super::super::Args::docopt().argv(argv().into_iter())
                .decode().unwrap();

            assert_eq!(args.flag_verbose, false);
            assert_eq!(args.flag_local_name, None);
            assert_eq!(args.flag_port, 3000);
            assert_eq!(args.flag_wsport, 4000);
            assert_eq!(args.flag_register, "http://localhost:4242/register");
            assert_eq!(args.flag_iface, None);
            assert_eq!(args.flag_tunnel, None);
            assert_eq!(args.flag_config, None);
            assert_eq!(args.flag_help, false);
        }

        it "should support short form" {
            let argv = || vec!["foxbox",
                               "-v",
                               "-p", "1234",
                               "-l", "foobar",
                               "-w", "4567",
                               "-r", "http://foo.bar:6868/register",
                               "-i", "eth99",
                               "-t", "tunnel.host",
                               "-c", "ns;key;value"];

           let args: super::super::Args = super::super::Args::docopt().argv(argv().into_iter())
               .decode().unwrap();

            assert_eq!(args.flag_verbose, true);
            assert_eq!(args.flag_local_name.unwrap(), "foobar");
            assert_eq!(args.flag_port, 1234);
            assert_eq!(args.flag_wsport, 4567);
            assert_eq!(args.flag_register, "http://foo.bar:6868/register");
            assert_eq!(args.flag_iface.unwrap(), "eth99");
            assert_eq!(args.flag_tunnel.unwrap(), "tunnel.host");
            assert_eq!(args.flag_config.unwrap(), vec!["ns;key;value"]);
        }

        it "should support long form" {
            let argv = || vec!["foxbox",
                               "--verbose",
                               "--port", "1234",
                               "--local-name", "foobar",
                               "--wsport", "4567",
                               "--register", "http://foo.bar:6868/register",
                               "--iface", "eth99",
                               "--tunnel", "tunnel.host",
                               "--config", "ns;key;value"];

            let args: super::super::Args = super::super::Args::docopt().argv(argv().into_iter())
                .decode().unwrap();

            assert_eq!(args.flag_verbose, true);
            assert_eq!(args.flag_local_name.unwrap(), "foobar");
            assert_eq!(args.flag_port, 1234);
            assert_eq!(args.flag_wsport, 4567);
            assert_eq!(args.flag_register, "http://foo.bar:6868/register");
            assert_eq!(args.flag_iface.unwrap(), "eth99");
            assert_eq!(args.flag_tunnel.unwrap(), "tunnel.host");
            assert_eq!(args.flag_config.unwrap(), vec!["ns;key;value"]);
        }
    }
}
<commit_msg>Fix command line arguments to fix the tunnel configuration r=sgiles<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/. */

// Needed to derive `Serialize` on ServiceProperties
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]
// For Docopt macro
#![plugin(docopt_macros)]

// Needed for IntoIter in controller.rs
#![feature(collections)]

// Make linter fail for every warning
#![plugin(clippy)]
#![deny(clippy)]

#![cfg_attr(test, feature(const_fn))] // Dependency of stainless
#![cfg_attr(test, plugin(stainless))] // Test runner

#![feature(reflect_marker)]

#![feature(associated_consts)]

extern crate chrono;
extern crate core;
extern crate docopt;
extern crate env_logger;
extern crate foxbox_adapters;
extern crate foxbox_taxonomy;
extern crate foxbox_users;
extern crate hyper;
#[macro_use]
extern crate iron;
extern crate iron_cors;
#[cfg(test)]
extern crate iron_test;
extern crate libc;
#[macro_use]
extern crate log;
extern crate mio;
extern crate mount;
extern crate nix;
extern crate openssl;
extern crate openssl_sys;
extern crate router;
extern crate rustc_serialize;
extern crate serde;
extern crate serde_json;
extern crate staticfile;
extern crate time;
extern crate timer;
extern crate transformable_channels;
extern crate unicase;
extern crate uuid;
extern crate ws;
extern crate multicast_dns;
extern crate xml;

#[cfg(test)]
extern crate regex;

// Need to be declared first so to let the macros be visible from other modules.
#[macro_use]
mod utils;
mod adapters;
mod config_store;
mod controller;
mod http_server;
mod managed_process;
mod profile_service;
mod registration;
mod service;
mod upnp;
mod service_router;
mod stable_uuid;
mod static_router;
mod tls;
mod tunnel_controller;
mod ws_server;

#[cfg(test)]
mod stubs {
    #![allow(dead_code)]
    #![allow(unused_variables)]
    #![allow(boxed_local)]
    pub mod service;
    pub mod controller;
}

use controller::{ Controller, FoxBox };
use env_logger::LogBuilder;
use tunnel_controller:: { TunnelConfig, Tunnel };
use libc::SIGINT;
use log::{ LogRecord, LogLevelFilter };

use multicast_dns::host::HostManager;
use std::env;
use std::mem;
use std::sync::atomic::{ AtomicBool, Ordering, ATOMIC_BOOL_INIT };
use tls::TlsOption;

docopt!(Args derive Debug, "
Usage: foxbox [-v] [-h] [-l <hostname>] [-p <port>] [-w <wsport>] [-r <url>] [-i <iface>] [-t <tunnel>] [-s <secret>] [--disable-tls] [--remote-name <hostname>] [-c <namespace;key;value>]...

Options:
    -v, --verbose            Toggle verbose output.
    -l, --local-name <hostname>    Set local hostname. Linux only. Requires to be a member of the netdev group.
    -p, --port <port>        Set port to listen on for http connections. [default: 3000]
    -w, --wsport <wsport>    Set port to listen on for websocket. [default: 4000]
    -r, --register <url>     Change the url of the registration endpoint. [default: http://localhost:4242/register]
    -i, --iface <iface>      Specify the local IP interface.
    -t, --tunnel <tunnel>    Set the tunnel endpoint's hostname. If omitted, the tunnel is disabled.
    -s, --tunnel-secret <secret>    Set the tunnel shared secret. [default: secret]
        --disable-tls               Run as a plain HTTP server, disabling encryption.
        --remote-name <hostname>    Set remote hostname. This the URL to access the box through the bridge. If omitted, the tunnel is disabled
    -c, --config <namespace;key;value>  Set configuration override
    -h, --help               Print this help menu.
",
        flag_local_name: Option<String>,
        flag_port: u16,
        flag_wsport: u16,
        flag_register: String,
        flag_iface: Option<String>,
        flag_tunnel: Option<String>,
        flag_tunnel_secret: String,
        flag_disable_tls: bool,
        flag_remote_name: Option<String>,
        flag_config: Option<Vec<String>>);

/// Updates local host name with the provided host name string. If requested host name
/// is not available (used by anyone else on the same network) then collision
/// resolution logic is triggered and alternative name is chosen automatically
/// (host name plus "-2", "-3" and etc. postfix). This function blocks until host name
/// is updated and returns actual host name.
///
/// # Panics
///
/// Panics if provided host name is not valid non-FQDN host name.
///
/// # Arguments
///
/// * `hostname` - host name name we'd like to set (should be a valid non-FQDN host name).
fn update_hostname(hostname: String) -> Option<String> {
    let host_manager = HostManager::new();

    if !host_manager.is_valid_name(&hostname) {
        panic!("Host name `{}` is not a valid host name!", &hostname);
    }

    Some(host_manager.set_name(&hostname))
}

// Handle SIGINT (Ctrl-C) for manual shutdown.
// Signal handlers must not do anything substantial. To trigger shutdown, we atomically
// flip this flag; the event loop checks the flag and exits accordingly.
static SHUTDOWN_FLAG: AtomicBool = ATOMIC_BOOL_INIT;
unsafe fn handle_sigint(_:i32) {
    SHUTDOWN_FLAG.store(true, Ordering::Release);
}

#[cfg(any(target_os = "linux", target_os = "android"))]
#[inline]
fn tid_str() -> String {
    // gettid only exists for the linux and android variants of nix
    format!("({}) ", nix::unistd::gettid())
}

#[cfg(not(any(target_os = "linux", target_os = "android")))]
#[inline]
fn tid_str() -> &'static str {
    ""
}

fn main() {
    unsafe {
        libc::signal(SIGINT, mem::transmute(handle_sigint));
    }

    let format = |record: &LogRecord| {
        let t = time::now();
        format!("{}.{:03}: {}{:5} {}",
            time::strftime("%Y-%m-%d %H:%M:%S", &t).unwrap(),
            t.tm_nsec / 1000_000,
            tid_str(),
            record.level(),
            record.args()
        )
    };
    let mut builder = LogBuilder::new();
    builder.format(format).filter(None, LogLevelFilter::Info);

    if env::var("RUST_LOG").is_ok() {
       builder.parse(&env::var("RUST_LOG").unwrap());
    }
    builder.init().unwrap();

    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

    // Start the tunnel.
    let mut tunnel: Option<Tunnel> = None;
    if let Some(tunnel_url) = args.flag_tunnel {
        if let Some(remote_name) = args.flag_remote_name {
            tunnel = Some(Tunnel::new(TunnelConfig::new(tunnel_url,
                                                        args.flag_tunnel_secret,
                                                        args.flag_port,
                                                        args.flag_wsport,
                                                        remote_name)));
            tunnel.as_mut().unwrap().start().unwrap();
        }
    }

    // Register with the nUPNP server.
    let registrar = registration::Registrar::new();
    registrar.start(args.flag_register, args.flag_iface, &tunnel);

    let mut controller = FoxBox::new(
        args.flag_verbose, args.flag_local_name.map_or(None, update_hostname), args.flag_port,
        args.flag_wsport,
        if args.flag_disable_tls { TlsOption::Disabled } else { TlsOption::Enabled });

    // Override config values
    {
        if let Some(flags) = args.flag_config {
            for flag in flags {
                let items: Vec<String> = utils::split_escaped(&flag, ';');
                if items.len() >= 3 {
                    let namespace = items[0].clone();
                    let key = items[1].clone();
                    let value = items[2..].join(";");
                    warn!("Setting config override: {}::{}->{}", namespace, key, value);
                    controller.config.set_override(&namespace, &key, &value);
                } else {
                    error!("Config override requires three fields: {}", flag)
                }
            }
        }
    }

    controller.run(&SHUTDOWN_FLAG);

    if let Some(mut tunnel) = tunnel {
        tunnel.stop().unwrap();
    }
}

#[cfg(test)]
describe! main {
    describe! args {
        it "should have default values" {
            let argv = || vec!["foxbox"];
            let args: super::super::Args = super::super::Args::docopt().argv(argv().into_iter())
                .decode().unwrap();

            assert_eq!(args.flag_verbose, false);
            assert_eq!(args.flag_local_name, None);
            assert_eq!(args.flag_port, 3000);
            assert_eq!(args.flag_wsport, 4000);
            assert_eq!(args.flag_register, "http://localhost:4242/register");
            assert_eq!(args.flag_iface, None);
            assert_eq!(args.flag_tunnel, None);
            assert_eq!(args.flag_config, None);
            assert_eq!(args.flag_help, false);
        }

        it "should support short form" {
            let argv = || vec!["foxbox",
                               "-v",
                               "-p", "1234",
                               "-l", "foobar",
                               "-w", "4567",
                               "-r", "http://foo.bar:6868/register",
                               "-i", "eth99",
                               "-t", "tunnel.host",
                               "-c", "ns;key;value"];

           let args: super::super::Args = super::super::Args::docopt().argv(argv().into_iter())
               .decode().unwrap();

            assert_eq!(args.flag_verbose, true);
            assert_eq!(args.flag_local_name.unwrap(), "foobar");
            assert_eq!(args.flag_port, 1234);
            assert_eq!(args.flag_wsport, 4567);
            assert_eq!(args.flag_register, "http://foo.bar:6868/register");
            assert_eq!(args.flag_iface.unwrap(), "eth99");
            assert_eq!(args.flag_tunnel.unwrap(), "tunnel.host");
            assert_eq!(args.flag_config.unwrap(), vec!["ns;key;value"]);
        }

        it "should support long form" {
            let argv = || vec!["foxbox",
                               "--verbose",
                               "--port", "1234",
                               "--local-name", "foobar",
                               "--wsport", "4567",
                               "--register", "http://foo.bar:6868/register",
                               "--iface", "eth99",
                               "--tunnel", "tunnel.host",
                               "--config", "ns;key;value"];

            let args: super::super::Args = super::super::Args::docopt().argv(argv().into_iter())
                .decode().unwrap();

            assert_eq!(args.flag_verbose, true);
            assert_eq!(args.flag_local_name.unwrap(), "foobar");
            assert_eq!(args.flag_port, 1234);
            assert_eq!(args.flag_wsport, 4567);
            assert_eq!(args.flag_register, "http://foo.bar:6868/register");
            assert_eq!(args.flag_iface.unwrap(), "eth99");
            assert_eq!(args.flag_tunnel.unwrap(), "tunnel.host");
            assert_eq!(args.flag_config.unwrap(), vec!["ns;key;value"]);
        }
    }
}
<|endoftext|>


<commit_before>
extern crate chrono;
extern crate docopt;

use std::process::Command;

use std::io::prelude::*;
use std::net::TcpStream;

use docopt::Docopt;

use std::str::FromStr;

extern crate libc;
use libc::*;
use std::ffi::CString;
use std::default::Default;

// #define MFSTYPENAMELEN  16  length of fs type name including null
// #define MAXPATHLEN      1024
// #define MNAMELEN        MAXPATHLEN
   // struct statfs { /* when _DARWIN_FEATURE_64_BIT_INODE is defined */
   //       uint32_t    f_bsize;        /* fundamental file system block size */
   //       int32_t     f_iosize;       /* optimal transfer block size */
   //       uint64_t    f_blocks;       /* total data blocks in file system */
   //       uint64_t    f_bfree;        /* free blocks in fs */
   //       uint64_t    f_bavail;       /* free blocks avail to non-superuser */
   //       uint64_t    f_files;        /* total file nodes in file system */
   //       uint64_t    f_ffree;        /* free file nodes in fs */
   //       fsid_t      f_fsid;         /* file system id */
   //       uid_t       f_owner;        /* user that mounted the filesystem */
   //       uint32_t    f_type;         /* type of filesystem */
   //       uint32_t    f_flags;        /* copy of mount exported flags */
   //       uint32_t    f_fssubtype;    /* fs sub-type (flavor) */
   //       char        f_fstypename[MFSTYPENAMELEN];   /* fs type name */
   //       char        f_mntonname[MAXPATHLEN];        /* directory on which mounted */
   //       char        f_mntfromname[MAXPATHLEN];      /* mounted filesystem */
   //       uint32_t    f_reserved[8];  /* For future use */
   //   };

type Uid = uint32_t;

#[repr(C)]
struct StatFs {
	f_bsize: uint32_t,
	f_iosize: int32_t,
	f_blocks: uint64_t,
	f_bfree:  uint64_t,
	f_bavail: uint64_t,
	f_files:  uint64_t,
	f_ffree:  uint64_t,
	f_fsid:	  [uint32_t; 2],
	f_owner:  Uid,
	f_type:	  uint32_t,
	f_flags:  uint32_t,
	f_fstypename: 	[c_char; 16],
	f_mntonname: 	[c_char; 1024],
	f_mntfromname: 	[c_char; 1024],
	f_reserved: 	[uint32_t; 8],
}

impl Default for StatFs {
	fn default() -> StatFs {
		StatFs{
			f_bsize: 0,
			f_iosize: 0,
			f_blocks: 0,
			f_bfree: 0,
			f_bavail: 0,
			f_files: 0,
			f_ffree: 0,
			f_fsid: [0; 2],
			f_owner: 0,
			f_type: 0,
			f_flags: 0,
			f_fstypename: [0; 16],
			f_mntonname:  [0; 1024],
			f_mntfromname:[0; 1024],
			f_reserved: [0; 8]
		}
	}
}

extern {
	fn statfs(path: *const c_char, stafs: *mut StatFs) -> size_t;
	// statfs(const char *path, struct statfs *buf);
}

// Write the Docopt usage string. dfrites ?
static USAGE: &'static str = "
Usage: durite -g GHOSTNAME -l HOSTNAME [-p PORT]
       durite (--help | -h)

Options:
    -h, --help     Show this screen.
    -l HOSTNAME    Hostname to advertise in graphite.
    -g GHOSTNAME   Graphite Hostname.
    -p PORT        Graphite port [default: 2003]
";

#[cfg(not(any(target_os="macos")))]
fn disk_free() -> std::process::Output {
	Command::new("df")
		.arg("--portability").output().unwrap_or_else(|e| { panic!("failed to execute process: {}", e) })
}

#[cfg(any(target_os="macos"))]
fn disk_free() -> std::process::Output {
	Command::new("df")
		.arg("-k").output().unwrap_or_else(|e| { panic!("failed to execute process: {}", e) })
}

fn send_content(stream: &mut std::net::TcpStream, hostname: &str, probe_and_value: String, timestamp: i64) {
	let content = format!("durite.{}.{} {}\n", hostname, probe_and_value, timestamp);
	let _ = stream.write(&content.as_bytes());
}

fn main() {

	// Parse argv and exit the program with an error message if it fails.
	let args = Docopt::new(USAGE)
		.and_then(|d| d.argv(std::env::args().into_iter()).parse())
		.unwrap_or_else(|e| e.exit());

    let connect_string = format!("{}:{}", args.get_str("-g"), args.get_str("-p"));
    println!("Connect string is {}", connect_string);
    let my_hostname = args.get_str("-l");

	while true {
	    let dt = chrono::UTC::now();
	    let timestamp = dt.timestamp();
	    let o = disk_free();
		let stdout = String::from_utf8(o.stdout).
			ok().
			unwrap();

		let lines = stdout.split("\n");

	    match TcpStream::connect(&*connect_string) {
	    	Ok(s) => {
	    		let mut stream = s;
				for line in lines {
					if line.starts_with("/") {
						let values: Vec<&str> = line.split(" ").filter(|e| {
							e.len() != 0
						}).collect();

						let disk = values[0];
						// du reports kbytes
                        let all: u64 = u64::from_str(values[1]).unwrap() * 1024;
						let available: u64 = u64::from_str(values[3]).unwrap() *1024;
						// let w = values[8].to_string();
						// let mut st: StatFs = Default::default();
						// let mp = CString::new(w.into_bytes()).unwrap();
						// unsafe {
						// 	let o = statfs(mp.as_ptr(), &mut st);
						// 	println!("o{} {:?}", o, st.f_bfree);
						// }
						send_content(&mut stream, my_hostname, format!("{}.available {}", disk, available as f32), timestamp);
						send_content(&mut stream, my_hostname, format!("{}.all {}", disk, all as f32), timestamp);
				 	}
				 }
	    	},
	    	Err(e) => println!("Unable to connect to {}: {:?}\nIgnoring this data point.", connect_string, e)
		}
	 	std::thread::sleep_ms(10000);
	}
}
<commit_msg>Send Mb instead of bytes<commit_after>
extern crate chrono;
extern crate docopt;

use std::process::Command;

use std::io::prelude::*;
use std::net::TcpStream;

use docopt::Docopt;

use std::str::FromStr;

extern crate libc;
use libc::*;
use std::ffi::CString;
use std::default::Default;

// #define MFSTYPENAMELEN  16  length of fs type name including null
// #define MAXPATHLEN      1024
// #define MNAMELEN        MAXPATHLEN
   // struct statfs { /* when _DARWIN_FEATURE_64_BIT_INODE is defined */
   //       uint32_t    f_bsize;        /* fundamental file system block size */
   //       int32_t     f_iosize;       /* optimal transfer block size */
   //       uint64_t    f_blocks;       /* total data blocks in file system */
   //       uint64_t    f_bfree;        /* free blocks in fs */
   //       uint64_t    f_bavail;       /* free blocks avail to non-superuser */
   //       uint64_t    f_files;        /* total file nodes in file system */
   //       uint64_t    f_ffree;        /* free file nodes in fs */
   //       fsid_t      f_fsid;         /* file system id */
   //       uid_t       f_owner;        /* user that mounted the filesystem */
   //       uint32_t    f_type;         /* type of filesystem */
   //       uint32_t    f_flags;        /* copy of mount exported flags */
   //       uint32_t    f_fssubtype;    /* fs sub-type (flavor) */
   //       char        f_fstypename[MFSTYPENAMELEN];   /* fs type name */
   //       char        f_mntonname[MAXPATHLEN];        /* directory on which mounted */
   //       char        f_mntfromname[MAXPATHLEN];      /* mounted filesystem */
   //       uint32_t    f_reserved[8];  /* For future use */
   //   };

type Uid = uint32_t;

#[repr(C)]
struct StatFs {
	f_bsize: uint32_t,
	f_iosize: int32_t,
	f_blocks: uint64_t,
	f_bfree:  uint64_t,
	f_bavail: uint64_t,
	f_files:  uint64_t,
	f_ffree:  uint64_t,
	f_fsid:	  [uint32_t; 2],
	f_owner:  Uid,
	f_type:	  uint32_t,
	f_flags:  uint32_t,
	f_fstypename: 	[c_char; 16],
	f_mntonname: 	[c_char; 1024],
	f_mntfromname: 	[c_char; 1024],
	f_reserved: 	[uint32_t; 8],
}

impl Default for StatFs {
	fn default() -> StatFs {
		StatFs{
			f_bsize: 0,
			f_iosize: 0,
			f_blocks: 0,
			f_bfree: 0,
			f_bavail: 0,
			f_files: 0,
			f_ffree: 0,
			f_fsid: [0; 2],
			f_owner: 0,
			f_type: 0,
			f_flags: 0,
			f_fstypename: [0; 16],
			f_mntonname:  [0; 1024],
			f_mntfromname:[0; 1024],
			f_reserved: [0; 8]
		}
	}
}

extern {
	fn statfs(path: *const c_char, stafs: *mut StatFs) -> size_t;
	// statfs(const char *path, struct statfs *buf);
}

// Write the Docopt usage string. dfrites ?
static USAGE: &'static str = "
Usage: durite -g GHOSTNAME -l HOSTNAME [-p PORT]
       durite (--help | -h)

Options:
    -h, --help     Show this screen.
    -l HOSTNAME    Hostname to advertise in graphite.
    -g GHOSTNAME   Graphite Hostname.
    -p PORT        Graphite port [default: 2003]
";

#[cfg(not(any(target_os="macos")))]
fn disk_free() -> std::process::Output {
	Command::new("df")
		.arg("--portability").output().unwrap_or_else(|e| { panic!("failed to execute process: {}", e) })
}

#[cfg(any(target_os="macos"))]
fn disk_free() -> std::process::Output {
	Command::new("df")
		.arg("-k").output().unwrap_or_else(|e| { panic!("failed to execute process: {}", e) })
}

fn send_content(stream: &mut std::net::TcpStream, hostname: &str, probe_and_value: String, timestamp: i64) {
	let content = format!("durite.{}.{} {}\n", hostname, probe_and_value, timestamp);
    println!("{}", content);
	let _ = stream.write(&content.as_bytes());
}

fn main() {

	// Parse argv and exit the program with an error message if it fails.
	let args = Docopt::new(USAGE)
		.and_then(|d| d.argv(std::env::args().into_iter()).parse())
		.unwrap_or_else(|e| e.exit());

    let connect_string = format!("{}:{}", args.get_str("-g"), args.get_str("-p"));
    println!("Connect string is {}", connect_string);
    let my_hostname = args.get_str("-l");

	while true {
	    let dt = chrono::UTC::now();
	    let timestamp = dt.timestamp();
	    let o = disk_free();
		let stdout = String::from_utf8(o.stdout).
			ok().
			unwrap();

		let lines = stdout.split("\n");

	    match TcpStream::connect(&*connect_string) {
	    	Ok(s) => {
	    		let mut stream = s;
				for line in lines {
					if line.starts_with("/") {
						let values: Vec<&str> = line.split(" ").filter(|e| {
							e.len() != 0
						}).collect();

						let disk = values[0];
						// du reports kbytes
                        let all: u64 = u64::from_str(values[1]).unwrap() / 1024;
						let available: u64 = u64::from_str(values[3]).unwrap() / 1024;
						// let w = values[8].to_string();
						// let mut st: StatFs = Default::default();
						// let mp = CString::new(w.into_bytes()).unwrap();
						// unsafe {
						// 	let o = statfs(mp.as_ptr(), &mut st);
						// 	println!("o{} {:?}", o, st.f_bfree);
						// }
						send_content(&mut stream, my_hostname, format!("{}.available {:3.3}", disk, available), timestamp);
						send_content(&mut stream, my_hostname, format!("{}.all {}", disk, all), timestamp);
				 	}
				 }
	    	},
	    	Err(e) => println!("Unable to connect to {}: {:?}\nIgnoring this data point.", connect_string, e)
		}
	 	std::thread::sleep_ms(10000);
	}
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![cfg_attr(test, feature(test))]
#![feature(conservative_impl_trait)]

#[macro_use] extern crate bitflags;
extern crate itertools;
extern crate ordermap;
extern crate rand;

pub mod crusader;
pub mod dps;
pub mod formation;
pub mod formation_search;
pub mod gear;
pub mod talent;
pub mod user_data;

use formation_search::*;
use crusader::*;
use dps::*;
use formation::*;
use gear::*;
use talent::*;
use user_data::*;

fn main() {
    let positions = vec![
        Coordinate::new(0, 0),
        Coordinate::new(0, 1),
        Coordinate::new(0, 2),
        Coordinate::new(0, 3),
        Coordinate::new(1, 0),
        Coordinate::new(1, 1),
        Coordinate::new(1, 2),
        Coordinate::new(2, 1),
        Coordinate::new(2, 2),
        Coordinate::new(3, 1),
    ];
    let formation = Formation::empty(positions);
    let crusaders = create_user_data().unlocked_crusaders();
    let mut search = FormationSearch::new(formation, &crusaders);
    search.perform_search(::std::time::Duration::from_secs(5));
    search.formation().print();
}

fn create_user_data() -> UserData {
    UserData::default()
        .with_dps_from_rings(455.0)
        .with_cooldown_percent(177.0)
        .with_dps_from_achievements(381.0)
        .with_unspent_idols(779)
        .level_talent(Talent::SpeedRunner, 10)
        .level_talent(Talent::RideTheStorm, 4)
        .level_talent(Talent::StormsBuilding, 6)
        .level_talent(Talent::PassiveCriticals, 22)
        .level_talent(Talent::SurplusCooldown, 19)
        .level_talent(Talent::Overenchanted, 9)
        .level_talent(Talent::SetBonus, 9)
        .level_talent(Talent::FastLearners, 2)
        .level_talent(Talent::WellEquipped, 4)
        .level_talent(Talent::SwapDay, 3)
        .level_talent(Talent::SpendItAll, 1)
        .level_talent(Talent::UpgradeThemAll, 1)
        .level_talent(Talent::Scavenger, 1)
        .level_talent(Talent::SpeedLooter, 1)
        .level_talent(Talent::EfficientCrusading, 25)
        .level_talent(Talent::DoingItAgain, 1)
        .level_talent(Talent::DeepIdolScavenger, 13)
        .level_talent(Talent::ExtraTraining, 2)
        .level_talent(Talent::TripleTierTrouble, 1)
        .add_crusader(CrusaderName::JimTheLumberjack, CrusaderData {
            enchantment_points: 77,
            gear: [GearQuality::Rare, GearQuality::Epic, GearQuality::Epic],
        }).add_crusader(CrusaderName::Arachnobuddy, CrusaderData {
            enchantment_points: 47,
            gear: [GearQuality::Rare, GearQuality::Rare, GearQuality::Rare],
        }).add_crusader(CrusaderName::VeronicaTheAndroidArcher, CrusaderData {
            enchantment_points: 4,
            gear: [GearQuality::Legendary(Level(3)), GearQuality::Rare, GearQuality::Rare],
        }).add_crusader(CrusaderName::SallyTheSuccubus, CrusaderData {
            enchantment_points: 153,
            gear: [
                GearQuality::GoldenLegendary(Level(3)),
                GearQuality::Legendary(Level(3)),
                GearQuality::Legendary(Level(2)),
            ],
        }).add_crusader(CrusaderName::EmoWerewolf, CrusaderData {
            enchantment_points: 176,
            gear: [GearQuality::Epic, GearQuality::Epic, GearQuality::Rare],
        }).add_crusader(CrusaderName::SashaTheFierceWarrior, CrusaderData {
            enchantment_points: 109,
            gear: [GearQuality::Rare, GearQuality::Epic, GearQuality::Legendary(Level(2))],
        }).add_crusader(CrusaderName::GroklokTheOrc, CrusaderData {
            enchantment_points: 41,
            gear: [GearQuality::GoldenEpic, GearQuality::Epic, GearQuality::Rare],
        }).add_crusader(CrusaderName::TheWashedUpHermit, CrusaderData {
            enchantment_points: 145,
            gear: [GearQuality::Rare, GearQuality::Rare, GearQuality::Rare],
        }).add_crusader(CrusaderName::KyleThePartyBro, CrusaderData {
            enchantment_points: 109,
            gear: [GearQuality::Rare, GearQuality::Rare, GearQuality::Uncommon],
        }).add_crusader(CrusaderName::Grandmora, CrusaderData {
            enchantment_points: 0,
            gear: [GearQuality::Epic, GearQuality::None, GearQuality::Rare],
        }).add_crusader(CrusaderName::DetectiveKaine, CrusaderData {
            enchantment_points: 82,
            gear: [GearQuality::Epic, GearQuality::Rare, GearQuality::Epic],
        }).add_crusader(CrusaderName::LarryTheLeprechaun, CrusaderData {
            enchantment_points: 13,
            gear: [GearQuality::Rare, GearQuality::Legendary(Level(2)), GearQuality::Rare],
        }).add_crusader(CrusaderName::BaenarallAngelOfHope, CrusaderData {
            enchantment_points: 0,
            gear: [GearQuality::Legendary(Level(1)), GearQuality::Uncommon, GearQuality::Rare],
        }).add_crusader(CrusaderName::ThePrincess, CrusaderData {
            enchantment_points: 85,
            gear: [GearQuality::Rare, GearQuality::Rare, GearQuality::Rare],
        }).add_crusader(CrusaderName::NatalieDragon, CrusaderData {
            enchantment_points: 69,
            gear: [
                GearQuality::Legendary(Level(2)),
                GearQuality::Legendary(Level(2)),
                GearQuality::Legendary(Level(1)),
            ],
        }).add_crusader(CrusaderName::PresidentBillySmithsonian, CrusaderData {
            enchantment_points: 0,
            gear: [GearQuality::Rare, GearQuality::Legendary(Level(2)), GearQuality::Epic],
        }).add_crusader(CrusaderName::JasonMasterOfShadows, CrusaderData {
            enchantment_points: 82,
            gear: [GearQuality::Epic, GearQuality::Rare, GearQuality::Epic],
        }).add_crusader(CrusaderName::Broot, CrusaderData {
            enchantment_points: 70,
            gear: [GearQuality::Uncommon, GearQuality::Uncommon, GearQuality::Uncommon],
        }).add_crusader(CrusaderName::ArtaxesTheLion, CrusaderData {
            enchantment_points: 94,
            gear: [
                GearQuality::Legendary(Level(3)),
                GearQuality::Legendary(Level(1)),
                GearQuality::Legendary(Level(3)),
            ],
        })
}
<commit_msg>Only enable test feature for benchmarks<commit_after>#![allow(dead_code)]
#![cfg_attr(bench, feature(test))]
#![feature(conservative_impl_trait)]

#[macro_use] extern crate bitflags;
extern crate itertools;
extern crate ordermap;
extern crate rand;

pub mod crusader;
pub mod dps;
pub mod formation;
pub mod formation_search;
pub mod gear;
pub mod talent;
pub mod user_data;

use formation_search::*;
use crusader::*;
use dps::*;
use formation::*;
use gear::*;
use talent::*;
use user_data::*;

fn main() {
    let positions = vec![
        Coordinate::new(0, 0),
        Coordinate::new(0, 1),
        Coordinate::new(0, 2),
        Coordinate::new(0, 3),
        Coordinate::new(1, 0),
        Coordinate::new(1, 1),
        Coordinate::new(1, 2),
        Coordinate::new(2, 1),
        Coordinate::new(2, 2),
        Coordinate::new(3, 1),
    ];
    let formation = Formation::empty(positions);
    let crusaders = create_user_data().unlocked_crusaders();
    let mut search = FormationSearch::new(formation, &crusaders);
    search.perform_search(::std::time::Duration::from_secs(5));
    search.formation().print();
}

fn create_user_data() -> UserData {
    UserData::default()
        .with_dps_from_rings(455.0)
        .with_cooldown_percent(177.0)
        .with_dps_from_achievements(381.0)
        .with_unspent_idols(779)
        .level_talent(Talent::SpeedRunner, 10)
        .level_talent(Talent::RideTheStorm, 4)
        .level_talent(Talent::StormsBuilding, 6)
        .level_talent(Talent::PassiveCriticals, 22)
        .level_talent(Talent::SurplusCooldown, 19)
        .level_talent(Talent::Overenchanted, 9)
        .level_talent(Talent::SetBonus, 9)
        .level_talent(Talent::FastLearners, 2)
        .level_talent(Talent::WellEquipped, 4)
        .level_talent(Talent::SwapDay, 3)
        .level_talent(Talent::SpendItAll, 1)
        .level_talent(Talent::UpgradeThemAll, 1)
        .level_talent(Talent::Scavenger, 1)
        .level_talent(Talent::SpeedLooter, 1)
        .level_talent(Talent::EfficientCrusading, 25)
        .level_talent(Talent::DoingItAgain, 1)
        .level_talent(Talent::DeepIdolScavenger, 13)
        .level_talent(Talent::ExtraTraining, 2)
        .level_talent(Talent::TripleTierTrouble, 1)
        .add_crusader(CrusaderName::JimTheLumberjack, CrusaderData {
            enchantment_points: 77,
            gear: [GearQuality::Rare, GearQuality::Epic, GearQuality::Epic],
        }).add_crusader(CrusaderName::Arachnobuddy, CrusaderData {
            enchantment_points: 47,
            gear: [GearQuality::Rare, GearQuality::Rare, GearQuality::Rare],
        }).add_crusader(CrusaderName::VeronicaTheAndroidArcher, CrusaderData {
            enchantment_points: 4,
            gear: [GearQuality::Legendary(Level(3)), GearQuality::Rare, GearQuality::Rare],
        }).add_crusader(CrusaderName::SallyTheSuccubus, CrusaderData {
            enchantment_points: 153,
            gear: [
                GearQuality::GoldenLegendary(Level(3)),
                GearQuality::Legendary(Level(3)),
                GearQuality::Legendary(Level(2)),
            ],
        }).add_crusader(CrusaderName::EmoWerewolf, CrusaderData {
            enchantment_points: 176,
            gear: [GearQuality::Epic, GearQuality::Epic, GearQuality::Rare],
        }).add_crusader(CrusaderName::SashaTheFierceWarrior, CrusaderData {
            enchantment_points: 109,
            gear: [GearQuality::Rare, GearQuality::Epic, GearQuality::Legendary(Level(2))],
        }).add_crusader(CrusaderName::GroklokTheOrc, CrusaderData {
            enchantment_points: 41,
            gear: [GearQuality::GoldenEpic, GearQuality::Epic, GearQuality::Rare],
        }).add_crusader(CrusaderName::TheWashedUpHermit, CrusaderData {
            enchantment_points: 145,
            gear: [GearQuality::Rare, GearQuality::Rare, GearQuality::Rare],
        }).add_crusader(CrusaderName::KyleThePartyBro, CrusaderData {
            enchantment_points: 109,
            gear: [GearQuality::Rare, GearQuality::Rare, GearQuality::Uncommon],
        }).add_crusader(CrusaderName::Grandmora, CrusaderData {
            enchantment_points: 0,
            gear: [GearQuality::Epic, GearQuality::None, GearQuality::Rare],
        }).add_crusader(CrusaderName::DetectiveKaine, CrusaderData {
            enchantment_points: 82,
            gear: [GearQuality::Epic, GearQuality::Rare, GearQuality::Epic],
        }).add_crusader(CrusaderName::LarryTheLeprechaun, CrusaderData {
            enchantment_points: 13,
            gear: [GearQuality::Rare, GearQuality::Legendary(Level(2)), GearQuality::Rare],
        }).add_crusader(CrusaderName::BaenarallAngelOfHope, CrusaderData {
            enchantment_points: 0,
            gear: [GearQuality::Legendary(Level(1)), GearQuality::Uncommon, GearQuality::Rare],
        }).add_crusader(CrusaderName::ThePrincess, CrusaderData {
            enchantment_points: 85,
            gear: [GearQuality::Rare, GearQuality::Rare, GearQuality::Rare],
        }).add_crusader(CrusaderName::NatalieDragon, CrusaderData {
            enchantment_points: 69,
            gear: [
                GearQuality::Legendary(Level(2)),
                GearQuality::Legendary(Level(2)),
                GearQuality::Legendary(Level(1)),
            ],
        }).add_crusader(CrusaderName::PresidentBillySmithsonian, CrusaderData {
            enchantment_points: 0,
            gear: [GearQuality::Rare, GearQuality::Legendary(Level(2)), GearQuality::Epic],
        }).add_crusader(CrusaderName::JasonMasterOfShadows, CrusaderData {
            enchantment_points: 82,
            gear: [GearQuality::Epic, GearQuality::Rare, GearQuality::Epic],
        }).add_crusader(CrusaderName::Broot, CrusaderData {
            enchantment_points: 70,
            gear: [GearQuality::Uncommon, GearQuality::Uncommon, GearQuality::Uncommon],
        }).add_crusader(CrusaderName::ArtaxesTheLion, CrusaderData {
            enchantment_points: 94,
            gear: [
                GearQuality::Legendary(Level(3)),
                GearQuality::Legendary(Level(1)),
                GearQuality::Legendary(Level(3)),
            ],
        })
}
<|endoftext|>


<commit_before>#![crate_name = "rboy"]

extern crate clap;
extern crate sdl2;
extern crate rboy;

use rboy::device::Device;
use std::sync::{Arc,RwLock};
use std::sync::mpsc::{Sender,Receiver};
use std::sync::mpsc::TryRecvError::{Disconnected,Empty};
use std::error::Error;

const EXITCODE_SUCCESS : i32 = 0;
const EXITCODE_CPULOADFAILS : i32 = 2;

fn main() {
    let exit_status = real_main();
    if exit_status != EXITCODE_SUCCESS {
        std::process::exit(exit_status);
    }
}

fn real_main() -> i32 {
    let matches = clap::App::new("rboy")
        .version("0.1")
        .author("Mathijs van de Nes")
        .about("A Gameboy Colour emulator written in Rust")
        .arg(clap::Arg::with_name("filename")
             .help("Sets the ROM file to load")
             .required(true))
        .arg(clap::Arg::with_name("serial")
             .help("Prints the data from the serial port to stdout")
             .short("s")
             .long("serial"))
        .arg(clap::Arg::with_name("classic")
             .help("Forces the emulator to run in classic Gameboy mode")
             .short("c")
             .long("classic"))
        .arg(clap::Arg::with_name("scale")
             .help("Sets the scale of the interface. Default: 2")
             .short("x")
             .long("scale")
             .validator(|s|
                 match s.parse::<u32>() {
                     Err(e) => Err(format!("Could not parse scale: {}", e.description())),
                     Ok(s) if s < 1 => Err("Scale must be at least 1".to_owned()),
                     Ok(s) if s > 8 => Err("Scale may be at most 8".to_owned()),
                     Ok(..) => Ok(()),
                 })
             .takes_value(true))
        .get_matches();

    let opt_serial = matches.is_present("serial");
    let opt_classic = matches.is_present("classic");
    let filename = matches.value_of("filename").unwrap();
    let scale = matches.value_of("scale").unwrap_or("2").parse::<u32>().unwrap();

    let cpu = construct_cpu(filename, opt_classic, opt_serial);
    if cpu.is_none() { return EXITCODE_CPULOADFAILS; }
    let cpu = cpu.unwrap();

    let sdl_context = sdl2::init().unwrap();
    let sdl_video = sdl_context.video().ok().expect("Could not open video");
    let window = match sdl2::video::WindowBuilder::new(&sdl_video,
                                                "RBoy - A gameboy in Rust",
                                                160*scale,
                                                144*scale).build() {
        Ok(window) => window,
        Err(err) => panic!("failed to open window: {}", err),
    };
    let mut renderer = match sdl2::render::RendererBuilder::new(window).software().build() {
        Ok(screen) => screen,
        Err(err) => panic!("failed to open screen: {}", err),
    };
    let mut texture = renderer.create_texture_streaming(sdl2::pixels::PixelFormatEnum::RGB24, (160, 144)).unwrap();

    let (sdl_tx, cpu_rx) = std::sync::mpsc::channel();
    let (cpu_tx, sdl_rx) = std::sync::mpsc::channel();
    let rawscreen = ::std::iter::repeat(0u8).take(160*144*3).collect();
    let arc = Arc::new(RwLock::new(rawscreen));
    let arc2 = arc.clone();

    let cpuloop_thread = std::thread::spawn(move|| cpuloop(&cpu_tx, &cpu_rx, arc2, cpu));

    let mut event_queue = sdl_context.event_pump().unwrap();
    'main : loop {
        let mut refreshed = false;
        'rx : loop {
            match sdl_rx.try_recv() {
                Err(Disconnected) => break 'main,
                Ok(_) => { if !refreshed { recalculate_screen(&mut renderer, &mut texture, &arc); refreshed = true } },
                Err(Empty) => break 'rx,
            }
        }
        for event in event_queue.wait_timeout_iter(2) {
            match event {
                sdl2::event::Event::Quit { .. } => break 'main,
                sdl2::event::Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::Escape), .. }
                    => break 'main,
                sdl2::event::Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::LShift), .. }
                    => { let _ = sdl_tx.send(GBEvent::SpeedUp); },
                sdl2::event::Event::KeyUp { keycode: Some(sdl2::keyboard::Keycode::LShift), .. }
                    => { let _ = sdl_tx.send(GBEvent::SlowDown); },
                sdl2::event::Event::KeyDown { keycode: Some(sdlkey), .. } => {
                    match sdl_to_keypad(sdlkey) {
                        Some(key) =>  { let _ = sdl_tx.send(GBEvent::KeyDown(key)); },
                        None => {},
                    }
                },
                sdl2::event::Event::KeyUp { keycode: Some(sdlkey), .. } => {
                    match sdl_to_keypad(sdlkey) {
                        Some(key) => { let _ = sdl_tx.send(GBEvent::KeyUp(key)); },
                        None => {},
                    }
                },
                _ => {}
            }
        }
    }

    drop(sdl_tx); // Disconnect such that the cpuloop will exit
    let _ = cpuloop_thread.join();

    EXITCODE_SUCCESS
}

fn sdl_to_keypad(key: sdl2::keyboard::Keycode) -> Option<rboy::KeypadKey> {
    match key {
        sdl2::keyboard::Keycode::Z => Some(rboy::KeypadKey::A),
        sdl2::keyboard::Keycode::X => Some(rboy::KeypadKey::B),
        sdl2::keyboard::Keycode::Up => Some(rboy::KeypadKey::Up),
        sdl2::keyboard::Keycode::Down => Some(rboy::KeypadKey::Down),
        sdl2::keyboard::Keycode::Left => Some(rboy::KeypadKey::Left),
        sdl2::keyboard::Keycode::Right => Some(rboy::KeypadKey::Right),
        sdl2::keyboard::Keycode::Space => Some(rboy::KeypadKey::Select),
        sdl2::keyboard::Keycode::Return => Some(rboy::KeypadKey::Start),
        _ => None,
    }
}

fn recalculate_screen(renderer: &mut sdl2::render::Renderer, texture: &mut sdl2::render::Texture, arc: &Arc<RwLock<Vec<u8>>>) {
    use std::io::Write;

    texture.with_lock(None, |ref mut buffer, _pitch| {
        buffer.write(&*arc.read().unwrap()).unwrap();
    }).unwrap();

    renderer.copy(&texture, None, None);
    renderer.present();
}

enum GBEvent {
    KeyUp(rboy::KeypadKey),
    KeyDown(rboy::KeypadKey),
    SpeedUp,
    SlowDown,
}

fn warn(message: &'static str) {
    use std::io::Write;
    let _ = write!(&mut std::io::stderr(), "{}\n", message);
}

fn construct_cpu(filename: &str, classic_mode: bool, output_serial: bool) -> Option<Device> {
    let opt_c = match classic_mode {
        true => Device::new(filename),
        false => Device::new_cgb(filename),
    };
    let mut c = match opt_c
    {
        Ok(cpu) => { cpu },
        Err(message) => { warn(message); return None; },
    };
    c.set_stdout(output_serial);
    Some(c)
}

fn cpuloop(cpu_tx: &Sender<()>, cpu_rx: &Receiver<GBEvent>, arc: Arc<RwLock<Vec<u8>>>, cpu: Device) {
    let mut c = cpu;
    let periodic = timer_periodic(8);
    let mut limit_speed = true;

    let waitticks = (4194304f64 / 1000.0 * 8.0) as u32;

    let mut ticks = 0;
    'cpuloop: loop {
        while ticks < waitticks {
            ticks += c.do_cycle();
            if c.check_and_reset_gpu_updated() {
                *arc.write().unwrap() = c.get_gpu_data().to_vec();
                if cpu_tx.send(()).is_err() { break 'cpuloop };
            }
        }
        ticks -= waitticks;
        if limit_speed { let _ = periodic.recv(); }

        'rx : loop {
            match cpu_rx.try_recv() {
                Ok(event) => match event {
                    GBEvent::KeyUp(key) => c.keyup(key),
                    GBEvent::KeyDown(key) => c.keydown(key),
                    GBEvent::SpeedUp => limit_speed = false,
                    GBEvent::SlowDown => limit_speed = true,
                },
                Err(Empty) => break 'rx,
                Err(Disconnected) => break 'cpuloop,
            }
        }
    }
}

fn timer_periodic(ms: u32) -> Receiver<()> {
    let (tx, rx) = std::sync::mpsc::channel();
    std::thread::spawn(move || {
        loop {
            std::thread::sleep_ms(ms);
            if tx.send(()).is_err() {
                break;
            }
        }
    });
    rx
}
<commit_msg>Allow the window to be resized manually<commit_after>#![crate_name = "rboy"]

extern crate clap;
extern crate sdl2;
extern crate rboy;

use rboy::device::Device;
use std::sync::{Arc,RwLock};
use std::sync::mpsc::{Sender,Receiver};
use std::sync::mpsc::TryRecvError::{Disconnected,Empty};
use std::error::Error;

const EXITCODE_SUCCESS : i32 = 0;
const EXITCODE_CPULOADFAILS : i32 = 2;

fn main() {
    let exit_status = real_main();
    if exit_status != EXITCODE_SUCCESS {
        std::process::exit(exit_status);
    }
}

fn real_main() -> i32 {
    let matches = clap::App::new("rboy")
        .version("0.1")
        .author("Mathijs van de Nes")
        .about("A Gameboy Colour emulator written in Rust")
        .arg(clap::Arg::with_name("filename")
             .help("Sets the ROM file to load")
             .required(true))
        .arg(clap::Arg::with_name("serial")
             .help("Prints the data from the serial port to stdout")
             .short("s")
             .long("serial"))
        .arg(clap::Arg::with_name("classic")
             .help("Forces the emulator to run in classic Gameboy mode")
             .short("c")
             .long("classic"))
        .arg(clap::Arg::with_name("scale")
             .help("Sets the scale of the interface. Default: 2")
             .short("x")
             .long("scale")
             .validator(|s|
                 match s.parse::<u32>() {
                     Err(e) => Err(format!("Could not parse scale: {}", e.description())),
                     Ok(s) if s < 1 => Err("Scale must be at least 1".to_owned()),
                     Ok(s) if s > 8 => Err("Scale may be at most 8".to_owned()),
                     Ok(..) => Ok(()),
                 })
             .takes_value(true))
        .get_matches();

    let opt_serial = matches.is_present("serial");
    let opt_classic = matches.is_present("classic");
    let filename = matches.value_of("filename").unwrap();
    let scale = matches.value_of("scale").unwrap_or("2").parse::<u32>().unwrap();

    let cpu = construct_cpu(filename, opt_classic, opt_serial);
    if cpu.is_none() { return EXITCODE_CPULOADFAILS; }
    let cpu = cpu.unwrap();

    let sdl_context = sdl2::init().unwrap();
    let sdl_video = sdl_context.video().ok().expect("Could not open video");
    let window = match sdl2::video::WindowBuilder::new(
            &sdl_video,
            "RBoy - A gameboy in Rust",
            160 * scale,
            144 * scale)
        .resizable()
        .build()
    {
        Ok(window) => window,
        Err(err) => panic!("failed to open window: {}", err),
    };
    let mut renderer = match sdl2::render::RendererBuilder::new(window).software().build() {
        Ok(screen) => screen,
        Err(err) => panic!("failed to open screen: {}", err),
    };
    let mut texture = renderer.create_texture_streaming(sdl2::pixels::PixelFormatEnum::RGB24, (160, 144)).unwrap();

    let (sdl_tx, cpu_rx) = std::sync::mpsc::channel();
    let (cpu_tx, sdl_rx) = std::sync::mpsc::channel();
    let rawscreen = ::std::iter::repeat(0u8).take(160*144*3).collect();
    let arc = Arc::new(RwLock::new(rawscreen));
    let arc2 = arc.clone();

    let cpuloop_thread = std::thread::spawn(move|| cpuloop(&cpu_tx, &cpu_rx, arc2, cpu));

    let mut event_queue = sdl_context.event_pump().unwrap();
    'main : loop {
        let mut refreshed = false;
        'rx : loop {
            match sdl_rx.try_recv() {
                Err(Disconnected) => break 'main,
                Ok(_) => { if !refreshed { recalculate_screen(&mut renderer, &mut texture, &arc); refreshed = true } },
                Err(Empty) => break 'rx,
            }
        }
        for event in event_queue.wait_timeout_iter(2) {
            match event {
                sdl2::event::Event::Quit { .. } => break 'main,
                sdl2::event::Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::Escape), .. }
                    => break 'main,
                sdl2::event::Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::Num1), .. }
                    => renderer.window_mut().unwrap().set_size(160, 144),
                sdl2::event::Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::R), .. }
                    => renderer.window_mut().unwrap().set_size(160*scale, 144*scale),
                sdl2::event::Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::LShift), .. }
                    => { let _ = sdl_tx.send(GBEvent::SpeedUp); },
                sdl2::event::Event::KeyUp { keycode: Some(sdl2::keyboard::Keycode::LShift), .. }
                    => { let _ = sdl_tx.send(GBEvent::SlowDown); },
                sdl2::event::Event::KeyDown { keycode: Some(sdlkey), .. } => {
                    match sdl_to_keypad(sdlkey) {
                        Some(key) =>  { let _ = sdl_tx.send(GBEvent::KeyDown(key)); },
                        None => {},
                    }
                },
                sdl2::event::Event::KeyUp { keycode: Some(sdlkey), .. } => {
                    match sdl_to_keypad(sdlkey) {
                        Some(key) => { let _ = sdl_tx.send(GBEvent::KeyUp(key)); },
                        None => {},
                    }
                },
                _ => {}
            }
        }
    }

    drop(sdl_tx); // Disconnect such that the cpuloop will exit
    let _ = cpuloop_thread.join();

    EXITCODE_SUCCESS
}

fn sdl_to_keypad(key: sdl2::keyboard::Keycode) -> Option<rboy::KeypadKey> {
    match key {
        sdl2::keyboard::Keycode::Z => Some(rboy::KeypadKey::A),
        sdl2::keyboard::Keycode::X => Some(rboy::KeypadKey::B),
        sdl2::keyboard::Keycode::Up => Some(rboy::KeypadKey::Up),
        sdl2::keyboard::Keycode::Down => Some(rboy::KeypadKey::Down),
        sdl2::keyboard::Keycode::Left => Some(rboy::KeypadKey::Left),
        sdl2::keyboard::Keycode::Right => Some(rboy::KeypadKey::Right),
        sdl2::keyboard::Keycode::Space => Some(rboy::KeypadKey::Select),
        sdl2::keyboard::Keycode::Return => Some(rboy::KeypadKey::Start),
        _ => None,
    }
}

fn recalculate_screen(renderer: &mut sdl2::render::Renderer, texture: &mut sdl2::render::Texture, arc: &Arc<RwLock<Vec<u8>>>) {
    use std::io::Write;

    texture.with_lock(None, |ref mut buffer, _pitch| {
        buffer.write(&*arc.read().unwrap()).unwrap();
    }).unwrap();

    renderer.copy(&texture, None, None);
    renderer.present();
}

enum GBEvent {
    KeyUp(rboy::KeypadKey),
    KeyDown(rboy::KeypadKey),
    SpeedUp,
    SlowDown,
}

fn warn(message: &'static str) {
    use std::io::Write;
    let _ = write!(&mut std::io::stderr(), "{}\n", message);
}

fn construct_cpu(filename: &str, classic_mode: bool, output_serial: bool) -> Option<Device> {
    let opt_c = match classic_mode {
        true => Device::new(filename),
        false => Device::new_cgb(filename),
    };
    let mut c = match opt_c
    {
        Ok(cpu) => { cpu },
        Err(message) => { warn(message); return None; },
    };
    c.set_stdout(output_serial);
    Some(c)
}

fn cpuloop(cpu_tx: &Sender<()>, cpu_rx: &Receiver<GBEvent>, arc: Arc<RwLock<Vec<u8>>>, cpu: Device) {
    let mut c = cpu;
    let periodic = timer_periodic(8);
    let mut limit_speed = true;

    let waitticks = (4194304f64 / 1000.0 * 8.0) as u32;

    let mut ticks = 0;
    'cpuloop: loop {
        while ticks < waitticks {
            ticks += c.do_cycle();
            if c.check_and_reset_gpu_updated() {
                *arc.write().unwrap() = c.get_gpu_data().to_vec();
                if cpu_tx.send(()).is_err() { break 'cpuloop };
            }
        }
        ticks -= waitticks;
        if limit_speed { let _ = periodic.recv(); }

        'rx : loop {
            match cpu_rx.try_recv() {
                Ok(event) => match event {
                    GBEvent::KeyUp(key) => c.keyup(key),
                    GBEvent::KeyDown(key) => c.keydown(key),
                    GBEvent::SpeedUp => limit_speed = false,
                    GBEvent::SlowDown => limit_speed = true,
                },
                Err(Empty) => break 'rx,
                Err(Disconnected) => break 'cpuloop,
            }
        }
    }
}

fn timer_periodic(ms: u32) -> Receiver<()> {
    let (tx, rx) = std::sync::mpsc::channel();
    std::thread::spawn(move || {
        loop {
            std::thread::sleep_ms(ms);
            if tx.send(()).is_err() {
                break;
            }
        }
    });
    rx
}
<|endoftext|>


<commit_before>// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]

#![allow(unknown_lints, missing_docs_in_private_items)]

extern crate clippy_lints;
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_plugin;
extern crate syntax;

use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation};
use rustc::session::{config, Session, CompileIncomplete};
use rustc::session::config::{Input, ErrorOutputType};
use std::collections::HashMap;
use std::path::PathBuf;
use std::process::{self, Command};
use syntax::ast;
use std::io::{self, Write};

extern crate cargo_metadata;

struct ClippyCompilerCalls {
    default: RustcDefaultCalls,
    run_lints: bool,
}

impl ClippyCompilerCalls {
    fn new(run_lints: bool) -> Self {
        ClippyCompilerCalls {
            default: RustcDefaultCalls,
            run_lints: run_lints,
        }
    }
}

impl<'a> CompilerCalls<'a> for ClippyCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default.early_callback(
            matches,
            sopts,
            cfg,
            descriptions,
            output,
        )
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default.no_input(
            matches,
            sopts,
            cfg,
            odir,
            ofile,
            descriptions,
        )
    }
    fn late_callback(
        &mut self,
        matches: &getopts::Matches,
        sess: &Session,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default.late_callback(
            matches,
            sess,
            input,
            odir,
            ofile,
        )
    }
    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
        let mut control = self.default.build_controller(sess, matches);

        if self.run_lints {
            let old = std::mem::replace(&mut control.after_parse.callback, box |_| {});
            control.after_parse.callback = Box::new(move |state| {
                {
                    let mut registry = rustc_plugin::registry::Registry::new(
                        state.session,
                        state
                            .krate
                            .as_ref()
                            .expect(
                                "at this compilation stage \
                                                                                the krate must be parsed",
                            )
                            .span,
                    );
                    registry.args_hidden = Some(Vec::new());
                    clippy_lints::register_plugins(&mut registry);

                    let rustc_plugin::registry::Registry {
                        early_lint_passes,
                        late_lint_passes,
                        lint_groups,
                        llvm_passes,
                        attributes,
                        ..
                    } = registry;
                    let sess = &state.session;
                    let mut ls = sess.lint_store.borrow_mut();
                    for pass in early_lint_passes {
                        ls.register_early_pass(Some(sess), true, pass);
                    }
                    for pass in late_lint_passes {
                        ls.register_late_pass(Some(sess), true, pass);
                    }

                    for (name, to) in lint_groups {
                        ls.register_group(Some(sess), true, name, to);
                    }

                    sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
                    sess.plugin_attributes.borrow_mut().extend(attributes);
                }
                old(state);
            });
        }

        control
    }
}

use std::path::Path;

const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    --features               Features to compile for the package
    -V, --version            Print version info and exit
    --all                    @@@ something sensible here (copy from cargo-edit?)

Other options are the same as `cargo rustc`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

The feature `cargo-clippy` is automatically defined for convenience. You can use
it to allow or deny lints from the code, eg.:

    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
"#;

#[allow(print_stdout)]
fn show_help() {
    println!("{}", CARGO_CLIPPY_HELP);
}

#[allow(print_stdout)]
fn show_version() {
    println!("{}", env!("CARGO_PKG_VERSION"));
}

pub fn main() {
    use std::env;

    if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) {
        panic!("yummy");
    }

    // Check for version and help flags even when invoked as 'cargo-clippy'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
        // this arm is executed on the initial call to `cargo clippy`

        let manifest_path_arg = std::env::args().skip(2).find(|val| {
            val.starts_with("--manifest-path=")
        });

        let mut metadata =
            if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) {
                metadata
            } else {
                let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n"));
                process::exit(101);
            };

        let manifest_path = manifest_path_arg.map(|arg| {
            Path::new(&arg["--manifest-path=".len()..])
                .canonicalize()
                .expect("manifest path could not be canonicalized")
        });

        let packages = if std::env::args().any(|a| a == "--all" ) {
            metadata.packages
        } else {
            let package_index = {
                if let Some(manifest_path) = manifest_path {
                    metadata.packages.iter().position(|package| {
                        let package_manifest_path = Path::new(&package.manifest_path).canonicalize().expect(
                            "package manifest path could not be canonicalized",
                        );
                        package_manifest_path == manifest_path
                    })
                } else {
                    let package_manifest_paths: HashMap<_, _> = metadata
                        .packages
                        .iter()
                        .enumerate()
                        .map(|(i, package)| {
                            let package_manifest_path = Path::new(&package.manifest_path)
                                .parent()
                                .expect("could not find parent directory of package manifest")
                                .canonicalize()
                                .expect("package directory cannot be canonicalized");
                            (package_manifest_path, i)
                        })
                        .collect();

                    let current_dir = std::env::current_dir()
                        .expect("could not read current directory")
                        .canonicalize()
                        .expect("current directory cannot be canonicalized");

                    let mut current_path: &Path = &current_dir;

                    // This gets the most-recent parent (the one that takes the fewest `cd ..`s to
                    // reach).
                    loop {
                        if let Some(&package_index) = package_manifest_paths.get(current_path) {
                            break Some(package_index);
                        } else {
                            // We'll never reach the filesystem root, because to get to this point in the
                            // code
                            // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to
                            // unwrap the current path's parent.
                            current_path = current_path.parent().unwrap_or_else(|| {
                                panic!("could not find parent of path {}", current_path.display())
                            });
                        }
                    }
                }
            }.expect("could not find matching package");

            vec![metadata.packages.remove(package_index)]
        };

        for package in packages {
            let manifest_path = package.manifest_path;

            for target in package.targets {
                let args = std::env::args().skip(2).filter(|a| a != "--all" && !a.starts_with("--manifest-path="));

                let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args);
                if let Some(first) = target.kind.get(0) {
                    if target.kind.len() > 1 || first.ends_with("lib") {
                        if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) {
                            std::process::exit(code);
                        }
                    } else if ["bin", "example", "test", "bench"].contains(&&**first) {
                        if let Err(code) = process(
                            vec![format!("--{}", first), target.name]
                                .into_iter()
                                .chain(args),
                        )
                        {
                            std::process::exit(code);
                        }
                    }
                } else {
                    panic!("badly formatted cargo metadata: target::kind is an empty array");
                }
            }
        }
    } else {
        // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC`
        // env var set to itself

        let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
        let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
        let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) {
            format!("{}/toolchains/{}", home, toolchain)
        } else {
            option_env!("SYSROOT")
                .map(|s| s.to_owned())
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| s.trim().to_owned())
                })
                .expect(
                    "need to specify SYSROOT env var during clippy compilation, or use rustup or multirust",
                )
        };

        rustc_driver::in_rustc_thread(|| {
            // this conditional check for the --sysroot flag is there so users can call
            // `cargo-clippy` directly
            // without having to pass --sysroot or anything
            let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") {
                env::args().collect()
            } else {
                env::args()
                    .chain(Some("--sysroot".to_owned()))
                    .chain(Some(sys_root))
                    .collect()
            };

            // this check ensures that dependencies are built but not linted and the final
            // crate is
            // linted but not built
            let clippy_enabled = env::args().any(|s| s == "--emit=metadata");

            if clippy_enabled {
                args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
            }

            let mut ccc = ClippyCompilerCalls::new(clippy_enabled);
            let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None);
            if let Err(CompileIncomplete::Errored(_)) = result {
                std::process::exit(1);
            }
        }).expect("rustc_thread failed");
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{

    let mut args = vec!["rustc".to_owned()];

    let mut found_dashes = false;
    for arg in old_args {
        found_dashes |= arg == "--";
        args.push(arg);
    }
    if !found_dashes {
        args.push("--".to_owned());
    }
    args.push("--emit=metadata".to_owned());
    args.push("--cfg".to_owned());
    args.push(r#"feature="cargo-clippy""#.to_owned());

    let path = std::env::current_exe().expect("current executable path invalid");
    let exit_status = std::process::Command::new("cargo")
        .args(&args)
        .env("RUSTC", path)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<commit_msg>Run Rustfmt-nightly<commit_after>// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]
#![allow(unknown_lints, missing_docs_in_private_items)]

extern crate clippy_lints;
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_plugin;
extern crate syntax;

use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls};
use rustc::session::{config, CompileIncomplete, Session};
use rustc::session::config::{ErrorOutputType, Input};
use std::collections::HashMap;
use std::path::PathBuf;
use std::process::{self, Command};
use syntax::ast;
use std::io::{self, Write};

extern crate cargo_metadata;

struct ClippyCompilerCalls {
    default: RustcDefaultCalls,
    run_lints: bool,
}

impl ClippyCompilerCalls {
    fn new(run_lints: bool) -> Self {
        ClippyCompilerCalls {
            default: RustcDefaultCalls,
            run_lints: run_lints,
        }
    }
}

impl<'a> CompilerCalls<'a> for ClippyCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default.early_callback(
            matches,
            sopts,
            cfg,
            descriptions,
            output,
        )
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default.no_input(
            matches,
            sopts,
            cfg,
            odir,
            ofile,
            descriptions,
        )
    }
    fn late_callback(
        &mut self,
        matches: &getopts::Matches,
        sess: &Session,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default.late_callback(
            matches,
            sess,
            input,
            odir,
            ofile,
        )
    }
    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
        let mut control = self.default.build_controller(sess, matches);

        if self.run_lints {
            let old = std::mem::replace(&mut control.after_parse.callback, box |_| {});
            control.after_parse.callback = Box::new(move |state| {
                {
                    let mut registry = rustc_plugin::registry::Registry::new(
                        state.session,
                        state
                            .krate
                            .as_ref()
                            .expect(
                                "at this compilation stage \
                                                                                the krate must be parsed",
                            )
                            .span,
                    );
                    registry.args_hidden = Some(Vec::new());
                    clippy_lints::register_plugins(&mut registry);

                    let rustc_plugin::registry::Registry {
                        early_lint_passes,
                        late_lint_passes,
                        lint_groups,
                        llvm_passes,
                        attributes,
                        ..
                    } = registry;
                    let sess = &state.session;
                    let mut ls = sess.lint_store.borrow_mut();
                    for pass in early_lint_passes {
                        ls.register_early_pass(Some(sess), true, pass);
                    }
                    for pass in late_lint_passes {
                        ls.register_late_pass(Some(sess), true, pass);
                    }

                    for (name, to) in lint_groups {
                        ls.register_group(Some(sess), true, name, to);
                    }

                    sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
                    sess.plugin_attributes.borrow_mut().extend(attributes);
                }
                old(state);
            });
        }

        control
    }
}

use std::path::Path;

const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    --features               Features to compile for the package
    -V, --version            Print version info and exit
    --all                    @@@ something sensible here (copy from cargo-edit?)

Other options are the same as `cargo rustc`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

The feature `cargo-clippy` is automatically defined for convenience. You can use
it to allow or deny lints from the code, eg.:

    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
"#;

#[allow(print_stdout)]
fn show_help() {
    println!("{}", CARGO_CLIPPY_HELP);
}

#[allow(print_stdout)]
fn show_version() {
    println!("{}", env!("CARGO_PKG_VERSION"));
}

pub fn main() {
    use std::env;

    if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) {
        panic!("yummy");
    }

    // Check for version and help flags even when invoked as 'cargo-clippy'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
        // this arm is executed on the initial call to `cargo clippy`

        let manifest_path_arg = std::env::args()
            .skip(2)
            .find(|val| val.starts_with("--manifest-path="));

        let mut metadata =
            if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) {
                metadata
            } else {
                let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n"));
                process::exit(101);
            };

        let manifest_path = manifest_path_arg.map(|arg| {
            Path::new(&arg["--manifest-path=".len()..])
                .canonicalize()
                .expect("manifest path could not be canonicalized")
        });

        let packages = if std::env::args().any(|a| a == "--all") {
            metadata.packages
        } else {
            let package_index = {
                if let Some(manifest_path) = manifest_path {
                    metadata.packages.iter().position(|package| {
                        let package_manifest_path = Path::new(&package.manifest_path)
                            .canonicalize()
                            .expect("package manifest path could not be canonicalized");
                        package_manifest_path == manifest_path
                    })
                } else {
                    let package_manifest_paths: HashMap<_, _> = metadata
                        .packages
                        .iter()
                        .enumerate()
                        .map(|(i, package)| {
                            let package_manifest_path = Path::new(&package.manifest_path)
                                .parent()
                                .expect("could not find parent directory of package manifest")
                                .canonicalize()
                                .expect("package directory cannot be canonicalized");
                            (package_manifest_path, i)
                        })
                        .collect();

                    let current_dir = std::env::current_dir()
                        .expect("could not read current directory")
                        .canonicalize()
                        .expect("current directory cannot be canonicalized");

                    let mut current_path: &Path = &current_dir;

                    // This gets the most-recent parent (the one that takes the fewest `cd ..`s to
                    // reach).
                    loop {
                        if let Some(&package_index) = package_manifest_paths.get(current_path) {
                            break Some(package_index);
                        } else {
                            // We'll never reach the filesystem root, because to get to this point in the
                            // code
                            // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to
                            // unwrap the current path's parent.
                            current_path = current_path
                                .parent()
                                .unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display()));
                        }
                    }
                }
            }.expect("could not find matching package");

            vec![metadata.packages.remove(package_index)]
        };

        for package in packages {
            let manifest_path = package.manifest_path;

            for target in package.targets {
                let args = std::env::args()
                    .skip(2)
                    .filter(|a| a != "--all" && !a.starts_with("--manifest-path="));

                let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args);
                if let Some(first) = target.kind.get(0) {
                    if target.kind.len() > 1 || first.ends_with("lib") {
                        if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) {
                            std::process::exit(code);
                        }
                    } else if ["bin", "example", "test", "bench"].contains(&&**first) {
                        if let Err(code) = process(
                            vec![format!("--{}", first), target.name]
                                .into_iter()
                                .chain(args),
                        ) {
                            std::process::exit(code);
                        }
                    }
                } else {
                    panic!("badly formatted cargo metadata: target::kind is an empty array");
                }
            }
        }
    } else {
        // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC`
        // env var set to itself

        let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
        let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
        let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) {
            format!("{}/toolchains/{}", home, toolchain)
        } else {
            option_env!("SYSROOT")
                .map(|s| s.to_owned())
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| s.trim().to_owned())
                })
                .expect(
                    "need to specify SYSROOT env var during clippy compilation, or use rustup or multirust",
                )
        };

        rustc_driver::in_rustc_thread(|| {
            // this conditional check for the --sysroot flag is there so users can call
            // `cargo-clippy` directly
            // without having to pass --sysroot or anything
            let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") {
                env::args().collect()
            } else {
                env::args()
                    .chain(Some("--sysroot".to_owned()))
                    .chain(Some(sys_root))
                    .collect()
            };

            // this check ensures that dependencies are built but not linted and the final
            // crate is
            // linted but not built
            let clippy_enabled = env::args().any(|s| s == "--emit=metadata");

            if clippy_enabled {
                args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
            }

            let mut ccc = ClippyCompilerCalls::new(clippy_enabled);
            let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None);
            if let Err(CompileIncomplete::Errored(_)) = result {
                std::process::exit(1);
            }
        }).expect("rustc_thread failed");
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{

    let mut args = vec!["rustc".to_owned()];

    let mut found_dashes = false;
    for arg in old_args {
        found_dashes |= arg == "--";
        args.push(arg);
    }
    if !found_dashes {
        args.push("--".to_owned());
    }
    args.push("--emit=metadata".to_owned());
    args.push("--cfg".to_owned());
    args.push(r#"feature="cargo-clippy""#.to_owned());

    let path = std::env::current_exe().expect("current executable path invalid");
    let exit_status = std::process::Command::new("cargo")
        .args(&args)
        .env("RUSTC", path)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<|endoftext|>


<commit_before>// This file is part of sokoban-rs
// Copyright 2015 Sébastien Watteau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This is an implement of Sokoban in Rust.

#[macro_use]
extern crate bitflags;
extern crate sdl2;
extern crate sdl2_image;
extern crate xml;

use std::path::Path;
use std::fs::File;
use std::io::BufReader;
use std::str::FromStr;
use sdl2::keyboard::Keycode;
use sdl2_image::INIT_PNG;
use xml::reader::EventReader;
use xml::reader::events::*;

pub mod game;
pub mod render;

use game::Level;
use render::Drawer;

pub fn main() {
    let slc_file = std::env::args()
        .skip(1)
        .next()
        .unwrap_or_else(|| {
            println!("Argument missing: pleasy specify the path to an SLC file.");
            std::process::exit(1);
        });

    let sdl_context = sdl2::init().unwrap_or_else(|err| {
        println!("Failed to initialize an SDL context: {}", err);
        std::process::exit(1);
    });

    let video_subsystem = sdl_context.video().unwrap_or_else(|err| {
        println!("Failed to initialize the video subsystem: {}", err);
        std::process::exit(1);
    });

    sdl2_image::init(INIT_PNG);

    let window = video_subsystem.window("sokoban-rs", 1024, 768)
        .position_centered()
        //.fullscreen()
        .opengl()
        .build()
        .unwrap_or_else(|err| {
            println!("Failed to create the window: {}", err);
            std::process::exit(1);
        });

    let renderer = window.renderer()
        .build()
        .unwrap_or_else(|err| {
            println!("Failed to get an SDL renderer for the main window: {}", err);
            std::process::exit(1);
        });

    let mut drawer = Drawer::new(renderer);

    let mut collection = load_slc_file(Path::new(&slc_file)).into_iter();
    let mut reference_level = collection.next().unwrap();
    let mut level = reference_level.clone();

    let mut running = true;
    let mut event_pump = sdl_context.event_pump().unwrap();
    let mut skip = false;
    while running {
        if level.is_completed() || skip {
            match collection.next() {
                Some(l) => {
                    level = l;
                    reference_level = level.clone();
                    skip = false;
                },
                None => {
                    break;
                }
            }
        }
        drawer.draw(&level);
        for event in event_pump.poll_iter() {
            use sdl2::event::Event;
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    running = false
                },
                Event::KeyDown { keycode: Some(Keycode::Left), .. } => {
                    level.step(game::Direction::Left);
                }
                Event::KeyDown { keycode: Some(Keycode::Right), .. } => {
                    level.step(game::Direction::Right);
                }
                Event::KeyDown { keycode: Some(Keycode::Up), .. } => {
                    level.step(game::Direction::Up);
                }
                Event::KeyDown { keycode: Some(Keycode::Down), .. } => {
                    level.step(game::Direction::Down);
                }
                Event::KeyDown { keycode: Some(Keycode::R), .. } => {
                    level = reference_level.clone();
                }
                Event::KeyDown { keycode: Some(Keycode::N), .. } => {
                    skip = true;
                }
                _ => {}
            }
        }
    }
    sdl2_image::quit();
}

/// Builds levels from a level collection file in the SLC format.
fn load_slc_file(path: &Path) -> Vec<Level> {
    let mut collection = Vec::new();
    let reader = BufReader::new(File::open(&path).unwrap());
    let mut parser = EventReader::new(reader);

    let mut level_str = String::new();
    let mut reading_level = false;
    for e in parser.events() {
        match e {
            XmlEvent::StartElement { name, .. } => {
                reading_level = name.local_name == "L";
            },
            XmlEvent::EndElement { name } => {
                if name.local_name == "Level" {
                    collection.push(Level::from_str(&level_str).unwrap());
                    level_str.clear();
                }
            },
            XmlEvent::Characters(ref data) => {
                if reading_level {
                    level_str.push_str(data);
                    level_str.push('\n');
                }
            }
            _ => {}
        }
    }

    collection
}
<commit_msg>Fixed typo<commit_after>// This file is part of sokoban-rs
// Copyright 2015 Sébastien Watteau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This is an implementation of Sokoban in Rust.

#[macro_use]
extern crate bitflags;
extern crate sdl2;
extern crate sdl2_image;
extern crate xml;

use std::path::Path;
use std::fs::File;
use std::io::BufReader;
use std::str::FromStr;
use sdl2::keyboard::Keycode;
use sdl2_image::INIT_PNG;
use xml::reader::EventReader;
use xml::reader::events::*;

pub mod game;
pub mod render;

use game::Level;
use render::Drawer;

pub fn main() {
    let slc_file = std::env::args()
        .skip(1)
        .next()
        .unwrap_or_else(|| {
            println!("Argument missing: pleasy specify the path to an SLC file.");
            std::process::exit(1);
        });

    let sdl_context = sdl2::init().unwrap_or_else(|err| {
        println!("Failed to initialize an SDL context: {}", err);
        std::process::exit(1);
    });

    let video_subsystem = sdl_context.video().unwrap_or_else(|err| {
        println!("Failed to initialize the video subsystem: {}", err);
        std::process::exit(1);
    });

    sdl2_image::init(INIT_PNG);

    let window = video_subsystem.window("sokoban-rs", 1024, 768)
        .position_centered()
        //.fullscreen()
        .opengl()
        .build()
        .unwrap_or_else(|err| {
            println!("Failed to create the window: {}", err);
            std::process::exit(1);
        });

    let renderer = window.renderer()
        .build()
        .unwrap_or_else(|err| {
            println!("Failed to get an SDL renderer for the main window: {}", err);
            std::process::exit(1);
        });

    let mut drawer = Drawer::new(renderer);

    let mut collection = load_slc_file(Path::new(&slc_file)).into_iter();
    let mut reference_level = collection.next().unwrap();
    let mut level = reference_level.clone();

    let mut running = true;
    let mut event_pump = sdl_context.event_pump().unwrap();
    let mut skip = false;
    while running {
        if level.is_completed() || skip {
            match collection.next() {
                Some(l) => {
                    level = l;
                    reference_level = level.clone();
                    skip = false;
                },
                None => {
                    break;
                }
            }
        }
        drawer.draw(&level);
        for event in event_pump.poll_iter() {
            use sdl2::event::Event;
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    running = false
                },
                Event::KeyDown { keycode: Some(Keycode::Left), .. } => {
                    level.step(game::Direction::Left);
                }
                Event::KeyDown { keycode: Some(Keycode::Right), .. } => {
                    level.step(game::Direction::Right);
                }
                Event::KeyDown { keycode: Some(Keycode::Up), .. } => {
                    level.step(game::Direction::Up);
                }
                Event::KeyDown { keycode: Some(Keycode::Down), .. } => {
                    level.step(game::Direction::Down);
                }
                Event::KeyDown { keycode: Some(Keycode::R), .. } => {
                    level = reference_level.clone();
                }
                Event::KeyDown { keycode: Some(Keycode::N), .. } => {
                    skip = true;
                }
                _ => {}
            }
        }
    }
    sdl2_image::quit();
}

/// Builds levels from a level collection file in the SLC format.
fn load_slc_file(path: &Path) -> Vec<Level> {
    let mut collection = Vec::new();
    let reader = BufReader::new(File::open(&path).unwrap());
    let mut parser = EventReader::new(reader);

    let mut level_str = String::new();
    let mut reading_level = false;
    for e in parser.events() {
        match e {
            XmlEvent::StartElement { name, .. } => {
                reading_level = name.local_name == "L";
            },
            XmlEvent::EndElement { name } => {
                if name.local_name == "Level" {
                    collection.push(Level::from_str(&level_str).unwrap());
                    level_str.clear();
                }
            },
            XmlEvent::Characters(ref data) => {
                if reading_level {
                    level_str.push_str(data);
                    level_str.push('\n');
                }
            }
            _ => {}
        }
    }

    collection
}
<|endoftext|>