<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
compile_error!("This crate is only for the `wasm32-unknown-unknown` target");

use core::cell::RefCell;
use std::thread_local;

use wasm_bindgen::prelude::*;

use getrandom::{register_custom_getrandom, Error};

#[derive(Clone, Debug)]
enum RngSource {
    Node(NodeCrypto),
    Browser(BrowserCrypto),
}

// JsValues are always per-thread, so we initialize RngSource for each thread.
//   See: https://github.com/rustwasm/wasm-bindgen/pull/955
thread_local!(
    static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);

register_custom_getrandom!(getrandom_inner);

fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
    RNG_SOURCE.with(|f| {
        let mut source = f.borrow_mut();
        if source.is_none() {
            *source = Some(getrandom_init()?);
        }

        match source.as_ref().unwrap() {
            RngSource::Node(n) => n.random_fill_sync(dest),
            RngSource::Browser(n) => {
                // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
                //
                // where it says:
                //
                // > A QuotaExceededError DOMException is thrown if the
                // > requested length is greater than 65536 bytes.
                for chunk in dest.chunks_mut(65536) {
                    n.get_random_values(chunk)
                }
            }
        };
        Ok(())
    })
}

fn getrandom_init() -> Result<RngSource, Error> {
    if let Ok(self_) = Global::get_self() {
        // If `self` is defined then we're in a browser somehow (main window
        // or web worker). Here we want to try to use
        // `crypto.getRandomValues`, but if `crypto` isn't defined we assume
        // we're in an older web browser and the OS RNG isn't available.

        let crypto = self_.crypto();
        if crypto.is_undefined() {
            return Err(Error::BINDGEN_CRYPTO_UNDEF);
        }

        // Test if `crypto.getRandomValues` is undefined as well
        let crypto: BrowserCrypto = crypto.into();
        if crypto.get_random_values_fn().is_undefined() {
            return Err(Error::BINDGEN_GRV_UNDEF);
        }

        return Ok(RngSource::Browser(crypto));
    }

    return Ok(RngSource::Node(node_require("crypto")));
}

#[wasm_bindgen]
extern "C" {
    type Global;
    #[wasm_bindgen(getter, catch, static_method_of = Global, js_class = self, js_name = self)]
    fn get_self() -> Result<Self_, JsValue>;

    type Self_;
    #[wasm_bindgen(method, getter, structural)]
    fn crypto(me: &Self_) -> JsValue;

    #[derive(Clone, Debug)]
    type BrowserCrypto;

    // TODO: these `structural` annotations here ideally wouldn't be here to
    // avoid a JS shim, but for now with feature detection they're
    // unavoidable.
    #[wasm_bindgen(method, js_name = getRandomValues, structural, getter)]
    fn get_random_values_fn(me: &BrowserCrypto) -> JsValue;
    #[wasm_bindgen(method, js_name = getRandomValues, structural)]
    fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]);

    #[wasm_bindgen(js_name = require)]
    fn node_require(s: &str) -> NodeCrypto;

    #[derive(Clone, Debug)]
    type NodeCrypto;

    #[wasm_bindgen(method, js_name = randomFillSync, structural)]
    fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]);
}
<commit_msg>wasm-bindgen: Added support for Internet Explorer 11<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
compile_error!("This crate is only for the `wasm32-unknown-unknown` target");

use core::cell::RefCell;
use std::thread_local;

use wasm_bindgen::prelude::*;

use getrandom::{register_custom_getrandom, Error};

#[derive(Clone, Debug)]
enum RngSource {
    Node(NodeCrypto),
    Browser(BrowserCrypto),
}

// JsValues are always per-thread, so we initialize RngSource for each thread.
//   See: https://github.com/rustwasm/wasm-bindgen/pull/955
thread_local!(
    static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);

register_custom_getrandom!(getrandom_inner);

fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
    RNG_SOURCE.with(|f| {
        let mut source = f.borrow_mut();
        if source.is_none() {
            *source = Some(getrandom_init()?);
        }

        match source.as_ref().unwrap() {
            RngSource::Node(n) => n.random_fill_sync(dest),
            RngSource::Browser(n) => {
                // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
                //
                // where it says:
                //
                // > A QuotaExceededError DOMException is thrown if the
                // > requested length is greater than 65536 bytes.
                for chunk in dest.chunks_mut(65536) {
                    n.get_random_values(chunk)
                }
            }
        };
        Ok(())
    })
}

fn getrandom_init() -> Result<RngSource, Error> {
    if let Ok(self_) = Global::get_self() {
        // If `self` is defined then we're in a browser somehow (main window
        // or web worker). We get `self.crypto` (called `msCrypto` on IE), so we
        // can call `crypto.getRandomValues`. If `crypto` isn't defined, we
        // assume we're in an older web browser and the OS RNG isn't available.

        let crypto: BrowserCrypto = match (self_.crypto(), self_.ms_crypto()) {
            (crypto, _) if !crypto.is_undefined() => crypto.into(),
            (_, crypto) if !crypto.is_undefined() => crypto.into(),
            _ => return Err(Error::BINDGEN_CRYPTO_UNDEF),
        };

        // Test if `crypto.getRandomValues` is undefined as well
        if crypto.get_random_values_fn().is_undefined() {
            return Err(Error::BINDGEN_GRV_UNDEF);
        }

        return Ok(RngSource::Browser(crypto));
    }

    return Ok(RngSource::Node(node_require("crypto")));
}

#[wasm_bindgen]
extern "C" {
    type Global;
    #[wasm_bindgen(getter, catch, static_method_of = Global, js_class = self, js_name = self)]
    fn get_self() -> Result<Self_, JsValue>;

    type Self_;
    #[wasm_bindgen(method, getter, js_name = "msCrypto", structural)]
    fn ms_crypto(me: &Self_) -> JsValue;
    #[wasm_bindgen(method, getter, structural)]
    fn crypto(me: &Self_) -> JsValue;

    #[derive(Clone, Debug)]
    type BrowserCrypto;

    // TODO: these `structural` annotations here ideally wouldn't be here to
    // avoid a JS shim, but for now with feature detection they're
    // unavoidable.
    #[wasm_bindgen(method, js_name = getRandomValues, structural, getter)]
    fn get_random_values_fn(me: &BrowserCrypto) -> JsValue;
    #[wasm_bindgen(method, js_name = getRandomValues, structural)]
    fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]);

    #[wasm_bindgen(js_name = require)]
    fn node_require(s: &str) -> NodeCrypto;

    #[derive(Clone, Debug)]
    type NodeCrypto;

    #[wasm_bindgen(method, js_name = randomFillSync, structural)]
    fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]);
}
<|endoftext|>


<commit_before>use std::thread;
use std::sync::{Arc, Mutex, MutexGuard};

use time::{self, Duration, Timespec};

use connection::{Event, Writer};
use message::Prefix;

#[derive(Clone)]
enum MonitorStatus {
    // Last activity, timespec is when.
    Activity(Timespec),
    // Ping was sent, timespec is when.
    Ping(Timespec),
}

#[derive(Clone)]
enum ConnectionStatus {
    // Connection is alive and well.
    Connected(MonitorStatus),
    // Connection was dropped.
    Disconnected,
    // When the monitor receives a close event, it sets the status
    // to this value to let the background thread know it should stop.
    Quit,
}

#[derive(Clone)]
struct State {
    // Holds the status of the connection.
    status: Arc<Mutex<ConnectionStatus>>,
    // When sending a ping message on irc, you need to specify the server.
    // This holds the current server's name, it's grabbed from the event
    // stream by the feed method.
    server: Arc<Mutex<Option<String>>>,
}

impl State {

    fn new(ts: Timespec) -> State {
        let conn_status = ConnectionStatus::Connected(MonitorStatus::Activity(ts));
        State {
            status: Arc::new(Mutex::new(conn_status)),
            server: Arc::new(Mutex::new(None)),
        }
    }

    // Set the last activity's timestamp.
    fn set_activity(&self, ts: Timespec) {
        *self.status.lock().unwrap() = ConnectionStatus::Connected(MonitorStatus::Activity(ts));
    }

    // Set the status to disconnected.
    fn set_disconnected(&self) {
        *self.status.lock().unwrap() = ConnectionStatus::Disconnected;
    }

    // Set the status to quit.
    fn quit(&self) {
        *self.status.lock().unwrap() = ConnectionStatus::Quit;
    }

    // Get the connection status.
    fn connection_status<'a>(&self) -> MutexGuard<ConnectionStatus> {
        self.status.lock().unwrap()
    }

    // Check if the server variable is set.
    fn has_server(&self) -> bool {
        self.server.lock().unwrap().is_some()
    }

    // Get the server's name.
    fn get_server(&self) -> MutexGuard<Option<String>> {
        self.server.lock().unwrap()
    }

    // Set the server's name.
    fn set_server(&self, name: String) {
        *self.server.lock().unwrap() = Some(name);
    }

    // Unsert the server name. Used when a disconnection occurs.
    fn unset_server(&self) {
        *self.server.lock().unwrap() = None;
    }

}

fn periodic_checker(state: State, handle: Writer, settings: MonitorSettings) {
    loop {
        let mut conn_status = state.connection_status();

        // Clone here, to we can mutate the status inside the match.
        // The type is Copy anyway.
        match conn_status.clone() {
            ConnectionStatus::Connected(ref mon_status) => {
                match *mon_status {
                    // The monitor is in activity mode.
                    // If the timer expires, it will ping the server and set the monitor status
                    // to ping mode.
                    MonitorStatus::Activity(activity_ts) => {
                        let diff = time::get_time() - activity_ts;
                        if diff > settings.activity_timeout {
                            // Make sure we have a server name.
                            match *state.get_server() {
                                Some(ref server) =>  {
                                    // Set the monitor's status to ping mode.
                                    *conn_status = ConnectionStatus::Connected(MonitorStatus::Ping(time::get_time()));
                                    // Send a ping, which should trigger activity is the connection is still alive.
                                    let _ = handle.ping(server);
                                }
                                None => {
                                    // This should really never happen. The server's name should be grabbed
                                    // almost instantly, when the first message is received from the server
                                    // after establishing a new connection.
                                    panic!("Server is None! This scenario is highly unlikely, please report this issue!");
                                }
                            }

                        }
                    }
                    // The monitor is in ping mode, which means it expects a ping response anytime.
                    // If the timer expires, the connection is set to disconnect mode.
                    MonitorStatus::Ping(ping_ts) => {
                        let diff = time::get_time() - ping_ts;
                        if diff > settings.ping_timeout {
                            // trigger reconnection process
                            let _ = handle.disconnect();
                        }
                    },
                }
            },
            // Do nothing if the socket is disconnected, for now.
            ConnectionStatus::Disconnected => {},
            ConnectionStatus::Quit => break,
        }

        // Drop the lock to avoid a dead lock.
        drop(conn_status);
        thread::sleep_ms(1000);
    }
}

/// These settings tell the monitor how to behave.
///
/// They allow you to configure the amount of time between the steps.
#[derive(Copy, Clone)]
pub struct MonitorSettings {
    /// Amount of time since the last activity.
    ///
    /// When the amount of time since the last activity gets higher than this value,
    /// tt will trigger a ping request. If there is not a lot of activity, this means
    /// that the server will be pinged everytime this duration expires.
    pub activity_timeout: Duration,
    /// Amount of time to wait for a ping reply.
    ///
    /// When the amount of time since the ping was sent gets higher than this value,
    /// and that no activity occured, assume the connection was dropped and trigger
    /// and a disconnect.
    pub ping_timeout: Duration,
}

/// Default values are provided for the settings.
///
/// They are:
///
/// `activity_timeout` = 60 seconds
///
/// `ping_timeout` = 15 seconds
impl Default for MonitorSettings {

    fn default() -> MonitorSettings {
        MonitorSettings {
            activity_timeout: Duration::seconds(60),
            ping_timeout: Duration::seconds(15),
        }
    }

}

/// This struct monitors a connection's activity.
///
/// It works in a few simple, steps.
/// First, it monitors activity via the feed method, saving a timestamp for relevant events.
/// If no activity is detected over the given period of time, it will send a ping request to
/// the IRC server. If no ping  reply is received, it will trigger a disconnect which may lead
/// to reconnection depending on the reconnection settings.
///
/// The amount of time to wait, without activity, before sending a ping request, and the amount
/// of time to wait for the ping reply can be configured via the `MonitorSettings` struct.
pub struct ActivityMonitor {
    state: State,
}

impl ActivityMonitor {

    /// Create a new ActivityMonitor.
    ///
    /// The handle to a Writer allows the monitor to notify the connection of disconnects.
    pub fn new(handle: &Writer, settings: MonitorSettings) -> ActivityMonitor {
        let state =  State::new(time::get_time());

        let state_clone = state.clone();
        let handle_clone = handle.clone();

        thread::spawn(move || {
            periodic_checker(state_clone, handle_clone, settings);
        });

        ActivityMonitor {
            state: state,
        }
    }

    /// Give an event received from the connection to the monitor.
    ///
    /// The monitor will process it accordingly. It an Event::Closed event
    /// is received, it will shutdown all of its activities.
    pub fn feed(&self, event: &Event) {
        match *event {
            Event::Closed(_) => {
                self.state.quit();
            }
            Event::Disconnected => {
                self.state.set_disconnected();
                self.state.unset_server();
            }
            Event::Reconnected => {
                self.state.set_activity(time::get_time());
            }
            Event::Message(ref msg) => {
                self.state.set_activity(time::get_time());
                if let Some(ref prefix) = msg.prefix {
                    match *prefix {
                        Prefix::Server(ref name) => {
                            if !self.state.has_server() {
                                self.state.set_server(name.clone());
                            }
                        }
                        _ => {}
                    }
                }
            }
            // Other events are irrelevant.
            _ => {}
        }
    }

}

/// Drop stops the background thread and clears the monitor's resources.
///
/// If you can the activity monitor to cease its activites, you can simply drop it.
/// It will not affect the connection on which the activity monitor operates.
impl Drop for ActivityMonitor {

    fn drop(&mut self) {
        self.state.quit();
    }

}
<commit_msg>Fix typos in the activity monitor's documentation<commit_after>use std::thread;
use std::sync::{Arc, Mutex, MutexGuard};

use time::{self, Duration, Timespec};

use connection::{Event, Writer};
use message::Prefix;

#[derive(Clone)]
enum MonitorStatus {
    // Last activity, timespec is when.
    Activity(Timespec),
    // Ping was sent, timespec is when.
    Ping(Timespec),
}

#[derive(Clone)]
enum ConnectionStatus {
    // Connection is alive and well.
    Connected(MonitorStatus),
    // Connection was dropped.
    Disconnected,
    // When the monitor receives a close event, it sets the status
    // to this value to let the background thread know it should stop.
    Quit,
}

#[derive(Clone)]
struct State {
    // Holds the status of the connection.
    status: Arc<Mutex<ConnectionStatus>>,
    // When sending a ping message on irc, you need to specify the server.
    // This holds the current server's name, it's grabbed from the event
    // stream by the feed method.
    server: Arc<Mutex<Option<String>>>,
}

impl State {

    fn new(ts: Timespec) -> State {
        let conn_status = ConnectionStatus::Connected(MonitorStatus::Activity(ts));
        State {
            status: Arc::new(Mutex::new(conn_status)),
            server: Arc::new(Mutex::new(None)),
        }
    }

    // Set the last activity's timestamp.
    fn set_activity(&self, ts: Timespec) {
        *self.status.lock().unwrap() = ConnectionStatus::Connected(MonitorStatus::Activity(ts));
    }

    // Set the status to disconnected.
    fn set_disconnected(&self) {
        *self.status.lock().unwrap() = ConnectionStatus::Disconnected;
    }

    // Set the status to quit.
    fn quit(&self) {
        *self.status.lock().unwrap() = ConnectionStatus::Quit;
    }

    // Get the connection status.
    fn connection_status<'a>(&self) -> MutexGuard<ConnectionStatus> {
        self.status.lock().unwrap()
    }

    // Check if the server variable is set.
    fn has_server(&self) -> bool {
        self.server.lock().unwrap().is_some()
    }

    // Get the server's name.
    fn get_server(&self) -> MutexGuard<Option<String>> {
        self.server.lock().unwrap()
    }

    // Set the server's name.
    fn set_server(&self, name: String) {
        *self.server.lock().unwrap() = Some(name);
    }

    // Unsert the server name. Used when a disconnection occurs.
    fn unset_server(&self) {
        *self.server.lock().unwrap() = None;
    }

}

fn periodic_checker(state: State, handle: Writer, settings: MonitorSettings) {
    loop {
        let mut conn_status = state.connection_status();

        // Clone here, to we can mutate the status inside the match.
        // The type is Copy anyway.
        match conn_status.clone() {
            ConnectionStatus::Connected(ref mon_status) => {
                match *mon_status {
                    // The monitor is in activity mode.
                    // If the timer expires, it will ping the server and set the monitor status
                    // to ping mode.
                    MonitorStatus::Activity(activity_ts) => {
                        let diff = time::get_time() - activity_ts;
                        if diff > settings.activity_timeout {
                            // Make sure we have a server name.
                            match *state.get_server() {
                                Some(ref server) =>  {
                                    // Set the monitor's status to ping mode.
                                    *conn_status = ConnectionStatus::Connected(MonitorStatus::Ping(time::get_time()));
                                    // Send a ping, which should trigger activity is the connection is still alive.
                                    let _ = handle.ping(server);
                                }
                                None => {
                                    // This should really never happen. The server's name should be grabbed
                                    // almost instantly, when the first message is received from the server
                                    // after establishing a new connection.
                                    panic!("Server is None! This scenario is highly unlikely, please report this issue!");
                                }
                            }

                        }
                    }
                    // The monitor is in ping mode, which means it expects a ping response anytime.
                    // If the timer expires, the connection is set to disconnect mode.
                    MonitorStatus::Ping(ping_ts) => {
                        let diff = time::get_time() - ping_ts;
                        if diff > settings.ping_timeout {
                            // trigger reconnection process
                            let _ = handle.disconnect();
                        }
                    },
                }
            },
            // Do nothing if the socket is disconnected, for now.
            ConnectionStatus::Disconnected => {},
            ConnectionStatus::Quit => break,
        }

        // Drop the lock to avoid a dead lock.
        drop(conn_status);
        thread::sleep_ms(1000);
    }
}

/// These settings tell the monitor how to behave.
///
/// They allow you to configure the amount of time between the steps.
#[derive(Copy, Clone)]
pub struct MonitorSettings {
    /// Amount of time since the last activity.
    ///
    /// When the amount of time since the last activity gets higher than this value,
    /// tt will trigger a ping request. If there is not a lot of activity, this means
    /// that the server will be pinged everytime this duration expires.
    pub activity_timeout: Duration,
    /// Amount of time to wait for a ping reply.
    ///
    /// When the amount of time since the ping was sent gets higher than this value,
    /// and that no activity occured, assume the connection was dropped and trigger
    /// and a disconnect.
    pub ping_timeout: Duration,
}

/// Default values are provided for the settings.
///
/// They are:
///
/// `activity_timeout` = 60 seconds
///
/// `ping_timeout` = 15 seconds
impl Default for MonitorSettings {

    fn default() -> MonitorSettings {
        MonitorSettings {
            activity_timeout: Duration::seconds(60),
            ping_timeout: Duration::seconds(15),
        }
    }

}

/// This struct monitors a connection's activity.
///
/// It works in a few simple, steps.
/// First, it monitors activity via the feed method, saving a timestamp for relevant events.
/// If no activity is detected over the given period of time, it will send a ping request to
/// the IRC server. If no ping  reply is received, it will trigger a disconnect which may lead
/// to reconnection depending on the reconnection settings.
///
/// The amount of time to wait, without activity, before sending a ping request, and the amount
/// of time to wait for the ping reply can be configured via the `MonitorSettings` struct.
pub struct ActivityMonitor {
    state: State,
}

impl ActivityMonitor {

    /// Create a new ActivityMonitor.
    ///
    /// The handle to a Writer allows the monitor to notify the connection of disconnects.
    pub fn new(handle: &Writer, settings: MonitorSettings) -> ActivityMonitor {
        let state =  State::new(time::get_time());

        let state_clone = state.clone();
        let handle_clone = handle.clone();

        thread::spawn(move || {
            periodic_checker(state_clone, handle_clone, settings);
        });

        ActivityMonitor {
            state: state,
        }
    }

    /// Give an event received from the connection to the monitor.
    ///
    /// The monitor will process it accordingly. If an Event::Closed event
    /// is received, it will shutdown all of its activities.
    pub fn feed(&self, event: &Event) {
        match *event {
            Event::Closed(_) => {
                self.state.quit();
            }
            Event::Disconnected => {
                self.state.set_disconnected();
                self.state.unset_server();
            }
            Event::Reconnected => {
                self.state.set_activity(time::get_time());
            }
            Event::Message(ref msg) => {
                self.state.set_activity(time::get_time());
                if let Some(ref prefix) = msg.prefix {
                    match *prefix {
                        Prefix::Server(ref name) => {
                            if !self.state.has_server() {
                                self.state.set_server(name.clone());
                            }
                        }
                        _ => {}
                    }
                }
            }
            // Other events are irrelevant.
            _ => {}
        }
    }

}

/// Drop stops the background thread and clears the monitor's resources.
///
/// If you want the activity monitor to cease its activites, you can simply drop it.
/// It will not affect the connection on which the activity monitor operates.
impl Drop for ActivityMonitor {

    fn drop(&mut self) {
        self.state.quit();
    }

}
<|endoftext|>


<commit_before>#[macro_use]
extern crate rustful;

use std::sync::RwLock;
use std::borrow::ToOwned;
use std::error::Error;

use rustful::{Server, TreeRouter, Context, Response, Log, Handler};
use rustful::plugin::{PluginContext, ResponseAction, ContextPlugin, ResponsePlugin};
use rustful::plugin::ContextAction::{self, Continue};
use rustful::response::ResponseData;
use rustful::Method::Get;
use rustful::StatusCode;
use rustful::header::Headers;

fn say_hello(context: Context, response: Response) {
    let person = match context.variables.get(&"person".to_owned()) {
        Some(name) => &name[..],
        None => "stranger"
    };

    if let Err(e) = response.into_writer().send(format!("{{\"message\": \"Hello, {}!\"}}", person))  {
        //There is not much we can do now
        context.log.note(&format!("could not send hello: {}", e.description()));
    }
}

//Dodge an ICE, related to functions as handlers.
struct HandlerFn(fn(Context, Response));

impl Handler for HandlerFn {
    fn handle_request(&self, context: Context, response: Response) {
        self.0(context, response);
    }
}

fn main() {
    println!("Visit http://localhost:8080 or http://localhost:8080/Peter (if your name is Peter) to try this example.");

    let mut router = TreeRouter::new();
    insert_routes!{
        &mut router => {
            "print" => {
                "/" => Get: HandlerFn(say_hello),
                ":person" => Get: HandlerFn(say_hello)
            }
        }
    };

    let server_result = Server::new()
           .handlers(router)
           .port(8080)

            //Log path, change path, log again
           .with_context_plugin(RequestLogger::new())
           .with_context_plugin(PathPrefix::new("print"))
           .with_context_plugin(RequestLogger::new())

           .with_response_plugin(Jsonp::new("setMessage"))

           .run();

    match server_result {
        Ok(_server) => {},
        Err(e) => println!("could not start server: {}", e.description())
    }
}

struct RequestLogger {
    counter: RwLock<u32>
}

impl RequestLogger {
    pub fn new() -> RequestLogger {
        RequestLogger {
            counter: RwLock::new(0)
        }
    }
}

impl ContextPlugin for RequestLogger {
    ///Count requests and log the path.
    fn modify(&self, ctx: PluginContext, context: &mut Context) -> ContextAction {
        *self.counter.write().unwrap() += 1;
        ctx.log.note(&format!("Request #{} is to '{}'", *self.counter.read().unwrap(), context.path));
        Continue
    }
}

struct PathPrefix {
    prefix: &'static str
}

impl PathPrefix {
    pub fn new(prefix: &'static str) -> PathPrefix {
        PathPrefix {
            prefix: prefix
        }
    }
}

impl ContextPlugin for PathPrefix {
    ///Append the prefix to the path
    fn modify(&self, _ctx: PluginContext, context: &mut Context) -> ContextAction {
        context.path = format!("/{}{}", self.prefix.trim_matches('/'), context.path);
        Continue
    }
}

struct Jsonp {
    function: &'static str
}

impl Jsonp {
    pub fn new(function: &'static str) -> Jsonp {
        Jsonp {
            function: function
        }
    }
}

impl ResponsePlugin for Jsonp {
    fn begin(&self, _ctx: PluginContext, status: StatusCode, headers: Headers) -> (StatusCode, Headers, ResponseAction) {
        let action = ResponseAction::write(Some(format!("{}(", self.function)));
        (status, headers, action)
    }

    fn write<'a>(&'a self, _ctx: PluginContext, bytes: Option<ResponseData<'a>>) -> ResponseAction {
        ResponseAction::write(bytes)
    }

    fn end(&self, _ctx: PluginContext) -> ResponseAction {
        ResponseAction::write(Some(");"))
    }
}<commit_msg>Update plugins example to use plugin storage<commit_after>#[macro_use]
extern crate rustful;

use std::sync::RwLock;
use std::error::Error;

use rustful::{Server, TreeRouter, Context, Response, Log, Handler};
use rustful::plugin::{PluginContext, ResponseAction, ContextPlugin, ResponsePlugin};
use rustful::plugin::ContextAction::{self, Continue};
use rustful::response::ResponseData;
use rustful::Method::Get;
use rustful::StatusCode;
use rustful::header::Headers;

fn say_hello(mut context: Context, mut response: Response) {
    //Take the name of the JSONP function from the query variables
    if let Some(jsonp_name) = context.query.remove("jsonp") {
        response.plugin_storage().insert(JsonpFn(jsonp_name));
    }

    let person = match context.variables.get("person") {
        Some(name) => &name[..],
        None => "stranger"
    };

    if let Err(e) = response.into_writer().send(format!("{{\"message\": \"Hello, {}!\"}}", person))  {
        //There is not much we can do now
        context.log.note(&format!("could not send hello: {}", e.description()));
    }
}

//Dodge an ICE, related to functions as handlers.
struct HandlerFn(fn(Context, Response));

impl Handler for HandlerFn {
    fn handle_request(&self, context: Context, response: Response) {
        self.0(context, response);
    }
}

fn main() {
    println!("Visit http://localhost:8080 or http://localhost:8080/Peter (if your name is Peter) to try this example.");
    println!("Append ?jsonp=someFunction to get a JSONP response.");

    let mut router = TreeRouter::new();
    insert_routes!{
        &mut router => {
            "print" => {
                "/" => Get: HandlerFn(say_hello),
                ":person" => Get: HandlerFn(say_hello)
            }
        }
    };

    let server_result = Server::new()
           .handlers(router)
           .port(8080)

            //Log path, change path, log again
           .with_context_plugin(RequestLogger::new())
           .with_context_plugin(PathPrefix::new("print"))
           .with_context_plugin(RequestLogger::new())

           .with_response_plugin(Jsonp)

           .run();

    match server_result {
        Ok(_server) => {},
        Err(e) => println!("could not start server: {}", e.description())
    }
}

struct RequestLogger {
    counter: RwLock<u32>
}

impl RequestLogger {
    pub fn new() -> RequestLogger {
        RequestLogger {
            counter: RwLock::new(0)
        }
    }
}

impl ContextPlugin for RequestLogger {
    ///Count requests and log the path.
    fn modify(&self, ctx: PluginContext, context: &mut Context) -> ContextAction {
        *self.counter.write().unwrap() += 1;
        ctx.log.note(&format!("Request #{} is to '{}'", *self.counter.read().unwrap(), context.path));
        Continue
    }
}

struct PathPrefix {
    prefix: &'static str
}

impl PathPrefix {
    pub fn new(prefix: &'static str) -> PathPrefix {
        PathPrefix {
            prefix: prefix
        }
    }
}

impl ContextPlugin for PathPrefix {
    ///Append the prefix to the path
    fn modify(&self, _ctx: PluginContext, context: &mut Context) -> ContextAction {
        context.path = format!("/{}{}", self.prefix.trim_matches('/'), context.path);
        Continue
    }
}

struct JsonpFn(String);

struct Jsonp;

impl ResponsePlugin for Jsonp {
    fn begin(&self, ctx: PluginContext, status: StatusCode, headers: Headers) -> (StatusCode, Headers, ResponseAction) {
        //Check if a JSONP function is defined and write the beginning of the call
        let output = if let Some(&JsonpFn(ref function)) = ctx.storage.get() {
            Some(format!("{}(", function))
        } else {
            None
        };

        (status, headers, ResponseAction::write(output))
    }

    fn write<'a>(&'a self, _ctx: PluginContext, bytes: Option<ResponseData<'a>>) -> ResponseAction {
        ResponseAction::write(bytes)
    }

    fn end(&self, ctx: PluginContext) -> ResponseAction {
        //Check if a JSONP function is defined and write the end of the call
        let output = ctx.storage.get::<JsonpFn>().map(|_| ");");
        ResponseAction::write(output)
    }
}<|endoftext|>


<commit_before>extern crate orbtk;

use orbtk::{Action, Button, Grid, Label, Menu, Point, ProgressBar, Rect, Separator, TextBox, Window};
use orbtk::traits::{Border, Click, Enter, Place, Text};

fn main() {
    let window = Window::new(Rect::new(100, 100, 420, 720), "OrbTK");

    let x = 10;
    let mut y = 0;

    let menu = Menu::new("Menu");
    menu.position(x, y)
        .size(32, 16);

    y += menu.rect.get().height as i32 + 10;

    let label = Label::new();
    label.position(x, y)
        .size(400, 16)
        .text("Test Label");
    window.add(&label);

    y += label.rect.get().height as i32 + 10;

    let text_box = TextBox::new();
    text_box.position(x, y)
        .size(342, 18)
        .text_offset(1, 1)
        .on_enter(move |text_box: &TextBox| {
            label.text.set(text_box.text.get());
        });
    window.add(&text_box);

    let button = Button::new();
    button.position(x + text_box.rect.get().width as i32 + 8, y)
        .size(48 + 2, text_box.rect.get().height)
        .text("Update")
        .text_offset(1, 1)
        .on_click(move |_button: &Button, _point: Point| {
            text_box.emit_enter();
        });
    window.add(&button);

    y += button.rect.get().height as i32 + 10;

    let progress_label = Label::new();
    progress_label.text("Progress: 0%")
        .position(x, y)
        .size(400, 16);
    window.add(&progress_label);

    y += progress_label.rect.get().height as i32 + 10;

    let progress_bar = ProgressBar::new();
    progress_bar.position(x, y)
        .size(400, 16)
        .on_click(move |progress_bar: &ProgressBar, point: Point| {
            let progress = point.x * 100 / progress_bar.rect.get().width as i32;
            progress_label.text.set(format!("Progress: {}%", progress));
            progress_bar.value.set(progress);
        });
    window.add(&progress_bar);

    y += progress_bar.rect.get().height as i32 + 10;

    let multi_line_label = Label::new();
    multi_line_label.text("Multi-Line Text")
        .position(x, y)
        .size(400, 16);
    window.add(&multi_line_label);

    y += multi_line_label.rect.get().height as i32 + 10;

    let multi_line_text_box = TextBox::new();
    multi_line_text_box.position(x, y)
        .size(400, 130)
        .text_offset(1, 1);
    window.add(&multi_line_text_box);

    y += multi_line_text_box.rect.get().height as i32 + 10;

    let offset_label = Label::new();
    offset_label.position(x, y)
        .size(400, 256)
        .border(true)
        .text("Test Offset")
        .text_offset(50, 50)
        .on_click(|label: &Label, _point: Point| {
            label.text("Clicked");
        });
    window.add(&offset_label);

    y += offset_label.rect.get().height as i32 + 10;

    {
        let action = Action::new("Label One");
        let offset_label_clone = offset_label.clone();
        action.on_click(move |_action: &Action, _point: Point| {
            offset_label_clone.text.set("One".to_owned());
        });
        menu.add(&action);
    }

    {
        let action = Action::new("Label Two");
        let offset_label_clone = offset_label.clone();
        action.on_click(move |_action: &Action, _point: Point| {
            offset_label_clone.text.set("Two".to_owned());
        });
        menu.add(&action);
    }

    menu.add(&Separator::new());

    {
        let action = Action::new("Reset Label");
        let offset_label_clone = offset_label.clone();
        action.on_click(move |_action: &Action, _point: Point| {
            offset_label_clone.text.set("Text Offset".to_owned());
        });
        menu.add(&action);
    }

    let grid = Grid::new();
    grid.position(x, y)
        .spacing(8, 8);

    let label = Label::new();
    label.size(32, 16).text("Grid");
    grid.add(0, 0, &label);

    let label = Label::new();
    label.size(32, 16).text("Test");
    grid.add(1, 0, &label);

    let mut i = 0;
    for row in 1..6 {
        for col in 0..5 {
            let cell = TextBox::new();
            let text = format!("{}: {}, {}", i, col, row);
            cell.size(text.len() as u32 * 8 + 2, 18).text(text).text_offset(1, 1);
            grid.add(col, row, &cell);
            i += 1;
        }
    }
    grid.arrange(true);

    window.add(&grid);

    // Add this last to put it on top
    window.add(&menu);

    window.exec();
}
<commit_msg>Add more headers<commit_after>extern crate orbtk;

use orbtk::{Action, Button, Grid, Label, Menu, Point, ProgressBar, Rect, Separator, TextBox, Window};
use orbtk::traits::{Border, Click, Enter, Place, Text};

fn main() {
    let window = Window::new(Rect::new(100, 100, 420, 720), "OrbTK");

    let x = 10;
    let mut y = 0;

    let menu = Menu::new("Menu");
    menu.position(x, y)
        .size(32, 16);

    y += menu.rect.get().height as i32 + 10;

    let label = Label::new();
    label.position(x, y)
        .size(400, 16)
        .text("Test Label");
    window.add(&label);

    y += label.rect.get().height as i32 + 10;

    let text_box = TextBox::new();
    text_box.position(x, y)
        .size(342, 18)
        .text_offset(1, 1)
        .on_enter(move |text_box: &TextBox| {
            label.text.set(text_box.text.get());
        });
    window.add(&text_box);

    let button = Button::new();
    button.position(x + text_box.rect.get().width as i32 + 8, y)
        .size(48 + 2, text_box.rect.get().height)
        .text("Update")
        .text_offset(1, 1)
        .on_click(move |_button: &Button, _point: Point| {
            text_box.emit_enter();
        });
    window.add(&button);

    y += button.rect.get().height as i32 + 10;

    let progress_label = Label::new();
    progress_label.text("Progress: 0%")
        .position(x, y)
        .size(400, 16);
    window.add(&progress_label);

    y += progress_label.rect.get().height as i32 + 10;

    let progress_bar = ProgressBar::new();
    progress_bar.position(x, y)
        .size(400, 16)
        .on_click(move |progress_bar: &ProgressBar, point: Point| {
            let progress = point.x * 100 / progress_bar.rect.get().width as i32;
            progress_label.text.set(format!("Progress: {}%", progress));
            progress_bar.value.set(progress);
        });
    window.add(&progress_bar);

    y += progress_bar.rect.get().height as i32 + 10;

    let multi_line_label = Label::new();
    multi_line_label.text("Multi-Line Text")
        .position(x, y)
        .size(400, 16);
    window.add(&multi_line_label);

    y += multi_line_label.rect.get().height as i32 + 10;

    let multi_line_text_box = TextBox::new();
    multi_line_text_box.position(x, y)
        .size(400, 130)
        .text_offset(1, 1);
    window.add(&multi_line_text_box);

    y += multi_line_text_box.rect.get().height as i32 + 10;

    let offset_label = Label::new();
    offset_label.position(x, y)
        .size(400, 256)
        .border(true)
        .text("Test Offset")
        .text_offset(50, 50)
        .on_click(|label: &Label, _point: Point| {
            label.text("Clicked");
        });
    window.add(&offset_label);

    y += offset_label.rect.get().height as i32 + 10;

    {
        let action = Action::new("Label One");
        let offset_label_clone = offset_label.clone();
        action.on_click(move |_action: &Action, _point: Point| {
            offset_label_clone.text.set("One".to_owned());
        });
        menu.add(&action);
    }

    {
        let action = Action::new("Label Two");
        let offset_label_clone = offset_label.clone();
        action.on_click(move |_action: &Action, _point: Point| {
            offset_label_clone.text.set("Two".to_owned());
        });
        menu.add(&action);
    }

    menu.add(&Separator::new());

    {
        let action = Action::new("Reset Label");
        let offset_label_clone = offset_label.clone();
        action.on_click(move |_action: &Action, _point: Point| {
            offset_label_clone.text.set("Text Offset".to_owned());
        });
        menu.add(&action);
    }

    let grid = Grid::new();
    grid.position(x, y)
        .spacing(8, 8);

    let label = Label::new();
    label.size(32, 16).text("Grid");
    grid.add(0, 0, &label);

    let label = Label::new();
    label.size(32, 16).text("Test");
    grid.add(1, 0, &label);

    let label = Label::new();
    label.size(32, 16).text("With");
    grid.add(2, 0, &label);

    let label = Label::new();
    label.size(48, 16).text("Resize");
    grid.add(3, 0, &label);

    let mut i = 0;
    for row in 1..6 {
        for col in 0..5 {
            let cell = TextBox::new();
            let text = format!("{}: {}, {}", i, col, row);
            cell.size(text.len() as u32 * 8 + 2, 18).text(text).text_offset(1, 1);
            grid.add(col, row, &cell);
            i += 1;
        }
    }
    grid.arrange(true);

    window.add(&grid);

    // Add this last to put it on top
    window.add(&menu);

    window.exec();
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::error;

use super::row::{Row, RowError};
use super::schema::{Schema, Type};
use super::field::Field;

pub enum StreamError {
    ValidationError(String),
    FieldNotFound(String),
    MissingRowId
}

impl From<RowError> for StreamError {
    fn from(err: RowError) -> StreamError {
        StreamError::MissingRowId
    }

}

pub struct Stream {
    max_id: u64,
    rows: Vec<Row>,
    schema: Schema,
}

/**
This is a weird DB.  There's no primary key, since everything is based off append only streaming

*/
impl Stream {
    pub fn new() -> Stream {
        let mut stream = Stream {
            max_id: 0,
            rows: Vec::new(),
            schema: Schema::new(),
        };
        stream.schema.add_type("_id", Type::Int);
        stream.schema.add_type("_created", Type::Timestamp);
        stream
    }

    /* we take a HashMap of String -> Field here
    * we're going to convert it to HashMap<u8, Field> for the Row struct
    */
    pub fn insert(&mut self, data: &mut HashMap<String, Field>) -> Result<Row, StreamError> {
        // validate the inserted data
        let mut row_map : HashMap<u8, Field> = HashMap::new();
        for (key, val) in data.drain() {
            // get the field from the schema
            // TypeDef
            let tmp = try!(self.schema.get(&key)
                                      .ok_or(StreamError::FieldNotFound(key.to_string())));
            row_map.insert(tmp.id, val);

        }
        let row = try!(Row::new(row_map));
        Ok(row)
    }
}

#[cfg(tests)]
mod tests {

}<commit_msg>moving the row data in instead of by ref<commit_after>use std::collections::HashMap;
use std::error;

use super::row::{Row, RowError};
use super::schema::{Schema, Type};
use super::field::Field;

pub enum StreamError {
    ValidationError(String),
    FieldNotFound(String),
    MissingRowId
}

impl From<RowError> for StreamError {
    fn from(err: RowError) -> StreamError {
        StreamError::MissingRowId
    }

}

pub struct Stream {
    max_id: u64,
    rows: Vec<Row>,
    schema: Schema,
}

/**
This is a weird DB.  There's no primary key, since everything is based off append only streaming

*/
impl Stream {
    pub fn new() -> Stream {
        let mut stream = Stream {
            max_id: 0,
            rows: Vec::new(),
            schema: Schema::new(),
        };
        stream.schema.add_type("_id", Type::Int);
        stream.schema.add_type("_created", Type::Timestamp);
        stream
    }

    /* we take a HashMap of String -> Field here
    * we're going to convert it to HashMap<u8, Field> for the Row struct
    */
    pub fn insert(&mut self, mut data: HashMap<String, Field>) -> Result<Row, StreamError> {
        // validate the inserted data
        let mut row_map : HashMap<u8, Field> = HashMap::new();
        for (key, val) in data.drain() {
            // get the field from the schema
            // TypeDef
            let tmp = try!(self.schema.get(&key)
                                      .ok_or(StreamError::FieldNotFound(key.to_string())));
            row_map.insert(tmp.id, val);

        }
        let row = try!(Row::new(row_map));
        Ok(row)
    }

}

#[cfg(test)]
mod tests {
    use super::Stream;
    use super::super::schema::{Schema, Type};
    use super::super::field::Field;
    use std::collections::HashMap;

    #[test]
    fn test_insert_works_normal_case() {
        let mut s = Stream::new();
        s.schema.add_type("name", Type::String);
        let mut row = HashMap::new();
        row.insert("name".to_string(), Field::String("Jon".to_string()));
        let result = s.insert(row);

    }
}<|endoftext|>


<commit_before>extern crate getopts;
extern crate libc;
extern crate regex;
extern crate itertools;

use getopts::Options;
use regex::Regex;
use std::boxed::Box;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::fs::File;
use std::io::{Read,Write,BufReader,BufRead,BufWriter,Error};
use std::process::exit;
use itertools::Itertools;

//use std::panic;

static RS_REGEX : &'static str = "^$|^(=====*|-----*)$";
static RS_TIMESTAMP : &'static str = concat!(
    "^(",
    "((Mon|Tue|Wed|Thu|Fri|Sat),?[ \t]+)?",  // Day of Week
    "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Dec),?[ \t]", // Months
    "[0-9]{1,2},?", // Date
    "[ \t]",
    "[0-2][0-9]:[0-5][0-9](:[0-5][0-9])?", // Time
    "(,?[ \t]20[0-9][0-9])?", //Year
    "|", "20[0-9][0-9]-(0[0-9]|11|12)-(0[1-9]|[12][0-9]|3[01])", // ISO date
    ")"
);

fn define_opts() -> getopts::Options {
    let mut opts = Options::new();
    opts.optflag("a", "and",    "Extract records with all of patterns.");
    opts.optflag("h", "help",   "print this help.");
    opts.optopt( "r", "rs", format!("Input record separator. default: /{}/", RS_REGEX).as_str(), "RS_REGEX");
    opts.optflag("t","timestamp",   "Same as --rs=TIMESTAMP_REGEX, where the regex matches\n\
                                     timestamps often used in log files, e.g., '2014-12-31\n\
                                     12:34:56' or 'Dec 31 12:34:56'.");
    opts.optflag("i","ignore-case", "Case insensitive matching.");
    opts.optflag("c","count",   "Print number of matches. (same as grep -c)");
    //opts.optflag("v","invert",  "Select non-matching records. (same as grep -v)");
    //opts.optflag("", "color",   "Highlight matches. Auto-enabled iff stdout is a TTY.");
    //opts.optflag("", "hl",      "Same as --color.");
    //opts.optflag("m","mono",    "Do not Highlight matches.");
    opts.optflag("d","debug",   "Enable debug.");

    return opts;
}

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

/* FIXME: should use */
fn log(header: &str, msg: &str) {
    match writeln!(&mut std::io::stderr(), "{}: {}", header, msg) {
        Ok(_) => (),
        Err(e) => { panic!("Failed writing to stderr: {}", e) }
    };
}
fn warn(msg: &str)  { log("WARNING", msg); }
//fn debug(msg: &str) { log("DEBUG", msg); }
//fn error(msg: &str) { log("ERROR", msg); } /* FIXME: */

/***********************************************************************/

fn fputs(bw:&mut BufWriter<Box<Write>>, s:&str) -> Result<(), Error>{
     bw.write_all(s.as_bytes());
     bw.write_all("\n".as_bytes())
}

fn re_to_plain_string(s:&str) -> Result<String, ()> {
    let regex_chars      = r"^$(|)[]{}.*\";
    let regex_ctrl_chars = r"nt";
    let mut to_ctrl_char = HashMap::new();
    to_ctrl_char.insert('n', '\n');
    to_ctrl_char.insert('t', '\t');

    let mut escaped = String::new();

    let mut i = s.chars().peekable();
    loop {
        if let Some(c) = i.next() {
            if c == '\\' {
                match i.next() {
                    None => { escaped.push(c) }
                    Some(nc) => {
                        if regex_ctrl_chars.contains(nc) {
                            escaped.push(*(to_ctrl_char.get(&nc).unwrap()));
                        } else if regex_chars.contains(nc) {
                            escaped.push(nc);
                        } else {
                            return Err(());
                        }
                    }
                }
            } else if regex_chars.contains(c) {
                return Err(());
            } else {
                escaped.push(c);
            }
        } else {
            break;
        }
    }
    return Ok(escaped);
}

fn mlrgrep<M,G,R>(rs_matcher:M,
                  grep:G,
                  in_reader:Box<BufRead>,
                  mut reporter:R,
                  counter: &mut i32)
        -> Result<bool, Error>
    where M: Fn(&str) -> bool,
          G: Fn(&str) -> bool,
          R: FnMut(&str) -> Result<(),Error>
{
    let mut iter = in_reader.lines();
    let mut found = false;
    let mut matching = false;

    let mut rec : Vec<String> = Vec::new();
    while let Some(line) = iter.next() {
        if rs_matcher(line.as_ref().unwrap().as_str()) {
            matching = false;
            rec = Vec::new();
            if grep(line.as_ref().unwrap().as_str()) {
                matching = true;
                found = true;
                *counter += 1;
                reporter(&line.unwrap());
            } else {
                rec.push( line.unwrap() );
            }
        } else if matching {
            reporter(&line.unwrap());
        } else if grep(line.as_ref().unwrap().as_str()) {
            matching = true;
            found = true;
            *counter += 1;
            for l in rec {
                reporter(&l);
            }
            rec = Vec::new();
            reporter(&line.unwrap());
        } else {
            rec.push(line.unwrap());
        }
    }

    return Ok(found);
}

fn do_grep(flags: getopts::Matches,
           patterns: Vec<String>,
           inputs: Vec<(String, Box<Read>)>,
           output: Box<Write>)
    -> Result<bool, Error>
{
    let rs = if flags.opt_present("timestamp") {
                 String::from(RS_TIMESTAMP)
             } else if let Some(rs) = flags.opt_str("rs") {
                 rs
             } else {
                 String::from(RS_REGEX)
             };

    let pat = &patterns[0].as_str();

    let ( rs_regex, pat ) =
        if flags.opt_present("ignore-case") {
            ( Regex::new( & (String::from("(?i)") + &rs)  ).unwrap(),
              Regex::new( & (String::from("(?i)") + &pat) ).unwrap() )
        } else {
            ( Regex::new(&rs).unwrap(),
              Regex::new(&pat).expect("Failed to compile pattern to regex") )
        };

    let mut buf_output = BufWriter::new(output);
    let mut rs_matcher = |line:&str| rs_regex.is_match(line);
    let mut grep       = |line:&str| pat.is_match(line);

    let fcount = inputs.len();
    let mut found = false;
    for (fname,reader) in inputs {
        let mut ireader = Box::new(BufReader::new(reader));
        let mut counter = 0i32;
        {
            let mut printer = |found:&str| {
                if flags.opt_present("count") {
                     Ok(())
                } else {
                     fputs(&mut buf_output, found)
                }};
            match mlrgrep(&rs_matcher, &grep, ireader, &mut printer, &mut counter)
            {
                Err(e) => { return Err(e) }
                Ok(ret) => { found = true }
            }
        }
        if flags.opt_present("count") {
            let count_str = if fcount > 1 {
                format!("{}:{}", fname, counter)
            } else {
                format!("{}", counter)
            };
            fputs(&mut buf_output, &count_str);
        }
    }

    return Ok(found);
}

/* Parse args into vec of patterns and filenames
 * A '/' or any valid (existing) filename will stop reading args as patterns
 */
fn parse_pattern_or_filename(args: Vec<String>)
    -> (Vec<String>, Vec<String>)
{
    let mut patterns = Vec::new();
    let mut filenames = Vec::new();

    let mut i = args.iter();
    for a in &mut i {
        if a == "/" {
            break;
        } else {
            match fs::metadata(a) {
                Ok(stat)  => {
                    if stat.is_dir() {
                        // ignore directory names.
                        patterns.push(a.clone());
                    } else {
                        filenames.push(a.clone()); break;
                    }
                }
                Err(_) => { patterns.push(a.clone()); }
            }
        }
    }
    for a in &mut i {
       filenames.push(a.clone());
    }
    return (patterns, filenames);
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let progname = args[0].clone();
    let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;

    /* Parse command-line options */
    let optdef  = define_opts();
    let opts = match optdef.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    if opts.opt_present("h") {
        print_usage(&progname , optdef);
        exit(0);
    }

    if opts.free.is_empty() {
        panic!("Too few arguments");
    }

    let (patterns, filenames) = parse_pattern_or_filename(opts.free.clone());
    if opts.opt_present("debug") {
        println!("DEBUG: patterns: {}", patterns.join(", "));
        println!("DEBUG: files:    {}", filenames.join(", "));
    }

    let inputs: Vec<(String, Box<Read>)>;
    if filenames.len() == 0 {
        inputs = vec![(String::from("-"), Box::new(std::io::stdin()))];
        if istty {
            warn("reading from terminal");
        }
    } else {
        inputs = filenames.iter().map( |fname| {
                    let reader = Box::new(File::open(fname).expect(fname));
                    (fname.clone(), reader as Box<Read>) }
                 ).collect();
    };

    match do_grep(opts, patterns, inputs, Box::new(std::io::stdout()) as Box<Write>) {
        Ok(ret) => {
            if ret {
                exit(0);
            } else {
                exit(1);
            }
        }
        Err(_) => exit(2)
    }
}

<commit_msg>rust - fix compiler warnings for latest rust compiler<commit_after>extern crate getopts;
extern crate libc;
extern crate regex;

use getopts::Options;
use regex::Regex;
use std::boxed::Box;
use std::env;
use std::fs;
use std::fs::File;
use std::io::{Read,Write,BufReader,BufRead,BufWriter,Error};
use std::process::exit;

//use std::panic;

static RS_REGEX : &'static str = "^$|^(=====*|-----*)$";
static RS_TIMESTAMP : &'static str = concat!(
    "^(",
    "((Mon|Tue|Wed|Thu|Fri|Sat),?[ \t]+)?",  // Day of Week
    "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Dec),?[ \t]", // Months
    "[0-9]{1,2},?", // Date
    "[ \t]",
    "[0-2][0-9]:[0-5][0-9](:[0-5][0-9])?", // Time
    "(,?[ \t]20[0-9][0-9])?", //Year
    "|", "20[0-9][0-9]-(0[0-9]|11|12)-(0[1-9]|[12][0-9]|3[01])", // ISO date
    ")"
);

fn define_opts() -> getopts::Options {
    let mut opts = Options::new();
    opts.optflag("a", "and",    "Extract records with all of patterns.");
    opts.optflag("h", "help",   "print this help.");
    opts.optopt( "r", "rs", format!("Input record separator. default: /{}/", RS_REGEX).as_str(), "RS_REGEX");
    opts.optflag("t","timestamp",   "Same as --rs=TIMESTAMP_REGEX, where the regex matches\n\
                                     timestamps often used in log files, e.g., '2014-12-31\n\
                                     12:34:56' or 'Dec 31 12:34:56'.");
    opts.optflag("i","ignore-case", "Case insensitive matching.");
    opts.optflag("c","count",   "Print number of matches. (same as grep -c)");
    //opts.optflag("v","invert",  "Select non-matching records. (same as grep -v)");
    //opts.optflag("", "color",   "Highlight matches. Auto-enabled iff stdout is a TTY.");
    //opts.optflag("", "hl",      "Same as --color.");
    //opts.optflag("m","mono",    "Do not Highlight matches.");
    opts.optflag("d","debug",   "Enable debug.");

    return opts;
}

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

/* FIXME: should use */
fn log(header: &str, msg: &str) {
    match writeln!(&mut std::io::stderr(), "{}: {}", header, msg) {
        Ok(_) => (),
        Err(e) => { panic!("Failed writing to stderr: {}", e) }
    };
}
fn warn(msg: &str)  { log("WARNING", msg); }
//fn debug(msg: &str) { log("DEBUG", msg); }
//fn error(msg: &str) { log("ERROR", msg); } /* FIXME: */

/***********************************************************************/

fn fputs(bw:&mut BufWriter<Box<Write>>, s:&str) -> Result<(), Error>{
     try!(bw.write_all(s.as_bytes()));
     try!(bw.write_all("\n".as_bytes()));
     Ok(())
}

fn mlrgrep<M,G,R>(rs_matcher:M,
                  grep:G,
                  in_reader:Box<BufRead>,
                  mut reporter:R,
                  counter: &mut i32)
        -> Result<bool, Error>
    where M: Fn(&str) -> bool,
          G: Fn(&str) -> bool,
          R: FnMut(&str) -> Result<(),Error>
{
    let mut iter = in_reader.lines();
    let mut found = false;
    let mut matching = false;

    let mut rec : Vec<String> = Vec::new();
    while let Some(line) = iter.next() {
        if rs_matcher(line.as_ref().unwrap().as_str()) {
            matching = false;
            rec = Vec::new();
            if grep(line.as_ref().unwrap().as_str()) {
                matching = true;
                found = true;
                *counter += 1;
                try!(reporter(&line.unwrap()));
            } else {
                rec.push( line.unwrap() );
            }
        } else if matching {
            try!(reporter(&line.unwrap()));
        } else if grep(line.as_ref().unwrap().as_str()) {
            matching = true;
            found = true;
            *counter += 1;
            for l in rec {
                try!(reporter(&l));
            }
            rec = Vec::new();
            try!(reporter(&line.unwrap()));
        } else {
            rec.push(line.unwrap());
        }
    }

    return Ok(found);
}

fn do_grep(flags: getopts::Matches,
           patterns: Vec<String>,
           inputs: Vec<(String, Box<Read>)>,
           output: Box<Write>)
    -> Result<bool, Error>
{
    let rs = if flags.opt_present("timestamp") {
                 String::from(RS_TIMESTAMP)
             } else if let Some(rs) = flags.opt_str("rs") {
                 rs
             } else {
                 String::from(RS_REGEX)
             };

    let pat = &patterns[0].as_str();

    let ( rs_regex, pat ) =
        if flags.opt_present("ignore-case") {
            ( Regex::new( & (String::from("(?i)") + &rs)  ).unwrap(),
              Regex::new( & (String::from("(?i)") + &pat) ).unwrap() )
        } else {
            ( Regex::new(&rs).unwrap(),
              Regex::new(&pat).expect("Failed to compile pattern to regex") )
        };

    let mut buf_output = BufWriter::new(output);
    let rs_matcher = |line:&str| rs_regex.is_match(line);
    let grep       = |line:&str| pat.is_match(line);

    let fcount = inputs.len();
    let mut found = false;
    for (fname,reader) in inputs {
        let mut ireader = Box::new(BufReader::new(reader));
        let mut counter = 0i32;
        {
            let mut printer = |found:&str| {
                if flags.opt_present("count") {
                     Ok(())
                } else {
                     fputs(&mut buf_output, found)
                }};
            match mlrgrep(&rs_matcher, &grep, ireader, &mut printer, &mut counter)
            {
                Err(e) => { return Err(e) }
                Ok(_ret) => { found = true }
            }
        }
        if flags.opt_present("count") {
            let count_str = if fcount > 1 {
                format!("{}:{}", fname, counter)
            } else {
                format!("{}", counter)
            };
            try!(fputs(&mut buf_output, &count_str));
        }
    }

    return Ok(found);
}

/* Parse args into vec of patterns and filenames
 * A '/' or any valid (existing) filename will stop reading args as patterns
 */
fn parse_pattern_or_filename(args: Vec<String>)
    -> (Vec<String>, Vec<String>)
{
    let mut patterns = Vec::new();
    let mut filenames = Vec::new();

    let mut i = args.iter();
    for a in &mut i {
        if a == "/" {
            break;
        } else {
            match fs::metadata(a) {
                Ok(stat)  => {
                    if stat.is_dir() {
                        // ignore directory names.
                        patterns.push(a.clone());
                    } else {
                        filenames.push(a.clone()); break;
                    }
                }
                Err(_) => { patterns.push(a.clone()); }
            }
        }
    }
    for a in &mut i {
       filenames.push(a.clone());
    }
    return (patterns, filenames);
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let progname = args[0].clone();
    let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;

    /* Parse command-line options */
    let optdef  = define_opts();
    let opts = match optdef.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    if opts.opt_present("h") {
        print_usage(&progname , optdef);
        exit(0);
    }

    if opts.free.is_empty() {
        panic!("Too few arguments");
    }

    let (patterns, filenames) = parse_pattern_or_filename(opts.free.clone());
    if opts.opt_present("debug") {
        println!("DEBUG: patterns: {}", patterns.join(", "));
        println!("DEBUG: files:    {}", filenames.join(", "));
    }

    let inputs: Vec<(String, Box<Read>)>;
    if filenames.len() == 0 {
        inputs = vec![(String::from("-"), Box::new(std::io::stdin()))];
        if istty {
            warn("reading from terminal");
        }
    } else {
        inputs = filenames.iter().map( |fname| {
                    let reader = Box::new(File::open(fname).expect(fname));
                    (fname.clone(), reader as Box<Read>) }
                 ).collect();
    };

    match do_grep(opts, patterns, inputs, Box::new(std::io::stdout()) as Box<Write>) {
        Ok(ret) => {
            if ret {
                exit(0);
            } else {
                exit(1);
            }
        }
        Err(_) => exit(2)
    }
}

<|endoftext|>


<commit_before>#![warn(rust_2018_idioms)] // while we're getting used to 2018
#![allow(clippy::all)]

use cargo::core::shell::Shell;
use cargo::util::toml::StringOrVec;
use cargo::util::CliError;
use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config};
use cargo_util::{ProcessBuilder, ProcessError};
use std::collections::BTreeMap;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

mod cli;
mod commands;

use crate::command_prelude::*;

fn main() {
    #[cfg(feature = "pretty-env-logger")]
    pretty_env_logger::init_custom_env("CARGO_LOG");
    #[cfg(not(feature = "pretty-env-logger"))]
    env_logger::init_from_env("CARGO_LOG");

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

    let result = match cargo::ops::fix_maybe_exec_rustc(&config) {
        Ok(true) => Ok(()),
        Ok(false) => {
            let _token = cargo::util::job::setup();
            cli::main(&mut config)
        }
        Err(e) => Err(CliError::from(e)),
    };

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

/// Table for defining the aliases which come builtin in `Cargo`.
/// The contents are structured as: `(alias, aliased_command, description)`.
const BUILTIN_ALIASES: [(&str, &str, &str); 5] = [
    ("b", "build", "alias: build"),
    ("c", "check", "alias: check"),
    ("d", "doc", "alias: doc"),
    ("r", "run", "alias: run"),
    ("t", "test", "alias: test"),
];

/// Function which contains the list of all of the builtin aliases and it's
/// corresponding execs represented as &str.
fn builtin_aliases_execs(cmd: &str) -> Option<&(&str, &str, &str)> {
    BUILTIN_ALIASES.iter().find(|alias| alias.0 == cmd)
}

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

    let result = user_alias.or_else(|| {
        builtin_aliases_execs(command).map(|command_str| vec![command_str.1.to_string()])
    });
    Ok(result)
}

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

    for cmd in commands::builtin() {
        commands.insert(
            cmd.get_name().to_string(),
            CommandInfo::BuiltIn {
                about: cmd.get_about().map(|s| s.to_string()),
            },
        );
    }

    // Add the builtin_aliases and them descriptions to the
    // `commands` `BTreeMap`.
    for command in &BUILTIN_ALIASES {
        commands.insert(
            command.0.to_string(),
            CommandInfo::BuiltIn {
                about: Some(command.2.to_string()),
            },
        );
    }

    // Add the user-defined aliases
    if let Ok(aliases) = config.get::<BTreeMap<String, StringOrVec>>("alias") {
        for (name, target) in aliases.iter() {
            commands.insert(
                name.to_string(),
                CommandInfo::Alias {
                    target: target.clone(),
                },
            );
        }
    }

    // `help` is special, so it needs to be inserted separately.
    commands.insert(
        "help".to_string(),
        CommandInfo::BuiltIn {
            about: Some("Displays help for a cargo subcommand".to_string()),
        },
    );

    commands
}

fn find_external_subcommand(config: &Config, cmd: &str) -> Option<PathBuf> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    search_directories(config)
        .iter()
        .map(|dir| dir.join(&command_exe))
        .find(|file| is_executable(file))
}

fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> CliResult {
    let path = find_external_subcommand(config, cmd);
    let command = match path {
        Some(command) => command,
        None => {
            let err = if cmd.starts_with('+') {
                anyhow::format_err!(
                    "no such subcommand: `{}`\n\n\t\
                    Cargo does not handle `+toolchain` directives.\n\t\
                    Did you mean to invoke `cargo` through `rustup` instead?",
                    cmd
                )
            } else {
                let suggestions = list_commands(config);
                let did_you_mean = closest_msg(cmd, suggestions.keys(), |c| c);

                anyhow::format_err!(
                    "no such subcommand: `{}`{}\n\n\t\
                    View all installed commands with `cargo --list`",
                    cmd,
                    did_you_mean
                )
            };

            return Err(CliError::new(err, 101));
        }
    };

    let cargo_exe = config.cargo_exe()?;
    let err = match ProcessBuilder::new(&command)
        .env(cargo::CARGO_ENV, cargo_exe)
        .args(args)
        .exec_replace()
    {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if let Some(perr) = err.downcast_ref::<ProcessError>() {
        if let Some(code) = perr.code {
            return Err(CliError::code(code));
        }
    }
    Err(CliError::new(err, 101))
}

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

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

fn init_git_transports(config: &Config) {
    // Only use a custom transport if any HTTP options are specified,
    // such as proxies or custom certificate authorities. The custom
    // transport, however, is not as well battle-tested.

    match cargo::ops::needs_custom_http_transport(config) {
        Ok(true) => {}
        _ => return,
    }

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

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>Disable owner validation for Cargo-as-a-binary<commit_after>#![warn(rust_2018_idioms)] // while we're getting used to 2018
#![allow(clippy::all)]

use cargo::core::shell::Shell;
use cargo::util::toml::StringOrVec;
use cargo::util::CliError;
use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config};
use cargo_util::{ProcessBuilder, ProcessError};
use std::collections::BTreeMap;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

mod cli;
mod commands;

use crate::command_prelude::*;

fn main() {
    #[cfg(feature = "pretty-env-logger")]
    pretty_env_logger::init_custom_env("CARGO_LOG");
    #[cfg(not(feature = "pretty-env-logger"))]
    env_logger::init_from_env("CARGO_LOG");

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

    let result = match cargo::ops::fix_maybe_exec_rustc(&config) {
        Ok(true) => Ok(()),
        Ok(false) => {
            let _token = cargo::util::job::setup();
            cli::main(&mut config)
        }
        Err(e) => Err(CliError::from(e)),
    };

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

/// Table for defining the aliases which come builtin in `Cargo`.
/// The contents are structured as: `(alias, aliased_command, description)`.
const BUILTIN_ALIASES: [(&str, &str, &str); 5] = [
    ("b", "build", "alias: build"),
    ("c", "check", "alias: check"),
    ("d", "doc", "alias: doc"),
    ("r", "run", "alias: run"),
    ("t", "test", "alias: test"),
];

/// Function which contains the list of all of the builtin aliases and it's
/// corresponding execs represented as &str.
fn builtin_aliases_execs(cmd: &str) -> Option<&(&str, &str, &str)> {
    BUILTIN_ALIASES.iter().find(|alias| alias.0 == cmd)
}

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

    let result = user_alias.or_else(|| {
        builtin_aliases_execs(command).map(|command_str| vec![command_str.1.to_string()])
    });
    Ok(result)
}

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

    for cmd in commands::builtin() {
        commands.insert(
            cmd.get_name().to_string(),
            CommandInfo::BuiltIn {
                about: cmd.get_about().map(|s| s.to_string()),
            },
        );
    }

    // Add the builtin_aliases and them descriptions to the
    // `commands` `BTreeMap`.
    for command in &BUILTIN_ALIASES {
        commands.insert(
            command.0.to_string(),
            CommandInfo::BuiltIn {
                about: Some(command.2.to_string()),
            },
        );
    }

    // Add the user-defined aliases
    if let Ok(aliases) = config.get::<BTreeMap<String, StringOrVec>>("alias") {
        for (name, target) in aliases.iter() {
            commands.insert(
                name.to_string(),
                CommandInfo::Alias {
                    target: target.clone(),
                },
            );
        }
    }

    // `help` is special, so it needs to be inserted separately.
    commands.insert(
        "help".to_string(),
        CommandInfo::BuiltIn {
            about: Some("Displays help for a cargo subcommand".to_string()),
        },
    );

    commands
}

fn find_external_subcommand(config: &Config, cmd: &str) -> Option<PathBuf> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    search_directories(config)
        .iter()
        .map(|dir| dir.join(&command_exe))
        .find(|file| is_executable(file))
}

fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> CliResult {
    let path = find_external_subcommand(config, cmd);
    let command = match path {
        Some(command) => command,
        None => {
            let err = if cmd.starts_with('+') {
                anyhow::format_err!(
                    "no such subcommand: `{}`\n\n\t\
                    Cargo does not handle `+toolchain` directives.\n\t\
                    Did you mean to invoke `cargo` through `rustup` instead?",
                    cmd
                )
            } else {
                let suggestions = list_commands(config);
                let did_you_mean = closest_msg(cmd, suggestions.keys(), |c| c);

                anyhow::format_err!(
                    "no such subcommand: `{}`{}\n\n\t\
                    View all installed commands with `cargo --list`",
                    cmd,
                    did_you_mean
                )
            };

            return Err(CliError::new(err, 101));
        }
    };

    let cargo_exe = config.cargo_exe()?;
    let err = match ProcessBuilder::new(&command)
        .env(cargo::CARGO_ENV, cargo_exe)
        .args(args)
        .exec_replace()
    {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if let Some(perr) = err.downcast_ref::<ProcessError>() {
        if let Some(code) = perr.code {
            return Err(CliError::code(code));
        }
    }
    Err(CliError::new(err, 101))
}

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

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

fn init_git_transports(config: &Config) {
    // Only use a custom transport if any HTTP options are specified,
    // such as proxies or custom certificate authorities. The custom
    // transport, however, is not as well battle-tested.

    match cargo::ops::needs_custom_http_transport(config) {
        Ok(true) => {}
        _ => return,
    }

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

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

    // Disabling the owner validation in git can, in theory, lead to code execution
    // vulnerabilities. However, libgit2 does not launch executables, which is the foundation of
    // the original security issue. Meanwhile, issues with refusing to load git repos in
    // `CARGO_HOME` for example will likely be very frustrating for users. So, we disable the
    // validation.
    //
    // For further discussion of Cargo's current interactions with git, see
    //
    //   https://github.com/rust-lang/rfcs/pull/3279
    //
    // and in particular the subsection on "Git support".
    //
    // Note that we only disable this when Cargo is run as a binary. If Cargo is used as a library,
    // this code won't be invoked. Instead, developers will need to explicitly disable the
    // validation in their code. This is inconvenient, but won't accidentally open consuming
    // applications up to security issues if they use git2 to open repositories elsewhere in their
    // code.
    unsafe {
        if git2::opts::set_verify_owner_validation(false).is_err() {
            return;
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use gluon::{
    self,
    base::{ast::OwnedExpr, fnv::FnvMap, symbol::Symbol, types::ArcType},
    import::Importer,
    query::Compilation,
    Error as GluonError, ModuleCompiler, Thread, ThreadExt,
};

use {futures::prelude::*, tokio::sync::Mutex, url::Url};

use crate::{name::module_name_to_file_, text_edit::TextChanges};

pub(crate) struct Module {
    pub source: Arc<gluon::base::source::FileMap>,
    pub expr: Arc<OwnedExpr<Symbol>>,
    pub uri: Url,
}

pub struct State {
    pub uri: Url,
    pub version: Option<i64>,
    pub text_changes: TextChanges,
}

impl State {
    pub(crate) fn empty(uri: Url) -> State {
        State {
            uri,
            version: None,
            text_changes: TextChanges::new(),
        }
    }
}

pub(crate) async fn get_module(uri: Url, thread: &Thread, module: &str) -> gluon::Result<Module> {
    let mut db = thread.get_database();
    let m = db
        .typechecked_source_module(module.into(), None)
        .await
        .or_else(|(opt, err)| opt.ok_or(err))?;
    Ok(Module {
        source: db.get_filemap(module).expect("Filemap"),
        expr: m.expr.clone(),
        uri,
    })
}

#[derive(Clone)]
pub(crate) struct CheckImporter(pub(crate) Arc<Mutex<FnvMap<String, State>>>);
impl CheckImporter {
    pub(crate) fn new() -> CheckImporter {
        CheckImporter(Arc::new(Mutex::new(FnvMap::default())))
    }

    pub(crate) async fn module(&self, thread: &Thread, module: &str) -> Option<Module> {
        let uri = {
            let map = self.0.lock().await;
            map.get(module)?.uri.clone()
        };
        get_module(uri, thread, module).await.ok()
    }

    pub(crate) async fn modules(&self, thread: &Thread) -> impl Iterator<Item = Module> {
        let uris = self
            .0
            .lock()
            .await
            .iter()
            .map(|(module, s)| (module.clone(), s.uri.clone()))
            .collect::<Vec<_>>();

        futures::stream::iter(uris)
            .filter_map(|(module, uri)| async move { get_module(uri, thread, &module).await.ok() })
            .collect::<Vec<_>>()
            .await
            .into_iter()
    }
}

#[async_trait::async_trait]
impl Importer for CheckImporter {
    async fn import(
        &self,
        compiler: &mut ModuleCompiler<'_>,
        _: &Thread,
        module_name: &str,
    ) -> Result<ArcType, (Option<ArcType>, GluonError)> {
        let typ = compiler
            .database
            .module_type(module_name.into(), None)
            .await
            .map_err(|err| (None, err))?;
        compiler
            .database
            .module_metadata(module_name.into(), None)
            .await
            .map_err(|err| (None, err))?;

        self.0.lock().await.insert(
            module_name.into(),
            State {
                uri: module_name_to_file_(module_name)
                    .map_err(|err| (None, GluonError::from(err.to_string())))?,
                version: None,
                text_changes: TextChanges::new(),
            },
        );

        Ok(typ)
    }
}
<commit_msg>Try to load modules before checking if they exist<commit_after>use std::sync::Arc;

use gluon::{
    self,
    base::{ast::OwnedExpr, fnv::FnvMap, symbol::Symbol, types::ArcType},
    import::Importer,
    query::Compilation,
    Error as GluonError, ModuleCompiler, Thread, ThreadExt,
};

use {futures::prelude::*, tokio::sync::Mutex, url::Url};

use crate::{name::module_name_to_file_, text_edit::TextChanges};

pub(crate) struct Module {
    pub source: Arc<gluon::base::source::FileMap>,
    pub expr: Arc<OwnedExpr<Symbol>>,
    pub uri: Url,
}

pub struct State {
    pub uri: Url,
    pub version: Option<i64>,
    pub text_changes: TextChanges,
}

impl State {
    pub(crate) fn empty(uri: Url) -> State {
        State {
            uri,
            version: None,
            text_changes: TextChanges::new(),
        }
    }
}

pub(crate) async fn get_module(
    thread: &Thread,
    module: &str,
) -> gluon::Result<(Arc<gluon::base::source::FileMap>, Arc<OwnedExpr<Symbol>>)> {
    let mut db = thread.get_database();
    let m = db
        .typechecked_source_module(module.into(), None)
        .await
        .or_else(|(opt, err)| opt.ok_or(err))?;
    Ok((db.get_filemap(module).expect("Filemap"), m.expr.clone()))
}

#[derive(Clone)]
pub(crate) struct CheckImporter(pub(crate) Arc<Mutex<FnvMap<String, State>>>);
impl CheckImporter {
    pub(crate) fn new() -> CheckImporter {
        CheckImporter(Arc::new(Mutex::new(FnvMap::default())))
    }

    pub(crate) async fn module(&self, thread: &Thread, module: &str) -> Option<Module> {
        let (source, expr) = get_module(thread, module).await.ok()?;

        let uri = {
            let map = self.0.lock().await;
            map.get(module)?.uri.clone()
        };

        Some(Module { source, expr, uri })
    }

    pub(crate) async fn modules(&self, thread: &Thread) -> impl Iterator<Item = Module> {
        let uris = self
            .0
            .lock()
            .await
            .iter()
            .map(|(module, s)| (module.clone(), s.uri.clone()))
            .collect::<Vec<_>>();

        futures::stream::iter(uris)
            .filter_map(|(module, uri)| async move {
                let (source, expr) = get_module(thread, &module).await.ok()?;
                Some(Module { source, expr, uri })
            })
            .collect::<Vec<_>>()
            .await
            .into_iter()
    }
}

#[async_trait::async_trait]
impl Importer for CheckImporter {
    async fn import(
        &self,
        compiler: &mut ModuleCompiler<'_>,
        _: &Thread,
        module_name: &str,
    ) -> Result<ArcType, (Option<ArcType>, GluonError)> {
        let typ = compiler
            .database
            .module_type(module_name.into(), None)
            .await
            .map_err(|err| (None, err))?;
        compiler
            .database
            .module_metadata(module_name.into(), None)
            .await
            .map_err(|err| (None, err))?;

        self.0.lock().await.insert(
            module_name.into(),
            State {
                uri: module_name_to_file_(module_name)
                    .map_err(|err| (None, GluonError::from(err.to_string())))?,
                version: None,
                text_changes: TextChanges::new(),
            },
        );

        Ok(typ)
    }
}
<|endoftext|>