<commit_before>use crate::error;
use crate::error::Result;
use lazy_static::lazy_static;
use regex::Regex;
use std::collections::hash_map::HashMap;
use std::fs;
use tree_sitter::{Language, Parser, Point};

lazy_static! {
    static ref HIGHLIGHT_NAME_REGEX: Regex = Regex::new("[\\w_\\-.]+").unwrap();
}

#[derive(Debug, Eq, PartialEq)]
pub struct CaptureInfo {
    pub name: String,
    pub position: Point,
}

#[derive(Debug, PartialEq, Eq)]
pub struct Assertion {
    pub position: Point,
    pub expected: String,
}

/// Parse the given source code, finding all of the comments that contain
/// highlighting assertions. Return a vector of (position, expected highlight name)
/// pairs.
pub fn parse_position_comments(
    parser: &mut Parser,
    language: Language,
    source: &[u8],
) -> Result<Vec<Assertion>> {
    let mut result = Vec::new();
    let mut assertion_ranges = Vec::new();

    // Parse the code.
    parser.set_included_ranges(&[]).unwrap();
    parser.set_language(language).unwrap();
    let tree = parser.parse(source, None).unwrap();

    // Walk the tree, finding comment nodes that contain assertions.
    let mut ascending = false;
    let mut cursor = tree.root_node().walk();
    loop {
        if ascending {
            let node = cursor.node();

            // Find every comment node.
            if node.kind().contains("comment") {
                if let Ok(text) = node.utf8_text(source) {
                    let mut position = node.start_position();
                    if position.row == 0 {
                        continue;
                    }

                    // Find the arrow character ("^" or '<-") in the comment. A left arrow
                    // refers to the column where the comment node starts. An up arrow refers
                    // to its own column.
                    let mut has_left_caret = false;
                    let mut has_arrow = false;
                    let mut arrow_end = 0;
                    for (i, c) in text.char_indices() {
                        arrow_end = i + 1;
                        if c == '-' && has_left_caret {
                            has_arrow = true;
                            break;
                        }
                        if c == '^' {
                            has_arrow = true;
                            position.column += i;
                            break;
                        }
                        has_left_caret = c == '<';
                    }

                    // If the comment node contains an arrow and a highlight name, record the
                    // highlight name and the position.
                    if let (true, Some(mat)) =
                        (has_arrow, HIGHLIGHT_NAME_REGEX.find(&text[arrow_end..]))
                    {
                        assertion_ranges.push((node.start_position(), node.end_position()));
                        result.push(Assertion {
                            position: position,
                            expected: mat.as_str().to_string(),
                        });
                    }
                }
            }

            // Continue walking the tree.
            if cursor.goto_next_sibling() {
                ascending = false;
            } else if !cursor.goto_parent() {
                break;
            }
        } else if !cursor.goto_first_child() {
            ascending = true;
        }
    }

    // Adjust the row number in each assertion's position to refer to the line of
    // code *above* the assertion. There can be multiple lines of assertion comments,
    // so the positions may have to be decremented by more than one row.
    let mut i = 0;
    for assertion in result.iter_mut() {
        loop {
            let on_assertion_line = assertion_ranges[i..]
                .iter()
                .any(|(start, _)| start.row == assertion.position.row);
            if on_assertion_line {
                assertion.position.row -= 1;
            } else {
                while i < assertion_ranges.len()
                    && assertion_ranges[i].0.row < assertion.position.row
                {
                    i += 1;
                }
                break;
            }
        }
    }

    // The assertions can end up out of order due to the line adjustments.
    result.sort_unstable_by_key(|a| a.position);

    Ok(result)
}

pub fn assert_expected_captures(
    infos: Vec<CaptureInfo>,
    path: String,
    parser: &mut Parser,
    language: Language,
) -> Result<()> {
    let contents = fs::read_to_string(path)?;
    let pairs = parse_position_comments(parser, language, contents.as_bytes())?;

    let per_position_index: HashMap<Point, &String> =
        pairs.iter().map(|a| (a.position, &a.expected)).collect();

    for info in &infos {
        if !per_position_index.contains_key(&info.position) {
            continue;
        }
        let found = per_position_index.get(&info.position).unwrap();
        if **found != info.name && info.name != "name" {
            Err(error::Error::new(format!(
                "Assertion failed: at {}, found {}, expected {}",
                info.position, found, info.name
            )))?
        }
    }
    Ok(())
}
<commit_msg>Better naming for this regex.<commit_after>use crate::error;
use crate::error::Result;
use lazy_static::lazy_static;
use regex::Regex;
use std::collections::hash_map::HashMap;
use std::fs;
use tree_sitter::{Language, Parser, Point};

lazy_static! {
    static ref PROPERTY_NAME_REGEX: Regex = Regex::new("[\\w_\\-.]+").unwrap();
}

#[derive(Debug, Eq, PartialEq)]
pub struct CaptureInfo {
    pub name: String,
    pub position: Point,
}

#[derive(Debug, PartialEq, Eq)]
pub struct Assertion {
    pub position: Point,
    pub expected: String,
}

/// Parse the given source code, finding all of the comments that contain
/// highlighting assertions. Return a vector of (position, expected highlight name)
/// pairs.
pub fn parse_position_comments(
    parser: &mut Parser,
    language: Language,
    source: &[u8],
) -> Result<Vec<Assertion>> {
    let mut result = Vec::new();
    let mut assertion_ranges = Vec::new();

    // Parse the code.
    parser.set_included_ranges(&[]).unwrap();
    parser.set_language(language).unwrap();
    let tree = parser.parse(source, None).unwrap();

    // Walk the tree, finding comment nodes that contain assertions.
    let mut ascending = false;
    let mut cursor = tree.root_node().walk();
    loop {
        if ascending {
            let node = cursor.node();

            // Find every comment node.
            if node.kind().contains("comment") {
                if let Ok(text) = node.utf8_text(source) {
                    let mut position = node.start_position();
                    if position.row == 0 {
                        continue;
                    }

                    // Find the arrow character ("^" or '<-") in the comment. A left arrow
                    // refers to the column where the comment node starts. An up arrow refers
                    // to its own column.
                    let mut has_left_caret = false;
                    let mut has_arrow = false;
                    let mut arrow_end = 0;
                    for (i, c) in text.char_indices() {
                        arrow_end = i + 1;
                        if c == '-' && has_left_caret {
                            has_arrow = true;
                            break;
                        }
                        if c == '^' {
                            has_arrow = true;
                            position.column += i;
                            break;
                        }
                        has_left_caret = c == '<';
                    }

                    // If the comment node contains an arrow and a highlight name, record the
                    // highlight name and the position.
                    if let (true, Some(mat)) =
                        (has_arrow, PROPERTY_NAME_REGEX.find(&text[arrow_end..]))
                    {
                        assertion_ranges.push((node.start_position(), node.end_position()));
                        result.push(Assertion {
                            position: position,
                            expected: mat.as_str().to_string(),
                        });
                    }
                }
            }

            // Continue walking the tree.
            if cursor.goto_next_sibling() {
                ascending = false;
            } else if !cursor.goto_parent() {
                break;
            }
        } else if !cursor.goto_first_child() {
            ascending = true;
        }
    }

    // Adjust the row number in each assertion's position to refer to the line of
    // code *above* the assertion. There can be multiple lines of assertion comments,
    // so the positions may have to be decremented by more than one row.
    let mut i = 0;
    for assertion in result.iter_mut() {
        loop {
            let on_assertion_line = assertion_ranges[i..]
                .iter()
                .any(|(start, _)| start.row == assertion.position.row);
            if on_assertion_line {
                assertion.position.row -= 1;
            } else {
                while i < assertion_ranges.len()
                    && assertion_ranges[i].0.row < assertion.position.row
                {
                    i += 1;
                }
                break;
            }
        }
    }

    // The assertions can end up out of order due to the line adjustments.
    result.sort_unstable_by_key(|a| a.position);

    Ok(result)
}

pub fn assert_expected_captures(
    infos: Vec<CaptureInfo>,
    path: String,
    parser: &mut Parser,
    language: Language,
) -> Result<()> {
    let contents = fs::read_to_string(path)?;
    let pairs = parse_position_comments(parser, language, contents.as_bytes())?;

    let per_position_index: HashMap<Point, &String> =
        pairs.iter().map(|a| (a.position, &a.expected)).collect();

    for info in &infos {
        if !per_position_index.contains_key(&info.position) {
            continue;
        }
        let found = per_position_index.get(&info.position).unwrap();
        if **found != info.name && info.name != "name" {
            Err(error::Error::new(format!(
                "Assertion failed: at {}, found {}, expected {}",
                info.position, found, info.name
            )))?
        }
    }
    Ok(())
}
<|endoftext|>


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

#![feature(box_syntax)]
#![feature(conservative_impl_trait)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(field_init_shorthand)]
#![feature(more_struct_aliases)]
#![feature(mpsc_select)]
#![feature(nonzero)]
#![feature(on_unimplemented)]
#![feature(optin_builtin_traits)]
#![feature(plugin)]
#![feature(slice_patterns)]
#![feature(stmt_expr_attributes)]
#![feature(try_from)]
#![feature(untagged_unions)]

#![deny(unsafe_code)]
#![allow(non_snake_case)]

#![doc = "The script crate contains all matters DOM."]

#![plugin(plugins)]

extern crate angle;
extern crate app_units;
extern crate atomic_refcell;
extern crate audio_video_metadata;
#[macro_use]
extern crate bitflags;
extern crate bluetooth_traits;
extern crate byteorder;
extern crate canvas_traits;
extern crate caseless;
extern crate cookie as cookie_rs;
extern crate core;
#[macro_use]
extern crate cssparser;
extern crate devtools_traits;
extern crate encoding;
extern crate euclid;
extern crate fnv;
extern crate gfx_traits;
extern crate heapsize;
#[macro_use] extern crate heapsize_derive;
extern crate html5ever;
#[macro_use] extern crate html5ever_atoms;
#[macro_use]
extern crate hyper;
extern crate hyper_serde;
extern crate image;
extern crate ipc_channel;
#[macro_use]
extern crate js;
#[macro_use]
extern crate jstraceable_derive;
extern crate libc;
#[macro_use]
extern crate log;
#[macro_use]
extern crate mime;
extern crate mime_guess;
extern crate msg;
extern crate net_traits;
extern crate num_traits;
extern crate offscreen_gl_context;
extern crate open;
extern crate parking_lot;
extern crate phf;
#[macro_use]
extern crate profile_traits;
extern crate range;
extern crate ref_filter_map;
extern crate ref_slice;
extern crate regex;
extern crate rustc_serialize;
extern crate script_layout_interface;
extern crate script_traits;
extern crate selectors;
extern crate serde;
#[macro_use] extern crate servo_atoms;
extern crate servo_config;
extern crate servo_geometry;
extern crate servo_rand;
extern crate servo_url;
extern crate smallvec;
#[macro_use]
extern crate style;
extern crate style_traits;
extern crate time;
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
extern crate tinyfiledialogs;
extern crate url;
extern crate uuid;
extern crate webrender_traits;
extern crate websocket;
extern crate webvr_traits;
extern crate xml5ever;

mod body;
pub mod clipboard_provider;
mod devtools;
pub mod document_loader;
#[macro_use]
mod dom;
pub mod fetch;
pub mod layout_wrapper;
mod mem;
mod microtask;
mod network_listener;
pub mod origin;
pub mod script_runtime;
#[allow(unsafe_code)]
pub mod script_thread;
mod serviceworker_manager;
mod serviceworkerjob;
mod stylesheet_loader;
mod task_source;
pub mod test;
pub mod textinput;
mod timers;
mod unpremultiplytable;
mod webdriver_handlers;

use dom::bindings::codegen::RegisterBindings;
use dom::bindings::proxyhandler;
use script_traits::SWManagerSenders;
use serviceworker_manager::ServiceWorkerManager;

#[cfg(target_os = "linux")]
#[allow(unsafe_code)]
fn perform_platform_specific_initialization() {
    use std::mem;
    // 4096 is default max on many linux systems
    const MAX_FILE_LIMIT: libc::rlim_t = 4096;

    // Bump up our number of file descriptors to save us from impending doom caused by an onslaught
    // of iframes.
    unsafe {
        let mut rlim: libc::rlimit = mem::uninitialized();
        match libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) {
            0 => {
                if rlim.rlim_cur >= MAX_FILE_LIMIT {
                    // we have more than enough
                    return;
                }

                rlim.rlim_cur = match rlim.rlim_max {
                    libc::RLIM_INFINITY => MAX_FILE_LIMIT,
                    _ => {
                        if rlim.rlim_max < MAX_FILE_LIMIT {
                            rlim.rlim_max
                        } else {
                            MAX_FILE_LIMIT
                        }
                    }
                };
                match libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) {
                    0 => (),
                    _ => warn!("Failed to set file count limit"),
                };
            },
            _ => warn!("Failed to get file count limit"),
        };
    }
}

#[cfg(not(target_os = "linux"))]
fn perform_platform_specific_initialization() {}

pub fn init_service_workers(sw_senders: SWManagerSenders) {
    // Spawn the service worker manager passing the constellation sender
    ServiceWorkerManager::spawn_manager(sw_senders);
}

#[allow(unsafe_code)]
pub fn init() {
    unsafe {
        proxyhandler::init();

        // Create the global vtables used by the (generated) DOM
        // bindings to implement JS proxies.
        RegisterBindings::RegisterProxyHandlers();
    }

    perform_platform_specific_initialization();
}
<commit_msg>Remove a gate for the stabilized more_struct_aliases feature.<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/. */

#![feature(box_syntax)]
#![feature(conservative_impl_trait)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(field_init_shorthand)]
#![feature(mpsc_select)]
#![feature(nonzero)]
#![feature(on_unimplemented)]
#![feature(optin_builtin_traits)]
#![feature(plugin)]
#![feature(slice_patterns)]
#![feature(stmt_expr_attributes)]
#![feature(try_from)]
#![feature(untagged_unions)]

#![deny(unsafe_code)]
#![allow(non_snake_case)]

#![doc = "The script crate contains all matters DOM."]

#![plugin(plugins)]

extern crate angle;
extern crate app_units;
extern crate atomic_refcell;
extern crate audio_video_metadata;
#[macro_use]
extern crate bitflags;
extern crate bluetooth_traits;
extern crate byteorder;
extern crate canvas_traits;
extern crate caseless;
extern crate cookie as cookie_rs;
extern crate core;
#[macro_use]
extern crate cssparser;
extern crate devtools_traits;
extern crate encoding;
extern crate euclid;
extern crate fnv;
extern crate gfx_traits;
extern crate heapsize;
#[macro_use] extern crate heapsize_derive;
extern crate html5ever;
#[macro_use] extern crate html5ever_atoms;
#[macro_use]
extern crate hyper;
extern crate hyper_serde;
extern crate image;
extern crate ipc_channel;
#[macro_use]
extern crate js;
#[macro_use]
extern crate jstraceable_derive;
extern crate libc;
#[macro_use]
extern crate log;
#[macro_use]
extern crate mime;
extern crate mime_guess;
extern crate msg;
extern crate net_traits;
extern crate num_traits;
extern crate offscreen_gl_context;
extern crate open;
extern crate parking_lot;
extern crate phf;
#[macro_use]
extern crate profile_traits;
extern crate range;
extern crate ref_filter_map;
extern crate ref_slice;
extern crate regex;
extern crate rustc_serialize;
extern crate script_layout_interface;
extern crate script_traits;
extern crate selectors;
extern crate serde;
#[macro_use] extern crate servo_atoms;
extern crate servo_config;
extern crate servo_geometry;
extern crate servo_rand;
extern crate servo_url;
extern crate smallvec;
#[macro_use]
extern crate style;
extern crate style_traits;
extern crate time;
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
extern crate tinyfiledialogs;
extern crate url;
extern crate uuid;
extern crate webrender_traits;
extern crate websocket;
extern crate webvr_traits;
extern crate xml5ever;

mod body;
pub mod clipboard_provider;
mod devtools;
pub mod document_loader;
#[macro_use]
mod dom;
pub mod fetch;
pub mod layout_wrapper;
mod mem;
mod microtask;
mod network_listener;
pub mod origin;
pub mod script_runtime;
#[allow(unsafe_code)]
pub mod script_thread;
mod serviceworker_manager;
mod serviceworkerjob;
mod stylesheet_loader;
mod task_source;
pub mod test;
pub mod textinput;
mod timers;
mod unpremultiplytable;
mod webdriver_handlers;

use dom::bindings::codegen::RegisterBindings;
use dom::bindings::proxyhandler;
use script_traits::SWManagerSenders;
use serviceworker_manager::ServiceWorkerManager;

#[cfg(target_os = "linux")]
#[allow(unsafe_code)]
fn perform_platform_specific_initialization() {
    use std::mem;
    // 4096 is default max on many linux systems
    const MAX_FILE_LIMIT: libc::rlim_t = 4096;

    // Bump up our number of file descriptors to save us from impending doom caused by an onslaught
    // of iframes.
    unsafe {
        let mut rlim: libc::rlimit = mem::uninitialized();
        match libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) {
            0 => {
                if rlim.rlim_cur >= MAX_FILE_LIMIT {
                    // we have more than enough
                    return;
                }

                rlim.rlim_cur = match rlim.rlim_max {
                    libc::RLIM_INFINITY => MAX_FILE_LIMIT,
                    _ => {
                        if rlim.rlim_max < MAX_FILE_LIMIT {
                            rlim.rlim_max
                        } else {
                            MAX_FILE_LIMIT
                        }
                    }
                };
                match libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) {
                    0 => (),
                    _ => warn!("Failed to set file count limit"),
                };
            },
            _ => warn!("Failed to get file count limit"),
        };
    }
}

#[cfg(not(target_os = "linux"))]
fn perform_platform_specific_initialization() {}

pub fn init_service_workers(sw_senders: SWManagerSenders) {
    // Spawn the service worker manager passing the constellation sender
    ServiceWorkerManager::spawn_manager(sw_senders);
}

#[allow(unsafe_code)]
pub fn init() {
    unsafe {
        proxyhandler::init();

        // Create the global vtables used by the (generated) DOM
        // bindings to implement JS proxies.
        RegisterBindings::RegisterProxyHandlers();
    }

    perform_platform_specific_initialization();
}
<|endoftext|>


<commit_before>use std::thread;

pub type IrcConfig = ::irc::client::data::Config;

use irc::client::data::Command;
use irc::client::server::IrcServer;
use irc::client::server::Server;
use irc::client::server::utils::ServerExt;

use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;

use regex::Regex;

use adapter::ChatAdapter;
use message::IncomingMessage;
use message::AdapterMsg;

/// Connect your bot to IRC with the IrcAdapter
///
/// # Examples
///
/// ```rust
/// use chatbot::Chatbot;
/// use chatbot::adapter::IrcAdapter;
/// use chatbot::adapter::IrcConfig;
///
/// let name = "mybot";
/// let mut bot = Chatbot::new(name);
///
/// let irc = IrcAdapter::new(IrcConfig {
///     nickname: Some(format!("{}", name)),
///     alt_nicks: Some(vec![format!("{}_", name), format!("{}__", name)]),
///     server: Some(format!("irc.mozilla.org")),
///     channels: Some(vec![format!("#chatbot")]),
///     .. Default::default()
/// }, name);
///
/// bot.add_adapter(irc);
/// ```
pub struct IrcAdapter {
    config: IrcConfig,
    address_regex: Regex,
    name: String,
}

impl IrcAdapter {
    pub fn new(config: IrcConfig, bot_name: &str) -> IrcAdapter {
        IrcAdapter {
            config: config,
            address_regex: Regex::new(format!(r"^{}:", bot_name).as_str()).unwrap(),
            name: bot_name.to_owned(),
        }
    }
}

impl ChatAdapter for IrcAdapter {
    fn get_name(&self) -> &str {
        "IrcAdapter"
    }

    fn addresser(&self) -> &Regex {
        &self.address_regex
    }

    fn process_events(&mut self, tx_incoming: Sender<IncomingMessage>) {
        let server = IrcServer::from_config(self.config.clone()).unwrap();
        server.identify().unwrap();

        let (tx_outgoing, rx_outgoing) = channel();
        let name = self.name.clone();

        {
            let server = server.clone();
            thread::Builder::new().name("IrcAdapter Incoming".to_owned()).spawn(move || {
                for message in server.iter() {
                    if message.is_err() {
                        continue;
                    }

                    let msg = message.unwrap();

                    let user = msg.source_nickname().map(|user| user.to_owned());
                    match msg.command {
                        Command::PRIVMSG(ref chan, ref msg) => {
                            let incoming = IncomingMessage::new("IrcAdapter".to_owned(),
                                Some(server.config().server().to_owned()),
                                Some(chan.to_owned()), user, msg.to_owned(),
                                tx_outgoing.clone());

                            tx_incoming.send(incoming)
                                .ok().expect("chatbot not receiving messages");
                        },
                        _ => ()
                    }
                }
            }).ok().expect("failed to create incoming thread for IrcAdapter");
        }

        thread::Builder::new().name("IrcAdapter Outgoing".to_owned()).spawn(move || {
            loop {
                match rx_outgoing.recv() {
                    Ok(msg) => {
                        match msg {
                            AdapterMsg::Outgoing(m) => {
                                let incoming = m.get_incoming();
                                let chan = incoming.channel().unwrap();
                                let user = incoming.user().unwrap();

                                if &name[..] == chan {
                                    server.send_privmsg(user, m.as_ref()).unwrap()
                                } else {
                                    server.send_privmsg(chan, m.as_ref()).unwrap()
                                };

                            }
                            AdapterMsg::Private(m) => {
                                let incoming = m.get_incoming();
                                let user = incoming.user().unwrap();
                                server.send_privmsg(user, m.as_ref()).unwrap()
                            }
                            AdapterMsg::Shutdown => {
                                break
                            }
                        }
                    },
                    Err(e) => {
                        println!("error receiving outgoing messages: {}", e);
                        break
                    }
                }
            }
        }).ok().expect("failed to create outgoing thread for IrcAdapter");
    }
}
<commit_msg>update irc adapter to conform to new irc api<commit_after>use std::thread;

pub type IrcConfig = ::irc::client::data::Config;

use irc::proto::command::Command;
use irc::client::server::IrcServer;
use irc::client::server::Server;
use irc::client::server::utils::ServerExt;

use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;

use regex::Regex;

use adapter::ChatAdapter;
use message::IncomingMessage;
use message::AdapterMsg;

/// Connect your bot to IRC with the IrcAdapter
///
/// # Examples
///
/// ```rust
/// use chatbot::Chatbot;
/// use chatbot::adapter::IrcAdapter;
/// use chatbot::adapter::IrcConfig;
///
/// let name = "mybot";
/// let mut bot = Chatbot::new(name);
///
/// let irc = IrcAdapter::new(IrcConfig {
///     nickname: Some(format!("{}", name)),
///     alt_nicks: Some(vec![format!("{}_", name), format!("{}__", name)]),
///     server: Some(format!("irc.mozilla.org")),
///     channels: Some(vec![format!("#chatbot")]),
///     .. Default::default()
/// }, name);
///
/// bot.add_adapter(irc);
/// ```
pub struct IrcAdapter {
    config: IrcConfig,
    address_regex: Regex,
    name: String,
}

impl IrcAdapter {
    pub fn new(config: IrcConfig, bot_name: &str) -> IrcAdapter {
        IrcAdapter {
            config: config,
            address_regex: Regex::new(format!(r"^{}:", bot_name).as_str()).unwrap(),
            name: bot_name.to_owned(),
        }
    }
}

impl ChatAdapter for IrcAdapter {
    fn get_name(&self) -> &str {
        "IrcAdapter"
    }

    fn addresser(&self) -> &Regex {
        &self.address_regex
    }

    fn process_events(&mut self, tx_incoming: Sender<IncomingMessage>) {
        let server = IrcServer::from_config(self.config.clone()).unwrap();
        server.identify().unwrap();

        let (tx_outgoing, rx_outgoing) = channel();
        let name = self.name.clone();

        {
            let server = server.clone();
            thread::Builder::new().name("IrcAdapter Incoming".to_owned()).spawn(move || {
                server.for_each_incoming(|message| {
                    let user = message.source_nickname().map(|user| user.to_owned());
                    match message.command {
                        Command::PRIVMSG(ref chan, ref msg) => {
                            let incoming = IncomingMessage::new("IrcAdapter".to_owned(),
                                Some(server.config().server().to_owned()),
                                Some(chan.to_owned()), user, msg.to_owned(),
                                tx_outgoing.clone());

                            tx_incoming.send(incoming)
                                .ok().expect("chatbot not receiving messages");
                        },
                        _ => ()
                    }
                }).expect("error processing IrcServer::for_each_incoming");
            }).ok().expect("failed to create incoming thread for IrcAdapter");
        }

        thread::Builder::new().name("IrcAdapter Outgoing".to_owned()).spawn(move || {
            loop {
                match rx_outgoing.recv() {
                    Ok(msg) => {
                        match msg {
                            AdapterMsg::Outgoing(m) => {
                                let incoming = m.get_incoming();
                                let chan = incoming.channel().unwrap();
                                let user = incoming.user().unwrap();

                                if &name[..] == chan {
                                    server.send_privmsg(user, m.as_ref()).unwrap()
                                } else {
                                    server.send_privmsg(chan, m.as_ref()).unwrap()
                                };

                            }
                            AdapterMsg::Private(m) => {
                                let incoming = m.get_incoming();
                                let user = incoming.user().unwrap();
                                server.send_privmsg(user, m.as_ref()).unwrap()
                            }
                            AdapterMsg::Shutdown => {
                                break
                            }
                        }
                    },
                    Err(e) => {
                        println!("error receiving outgoing messages: {}", e);
                        break
                    }
                }
            }
        }).ok().expect("failed to create outgoing thread for IrcAdapter");
    }
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use serde_json;
use directory::error::{OpenReadError, DeleteError, OpenWriteError};
use directory::{ReadOnlySource, WritePtr};
use std::result;
use std::io;
use Directory;
use std::sync::{Arc, RwLock};
use std::collections::HashSet;
use std::sync::RwLockWriteGuard;
use std::io::Write;
use core::MANAGED_FILEPATH;
use std::collections::HashMap;
use std::fmt;
use Result;
use Error;

/// Wrapper of directories that keeps track of files created by Tantivy.
///
/// A managed directory is just a wrapper of a directory
/// that keeps a (persisted) list of the files that
/// have been created (and not deleted) by tantivy so far.
///
/// Thanks to this list, it implements a `garbage_collect` method
/// that removes the files that were created by tantivy and are not
/// useful anymore.
#[derive(Debug)]
pub struct ManagedDirectory {
    directory: Box<Directory>,
    meta_informations: Arc<RwLock<MetaInformation>>,
}

#[derive(Debug, Default)]
struct MetaInformation {
    managed_paths: HashSet<PathBuf>,
    protected_files: HashMap<PathBuf, usize>,
}

/// A `FileProtection` prevents the garbage collection of a file.
///
/// See `ManagedDirectory.protect_file_from_delete`.
pub struct FileProtection {
    directory: ManagedDirectory,
    path: PathBuf,
}

fn unprotect_file_from_delete(directory: &ManagedDirectory, path: &Path) {
    let mut meta_informations_wlock = directory.meta_informations
        .write()
        .expect("Managed file lock poisoned");
    if let Some(counter_ref_mut) = meta_informations_wlock
        .protected_files
        .get_mut(path) {
        (*counter_ref_mut) -= 1;
    }
}

impl fmt::Debug for FileProtection {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        write!(formatter, "FileProtectionFor({:?})", self.path)
    }
}

impl Drop for FileProtection {
    fn drop(&mut self) {
        unprotect_file_from_delete(&self.directory, &*self.path);
    }
}

/// Saves the file containing the list of existing files
/// that were created by tantivy.
fn save_managed_paths(directory: &mut Directory, wlock: &RwLockWriteGuard<MetaInformation>) -> io::Result<()> {
    let mut w = serde_json::to_vec(&wlock.managed_paths)?;
    write!(&mut w, "\n")?;
    directory.atomic_write(&MANAGED_FILEPATH, &w[..])?;
    Ok(())
}

impl ManagedDirectory {

    /// Wraps a directory as managed directory.
    pub fn new<Dir: Directory>(directory: Dir) -> Result<ManagedDirectory> {
        match directory.atomic_read(&MANAGED_FILEPATH) {
            Ok(data) => {
                let managed_files_json = String::from_utf8_lossy(&data);
                let managed_files: HashSet<PathBuf> = serde_json::from_str(&managed_files_json)
                    .map_err(|e| Error::CorruptedFile(MANAGED_FILEPATH.clone(), Box::new(e)))?;
                Ok(ManagedDirectory {
                    directory: box directory,
                    meta_informations: Arc::new(RwLock::new(
                        MetaInformation {
                            managed_paths: managed_files,
                            protected_files: HashMap::default()
                        })),
                })
            }
            Err(OpenReadError::FileDoesNotExist(_)) => {
                Ok(ManagedDirectory {
                    directory: box directory,
                    meta_informations: Arc::default(),
                })
            }
            Err(OpenReadError::IOError(e)) => {
                Err(From::from(e))
            }
        }
    }

    /// Garbage collect unused files.
    ///
    /// Removes the files that were created by `tantivy` and are not
    /// used by any segment anymore.
    ///
    /// * `living_files` - List of files that are still used by the index.
    ///
    /// This method does not panick nor returns errors.
    /// If a file cannot be deleted (for permission reasons for instance)
    /// an error is simply logged, and the file remains in the list of managed
    /// files.
    pub fn garbage_collect(&mut self, living_files: HashSet<PathBuf>) {
        let mut files_to_delete = vec!();
        {   // releasing the lock as .delete() will use it too.
            let meta_informations_rlock = self.meta_informations
                .read()
                .expect("Managed directory rlock poisoned in garbage collect.");
            for managed_path in &meta_informations_rlock.managed_paths {
                if !living_files.contains(managed_path) {
                    files_to_delete.push(managed_path.clone());
                }
            }
        }

        let mut deleted_files = vec!();
        {
            for file_to_delete in files_to_delete {
                match self.delete(&file_to_delete) {
                    Ok(_) => {
                        info!("Deleted {:?}", file_to_delete);
                        deleted_files.push(file_to_delete);
                    }
                    Err(file_error) => {
                        error!("Failed to delete {:?}", file_to_delete);
                        match file_error {
                            DeleteError::FileDoesNotExist(_) => {
                                deleted_files.push(file_to_delete);
                            }
                            DeleteError::IOError(_) => {
                                if !cfg!(target_os = "windows") {
                                    error!("Failed to delete {:?}", file_to_delete);
                                }
                            }
                            DeleteError::FileProtected(_) => {
                                // this is expected.
                            }
                        }

                    }
                }
            }
        }

        if !deleted_files.is_empty() {
            // update the list of managed files by removing
            // the file that were removed.
            let mut meta_informations_wlock = self.meta_informations
                .write()
                .expect("Managed directory wlock poisoned (2).");
            {
                let managed_paths_write = &mut meta_informations_wlock.managed_paths;
                for delete_file in &deleted_files {
                    managed_paths_write.remove(delete_file);
                }
            }
            if let Err(_) = save_managed_paths(self.directory.as_mut(), &meta_informations_wlock) {
                error!("Failed to save the list of managed files.");
            }
        }

    }

    /// Protects a file from being garbage collected.
    ///
    /// The method returns a `FileProtection` object.
    /// The file will not be garbage collected as long as the
    /// `FileProtection` object is kept alive.
    pub fn protect_file_from_delete(&self, path: &Path) -> FileProtection {
        let pathbuf = path.to_owned();
        {
            let mut meta_informations_wlock = self.meta_informations
                .write()
                .expect("Managed file lock poisoned on protect");
            *meta_informations_wlock
                .protected_files
                .entry(pathbuf.clone())
                .or_insert(0) += 1;
        }
        FileProtection {
            directory: self.clone(),
            path: pathbuf.clone(),
        }
    }

    /// Registers a file as managed
    ///
    /// This method must be called before the file is
    /// actually created to ensure that a failure between
    /// registering the filepath and creating the file
    /// will not lead to garbage files that will
    /// never get removed.
    fn register_file_as_managed(&mut self, filepath: &Path) -> io::Result<()> {
        let mut meta_wlock = self.meta_informations
                .write()
                .expect("Managed file lock poisoned");
        let has_changed = meta_wlock.managed_paths.insert(filepath.to_owned());
        if has_changed {
            save_managed_paths(self.directory.as_mut(), &meta_wlock)?;
        }
        Ok(())
    }
}

impl Directory for ManagedDirectory {

    fn open_read(&self, path: &Path) -> result::Result<ReadOnlySource, OpenReadError> {
        self.directory.open_read(path)
    }

    fn open_write(&mut self, path: &Path) -> result::Result<WritePtr, OpenWriteError> {
        self.register_file_as_managed(path)?;
        self.directory.open_write(path)
    }

    fn atomic_write(&mut self, path: &Path, data: &[u8]) -> io::Result<()> {
        self.register_file_as_managed(path)?;
        self.directory.atomic_write(path, data)
    }

    fn atomic_read(&self, path: &Path) -> result::Result<Vec<u8>, OpenReadError> {
        self.directory.atomic_read(path)
    }

    fn delete(&self, path: &Path) -> result::Result<(), DeleteError> {
        {
            let metas_rlock = self.meta_informations
                .read()
                .expect("poisoned lock in managed directory meta");
            if let Some(counter) = metas_rlock.protected_files.get(path) {
                if *counter > 0 {
                    return Err(DeleteError::FileProtected(path.to_owned()))
                }
            }
        }
        self.directory.delete(path)
    }

    fn exists(&self, path: &Path) -> bool {
        self.directory.exists(path)
    }

    fn box_clone(&self) -> Box<Directory> {
        box self.clone()
    }

}

impl Clone for ManagedDirectory {
    fn clone(&self) -> ManagedDirectory {
        ManagedDirectory {
            directory: self.directory.box_clone(),
            meta_informations: self.meta_informations.clone(),
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use directory::MmapDirectory;
    use std::path::Path;
    use std::io::Write;
    use tempdir::TempDir;

    lazy_static! {
        static ref TEST_PATH1: &'static Path = Path::new("some_path_for_test");
        static ref TEST_PATH2: &'static Path = Path::new("some_path_for_test2");
    }

    #[test]
    fn test_managed_directory() {
        let tempdir = TempDir::new("index").unwrap();
        let tempdir_path = PathBuf::from(tempdir.path());
        {
            let mmap_directory = MmapDirectory::open(&tempdir_path).unwrap();
            let mut managed_directory = ManagedDirectory::new(mmap_directory).unwrap();
            {
                let mut write_file = managed_directory.open_write(*TEST_PATH1).unwrap();
                write_file.flush().unwrap();
            }
            {
                managed_directory.atomic_write(*TEST_PATH2, &vec!(0u8,1u8)).unwrap();
            }
            {
                assert!(managed_directory.exists(*TEST_PATH1));
                assert!(managed_directory.exists(*TEST_PATH2));
            }
            {
                let living_files: HashSet<PathBuf> = [TEST_PATH1.to_owned()]
                    .into_iter()
                    .cloned()
                    .collect();
                managed_directory.garbage_collect(living_files);
            }
            {
                assert!(managed_directory.exists(*TEST_PATH1));
                assert!(!managed_directory.exists(*TEST_PATH2));
            }
        }
        {
            let mmap_directory = MmapDirectory::open(&tempdir_path).unwrap();
            let mut managed_directory = ManagedDirectory::new(mmap_directory).unwrap();
            {
                assert!(managed_directory.exists(*TEST_PATH1));
                assert!(!managed_directory.exists(*TEST_PATH2));
            }
            {
                let living_files: HashSet<PathBuf> = HashSet::new();
                managed_directory.garbage_collect(living_files);
            }
            {
                assert!(!managed_directory.exists(*TEST_PATH1));
                assert!(!managed_directory.exists(*TEST_PATH2));
            }
        }
    }

    #[test]
    fn test_managed_directory_gc_while_mmapped() {
        let tempdir = TempDir::new("index").unwrap();
        let tempdir_path = PathBuf::from(tempdir.path());
        let living_files = HashSet::new();

        let mmap_directory = MmapDirectory::open(&tempdir_path).unwrap();
        let mut managed_directory = ManagedDirectory::new(mmap_directory).unwrap();
        managed_directory.atomic_write(*TEST_PATH1, &vec!(0u8,1u8)).unwrap();
        assert!(managed_directory.exists(*TEST_PATH1));

        let _mmap_read = managed_directory.open_read(*TEST_PATH1).unwrap();
        managed_directory.garbage_collect(living_files.clone());
        if cfg!(target_os = "windows") {
            // On Windows, gc should try and fail the file as it is mmapped.
            assert!(managed_directory.exists(*TEST_PATH1));
            // unmap should happen here.
            drop(_mmap_read);
            // The file should still be in the list of managed file and
            // eventually be deleted once mmap is released.
            managed_directory.garbage_collect(living_files);
            assert!(!managed_directory.exists(*TEST_PATH1));
        }
        else {
            assert!(!managed_directory.exists(*TEST_PATH1));
        }

    }

    #[test]
    fn test_managed_directory_protect() {
        let tempdir = TempDir::new("index").unwrap();
        let tempdir_path = PathBuf::from(tempdir.path());
        let living_files = HashSet::new();

        let mmap_directory = MmapDirectory::open(&tempdir_path).unwrap();
        let mut managed_directory = ManagedDirectory::new(mmap_directory).unwrap();
        managed_directory.atomic_write(*TEST_PATH1, &vec!(0u8,1u8)).unwrap();
        assert!(managed_directory.exists(*TEST_PATH1));

        {
            let _file_protection = managed_directory.protect_file_from_delete(*TEST_PATH1);
            managed_directory.garbage_collect(living_files.clone());
            assert!(managed_directory.exists(*TEST_PATH1));
        }

        managed_directory.garbage_collect(living_files.clone());
        assert!(!managed_directory.exists(*TEST_PATH1));

    }

}
<commit_msg>Fixed logging deleted files twice<commit_after>use std::path::{Path, PathBuf};
use serde_json;
use directory::error::{OpenReadError, DeleteError, OpenWriteError};
use directory::{ReadOnlySource, WritePtr};
use std::result;
use std::io;
use Directory;
use std::sync::{Arc, RwLock};
use std::collections::HashSet;
use std::sync::RwLockWriteGuard;
use std::io::Write;
use core::MANAGED_FILEPATH;
use std::collections::HashMap;
use std::fmt;
use Result;
use Error;

/// Wrapper of directories that keeps track of files created by Tantivy.
///
/// A managed directory is just a wrapper of a directory
/// that keeps a (persisted) list of the files that
/// have been created (and not deleted) by tantivy so far.
///
/// Thanks to this list, it implements a `garbage_collect` method
/// that removes the files that were created by tantivy and are not
/// useful anymore.
#[derive(Debug)]
pub struct ManagedDirectory {
    directory: Box<Directory>,
    meta_informations: Arc<RwLock<MetaInformation>>,
}

#[derive(Debug, Default)]
struct MetaInformation {
    managed_paths: HashSet<PathBuf>,
    protected_files: HashMap<PathBuf, usize>,
}

/// A `FileProtection` prevents the garbage collection of a file.
///
/// See `ManagedDirectory.protect_file_from_delete`.
pub struct FileProtection {
    directory: ManagedDirectory,
    path: PathBuf,
}

fn unprotect_file_from_delete(directory: &ManagedDirectory, path: &Path) {
    let mut meta_informations_wlock = directory.meta_informations
        .write()
        .expect("Managed file lock poisoned");
    if let Some(counter_ref_mut) = meta_informations_wlock
        .protected_files
        .get_mut(path) {
        (*counter_ref_mut) -= 1;
    }
}

impl fmt::Debug for FileProtection {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        write!(formatter, "FileProtectionFor({:?})", self.path)
    }
}

impl Drop for FileProtection {
    fn drop(&mut self) {
        unprotect_file_from_delete(&self.directory, &*self.path);
    }
}

/// Saves the file containing the list of existing files
/// that were created by tantivy.
fn save_managed_paths(directory: &mut Directory, wlock: &RwLockWriteGuard<MetaInformation>) -> io::Result<()> {
    let mut w = serde_json::to_vec(&wlock.managed_paths)?;
    write!(&mut w, "\n")?;
    directory.atomic_write(&MANAGED_FILEPATH, &w[..])?;
    Ok(())
}

impl ManagedDirectory {

    /// Wraps a directory as managed directory.
    pub fn new<Dir: Directory>(directory: Dir) -> Result<ManagedDirectory> {
        match directory.atomic_read(&MANAGED_FILEPATH) {
            Ok(data) => {
                let managed_files_json = String::from_utf8_lossy(&data);
                let managed_files: HashSet<PathBuf> = serde_json::from_str(&managed_files_json)
                    .map_err(|e| Error::CorruptedFile(MANAGED_FILEPATH.clone(), Box::new(e)))?;
                Ok(ManagedDirectory {
                    directory: box directory,
                    meta_informations: Arc::new(RwLock::new(
                        MetaInformation {
                            managed_paths: managed_files,
                            protected_files: HashMap::default()
                        })),
                })
            }
            Err(OpenReadError::FileDoesNotExist(_)) => {
                Ok(ManagedDirectory {
                    directory: box directory,
                    meta_informations: Arc::default(),
                })
            }
            Err(OpenReadError::IOError(e)) => {
                Err(From::from(e))
            }
        }
    }

    /// Garbage collect unused files.
    ///
    /// Removes the files that were created by `tantivy` and are not
    /// used by any segment anymore.
    ///
    /// * `living_files` - List of files that are still used by the index.
    ///
    /// This method does not panick nor returns errors.
    /// If a file cannot be deleted (for permission reasons for instance)
    /// an error is simply logged, and the file remains in the list of managed
    /// files.
    pub fn garbage_collect(&mut self, living_files: HashSet<PathBuf>) {
        let mut files_to_delete = vec!();
        {   // releasing the lock as .delete() will use it too.
            let meta_informations_rlock = self.meta_informations
                .read()
                .expect("Managed directory rlock poisoned in garbage collect.");
            for managed_path in &meta_informations_rlock.managed_paths {
                if !living_files.contains(managed_path) {
                    files_to_delete.push(managed_path.clone());
                }
            }
        }

        let mut deleted_files = vec!();
        {
            for file_to_delete in files_to_delete {
                match self.delete(&file_to_delete) {
                    Ok(_) => {
                        info!("Deleted {:?}", file_to_delete);
                        deleted_files.push(file_to_delete);
                    }
                    Err(file_error) => {
                        match file_error {
                            DeleteError::FileDoesNotExist(_) => {
                                deleted_files.push(file_to_delete);
                            }
                            DeleteError::IOError(_) => {
                                if !cfg!(target_os = "windows") {
                                    // On windows, delete is expected to fail if the file
                                    // is mmapped.
                                    error!("Failed to delete {:?}", file_to_delete);
                                }
                            }
                            DeleteError::FileProtected(_) => {
                                // this is expected.
                            }
                        }

                    }
                }
            }
        }

        if !deleted_files.is_empty() {
            // update the list of managed files by removing
            // the file that were removed.
            let mut meta_informations_wlock = self.meta_informations
                .write()
                .expect("Managed directory wlock poisoned (2).");
            {
                let managed_paths_write = &mut meta_informations_wlock.managed_paths;
                for delete_file in &deleted_files {
                    managed_paths_write.remove(delete_file);
                }
            }
            if let Err(_) = save_managed_paths(self.directory.as_mut(), &meta_informations_wlock) {
                error!("Failed to save the list of managed files.");
            }
        }

    }

    /// Protects a file from being garbage collected.
    ///
    /// The method returns a `FileProtection` object.
    /// The file will not be garbage collected as long as the
    /// `FileProtection` object is kept alive.
    pub fn protect_file_from_delete(&self, path: &Path) -> FileProtection {
        let pathbuf = path.to_owned();
        {
            let mut meta_informations_wlock = self.meta_informations
                .write()
                .expect("Managed file lock poisoned on protect");
            *meta_informations_wlock
                .protected_files
                .entry(pathbuf.clone())
                .or_insert(0) += 1;
        }
        FileProtection {
            directory: self.clone(),
            path: pathbuf.clone(),
        }
    }

    /// Registers a file as managed
    ///
    /// This method must be called before the file is
    /// actually created to ensure that a failure between
    /// registering the filepath and creating the file
    /// will not lead to garbage files that will
    /// never get removed.
    fn register_file_as_managed(&mut self, filepath: &Path) -> io::Result<()> {
        let mut meta_wlock = self.meta_informations
                .write()
                .expect("Managed file lock poisoned");
        let has_changed = meta_wlock.managed_paths.insert(filepath.to_owned());
        if has_changed {
            save_managed_paths(self.directory.as_mut(), &meta_wlock)?;
        }
        Ok(())
    }
}

impl Directory for ManagedDirectory {

    fn open_read(&self, path: &Path) -> result::Result<ReadOnlySource, OpenReadError> {
        self.directory.open_read(path)
    }

    fn open_write(&mut self, path: &Path) -> result::Result<WritePtr, OpenWriteError> {
        self.register_file_as_managed(path)?;
        self.directory.open_write(path)
    }

    fn atomic_write(&mut self, path: &Path, data: &[u8]) -> io::Result<()> {
        self.register_file_as_managed(path)?;
        self.directory.atomic_write(path, data)
    }

    fn atomic_read(&self, path: &Path) -> result::Result<Vec<u8>, OpenReadError> {
        self.directory.atomic_read(path)
    }

    fn delete(&self, path: &Path) -> result::Result<(), DeleteError> {
        {
            let metas_rlock = self.meta_informations
                .read()
                .expect("poisoned lock in managed directory meta");
            if let Some(counter) = metas_rlock.protected_files.get(path) {
                if *counter > 0 {
                    return Err(DeleteError::FileProtected(path.to_owned()))
                }
            }
        }
        self.directory.delete(path)
    }

    fn exists(&self, path: &Path) -> bool {
        self.directory.exists(path)
    }

    fn box_clone(&self) -> Box<Directory> {
        box self.clone()
    }

}

impl Clone for ManagedDirectory {
    fn clone(&self) -> ManagedDirectory {
        ManagedDirectory {
            directory: self.directory.box_clone(),
            meta_informations: self.meta_informations.clone(),
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use directory::MmapDirectory;
    use std::path::Path;
    use std::io::Write;
    use tempdir::TempDir;

    lazy_static! {
        static ref TEST_PATH1: &'static Path = Path::new("some_path_for_test");
        static ref TEST_PATH2: &'static Path = Path::new("some_path_for_test2");
    }

    #[test]
    fn test_managed_directory() {
        let tempdir = TempDir::new("index").unwrap();
        let tempdir_path = PathBuf::from(tempdir.path());
        {
            let mmap_directory = MmapDirectory::open(&tempdir_path).unwrap();
            let mut managed_directory = ManagedDirectory::new(mmap_directory).unwrap();
            {
                let mut write_file = managed_directory.open_write(*TEST_PATH1).unwrap();
                write_file.flush().unwrap();
            }
            {
                managed_directory.atomic_write(*TEST_PATH2, &vec!(0u8,1u8)).unwrap();
            }
            {
                assert!(managed_directory.exists(*TEST_PATH1));
                assert!(managed_directory.exists(*TEST_PATH2));
            }
            {
                let living_files: HashSet<PathBuf> = [TEST_PATH1.to_owned()]
                    .into_iter()
                    .cloned()
                    .collect();
                managed_directory.garbage_collect(living_files);
            }
            {
                assert!(managed_directory.exists(*TEST_PATH1));
                assert!(!managed_directory.exists(*TEST_PATH2));
            }
        }
        {
            let mmap_directory = MmapDirectory::open(&tempdir_path).unwrap();
            let mut managed_directory = ManagedDirectory::new(mmap_directory).unwrap();
            {
                assert!(managed_directory.exists(*TEST_PATH1));
                assert!(!managed_directory.exists(*TEST_PATH2));
            }
            {
                let living_files: HashSet<PathBuf> = HashSet::new();
                managed_directory.garbage_collect(living_files);
            }
            {
                assert!(!managed_directory.exists(*TEST_PATH1));
                assert!(!managed_directory.exists(*TEST_PATH2));
            }
        }
    }

    #[test]
    fn test_managed_directory_gc_while_mmapped() {
        let tempdir = TempDir::new("index").unwrap();
        let tempdir_path = PathBuf::from(tempdir.path());
        let living_files = HashSet::new();

        let mmap_directory = MmapDirectory::open(&tempdir_path).unwrap();
        let mut managed_directory = ManagedDirectory::new(mmap_directory).unwrap();
        managed_directory.atomic_write(*TEST_PATH1, &vec!(0u8,1u8)).unwrap();
        assert!(managed_directory.exists(*TEST_PATH1));

        let _mmap_read = managed_directory.open_read(*TEST_PATH1).unwrap();
        managed_directory.garbage_collect(living_files.clone());
        if cfg!(target_os = "windows") {
            // On Windows, gc should try and fail the file as it is mmapped.
            assert!(managed_directory.exists(*TEST_PATH1));
            // unmap should happen here.
            drop(_mmap_read);
            // The file should still be in the list of managed file and
            // eventually be deleted once mmap is released.
            managed_directory.garbage_collect(living_files);
            assert!(!managed_directory.exists(*TEST_PATH1));
        }
        else {
            assert!(!managed_directory.exists(*TEST_PATH1));
        }

    }

    #[test]
    fn test_managed_directory_protect() {
        let tempdir = TempDir::new("index").unwrap();
        let tempdir_path = PathBuf::from(tempdir.path());
        let living_files = HashSet::new();

        let mmap_directory = MmapDirectory::open(&tempdir_path).unwrap();
        let mut managed_directory = ManagedDirectory::new(mmap_directory).unwrap();
        managed_directory.atomic_write(*TEST_PATH1, &vec!(0u8,1u8)).unwrap();
        assert!(managed_directory.exists(*TEST_PATH1));

        {
            let _file_protection = managed_directory.protect_file_from_delete(*TEST_PATH1);
            managed_directory.garbage_collect(living_files.clone());
            assert!(managed_directory.exists(*TEST_PATH1));
        }

        managed_directory.garbage_collect(living_files.clone());
        assert!(!managed_directory.exists(*TEST_PATH1));

    }

}
<|endoftext|>


<commit_before>#![crate_name = "bindgen"]
#![crate_type = "bin"]

extern crate bindgen;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate clang_sys;
extern crate rustc_serialize;

use bindgen::{Bindings, BindgenOptions, LinkType};
use std::default::Default;
use std::io;
use std::path;
use std::process;
use std::env;
use std::fs;

const USAGE: &'static str = "
Usage:
    bindgen [options] \
        [--link=<lib>...] \
        [--static-link=<lib>...] \
        [--framework-link=<framework>...] \
        [--raw-line=<raw>...] \
        [--opaque-type=<type>...] \
        [--blacklist-type=<type>...] \
        [--whitelist-type=<type>...] \
        [--whitelist-function=<name>...] \
        [--whitelist-var=<name>...] \
        <input-header> \
        [-- <clang-args>...]

    bindgen (-h | --help)

Options:
    -h, --help                    Display this help message.

    -l=<lib>, --link=<lib>        Link to a dynamic library, can be provided
                                  multiple times.

    --static-link=<lib>           Link to a static library, can be provided
                                  multiple times.

    --framework-link=<framework>  Link to a framework.

    -o=<output-rust-file>         Write bindings to <output-rust-file>
                                  (defaults to stdout)

    --builtins                    Output bindings for builtin definitions (for
                                  example __builtin_va_list)

    --ignore-functions            Don't generate bindings for functions and
                                  methods. This is useful when you only care
                                  about struct layouts.

    --ignore-methods              Avoid generating all kind of methods.

    --enable-cxx-namespaces       Enable support for C++ namespaces.

    --no-type-renaming            Don't rename types.

    --allow-unknown-types         Don't fail if we encounter types we do not
                                  support, instead treat them as void

    --emit-clang-ast              Output the ast (for debugging purposes)

    --use-msvc-mangling           Handle MSVC C++ ABI mangling; requires that
                                  target be set to (i686|x86_64)-pc-win32

    --raw-line=<raw>              Add a raw line at the beginning of the output.
    --no-unstable-rust            Avoid generating unstable rust.
    --no-bitfield-methods         Avoid generating methods for bitfield access.
    --opaque-type=<type>          Mark a type as opaque.
    --blacklist-type=<type>       Mark a type as hidden.
    --whitelist-type=<type>       Whitelist the type. If this set or any other
                                  of the whitelisting sets is not empty, then
                                  all the non-whitelisted types (or dependant)
                                  won't be generated.
    --whitelist-function=<regex>  Whitelist all the free-standing functions
                                  matching <regex>.  Same behavior on emptyness
                                  than the type whitelisting.
    --whitelist-var=<regex>       Whitelist all the free-standing variables
                                  matching <regex>.  Same behavior on emptyness
                                  than the type whitelisting.

    <clang-args>                  Options other than stated above are passed
                                  directly through to clang.
";

// FIXME(emilio): Replace this with docopt if/when they fix their exponential
// algorithm for argument parsing.
fn parse_args_or_exit(args: Vec<String>) -> (BindgenOptions, Box<io::Write>) {
    let mut options = BindgenOptions::default();
    let mut dest_file = None;
    let mut source_file = None;

    let mut iter = args.into_iter().skip(1);
    loop {
        let next = match iter.next() {
            Some(arg) => arg,
            _ => break,
        };

        match &*next {
            "-h" | "--help" => {
                println!("{}", USAGE);
                process::exit(0);
            }
            "-l" | "--link" => {
                let lib = iter.next().expect("--link needs an argument");
                options.links.push((lib, LinkType::Default));
            }
            "--static-link" => {
                let lib = iter.next().expect("--static-link needs an argument");
                options.links.push((lib, LinkType::Static));
            }
            "--framework-link" => {
                let lib = iter.next().expect("--framework-link needs an argument");
                options.links.push((lib, LinkType::Framework));
            }
            "--raw-line" => {
                let line = iter.next().expect("--raw-line needs an argument");
                options.raw_lines.push(line);
            }
            "--opaque-type" => {
                let ty_canonical_name = iter.next().expect("--opaque-type expects a type");
                options.opaque_types.insert(ty_canonical_name);
            }
            "--blacklist-type" => {
                let ty_canonical_name = iter.next().expect("--blacklist-type expects a type");
                options.hidden_types.insert(ty_canonical_name);
            }
            "--whitelist-type" => {
                let ty_pat = iter.next().expect("--whitelist-type expects a type pattern");
                options.whitelisted_types.insert(&ty_pat);
            }
            "--whitelist-function" => {
                let function_pat = iter.next().expect("--whitelist-function expects a pattern");
                options.whitelisted_functions.insert(&function_pat);
            }
            "--whitelist-var" => {
                let var_pat = iter.next().expect("--whitelist-var expects a pattern");
                options.whitelisted_vars.insert(&var_pat);
            }
            "--" => {
                while let Some(clang_arg) = iter.next() {
                    options.clang_args.push(clang_arg);
                }
            }
            "--output" | "-o" => {
                let out_name = iter.next().expect("-o expects a file name");
                dest_file = Some(out_name);
            }
            "--builtins" => {
                options.builtins = true;
            }
            "--ignore-functions" => {
                options.ignore_functions = true;
            }
            "--no-bitfield-methods" => {
                options.gen_bitfield_methods = false;
            }
            "--ignore-methods" => {
                options.ignore_methods = true;
            }
            "--enable-cxx-namespaces" => {
                options.enable_cxx_namespaces = true;
            }
            "--no-type-renaming" => {
                options.rename_types = false;
            }
            "--no-unstable-rust" => {
                options.unstable_rust = false;
            }
            "--emit-clang-ast" => {
                options.emit_ast = true;
            }
            "--use-msvc-mangling" => {
                options.msvc_mangling = true;
            }
            other if source_file.is_none() => {
                source_file = Some(other.into());
            }
            other => {
                panic!("Unknown option: \"{}\"", other);
            }
        }
    }

    if let Some(source_file) = source_file.take() {
        options.clang_args.push(source_file);
    }

    let out = if let Some(ref path_name) = dest_file {
        let path = path::Path::new(path_name);
        let file = fs::File::create(path).expect("Opening out file failed");
        Box::new(io::BufWriter::new(file)) as Box<io::Write>
    } else {
        Box::new(io::BufWriter::new(io::stdout())) as Box<io::Write>
    };

    (options, out)
}

pub fn main() {
    log::set_logger(|max_log_level| {
        use env_logger::Logger;
        let env_logger = Logger::new();
        max_log_level.set(env_logger.filter());
        Box::new(env_logger)
    }).expect("Failed to set logger.");

    let mut bind_args: Vec<_> = env::args().collect();

    if let Some(clang) = clang_sys::support::Clang::find(None) {
        let has_clang_args = bind_args.iter().rposition(|arg| *arg == "--").is_some();
        if !has_clang_args {
            bind_args.push("--".to_owned());
        }

        // If --target is specified, assume caller knows what they're doing and don't mess with
        // include paths for them
        let has_target_arg = bind_args.iter().rposition(|arg| arg.starts_with("--target")).is_some();
        if !has_target_arg {
            // TODO: distinguish C and C++ paths? C++'s should be enough, I guess.
            for path in clang.cpp_search_paths.into_iter() {
                if let Ok(path) = path.into_os_string().into_string() {
                    bind_args.push("-isystem".to_owned());
                    bind_args.push(path);
                }
            }
        }
    }

    let (options, out) = parse_args_or_exit(bind_args);

    let bindings = Bindings::generate(options, None)
                        .expect("Unable to generate bindings");

    bindings.write(out)
            .expect("Unable to write bindings to file.");
}
<commit_msg>Remove the --allow-unknown-types flag from USAGE<commit_after>#![crate_name = "bindgen"]
#![crate_type = "bin"]

extern crate bindgen;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate clang_sys;
extern crate rustc_serialize;

use bindgen::{Bindings, BindgenOptions, LinkType};
use std::default::Default;
use std::io;
use std::path;
use std::process;
use std::env;
use std::fs;

const USAGE: &'static str = "
Usage:
    bindgen [options] \
        [--link=<lib>...] \
        [--static-link=<lib>...] \
        [--framework-link=<framework>...] \
        [--raw-line=<raw>...] \
        [--opaque-type=<type>...] \
        [--blacklist-type=<type>...] \
        [--whitelist-type=<type>...] \
        [--whitelist-function=<name>...] \
        [--whitelist-var=<name>...] \
        <input-header> \
        [-- <clang-args>...]

    bindgen (-h | --help)

Options:
    -h, --help                    Display this help message.

    -l=<lib>, --link=<lib>        Link to a dynamic library, can be provided
                                  multiple times.

    --static-link=<lib>           Link to a static library, can be provided
                                  multiple times.

    --framework-link=<framework>  Link to a framework.

    -o=<output-rust-file>         Write bindings to <output-rust-file>
                                  (defaults to stdout)

    --builtins                    Output bindings for builtin definitions (for
                                  example __builtin_va_list)

    --ignore-functions            Don't generate bindings for functions and
                                  methods. This is useful when you only care
                                  about struct layouts.

    --ignore-methods              Avoid generating all kind of methods.

    --enable-cxx-namespaces       Enable support for C++ namespaces.

    --no-type-renaming            Don't rename types.

    --emit-clang-ast              Output the ast (for debugging purposes)

    --use-msvc-mangling           Handle MSVC C++ ABI mangling; requires that
                                  target be set to (i686|x86_64)-pc-win32

    --raw-line=<raw>              Add a raw line at the beginning of the output.
    --no-unstable-rust            Avoid generating unstable rust.
    --no-bitfield-methods         Avoid generating methods for bitfield access.
    --opaque-type=<type>          Mark a type as opaque.
    --blacklist-type=<type>       Mark a type as hidden.
    --whitelist-type=<type>       Whitelist the type. If this set or any other
                                  of the whitelisting sets is not empty, then
                                  all the non-whitelisted types (or dependant)
                                  won't be generated.
    --whitelist-function=<regex>  Whitelist all the free-standing functions
                                  matching <regex>.  Same behavior on emptyness
                                  than the type whitelisting.
    --whitelist-var=<regex>       Whitelist all the free-standing variables
                                  matching <regex>.  Same behavior on emptyness
                                  than the type whitelisting.

    <clang-args>                  Options other than stated above are passed
                                  directly through to clang.
";

// FIXME(emilio): Replace this with docopt if/when they fix their exponential
// algorithm for argument parsing.
fn parse_args_or_exit(args: Vec<String>) -> (BindgenOptions, Box<io::Write>) {
    let mut options = BindgenOptions::default();
    let mut dest_file = None;
    let mut source_file = None;

    let mut iter = args.into_iter().skip(1);
    loop {
        let next = match iter.next() {
            Some(arg) => arg,
            _ => break,
        };

        match &*next {
            "-h" | "--help" => {
                println!("{}", USAGE);
                process::exit(0);
            }
            "-l" | "--link" => {
                let lib = iter.next().expect("--link needs an argument");
                options.links.push((lib, LinkType::Default));
            }
            "--static-link" => {
                let lib = iter.next().expect("--static-link needs an argument");
                options.links.push((lib, LinkType::Static));
            }
            "--framework-link" => {
                let lib = iter.next().expect("--framework-link needs an argument");
                options.links.push((lib, LinkType::Framework));
            }
            "--raw-line" => {
                let line = iter.next().expect("--raw-line needs an argument");
                options.raw_lines.push(line);
            }
            "--opaque-type" => {
                let ty_canonical_name = iter.next().expect("--opaque-type expects a type");
                options.opaque_types.insert(ty_canonical_name);
            }
            "--blacklist-type" => {
                let ty_canonical_name = iter.next().expect("--blacklist-type expects a type");
                options.hidden_types.insert(ty_canonical_name);
            }
            "--whitelist-type" => {
                let ty_pat = iter.next().expect("--whitelist-type expects a type pattern");
                options.whitelisted_types.insert(&ty_pat);
            }
            "--whitelist-function" => {
                let function_pat = iter.next().expect("--whitelist-function expects a pattern");
                options.whitelisted_functions.insert(&function_pat);
            }
            "--whitelist-var" => {
                let var_pat = iter.next().expect("--whitelist-var expects a pattern");
                options.whitelisted_vars.insert(&var_pat);
            }
            "--" => {
                while let Some(clang_arg) = iter.next() {
                    options.clang_args.push(clang_arg);
                }
            }
            "--output" | "-o" => {
                let out_name = iter.next().expect("-o expects a file name");
                dest_file = Some(out_name);
            }
            "--builtins" => {
                options.builtins = true;
            }
            "--ignore-functions" => {
                options.ignore_functions = true;
            }
            "--no-bitfield-methods" => {
                options.gen_bitfield_methods = false;
            }
            "--ignore-methods" => {
                options.ignore_methods = true;
            }
            "--enable-cxx-namespaces" => {
                options.enable_cxx_namespaces = true;
            }
            "--no-type-renaming" => {
                options.rename_types = false;
            }
            "--no-unstable-rust" => {
                options.unstable_rust = false;
            }
            "--emit-clang-ast" => {
                options.emit_ast = true;
            }
            "--use-msvc-mangling" => {
                options.msvc_mangling = true;
            }
            other if source_file.is_none() => {
                source_file = Some(other.into());
            }
            other => {
                panic!("Unknown option: \"{}\"", other);
            }
        }
    }

    if let Some(source_file) = source_file.take() {
        options.clang_args.push(source_file);
    }

    let out = if let Some(ref path_name) = dest_file {
        let path = path::Path::new(path_name);
        let file = fs::File::create(path).expect("Opening out file failed");
        Box::new(io::BufWriter::new(file)) as Box<io::Write>
    } else {
        Box::new(io::BufWriter::new(io::stdout())) as Box<io::Write>
    };

    (options, out)
}

pub fn main() {
    log::set_logger(|max_log_level| {
        use env_logger::Logger;
        let env_logger = Logger::new();
        max_log_level.set(env_logger.filter());
        Box::new(env_logger)
    }).expect("Failed to set logger.");

    let mut bind_args: Vec<_> = env::args().collect();

    if let Some(clang) = clang_sys::support::Clang::find(None) {
        let has_clang_args = bind_args.iter().rposition(|arg| *arg == "--").is_some();
        if !has_clang_args {
            bind_args.push("--".to_owned());
        }

        // If --target is specified, assume caller knows what they're doing and don't mess with
        // include paths for them
        let has_target_arg = bind_args.iter().rposition(|arg| arg.starts_with("--target")).is_some();
        if !has_target_arg {
            // TODO: distinguish C and C++ paths? C++'s should be enough, I guess.
            for path in clang.cpp_search_paths.into_iter() {
                if let Ok(path) = path.into_os_string().into_string() {
                    bind_args.push("-isystem".to_owned());
                    bind_args.push(path);
                }
            }
        }
    }

    let (options, out) = parse_args_or_exit(bind_args);

    let bindings = Bindings::generate(options, None)
                        .expect("Unable to generate bindings");

    bindings.write(out)
            .expect("Unable to write bindings to file.");
}
<|endoftext|>


<commit_before>pub static AGENT_VERSION: &'static str = "7d719c2";
<commit_msg>Bump agent<commit_after>pub static AGENT_VERSION: &'static str = "6c49a19";
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::ops;
use std::str;

use bytes::Bytes;
use std::fmt;

#[derive(Debug)]
pub struct AsciiError(());

/// Bytes wrapper that guarantees that contained bytes are ASCII.
#[derive(Eq, PartialEq, Hash, Clone)]
pub struct Ascii(Bytes);

impl Ascii {
    pub fn new() -> Ascii {
        Ascii(Bytes::new())
    }

    pub fn from_bytes(bs: Bytes) -> Result<Ascii, (AsciiError, Bytes)> {
        for &b in &bs {
            if b > i8::max_value() as u8 {
                return Err((AsciiError(()), bs));
            }
        }
        Ok(Ascii(bs))
    }

    pub fn as_str(&self) -> &str {
        unsafe { str::from_utf8_unchecked(self.0.as_ref()) }
    }
}

impl ops::Deref for Ascii {
    type Target = str;

    fn deref(&self) -> &str {
        unsafe { str::from_utf8_unchecked(&self.0) }
    }
}

impl fmt::Debug for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.as_str(), f)
    }
}

pub struct AsciiLower(Ascii);

impl AsciiLower {
    pub fn new() -> AsciiLower {
        AsciiLower(Ascii::new())
    }
}

impl ops::Deref for AsciiLower {
    type Target = str;

    fn deref(&self) -> &str {
        self.0.deref()
    }
}

impl<'a> From<&'a str> for AsciiLower {
    fn from(_s: &'a str) -> AsciiLower {
        unimplemented!()
    }
}

#[cfg(test)]
mod test {
    use crate::ascii::Ascii;
    use bytes::Bytes;

    #[test]
    fn from_utf8() {
        assert!(Ascii::from_bytes(Bytes::from_static("ю".as_bytes())).is_err());
    }
}
<commit_msg>Fix test name<commit_after>#![allow(dead_code)]

use std::ops;
use std::str;

use bytes::Bytes;
use std::fmt;

#[derive(Debug)]
pub struct AsciiError(());

/// Bytes wrapper that guarantees that contained bytes are ASCII.
#[derive(Eq, PartialEq, Hash, Clone)]
pub struct Ascii(Bytes);

impl Ascii {
    pub fn new() -> Ascii {
        Ascii(Bytes::new())
    }

    pub fn from_bytes(bs: Bytes) -> Result<Ascii, (AsciiError, Bytes)> {
        for &b in &bs {
            if b > i8::max_value() as u8 {
                return Err((AsciiError(()), bs));
            }
        }
        Ok(Ascii(bs))
    }

    pub fn as_str(&self) -> &str {
        unsafe { str::from_utf8_unchecked(self.0.as_ref()) }
    }
}

impl ops::Deref for Ascii {
    type Target = str;

    fn deref(&self) -> &str {
        unsafe { str::from_utf8_unchecked(&self.0) }
    }
}

impl fmt::Debug for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.as_str(), f)
    }
}

pub struct AsciiLower(Ascii);

impl AsciiLower {
    pub fn new() -> AsciiLower {
        AsciiLower(Ascii::new())
    }
}

impl ops::Deref for AsciiLower {
    type Target = str;

    fn deref(&self) -> &str {
        self.0.deref()
    }
}

impl<'a> From<&'a str> for AsciiLower {
    fn from(_s: &'a str) -> AsciiLower {
        unimplemented!()
    }
}

#[cfg(test)]
mod test {
    use crate::ascii::Ascii;
    use bytes::Bytes;

    #[test]
    fn ascii_from_bytes() {
        assert!(Ascii::from_bytes(Bytes::from_static("ю".as_bytes())).is_err());
    }
}
<|endoftext|>