<commit_before>//! File locking via POSIX advisory record locks.
//!
//! This crate provides the facility to lock and unlock a file following the
//! advisory record lock scheme as specified by UNIX IEEE Std 1003.1-2001
//! (POSIX.1) via `fcntl()`.
//!
//! # Examples
//!
//! ```
//! extern crate file_lock;
//!
//! use file_lock::*;
//! use file_lock::Error::*;
//!
//! fn main() {
//!     let l = lock("/tmp/file-lock-test");
//!
//!     match l {
//!         Ok(_)  => println!("Got lock"),
//!         Err(e) => match e {
//!             InvalidFilename => println!("Invalid filename"),
//!             Errno(i)        => println!("Got filesystem error {}", i),
//!         }
//!     }
//! }
//! ```

extern crate libc;

use std::ffi::CString;

/// Represents a lock on a file.
#[derive(Debug, Eq, PartialEq)]
pub struct Lock {
  _fd: i32,
}

/// Represents the error that occurred while trying to lock or unlock a file.
#[derive(Debug, Eq, PartialEq)]
pub enum Error {
  /// caused when the filename is invalid as it contains a null byte.
  InvalidFilename,
  /// caused when the error occurred at the filesystem layer (see
  /// [errno](https://crates.io/crates/errno)).
  Errno(i32),
}

#[repr(C)]
struct c_result {
  _fd:    i32,
  _errno: i32,
}

macro_rules! _create_lock_type {
  ($lock_type:ident, $c_lock_type:ident) => {
    extern {
        fn $c_lock_type(filename: *const libc::c_char) -> c_result;
    }

    /// Locks the specified file.
    ///
    /// The `lock()` and `lock_wait()` functions try to perform a lock on the
    /// specified file. The difference between the two is what they do when
    /// another process has a lock on the same file:
    ///
    /// * lock() - immediately return with an `Errno` error.
    /// * lock_wait() - waits (i.e. blocks the running thread) for the current
    /// owner of the lock to relinquish the lock.
    ///
    /// # Example
    ///
    /// ```
    /// extern crate file_lock;
    ///
    /// use file_lock::*;
    /// use file_lock::Error::*;
    ///
    /// fn main() {
    ///     let l = lock("/tmp/file-lock-test");
    ///
    ///     match l {
    ///         Ok(_)  => println!("Got lock"),
    ///         Err(e) => match e {
    ///             InvalidFilename => println!("Invalid filename"),
    ///             Errno(i)        => println!("Got filesystem error {}", i),
    ///         }
    ///     }
    /// }
    /// ```
    pub fn $lock_type(filename: &str) -> Result<Lock, Error> {
        match CString::new(filename) {
            Err(_) => Err(Error::InvalidFilename),
            Ok(raw_filename) => {
                let my_result = unsafe { $c_lock_type(raw_filename.as_ptr()) };

                return match my_result._errno {
                   0 => Ok(Lock{_fd: my_result._fd}),
                   _ => Err(Error::Errno(my_result._errno)),
                }
            }
        }
    }
  };
}

_create_lock_type!(lock, c_lock);
_create_lock_type!(lock_wait, c_lock_wait);

extern {
  fn c_unlock(_fd: i32) -> c_result;
}

/// Unlocks the file held by `Lock`.
///
/// In reality, you shouldn't need to call `unlock()`. As `Lock` implements
/// the `Drop` trait, once the `Lock` reference goes out of scope, `unlock()`
/// will be called automatically.
///
/// # Example
///
/// ```
/// extern crate file_lock;
///
/// use file_lock::*;
///
/// fn main() {
///     let l = lock("/tmp/file-lock-test").unwrap();
///
///     if unlock(&l).is_ok() {
///         println!("Unlocked!");
///     }
/// }
/// ```
pub fn unlock(lock: &Lock) -> Result<(), Error> {
  unsafe {
    let my_result = c_unlock(lock._fd);

    return match my_result._errno {
       0 => Ok(()),
       _ => Err(Error::Errno(my_result._errno)),
    }
  }
}

#[allow(unused_must_use)]
impl Drop for Lock {
  fn drop(&mut self) {
    unlock(self);
  }
}

#[cfg(test)]
mod test {
    use libc;

    use super::*;
    use super::Error::*;

    //
    // unfortunately we can't abstract this out for lock() and lock_wait()
    // into a macro because string concat doesn't exist
    //

    // lock_wait() tests

    #[test]
    fn lock_invalid_filename() {
        assert_eq!(lock("null\0inside"), Err(Error::InvalidFilename));
    }

    #[test]
    fn lock_errno() {
        assert_eq!(lock(""), Err(Error::Errno(libc::consts::os::posix88::ENOENT)));
    }

    #[test]
    fn lock_ok() {
        assert!(lock("/tmp/file-lock-test").is_ok());
    }

    // lock_wait() tests

    #[test]
    fn lock_wait_invalid_filename() {
        assert_eq!(lock_wait("null\0inside"), Err(Error::InvalidFilename));
    }

    #[test]
    fn lock_wait_errno() {
        assert_eq!(lock_wait(""), Err(Error::Errno(libc::consts::os::posix88::ENOENT)));
    }

    #[test]
    fn lock_wait_ok() {
        assert!(lock_wait("/tmp/file-lock-test").is_ok());
    }

    // unlock()

    // fcntl() will only allow us to hold a single lock on a file at a time
    // so this test can't work :(

    #[test]
    #[should_panic]
    fn unlock_error() {
        let l1 = lock("/tmp/file-lock-test");
        let l2 = lock("/tmp/file-lock-test");

        assert!(l1.is_ok());
        assert!(l2.is_err());
    }

    #[test]
    fn unlock_ok() {
        let l        = lock_wait("/tmp/file-lock-test");
        let unlocked = l.unwrap();

        assert!(unlock(&unlocked).is_ok(), true);
    }
}
<commit_msg>refactor(lock): use RawFd type<commit_after>//! File locking via POSIX advisory record locks.
//!
//! This crate provides the facility to lock and unlock a file following the
//! advisory record lock scheme as specified by UNIX IEEE Std 1003.1-2001
//! (POSIX.1) via `fcntl()`.
//!
//! # Examples
//!
//! ```
//! extern crate file_lock;
//!
//! use file_lock::*;
//! use file_lock::Error::*;
//!
//! fn main() {
//!     let l = lock("/tmp/file-lock-test");
//!
//!     match l {
//!         Ok(_)  => println!("Got lock"),
//!         Err(e) => match e {
//!             InvalidFilename => println!("Invalid filename"),
//!             Errno(i)        => println!("Got filesystem error {}", i),
//!         }
//!     }
//! }
//! ```

extern crate libc;

use std::ffi::CString;
use std::os::unix::io::RawFd;

/// Represents a lock on a file.
#[derive(Debug, Eq, PartialEq)]
pub struct Lock {
  _fd: RawFd,
}

/// Represents the error that occurred while trying to lock or unlock a file.
#[derive(Debug, Eq, PartialEq)]
pub enum Error {
  /// caused when the filename is invalid as it contains a null byte.
  InvalidFilename,
  /// caused when the error occurred at the filesystem layer (see
  /// [errno](https://crates.io/crates/errno)).
  Errno(i32),
}

#[repr(C)]
struct c_result {
  _fd:    RawFd,
  _errno: i32,
}

macro_rules! _create_lock_type {
  ($lock_type:ident, $c_lock_type:ident) => {
    extern {
        fn $c_lock_type(filename: *const libc::c_char) -> c_result;
    }

    /// Locks the specified file.
    ///
    /// The `lock()` and `lock_wait()` functions try to perform a lock on the
    /// specified file. The difference between the two is what they do when
    /// another process has a lock on the same file:
    ///
    /// * lock() - immediately return with an `Errno` error.
    /// * lock_wait() - waits (i.e. blocks the running thread) for the current
    /// owner of the lock to relinquish the lock.
    ///
    /// # Example
    ///
    /// ```
    /// extern crate file_lock;
    ///
    /// use file_lock::*;
    /// use file_lock::Error::*;
    ///
    /// fn main() {
    ///     let l = lock("/tmp/file-lock-test");
    ///
    ///     match l {
    ///         Ok(_)  => println!("Got lock"),
    ///         Err(e) => match e {
    ///             InvalidFilename => println!("Invalid filename"),
    ///             Errno(i)        => println!("Got filesystem error {}", i),
    ///         }
    ///     }
    /// }
    /// ```
    pub fn $lock_type(filename: &str) -> Result<Lock, Error> {
        match CString::new(filename) {
            Err(_) => Err(Error::InvalidFilename),
            Ok(raw_filename) => {
                let my_result = unsafe { $c_lock_type(raw_filename.as_ptr()) };

                return match my_result._errno {
                   0 => Ok(Lock{_fd: my_result._fd}),
                   _ => Err(Error::Errno(my_result._errno)),
                }
            }
        }
    }
  };
}

_create_lock_type!(lock, c_lock);
_create_lock_type!(lock_wait, c_lock_wait);

extern {
  fn c_unlock(_fd: i32) -> c_result;
}

/// Unlocks the file held by `Lock`.
///
/// In reality, you shouldn't need to call `unlock()`. As `Lock` implements
/// the `Drop` trait, once the `Lock` reference goes out of scope, `unlock()`
/// will be called automatically.
///
/// # Example
///
/// ```
/// extern crate file_lock;
///
/// use file_lock::*;
///
/// fn main() {
///     let l = lock("/tmp/file-lock-test").unwrap();
///
///     if unlock(&l).is_ok() {
///         println!("Unlocked!");
///     }
/// }
/// ```
pub fn unlock(lock: &Lock) -> Result<(), Error> {
  unsafe {
    let my_result = c_unlock(lock._fd);

    return match my_result._errno {
       0 => Ok(()),
       _ => Err(Error::Errno(my_result._errno)),
    }
  }
}

#[allow(unused_must_use)]
impl Drop for Lock {
  fn drop(&mut self) {
    unlock(self);
  }
}

#[cfg(test)]
mod test {
    use libc;

    use super::*;
    use super::Error::*;

    //
    // unfortunately we can't abstract this out for lock() and lock_wait()
    // into a macro because string concat doesn't exist
    //

    // lock_wait() tests

    #[test]
    fn lock_invalid_filename() {
        assert_eq!(lock("null\0inside"), Err(Error::InvalidFilename));
    }

    #[test]
    fn lock_errno() {
        assert_eq!(lock(""), Err(Error::Errno(libc::consts::os::posix88::ENOENT)));
    }

    #[test]
    fn lock_ok() {
        assert!(lock("/tmp/file-lock-test").is_ok());
    }

    // lock_wait() tests

    #[test]
    fn lock_wait_invalid_filename() {
        assert_eq!(lock_wait("null\0inside"), Err(Error::InvalidFilename));
    }

    #[test]
    fn lock_wait_errno() {
        assert_eq!(lock_wait(""), Err(Error::Errno(libc::consts::os::posix88::ENOENT)));
    }

    #[test]
    fn lock_wait_ok() {
        assert!(lock_wait("/tmp/file-lock-test").is_ok());
    }

    // unlock()

    // fcntl() will only allow us to hold a single lock on a file at a time
    // so this test can't work :(

    #[test]
    #[should_panic]
    fn unlock_error() {
        let l1 = lock("/tmp/file-lock-test");
        let l2 = lock("/tmp/file-lock-test");

        assert!(l1.is_ok());
        assert!(l2.is_err());
    }

    #[test]
    fn unlock_ok() {
        let l        = lock_wait("/tmp/file-lock-test");
        let unlocked = l.unwrap();

        assert!(unlock(&unlocked).is_ok(), true);
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(phf_macros)]

#[macro_use]
extern crate phf;

mod tld;

pub use tld::TLD;

pub fn exist(s: &str) -> bool {
    TLD.contains_key(s)
}

#[test]
fn test_tld() {
    use tld::TLD;
    assert!(TLD.get("aaa").is_some());
    assert!(TLD.get("#33dawaaa").is_none());
    assert!(TLD.get("aco").is_some());
    assert!(TLD.get("uk").is_some());
    assert!(TLD.get("ye").is_some());
    assert!(TLD.get("com").is_some());
    assert!(TLD.get("de").is_some());
    assert!(TLD.get("fr").is_some());
    assert!(TLD.get("ag").is_some());
    assert!(TLD.get("ru").is_some());
    assert!(TLD.get("nl").is_some());
    assert!(TLD.get("lt").is_some());
    assert!(TLD.get("amex").is_some());
    assert!(TLD.get("zw").is_some());
}

#[test]
fn test_exist() {
    assert!(exist("fr"));
    assert!(exist("de"));
    assert!(exist("zw"));
    assert!(!exist("a9292zw"));
}
<commit_msg>Remove unused macro_use<commit_after>#![feature(plugin)]
#![plugin(phf_macros)]

extern crate phf;

mod tld;

pub use tld::TLD;

pub fn exist(s: &str) -> bool {
    TLD.contains_key(s)
}

#[test]
fn test_tld() {
    use tld::TLD;
    assert!(TLD.get("aaa").is_some());
    assert!(TLD.get("#33dawaaa").is_none());
    assert!(TLD.get("aco").is_some());
    assert!(TLD.get("uk").is_some());
    assert!(TLD.get("ye").is_some());
    assert!(TLD.get("com").is_some());
    assert!(TLD.get("de").is_some());
    assert!(TLD.get("fr").is_some());
    assert!(TLD.get("ag").is_some());
    assert!(TLD.get("ru").is_some());
    assert!(TLD.get("nl").is_some());
    assert!(TLD.get("lt").is_some());
    assert!(TLD.get("amex").is_some());
    assert!(TLD.get("zw").is_some());
}

#[test]
fn test_exist() {
    assert!(exist("fr"));
    assert!(exist("de"));
    assert!(exist("zw"));
    assert!(!exist("a9292zw"));
}
<|endoftext|>


<commit_before>#![feature(core, os, fs, std_misc, unsafe_destructor, io)]

use std::fs::File;
use std::os::{MemoryMap, MapOption};
use std::os::unix::AsRawFd;
use std::mem;
use std::slice;
use std::marker;
use std::num::Int;
use std::io::{Result, Error, ErrorKind};

/**
 * Maps a file into memory and represents this memory
 * as a read-only Rust slice.
 */
pub struct MmapSlice<T:Sized> {
    /// Underlying file
    file: File,

    /// The mmap handle
    mmap: MemoryMap,

    /// Number of elements of type `T`
    nelems: usize,

    ///
    marker: marker::PhantomData<T>,
}

fn other_io_error(description: &'static str) -> Error {
    Error::new(ErrorKind::Other, description, None)
}

impl<T:Sized> MmapSlice<T> {
    /**
     * Creates a MmapSlice. Maps `nelems` of type `T`.
     */
    pub fn new(file: File, nelems: usize) -> Result<MmapSlice<T>> {
        match nelems.checked_mul(mem::size_of::<T>()) {
            Some(map_len) => {
                let meta = try!(file.metadata());
                if map_len as u64 > meta.len() {
                    return Err(other_io_error("File too small to mmap"))
                }
                let opts = [MapOption::MapReadable,
                            MapOption::MapFd(file.as_raw_fd())];
                let map = try!(MemoryMap::new(map_len, &opts).map_err(|_| other_io_error("Mmap error")));
                if map.len() > 0 && map.len() >= map_len {
                    Ok(MmapSlice {
                        file:   file,
                        mmap:   map,
                        nelems: nelems,
                        marker: marker::PhantomData
                    })
                }
                else {
                    Err(other_io_error("Mmaped region too small"))
                }
            }
            None => {
                Err(other_io_error("Size overflow"))
            }
        }
    }
}

impl<T:Sized> AsSlice<T> for MmapSlice<T> {
    fn as_slice<'a>(&'a self) -> &'a [T] {
         unsafe {
             slice::from_raw_parts(self.mmap.data() as *const T, self.nelems)
         }
    }
}

// FIXME: Do we really need our custom Drop?
#[unsafe_destructor]
impl<T:Sized> Drop for MmapSlice<T> {
    fn drop(&mut self) {
        drop(&mut self.mmap);
        drop(&mut self.file);
    }
}
<commit_msg>Update for new version of Rust<commit_after>#![feature(core, os, unsafe_destructor, io, io_ext)]

use std::fs::File;
use std::os::{MemoryMap, MapOption};
use std::os::unix::io::AsRawFd;
use std::mem;
use std::slice;
use std::marker;
use std::num::Int;
use std::io::{Result, Error, ErrorKind};

/**
 * Maps a file into memory and represents this memory
 * as a read-only Rust slice.
 */
pub struct MmapSlice<T:Sized> {
    /// Underlying file
    file: File,

    /// The mmap handle
    mmap: MemoryMap,

    /// Number of elements of type `T`
    nelems: usize,

    ///
    marker: marker::PhantomData<T>,
}

fn other_io_error(description: &'static str) -> Error {
    Error::new(ErrorKind::Other, description, None)
}

impl<T:Sized> MmapSlice<T> {
    /**
     * Creates a MmapSlice. Maps `nelems` of type `T`.
     */
    pub fn new(file: File, nelems: usize) -> Result<MmapSlice<T>> {
        match nelems.checked_mul(mem::size_of::<T>()) {
            Some(map_len) => {
                let meta = try!(file.metadata());
                if map_len as u64 > meta.len() {
                    return Err(other_io_error("File too small to mmap"))
                }
                let opts = [MapOption::MapReadable,
                            MapOption::MapFd(file.as_raw_fd())];
                let map = try!(MemoryMap::new(map_len, &opts).map_err(|_| other_io_error("Mmap error")));
                if map.len() > 0 && map.len() >= map_len {
                    Ok(MmapSlice {
                        file:   file,
                        mmap:   map,
                        nelems: nelems,
                        marker: marker::PhantomData
                    })
                }
                else {
                    Err(other_io_error("Mmaped region too small"))
                }
            }
            None => {
                Err(other_io_error("Size overflow"))
            }
        }
    }
}

impl<T:Sized> AsSlice<T> for MmapSlice<T> {
    fn as_slice<'a>(&'a self) -> &'a [T] {
         unsafe {
             slice::from_raw_parts(self.mmap.data() as *const T, self.nelems)
         }
    }
}

// FIXME: Do we really need our custom Drop?
#[unsafe_destructor]
impl<T:Sized> Drop for MmapSlice<T> {
    fn drop(&mut self) {
        drop(&mut self.mmap);
        drop(&mut self.file);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

mod assembler;
mod parser;
mod tokens;
<commit_msg>export assembler module<commit_after>#[macro_use]
extern crate nom;

pub mod assembler;
mod parser;
mod tokens;
<|endoftext|>


<commit_before>//! Test harness for Exonum blockchain framework, allowing to test service APIs synchronously
//! and in the same process as the harness.

#![deny(missing_docs)]

extern crate exonum;
extern crate futures;
extern crate mount;
extern crate iron;
extern crate iron_test;
extern crate serde;
extern crate serde_json;

use std::collections::BTreeMap;

use exonum::blockchain::{ApiContext, Blockchain, Service, Transaction, GenesisConfig,
                         SharedNodeState};
use exonum::crypto;
// A bit hacky, `exonum::events` is hidden from docs.
use exonum::events::{Event as ExonumEvent, EventHandler};
use exonum::node::{ApiSender, NodeChannel, NodeHandler, Configuration, ListenerConfig,
                   ServiceConfig, DefaultSystemState, State as NodeState};
use exonum::storage::MemoryDB;
use futures::Stream;
use futures::executor;
use iron::headers::{Headers, ContentType};
use iron_test::{request, response};
use mount::Mount;
use serde::{Serialize, Deserialize};

mod greedy_fold;
#[doc(hidden)]
pub use greedy_fold::GreedilyFoldable;

const STATE_UPDATE_TIMEOUT: u64 = 10_000;

/// Harness for testing blockchain with a single-node, no-network setup.
pub struct TestHarness {
    handler: NodeHandler,
    channel: NodeChannel,
    api_context: ApiContext,
}

impl TestHarness {
    /// Initializes a harness with a blockchain and no service-specific configuration.
    pub fn new(blockchain: Blockchain) -> Self {
        TestHarness::with_config(blockchain, BTreeMap::new())
    }

    /// Initializes a harness with a blockchain that hosts a given set of services.
    /// The blockchain uses `MemoryDB` for storage.
    pub fn with_services<I>(services: I) -> Self
    where
        I: IntoIterator<Item = Box<Service>>,
    {
        let db = MemoryDB::new();
        let blockchain = Blockchain::new(Box::new(db), services.into_iter().collect());
        TestHarness::new(blockchain)
    }

    /// Initializes a harness with a blockchain and a service-specific configuration.
    pub fn with_config(
        mut blockchain: Blockchain,
        _services_configs: BTreeMap<String, serde_json::Value>,
    ) -> Self {
        crypto::init();

        let (consensus_public_key, consensus_secret_key) = crypto::gen_keypair();
        let (service_public_key, service_secret_key) = crypto::gen_keypair();

        let validator_keys = exonum::blockchain::config::ValidatorKeys {
            consensus_key: consensus_public_key,
            service_key: service_public_key,
        };
        let genesis = GenesisConfig::new(vec![validator_keys].into_iter());

        blockchain.create_genesis_block(genesis.clone()).unwrap();

        let listen_address = "0.0.0.0:2000".parse().unwrap();
        let config = Configuration {
            listener: ListenerConfig {
                consensus_public_key,
                consensus_secret_key: consensus_secret_key.clone(),
                whitelist: Default::default(),
                address: listen_address,
            },
            service: ServiceConfig {
                service_public_key,
                service_secret_key: service_secret_key.clone(),
            },
            mempool: Default::default(),
            network: Default::default(),
            peer_discovery: vec![],
        };

        let api_state = SharedNodeState::new(STATE_UPDATE_TIMEOUT);
        let system_state = Box::new(DefaultSystemState(listen_address));
        let channel = NodeChannel::new(Default::default());
        let api_sender = ApiSender::new(channel.api_requests.0.clone());

        let api_context = ApiContext::from_parts(
            &blockchain,
            api_sender,
            &service_public_key,
            &service_secret_key,
        );

        let handler = NodeHandler::new(
            blockchain,
            listen_address,
            channel.node_sender(),
            system_state,
            config,
            api_state,
        );

        TestHarness {
            handler,
            channel,
            api_context,
        }
    }

    /// Returns the node state of the harness.
    pub fn state(&self) -> &NodeState {
        self.handler.state()
    }

    /// Creates a mounting point for public APIs used by the blockchain.
    // TODO: consider making public
    fn public_api_mount(&self) -> Mount {
        self.api_context.mount_public_api()
    }

    /// Creates a mounting point for public APIs used by the blockchain.
    // TODO: consider making public
    fn private_api_mount(&self) -> Mount {
        self.api_context.mount_private_api()
    }

    /// Creates an instance of `HarnessApi` to test the API provided by services.
    pub fn api(&self) -> HarnessApi {
        HarnessApi::new(self)
    }

    /// Polls the *existing* events from the event loop until exhaustion. Does not wait
    /// until new events arrive.
    pub fn poll_events(&mut self) -> Option<Result<(), ()>> {
        // XXX: Creating a new executor each time seems very inefficient, but sharing
        // a single executor seems to be impossible
        // because `handler` needs to be borrowed mutably into the closure. Use `RefCell`?
        let handler = &mut self.handler;
        let event_stream = self.channel.api_requests.1.by_ref().greedy_fold(
            (),
            |_, event| {
                handler.handle_event(ExonumEvent::Api(event))
            },
        );
        let mut event_exec = executor::spawn(event_stream);
        event_exec.wait_stream()
    }

    fn do_create_block(&mut self, tx_hashes: &[crypto::Hash]) {
        use std::time::SystemTime;
        use exonum::helpers::Round;
        use exonum::messages::{Message, Propose, Precommit};

        let validator_id = self.state().validator_id().expect(
            "Tested node is not a validator",
        );
        let height = self.state().height();
        let last_hash = *self.state().last_hash();
        let consensus_secret_key = self.state().consensus_secret_key().clone();
        let round = Round::first();

        let handler = &mut self.handler;
        let (block_hash, patch) = handler.create_block(validator_id, height.next(), tx_hashes);
        handler.state.add_block(
            block_hash,
            patch,
            tx_hashes.to_vec(),
            validator_id,
        );

        let propose = Propose::new(
            validator_id,
            height,
            round,
            &last_hash,
            tx_hashes,
            &consensus_secret_key,
        );
        let precommit = Precommit::new(
            validator_id,
            height,
            round,
            &propose.hash(),
            &block_hash,
            SystemTime::now(),
            &consensus_secret_key,
        );

        handler.commit(block_hash, vec![precommit].iter(), Some(round));
    }

    /// Creates block with the specified transactions. The transactions must be previously
    /// sent to the node via API or directly put into the `channel()`.
    ///
    /// # Panics
    ///
    /// In the case any of transaction hashes are not in the mempool.
    pub fn create_block_with_transactions(&mut self, tx_hashes: &[crypto::Hash]) {
        self.poll_events();

        {
            let txs = self.state().transactions().read().expect(
                "Cannot read transactions from node",
            );
            for hash in tx_hashes {
                assert!(txs.contains_key(hash));
            }
        }

        self.do_create_block(tx_hashes);
    }

    /// Creates block with all transactions in the mempool.
    pub fn create_block(&mut self) {
        self.poll_events();

        let tx_hashes: Vec<_> = {
            let txs = self.state().transactions().read().expect(
                "Cannot read transactions from node",
            );
            txs.keys().cloned().collect()
        };

        self.do_create_block(&tx_hashes);
    }
}

/// API encapsulation for the test harness. Allows to execute and synchronously retrieve results
/// for REST-ful endpoints of services.
pub struct HarnessApi {
    public_mount: Mount,
    private_mount: Mount,
}

impl HarnessApi {
    /// Creates new instance of Api.
    fn new(harness: &TestHarness) -> Self {
        HarnessApi {
            public_mount: harness.public_api_mount(),
            private_mount: harness.private_api_mount(),
        }
    }

    fn do_get<D>(&self, service_name: &str, endpoint: &str, mount: &Mount) -> D
    where
        for<'de> D: Deserialize<'de>,
    {
        let url = format!("http://localhost:3000/{}/{}", service_name, endpoint);
        let resp = request::get(&url, Headers::new(), mount).unwrap();
        let resp = response::extract_body_to_string(resp);
        // TODO: check status
        serde_json::from_str(&resp).unwrap()
    }

    fn do_post<T, D>(&self, service_name: &str, endpoint: &str, mount: &Mount, transaction: &T) -> D
    where
        T: Transaction + Serialize,
        for<'de> D: Deserialize<'de>,
    {
        let url = format!("http://localhost:3000/{}/{}", service_name, endpoint);
        let resp =
            request::post(
                &url,
                {
                    let mut headers = Headers::new();
                    headers.set(ContentType::json());
                    headers
                },
                &serde_json::to_string(&transaction).expect("Cannot serialize transaction to JSON"),
                mount,
            ).expect("Cannot send transaction");

        let resp = response::extract_body_to_string(resp);
        serde_json::from_str(&resp).expect("Cannot parse result")
    }

    /// Retrieves information from a service using a `GET` method of the public API.
    pub fn get<D>(&self, service_name: &str, endpoint: &str) -> D
    where
        for<'de> D: Deserialize<'de>,
    {
        self.do_get(service_name, endpoint, &self.public_mount)
    }

    /// Posts a transaction to the service using the public API. The returned value is the result
    /// of synchronous transaction processing, which includes running the API shim
    /// and `Transaction.verify()`. `Transaction.execute()` is not run until the transaction
    /// gets to a block via one of `create_block*()` methods.
    pub fn post<T, D>(&self, service_name: &str, endpoint: &str, transaction: &T) -> D
    where
        T: Transaction + Serialize,
        for<'de> D: Deserialize<'de>,
    {
        self.do_post(service_name, endpoint, &self.public_mount, transaction)
    }

    /// Posts a transaction to the service using the private API. The returned value is the result
    /// of synchronous transaction processing, which includes running the API shim
    /// and `Transaction.verify()`. `Transaction.execute()` is not run until the transaction
    /// gets to a block via one of `create_block*()` methods.
    pub fn post_private<T, D>(&self, service_name: &str, endpoint: &str, transaction: &T) -> D
    where
        T: Transaction + Serialize,
        for<'de> D: Deserialize<'de>,
    {
        self.do_post(service_name, endpoint, &self.private_mount, transaction)
    }
}
<commit_msg>Implement `send()` method for `HarnessApi`<commit_after>//! Test harness for Exonum blockchain framework, allowing to test service APIs synchronously
//! and in the same process as the harness.

#![deny(missing_docs)]

extern crate exonum;
extern crate futures;
extern crate mount;
extern crate iron;
extern crate iron_test;
extern crate serde;
extern crate serde_json;

use std::collections::BTreeMap;

use exonum::blockchain::{ApiContext, Blockchain, Service, Transaction, GenesisConfig,
                         SharedNodeState};
use exonum::crypto;
// A bit hacky, `exonum::events` is hidden from docs.
use exonum::events::{Event as ExonumEvent, EventHandler};
use exonum::node::{ApiSender, NodeChannel, NodeHandler, Configuration, ListenerConfig,
                   ServiceConfig, DefaultSystemState, State as NodeState};
use exonum::storage::MemoryDB;
use futures::Stream;
use futures::executor;
use iron::headers::{Headers, ContentType};
use iron_test::{request, response};
use mount::Mount;
use serde::{Serialize, Deserialize};

mod greedy_fold;
#[doc(hidden)]
pub use greedy_fold::GreedilyFoldable;

const STATE_UPDATE_TIMEOUT: u64 = 10_000;

/// Harness for testing blockchain with a single-node, no-network setup.
pub struct TestHarness {
    handler: NodeHandler,
    channel: NodeChannel,
    api_context: ApiContext,
}

impl TestHarness {
    /// Initializes a harness with a blockchain and no service-specific configuration.
    pub fn new(blockchain: Blockchain) -> Self {
        TestHarness::with_config(blockchain, BTreeMap::new())
    }

    /// Initializes a harness with a blockchain that hosts a given set of services.
    /// The blockchain uses `MemoryDB` for storage.
    pub fn with_services<I>(services: I) -> Self
    where
        I: IntoIterator<Item = Box<Service>>,
    {
        let db = MemoryDB::new();
        let blockchain = Blockchain::new(Box::new(db), services.into_iter().collect());
        TestHarness::new(blockchain)
    }

    /// Initializes a harness with a blockchain and a service-specific configuration.
    pub fn with_config(
        mut blockchain: Blockchain,
        _services_configs: BTreeMap<String, serde_json::Value>,
    ) -> Self {
        crypto::init();

        let (consensus_public_key, consensus_secret_key) = crypto::gen_keypair();
        let (service_public_key, service_secret_key) = crypto::gen_keypair();

        let validator_keys = exonum::blockchain::config::ValidatorKeys {
            consensus_key: consensus_public_key,
            service_key: service_public_key,
        };
        let genesis = GenesisConfig::new(vec![validator_keys].into_iter());

        blockchain.create_genesis_block(genesis.clone()).unwrap();

        let listen_address = "0.0.0.0:2000".parse().unwrap();
        let config = Configuration {
            listener: ListenerConfig {
                consensus_public_key,
                consensus_secret_key: consensus_secret_key.clone(),
                whitelist: Default::default(),
                address: listen_address,
            },
            service: ServiceConfig {
                service_public_key,
                service_secret_key: service_secret_key.clone(),
            },
            mempool: Default::default(),
            network: Default::default(),
            peer_discovery: vec![],
        };

        let api_state = SharedNodeState::new(STATE_UPDATE_TIMEOUT);
        let system_state = Box::new(DefaultSystemState(listen_address));
        let channel = NodeChannel::new(Default::default());
        let api_sender = ApiSender::new(channel.api_requests.0.clone());

        let api_context = ApiContext::from_parts(
            &blockchain,
            api_sender,
            &service_public_key,
            &service_secret_key,
        );

        let handler = NodeHandler::new(
            blockchain,
            listen_address,
            channel.node_sender(),
            system_state,
            config,
            api_state,
        );

        TestHarness {
            handler,
            channel,
            api_context,
        }
    }

    /// Returns the node state of the harness.
    pub fn state(&self) -> &NodeState {
        self.handler.state()
    }

    /// Creates a mounting point for public APIs used by the blockchain.
    // TODO: consider making public
    fn public_api_mount(&self) -> Mount {
        self.api_context.mount_public_api()
    }

    /// Creates a mounting point for public APIs used by the blockchain.
    // TODO: consider making public
    fn private_api_mount(&self) -> Mount {
        self.api_context.mount_private_api()
    }

    /// Creates an instance of `HarnessApi` to test the API provided by services.
    pub fn api(&self) -> HarnessApi {
        HarnessApi::new(self)
    }

    /// Polls the *existing* events from the event loop until exhaustion. Does not wait
    /// until new events arrive.
    pub fn poll_events(&mut self) -> Option<Result<(), ()>> {
        // XXX: Creating a new executor each time seems very inefficient, but sharing
        // a single executor seems to be impossible
        // because `handler` needs to be borrowed mutably into the closure. Use `RefCell`?
        let handler = &mut self.handler;
        let event_stream = self.channel.api_requests.1.by_ref().greedy_fold(
            (),
            |_, event| {
                handler.handle_event(ExonumEvent::Api(event))
            },
        );
        let mut event_exec = executor::spawn(event_stream);
        event_exec.wait_stream()
    }

    fn do_create_block(&mut self, tx_hashes: &[crypto::Hash]) {
        use std::time::SystemTime;
        use exonum::helpers::Round;
        use exonum::messages::{Message, Propose, Precommit};

        let validator_id = self.state().validator_id().expect(
            "Tested node is not a validator",
        );
        let height = self.state().height();
        let last_hash = *self.state().last_hash();
        let consensus_secret_key = self.state().consensus_secret_key().clone();
        let round = Round::first();

        let handler = &mut self.handler;
        let (block_hash, patch) = handler.create_block(validator_id, height.next(), tx_hashes);
        handler.state.add_block(
            block_hash,
            patch,
            tx_hashes.to_vec(),
            validator_id,
        );

        let propose = Propose::new(
            validator_id,
            height,
            round,
            &last_hash,
            tx_hashes,
            &consensus_secret_key,
        );
        let precommit = Precommit::new(
            validator_id,
            height,
            round,
            &propose.hash(),
            &block_hash,
            SystemTime::now(),
            &consensus_secret_key,
        );

        handler.commit(block_hash, vec![precommit].iter(), Some(round));
    }

    /// Creates block with the specified transactions. The transactions must be previously
    /// sent to the node via API or directly put into the `channel()`.
    ///
    /// # Panics
    ///
    /// In the case any of transaction hashes are not in the mempool.
    pub fn create_block_with_transactions(&mut self, tx_hashes: &[crypto::Hash]) {
        self.poll_events();

        {
            let txs = self.state().transactions().read().expect(
                "Cannot read transactions from node",
            );
            for hash in tx_hashes {
                assert!(txs.contains_key(hash));
            }
        }

        self.do_create_block(tx_hashes);
    }

    /// Creates block with all transactions in the mempool.
    pub fn create_block(&mut self) {
        self.poll_events();

        let tx_hashes: Vec<_> = {
            let txs = self.state().transactions().read().expect(
                "Cannot read transactions from node",
            );
            txs.keys().cloned().collect()
        };

        self.do_create_block(&tx_hashes);
    }
}

/// API encapsulation for the test harness. Allows to execute and synchronously retrieve results
/// for REST-ful endpoints of services.
pub struct HarnessApi {
    public_mount: Mount,
    private_mount: Mount,
    api_sender: ApiSender,
}

impl HarnessApi {
    /// Creates a new instance of Api.
    fn new(harness: &TestHarness) -> Self {
        HarnessApi {
            public_mount: harness.public_api_mount(),
            private_mount: harness.private_api_mount(),
            api_sender: harness.api_context.node_channel().clone(),
        }
    }

    /// Sends a transaction to the node via `ApiSender`.
    pub fn send<T: Transaction>(&self, transaction: T) {
        self.api_sender.send(Box::new(transaction)).expect(
            "Cannot send transaction",
        );
    }

    fn do_get<D>(&self, service_name: &str, endpoint: &str, mount: &Mount) -> D
    where
        for<'de> D: Deserialize<'de>,
    {
        let url = format!("http://localhost:3000/{}/{}", service_name, endpoint);
        let resp = request::get(&url, Headers::new(), mount).unwrap();
        let resp = response::extract_body_to_string(resp);
        // TODO: check status
        serde_json::from_str(&resp).unwrap()
    }

    fn do_post<T, D>(&self, service_name: &str, endpoint: &str, mount: &Mount, transaction: &T) -> D
    where
        T: Transaction + Serialize,
        for<'de> D: Deserialize<'de>,
    {
        let url = format!("http://localhost:3000/{}/{}", service_name, endpoint);
        let resp =
            request::post(
                &url,
                {
                    let mut headers = Headers::new();
                    headers.set(ContentType::json());
                    headers
                },
                &serde_json::to_string(&transaction).expect("Cannot serialize transaction to JSON"),
                mount,
            ).expect("Cannot send transaction");

        let resp = response::extract_body_to_string(resp);
        serde_json::from_str(&resp).expect("Cannot parse result")
    }

    /// Retrieves information from a service using a `GET` method of the public API.
    pub fn get<D>(&self, service_name: &str, endpoint: &str) -> D
    where
        for<'de> D: Deserialize<'de>,
    {
        self.do_get(service_name, endpoint, &self.public_mount)
    }

    /// Posts a transaction to the service using the public API. The returned value is the result
    /// of synchronous transaction processing, which includes running the API shim
    /// and `Transaction.verify()`. `Transaction.execute()` is not run until the transaction
    /// gets to a block via one of `create_block*()` methods.
    pub fn post<T, D>(&self, service_name: &str, endpoint: &str, transaction: &T) -> D
    where
        T: Transaction + Serialize,
        for<'de> D: Deserialize<'de>,
    {
        self.do_post(service_name, endpoint, &self.public_mount, transaction)
    }

    /// Posts a transaction to the service using the private API. The returned value is the result
    /// of synchronous transaction processing, which includes running the API shim
    /// and `Transaction.verify()`. `Transaction.execute()` is not run until the transaction
    /// gets to a block via one of `create_block*()` methods.
    pub fn post_private<T, D>(&self, service_name: &str, endpoint: &str, transaction: &T) -> D
    where
        T: Transaction + Serialize,
        for<'de> D: Deserialize<'de>,
    {
        self.do_post(service_name, endpoint, &self.private_mount, transaction)
    }
}
<|endoftext|>


<commit_before>// error-pattern:cargo-clippy
#![feature(plugin_registrar)]
#![feature(rustc_private)]
#![allow(unknown_lints)]

extern crate rustc_plugin;
use rustc_plugin::Registry;

extern crate clippy_lints;

pub use clippy_lints::*;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    if reg.sess.lint_store.borrow().get_lint_groups().iter().any(|&(s, _, _)| s == "clippy") {
        reg.sess.struct_warn("running cargo clippy on a crate that also imports the clippy plugin").emit();
    } else {
        register_plugins(reg);
    }
}

// only exists to let the dogfood integration test works.
// Don't run clippy as an executable directly
#[allow(dead_code, print_stdout)]
fn main() {
    panic!("Please use the cargo-clippy executable");
}
<commit_msg>plugin mode still needs to work<commit_after>// error-pattern:cargo-clippy
#![feature(plugin_registrar)]
#![feature(rustc_private)]
#![allow(unknown_lints)]
#![feature(borrow_state)]

extern crate rustc_plugin;
use rustc_plugin::Registry;

extern crate clippy_lints;

pub use clippy_lints::*;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    if reg.sess.lint_store.borrow_state() == std::cell::BorrowState::Unused && reg.sess.lint_store.borrow().get_lint_groups().iter().any(|&(s, _, _)| s == "clippy") {
        reg.sess.struct_warn("running cargo clippy on a crate that also imports the clippy plugin").emit();
    } else {
        register_plugins(reg);
    }
}

// only exists to let the dogfood integration test works.
// Don't run clippy as an executable directly
#[allow(dead_code, print_stdout)]
fn main() {
    panic!("Please use the cargo-clippy executable");
}
<|endoftext|>


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

//! A simple logger to provide symantics similar to what is expected
//! of most UNIX utilities by logging to stderr and the higher the
//! verbosity the higher the log level
//!
//! ### Examples
//!
//! ```rust
//! #[macro_use]
//! extern crate log;
//! extern crate stderrlog;
//!
//! fn main() {
//!     stderrlog::new().module(module_path!()).init().unwrap();
//!
//!     info!("starting up");
//!
//!     // ...
//! }
//! ```
//!
//! ```rust
//! extern crate docopt;
//! #[macro_use]
//! extern crate log;
//! extern crate rustc_serialize;
//! extern crate stderrlog;
//!
//! use docopt::Docopt;
//!
//! const USAGE: &'static str = "
//! Usage: program [-q] [-v...]
//! ";
//!
//! #[derive(Debug, RustcDecodable)]
//! struct Args {
//!     flag_q: bool,
//!     flag_v: usize,
//! }
//!
//! fn main() {
//!     let args: Args = Docopt::new(USAGE)
//!                             .and_then(|d| d.decode())
//!                             .unwrap_or_else(|e| e.exit());
//!
//!     stderrlog::new()
//!             .module(module_path!())
//!             .quiet(args.flag_q)
//!             .timestamp(stderrlog::Timestamp::Second)
//!             .verbosity(args.flag_v)
//!             .init()
//!             .unwrap();
//!     info!("starting up");
//!
//!     // ...
//! }

extern crate log;
extern crate time;

use log::{LogLevelFilter, LogMetadata};
use std::io::Write;

/// State of the timestampping in the logger.
#[derive(Clone, Copy, Debug)]
pub enum Timestamp {
    /// Disable timestamping of log messages
    Off,
    /// Timestamp with second granularity
    Second,
}

#[derive(Clone, Debug)]
pub struct StdErrLog {
    verbosity: LogLevelFilter,
    quiet: bool,
    timestamp: Timestamp,
    modules: Vec<String>,
}

impl log::Log for StdErrLog {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= log::max_log_level()
    }

    fn log(&self, record: &log::LogRecord) {

        // if logging isn't enabled for this level do a quick out
        if !self.enabled(record.metadata()) {
            return;
        }

        // module we are logging for
        let curr_mod = record.location().module_path();

        // create the timestamp prefix string
        let timestamp_prefix = match self.timestamp {
            Timestamp::Off => String::new(),
            Timestamp::Second => format!("{} - ", time::now().rfc3339()),
        };

        // this logger only logs the requested modules unless the
        // vector of modules is empty
        // modules will have module::file in the module_path
        if self.modules.is_empty() || self.modules.iter().any(|x| curr_mod.starts_with(x)) {
            let _ = writeln!(&mut ::std::io::stderr(),
                             "{}{} - {}",
                             timestamp_prefix,
                             record.level(),
                             record.args());
        }
    }
}

impl StdErrLog {
    pub fn new() -> StdErrLog {
        StdErrLog {
            verbosity: LogLevelFilter::Error,
            quiet: false,
            timestamp: Timestamp::Off,
            modules: vec![],
        }
    }

    /// Sets the verbosity level of messages that will be displayed
    pub fn verbosity(&mut self, verbosity: usize) -> &mut StdErrLog {
        let log_lvl = match verbosity {
            0 => LogLevelFilter::Error,
            1 => LogLevelFilter::Warn,
            2 => LogLevelFilter::Info,
            3 => LogLevelFilter::Debug,
            _ => LogLevelFilter::Trace,
        };

        self.verbosity = log_lvl;
        self
    }

    pub fn quiet(&mut self, quiet: bool) -> &mut StdErrLog {
        self.quiet = quiet;
        self
    }

    /// Enables or disables the use of timestamps in log messages
    pub fn timestamp(&mut self, timestamp: Timestamp) -> &mut StdErrLog {
        self.timestamp = timestamp;
        self
    }

    pub fn module(&mut self, module: &str) -> &mut StdErrLog {
        self.modules.push(module.to_owned());
        self
    }

    pub fn modules(&mut self, modules: Vec<String>) -> &mut StdErrLog {
        self.modules.extend(modules);
        self
    }

    pub fn init(&self) -> Result<(), log::SetLoggerError> {

        log::set_logger(|max_log_level| {
            if self.quiet {
                max_log_level.set(LogLevelFilter::Off);
            } else {
                max_log_level.set(self.verbosity);
            }

            Box::new(self.clone())
        })
    }
}

pub fn new() -> StdErrLog {
    StdErrLog::new()
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_default_level() {
        extern crate log;

        super::new().module(module_path!()).init().unwrap();

        assert_eq!(log::LogLevel::Error, log::max_log_level())
    }
}
<commit_msg>Do not require .init() to be called.<commit_after>// Copyright 2016 Doug Goldstein
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A simple logger to provide symantics similar to what is expected
//! of most UNIX utilities by logging to stderr and the higher the
//! verbosity the higher the log level
//!
//! ### Examples
//!
//! ```rust
//! #[macro_use]
//! extern crate log;
//! extern crate stderrlog;
//!
//! fn main() {
//!     stderrlog::new().module(module_path!()).init().unwrap();
//!
//!     info!("starting up");
//!
//!     // ...
//! }
//! ```
//!
//! ```rust
//! extern crate docopt;
//! #[macro_use]
//! extern crate log;
//! extern crate rustc_serialize;
//! extern crate stderrlog;
//!
//! use docopt::Docopt;
//!
//! const USAGE: &'static str = "
//! Usage: program [-q] [-v...]
//! ";
//!
//! #[derive(Debug, RustcDecodable)]
//! struct Args {
//!     flag_q: bool,
//!     flag_v: usize,
//! }
//!
//! fn main() {
//!     let args: Args = Docopt::new(USAGE)
//!                             .and_then(|d| d.decode())
//!                             .unwrap_or_else(|e| e.exit());
//!
//!     stderrlog::new()
//!             .module(module_path!())
//!             .quiet(args.flag_q)
//!             .timestamp(stderrlog::Timestamp::Second)
//!             .verbosity(args.flag_v)
//!             .init()
//!             .unwrap();
//!     info!("starting up");
//!
//!     // ...
//! }

extern crate log;
extern crate time;

use log::{LogLevelFilter, LogMetadata};
use std::io::Write;

/// State of the timestampping in the logger.
#[derive(Clone, Copy, Debug)]
pub enum Timestamp {
    /// Disable timestamping of log messages
    Off,
    /// Timestamp with second granularity
    Second,
}

#[derive(Clone, Debug)]
pub struct StdErrLog {
    verbosity: LogLevelFilter,
    quiet: bool,
    timestamp: Timestamp,
    modules: Vec<String>,
}

impl log::Log for StdErrLog {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.log_level_filter()
    }

    fn log(&self, record: &log::LogRecord) {

        // if logging isn't enabled for this level do a quick out
        if !self.enabled(record.metadata()) {
            return;
        }

        // module we are logging for
        let curr_mod = record.location().module_path();

        // create the timestamp prefix string
        let timestamp_prefix = match self.timestamp {
            Timestamp::Off => String::new(),
            Timestamp::Second => format!("{} - ", time::now().rfc3339()),
        };

        // this logger only logs the requested modules unless the
        // vector of modules is empty
        // modules will have module::file in the module_path
        if self.modules.is_empty() || self.modules.iter().any(|x| curr_mod.starts_with(x)) {
            let _ = writeln!(&mut ::std::io::stderr(),
                             "{}{} - {}",
                             timestamp_prefix,
                             record.level(),
                             record.args());
        }
    }
}

impl StdErrLog {
    pub fn new() -> StdErrLog {
        StdErrLog {
            verbosity: LogLevelFilter::Error,
            quiet: false,
            timestamp: Timestamp::Off,
            modules: vec![],
        }
    }

    /// Sets the verbosity level of messages that will be displayed
    pub fn verbosity(&mut self, verbosity: usize) -> &mut StdErrLog {
        let log_lvl = match verbosity {
            0 => LogLevelFilter::Error,
            1 => LogLevelFilter::Warn,
            2 => LogLevelFilter::Info,
            3 => LogLevelFilter::Debug,
            _ => LogLevelFilter::Trace,
        };

        self.verbosity = log_lvl;
        self
    }

    pub fn quiet(&mut self, quiet: bool) -> &mut StdErrLog {
        self.quiet = quiet;
        self
    }

    /// Enables or disables the use of timestamps in log messages
    pub fn timestamp(&mut self, timestamp: Timestamp) -> &mut StdErrLog {
        self.timestamp = timestamp;
        self
    }

    pub fn module(&mut self, module: &str) -> &mut StdErrLog {
        self.modules.push(module.to_owned());
        self
    }

    pub fn modules(&mut self, modules: Vec<String>) -> &mut StdErrLog {
        self.modules.extend(modules);
        self
    }

    fn log_level_filter(&self) -> LogLevelFilter {
        if self.quiet {
            LogLevelFilter::Off
        } else {
            self.verbosity
        }
    }

    pub fn init(&self) -> Result<(), log::SetLoggerError> {

        log::set_logger(|max_log_level| {
            max_log_level.set(self.log_level_filter());

            Box::new(self.clone())
        })
    }
}

pub fn new() -> StdErrLog {
    StdErrLog::new()
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_default_level() {
        extern crate log;

        super::new().module(module_path!()).init().unwrap();

        assert_eq!(log::LogLevel::Error, log::max_log_level())
    }
}
<|endoftext|>


<commit_before>//! Hubcaps provides a set of building blocks for interacting with the Github API

#[macro_use]
extern crate serializable_enum;
#[macro_use]
extern crate log;
#[macro_use]
extern crate hyper;
extern crate serde;
extern crate serde_json;
extern crate url;

use serde::de::Deserialize;
pub mod keys;
pub mod gists;
pub mod deployments;
pub mod errors;
pub mod issues;
pub mod labels;
pub mod rep;
pub mod releases;
pub mod repositories;
pub mod statuses;
pub mod pulls;
pub mod search;
pub mod organizations;

pub use rep::*;
pub use errors::Error;
use gists::{Gists, UserGists};
use search::Search;
use hyper::Client;
use hyper::client::RequestBuilder;
use hyper::method::Method;
use hyper::header::{Accept, Authorization, ContentLength, UserAgent};
use hyper::status::StatusCode;
use repositories::{Repository, Repositories, UserRepositories, OrganizationRepositories};
use organizations::{Organizations, UserOrganizations};
use std::fmt;
use std::io::Read;
use url::Url;
use std::collections::HashMap;

header! { (Link, "Link") => [String] }

const DEFAULT_HOST: &'static str = "https://api.github.com";

/// alias for Result that infers hubcaps::Error as Err
pub type Result<T> = std::result::Result<T, Error>;

/// enum representation of github pull and issue state
#[derive(Clone, Debug, PartialEq)]
pub enum State {
    /// Only open issues
    Open,
    /// Only closed issues
    Closed,
    /// All issues, open or closed
    All,
}

impl fmt::Display for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   State::Open => "open",
                   State::Closed => "closed",
                   State::All => "all",
               })
    }
}

impl Default for State {
    fn default() -> State {
        State::Open
    }
}

/// enum representation of Github list sorting options
#[derive(Clone, Debug, PartialEq)]
pub enum SortDirection {
    /// Sort in ascending order
    Asc,
    /// Sort in descending order
    Desc,
}

impl fmt::Display for SortDirection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   SortDirection::Asc => "asc",
                   SortDirection::Desc => "desc",
               })
    }
}

impl Default for SortDirection {
    fn default() -> SortDirection {
        SortDirection::Asc
    }
}

/// Various forms of authentication credentials supported by Github
#[derive(Debug, PartialEq)]
pub enum Credentials {
    /// No authentication
    None,
    /// Oauth token string
    /// https://developer.github.com/v3/#oauth2-token-sent-in-a-header
    Token(String),
    /// Oauth client id and secret
    /// https://developer.github.com/v3/#oauth2-keysecret
    Client(String, String),
}

impl Default for Credentials {
    fn default() -> Credentials {
        Credentials::None
    }
}

/// Entry point interface for interacting with Github API
pub struct Github<'a> {
    host: String,
    agent: String,
    client: &'a Client,
    credentials: Credentials,
}

impl<'a> Github<'a> {
    /// Create a new Github instance
    pub fn new<A>(agent: A, client: &'a Client, credentials: Credentials) -> Github<'a>
        where A: Into<String>
    {
        Github::host(DEFAULT_HOST, agent, client, credentials)
    }

    /// Create a new Github instance hosted at a custom location.
    /// Useful for github enterprise installations ( yourdomain.com/api/v3/ )
    pub fn host<H, A>(host: H, agent: A, client: &'a Client, credentials: Credentials) -> Github<'a>
        where H: Into<String>,
              A: Into<String>
    {
        Github {
            host: host.into(),
            agent: agent.into(),
            client: client,
            credentials: credentials,
        }
    }

    /// Return a reference to a Github reposistory
    pub fn repo<O, R>(&self, owner: O, repo: R) -> Repository
        where O: Into<String>,
              R: Into<String>
    {
        Repository::new(self, owner, repo)
    }

    /// Return a reference to the collection of repositories owned by and
    /// associated with an owner
    pub fn user_repos<S>(&self, owner: S) -> UserRepositories
        where S: Into<String>
    {
        UserRepositories::new(self, owner)
    }

    /// Return a reference to the collection of repositories owned by the user
    /// associated with the current authentication credentials
    pub fn repos(&self) -> Repositories {
        Repositories::new(self)
    }

    /// Return a reference to the collection of organizations that the user
    /// associated with the current authentication credentials is in
    pub fn orgs(&self) -> Organizations {
        Organizations::new(self)
    }

    /// Return a reference to the collection of organizations a user
    /// is publicly associated with
    pub fn user_orgs<U>(&self, user: U) -> UserOrganizations
        where U: Into<String>
    {
        UserOrganizations::new(self, user)
    }

    /// Return a reference to an interface that provides access to a user's gists
    pub fn user_gists<O>(&self, owner: O) -> UserGists
        where O: Into<String>
    {
        UserGists::new(self, owner)
    }

    /// Return a reference to an interface that provides access to the
    /// gists belonging to the owner of the token used to configure this client
    pub fn gists(&self) -> Gists {
        Gists::new(self)
    }

    pub fn search(&self) -> Search {
        Search::new(self)
    }

    /// Return a reference to the collection of repositories owned by and
    /// associated with an organization
    pub fn org_repos<O>(&self, org: O) -> OrganizationRepositories
        where O: Into<String>
    {
        OrganizationRepositories::new(self, org)
    }

    fn authenticate(&self, method: Method, url: String) -> RequestBuilder {
        match self.credentials {
            Credentials::Token(ref token) => {
                self.client.request(method, &url).header(Authorization(format!("token {}", token)))
            }
            Credentials::Client(ref id, ref secret) => {

                let mut parsed = Url::parse(&url).unwrap();
                parsed.query_pairs_mut()
                    .append_pair("client_id", id)
                    .append_pair("client_secret", secret);
                self.client.request(method, parsed)
            }
            Credentials::None => self.client.request(method, &url),
        }
    }

    fn request<D>(&self,
                  method: Method,
                  uri: String,
                  body: Option<&'a [u8]>)
                  -> Result<(Option<Links>, D)>
        where D: Deserialize
    {
        let builder = self.authenticate(method, uri)
            .header(UserAgent(self.agent.to_owned()))
            // todo: parameterize media type
            .header(Accept(vec!["application/vnd.github.v3+json".parse().unwrap()]));

        let mut res = try!(match body {
            Some(ref bod) => builder.body(*bod).send(),
            _ => builder.send(),
        });

        let mut body = match res.headers.clone().get::<ContentLength>() {
            Some(&ContentLength(len)) => String::with_capacity(len as usize),
            _ => String::new(),
        };
        try!(res.read_to_string(&mut body));

        let links = res.headers.get::<Link>().map(|&Link(ref value)| Links::new(value.to_owned()));

        debug!("rec response {:#?} {:#?} {}", res.status, res.headers, body);
        match res.status {
            StatusCode::Conflict |
            StatusCode::BadRequest |
            StatusCode::UnprocessableEntity |
            StatusCode::Unauthorized |
            StatusCode::NotFound |
            StatusCode::Forbidden => {
                Err(Error::Fault {
                    code: res.status,
                    error: try!(serde_json::from_str::<ClientError>(&body)),
                })
            }
            _ => Ok((links, try!(serde_json::from_str::<D>(&body)))),
        }
    }

    fn request_entity<D>(&self, method: Method, uri: String, body: Option<&'a [u8]>) -> Result<D>
        where D: Deserialize
    {
        self.request(method, uri, body).map(|(_, entity)| entity)
    }

    fn get<D>(&self, uri: &str) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Get, format!("{}{}", self.host, uri), None)
    }

    fn delete(&self, uri: &str) -> Result<()> {
        match self.request_entity::<()>(Method::Delete, format!("{}{}", self.host, uri), None) {
            Err(Error::Codec(_)) => Ok(()),
            otherwise => otherwise,
        }
    }

    fn post<D>(&self, uri: &str, message: &[u8]) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Post, format!("{}{}", self.host, uri), Some(message))
    }

    fn patch<D>(&self, uri: &str, message: &[u8]) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Patch,
                            format!("{}{}", self.host, uri),
                            Some(message))
    }

    fn put<D>(&self, uri: &str, message: &[u8]) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Put, format!("{}{}", self.host, uri), Some(message))
    }
}

pub struct Iter<'a, D> {
    github: &'a Github<'a>,
    next_link: Option<String>,
    items: Vec<D>,
}

impl<'a, D> Iter<'a, D>
    where D: Deserialize
{
    pub fn new(github: &'a Github<'a>, uri: String) -> Result<Iter<'a, D>> {
        let (links, items) = try!(github.request::<Vec<D>>(Method::Get, uri, None));
        Ok(Iter {
            github: github,
            next_link: links.and_then(|l| l.next()),
            items: items,
        })
    }

    fn set_next(&mut self, next: Option<String>) {
        self.next_link = next;
    }
}

impl<'a, D> Iterator for Iter<'a, D>
    where D: Deserialize
{
    type Item = D;
    fn next(&mut self) -> Option<D> {
        match self.items.pop() {
            None => {
                match self.next_link.clone() {
                    None => None,
                    Some(ref next_link) => {
                        match self.github
                            .request::<Vec<D>>(Method::Get, next_link.to_owned(), None) {
                            Ok((links, items)) => {
                                self.set_next(links.and_then(|l| l.next()));
                                self.items = items;
                                None
                            }
                            _ => None,
                        }
                    }
                }
            }
            item => item,
        }
    }
}

#[derive(Debug)]
pub struct Links {
    values: HashMap<String, String>,
}

impl Links {
    pub fn new<V>(value: V) -> Links
        where V: Into<String>
    {
        let values = value.into()
            .split(",")
            .map(|link| {
                let parts = link.split(";").collect::<Vec<_>>();
                (parts[1].to_owned().replace(" rel=\\\"", "").replace("\\\"", ""),
                 parts[0].to_owned().replace("<", "").replace(">", "").replace(" ", ""))
            })
            .fold(HashMap::new(), |mut acc, (rel, link)| {
                acc.insert(rel, link);
                acc
            });
        Links { values: values }
    }

    pub fn next(&self) -> Option<String> {
        self.values.get("next").map(|s| s.to_owned())
    }

    pub fn prev(&self) -> Option<String> {
        self.values.get("prev").map(|s| s.to_owned())
    }

    pub fn last(&self) -> Option<String> {
        self.values.get("last").map(|s| s.to_owned())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_links() {
        let links = Links::new(r#"<linknext>; rel=\"next\", <linklast>; rel=\"last\""#);
        assert_eq!(links.next(), Some("linknext".to_owned()));
        assert_eq!(links.last(), Some("linklast".to_owned()));
    }

    #[test]
    fn default_state() {
        let default: State = Default::default();
        assert_eq!(default, State::Open)
    }

    #[test]
    fn default_sort_direction() {
        let default: SortDirection = Default::default();
        assert_eq!(default, SortDirection::Asc)
    }

    #[test]
    fn default_credentials() {
        let default: Credentials = Default::default();
        assert_eq!(default, Credentials::None)
    }
}
<commit_msg>fix up iter impl, prefer string + to format<commit_after>//! Hubcaps provides a set of building blocks for interacting with the Github API

#[macro_use]
extern crate serializable_enum;
#[macro_use]
extern crate log;
#[macro_use]
extern crate hyper;
extern crate serde;
extern crate serde_json;
extern crate url;

use serde::de::Deserialize;
pub mod keys;
pub mod gists;
pub mod deployments;
pub mod errors;
pub mod issues;
pub mod labels;
pub mod rep;
pub mod releases;
pub mod repositories;
pub mod statuses;
pub mod pulls;
pub mod search;
pub mod organizations;

pub use rep::*;
pub use errors::Error;
use gists::{Gists, UserGists};
use search::Search;
use hyper::Client;
use hyper::client::RequestBuilder;
use hyper::method::Method;
use hyper::header::{Accept, Authorization, ContentLength, UserAgent};
use hyper::status::StatusCode;
use repositories::{Repository, Repositories, UserRepositories, OrganizationRepositories};
use organizations::{Organizations, UserOrganizations};
use std::fmt;
use std::io::Read;
use url::Url;
use std::collections::HashMap;

header! { (Link, "Link") => [String] }

const DEFAULT_HOST: &'static str = "https://api.github.com";

/// alias for Result that infers hubcaps::Error as Err
pub type Result<T> = std::result::Result<T, Error>;

/// enum representation of github pull and issue state
#[derive(Clone, Debug, PartialEq)]
pub enum State {
    /// Only open issues
    Open,
    /// Only closed issues
    Closed,
    /// All issues, open or closed
    All,
}

impl fmt::Display for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   State::Open => "open",
                   State::Closed => "closed",
                   State::All => "all",
               })
    }
}

impl Default for State {
    fn default() -> State {
        State::Open
    }
}

/// enum representation of Github list sorting options
#[derive(Clone, Debug, PartialEq)]
pub enum SortDirection {
    /// Sort in ascending order
    Asc,
    /// Sort in descending order
    Desc,
}

impl fmt::Display for SortDirection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   SortDirection::Asc => "asc",
                   SortDirection::Desc => "desc",
               })
    }
}

impl Default for SortDirection {
    fn default() -> SortDirection {
        SortDirection::Asc
    }
}

/// Various forms of authentication credentials supported by Github
#[derive(Debug, PartialEq)]
pub enum Credentials {
    /// No authentication
    None,
    /// Oauth token string
    /// https://developer.github.com/v3/#oauth2-token-sent-in-a-header
    Token(String),
    /// Oauth client id and secret
    /// https://developer.github.com/v3/#oauth2-keysecret
    Client(String, String),
}

impl Default for Credentials {
    fn default() -> Credentials {
        Credentials::None
    }
}

/// Entry point interface for interacting with Github API
pub struct Github<'a> {
    host: String,
    agent: String,
    client: &'a Client,
    credentials: Credentials,
}

impl<'a> Github<'a> {
    /// Create a new Github instance
    pub fn new<A>(agent: A, client: &'a Client, credentials: Credentials) -> Github<'a>
        where A: Into<String>
    {
        Github::host(DEFAULT_HOST, agent, client, credentials)
    }

    /// Create a new Github instance hosted at a custom location.
    /// Useful for github enterprise installations ( yourdomain.com/api/v3/ )
    pub fn host<H, A>(host: H, agent: A, client: &'a Client, credentials: Credentials) -> Github<'a>
        where H: Into<String>,
              A: Into<String>
    {
        Github {
            host: host.into(),
            agent: agent.into(),
            client: client,
            credentials: credentials,
        }
    }

    /// Return a reference to a Github reposistory
    pub fn repo<O, R>(&self, owner: O, repo: R) -> Repository
        where O: Into<String>,
              R: Into<String>
    {
        Repository::new(self, owner, repo)
    }

    /// Return a reference to the collection of repositories owned by and
    /// associated with an owner
    pub fn user_repos<S>(&self, owner: S) -> UserRepositories
        where S: Into<String>
    {
        UserRepositories::new(self, owner)
    }

    /// Return a reference to the collection of repositories owned by the user
    /// associated with the current authentication credentials
    pub fn repos(&self) -> Repositories {
        Repositories::new(self)
    }

    /// Return a reference to the collection of organizations that the user
    /// associated with the current authentication credentials is in
    pub fn orgs(&self) -> Organizations {
        Organizations::new(self)
    }

    /// Return a reference to the collection of organizations a user
    /// is publicly associated with
    pub fn user_orgs<U>(&self, user: U) -> UserOrganizations
        where U: Into<String>
    {
        UserOrganizations::new(self, user)
    }

    /// Return a reference to an interface that provides access to a user's gists
    pub fn user_gists<O>(&self, owner: O) -> UserGists
        where O: Into<String>
    {
        UserGists::new(self, owner)
    }

    /// Return a reference to an interface that provides access to the
    /// gists belonging to the owner of the token used to configure this client
    pub fn gists(&self) -> Gists {
        Gists::new(self)
    }

    pub fn search(&self) -> Search {
        Search::new(self)
    }

    /// Return a reference to the collection of repositories owned by and
    /// associated with an organization
    pub fn org_repos<O>(&self, org: O) -> OrganizationRepositories
        where O: Into<String>
    {
        OrganizationRepositories::new(self, org)
    }

    fn authenticate(&self, method: Method, url: String) -> RequestBuilder {
        match self.credentials {
            Credentials::Token(ref token) => {
                self.client.request(method, &url).header(Authorization(format!("token {}", token)))
            }
            Credentials::Client(ref id, ref secret) => {

                let mut parsed = Url::parse(&url).unwrap();
                parsed.query_pairs_mut()
                    .append_pair("client_id", id)
                    .append_pair("client_secret", secret);
                self.client.request(method, parsed)
            }
            Credentials::None => self.client.request(method, &url),
        }
    }

    fn iter<D, I>(&'a self, uri: String, into_items: fn(D) -> Vec<I>) -> Result<Iter<'a, D, I>>
        where D: Deserialize
    {
        Iter::new(self, self.host.clone() + &uri, into_items)
    }

    fn request<D>(&self,
                  method: Method,
                  uri: String,
                  body: Option<&'a [u8]>)
                  -> Result<(Option<Links>, D)>
        where D: Deserialize
    {
        let builder = self.authenticate(method, uri)
            .header(UserAgent(self.agent.to_owned()))
            // todo: parameterize media type
            .header(Accept(vec!["application/vnd.github.v3+json".parse().unwrap()]));

        let mut res = try!(match body {
            Some(ref bod) => builder.body(*bod).send(),
            _ => builder.send(),
        });

        let mut body = match res.headers.clone().get::<ContentLength>() {
            Some(&ContentLength(len)) => String::with_capacity(len as usize),
            _ => String::new(),
        };
        try!(res.read_to_string(&mut body));

        let links = res.headers.get::<Link>().map(|&Link(ref value)| Links::new(value.to_owned()));

        debug!("rec response {:#?} {:#?} {}", res.status, res.headers, body);
        match res.status {
            StatusCode::Conflict |
            StatusCode::BadRequest |
            StatusCode::UnprocessableEntity |
            StatusCode::Unauthorized |
            StatusCode::NotFound |
            StatusCode::Forbidden => {
                Err(Error::Fault {
                    code: res.status,
                    error: try!(serde_json::from_str::<ClientError>(&body)),
                })
            }
            _ => Ok((links, try!(serde_json::from_str::<D>(&body)))),
        }
    }

    fn request_entity<D>(&self, method: Method, uri: String, body: Option<&'a [u8]>) -> Result<D>
        where D: Deserialize
    {
        self.request(method, uri, body).map(|(_, entity)| entity)
    }

    fn get<D>(&self, uri: &str) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Get, self.host.clone() + uri, None)
    }

    fn delete(&self, uri: &str) -> Result<()> {
        match self.request_entity::<()>(Method::Delete, self.host.clone() + uri, None) {
            Err(Error::Codec(_)) => Ok(()),
            otherwise => otherwise,
        }
    }

    fn post<D>(&self, uri: &str, message: &[u8]) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Post, self.host.clone() + uri, Some(message))
    }

    fn patch<D>(&self, uri: &str, message: &[u8]) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Patch,
                            self.host.clone() + uri,
                            Some(message))
    }

    fn put<D>(&self, uri: &str, message: &[u8]) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Put, self.host.clone() + uri, Some(message))
    }
}

pub struct Iter<'a, D, I> {
    github: &'a Github<'a>,
    next_link: Option<String>,
    into_items: fn(D) -> Vec<I>,
    items: Vec<I>,
}

impl<'a, D, I> Iter<'a, D, I>
    where D: Deserialize
{
    pub fn new(github: &'a Github<'a>,
               uri: String,
               into_items: fn(D) -> Vec<I>)
               -> Result<Iter<'a, D, I>> {
        let (links, payload) = try!(github.request::<D>(Method::Get, uri, None));
        Ok(Iter {
            github: github,
            next_link: links.and_then(|l| l.next()),
            into_items: into_items,
            items: into_items(payload),
        })
    }

    fn set_next(&mut self, next: Option<String>) {
        self.next_link = next;
    }
}

impl<'a, D, I> Iterator for Iter<'a, D, I>
    where D: Deserialize
{
    type Item = I;
    fn next(&mut self) -> Option<I> {
        match self.items.pop() {
            None => {
                match self.next_link.clone() {
                    None => None,
                    Some(ref next_link) => {
                        match self.github
                            .request::<D>(Method::Get, next_link.to_owned(), None) {
                            Ok((links, payload)) => {
                                self.set_next(links.and_then(|l| l.next()));
                                self.items = (self.into_items)(payload);
                                self.next()
                            }
                            _ => None,
                        }
                    }
                }
            }
            item => item,
        }
    }
}

#[derive(Debug)]
pub struct Links {
    values: HashMap<String, String>,
}

impl Links {
    pub fn new<V>(value: V) -> Links
        where V: Into<String>
    {
        let values = value.into()
            .split(",")
            .map(|link| {
                let parts = link.split(";").collect::<Vec<_>>();
                (parts[1].to_owned().replace(" rel=\"", "").replace("\"", ""),
                 parts[0].to_owned().replace("<", "").replace(">", "").replace(" ", ""))
            })
            .fold(HashMap::new(), |mut acc, (rel, link)| {
                acc.insert(rel, link);
                acc
            });
        Links { values: values }
    }

    pub fn next(&self) -> Option<String> {
        self.values.get("next").map(|s| s.to_owned())
    }

    pub fn prev(&self) -> Option<String> {
        self.values.get("prev").map(|s| s.to_owned())
    }

    pub fn last(&self) -> Option<String> {
        self.values.get("last").map(|s| s.to_owned())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_links() {
        let links = Links::new(r#"<linknext>; rel="next", <linklast>; rel="last""#);
        assert_eq!(links.next(), Some("linknext".to_owned()));
        assert_eq!(links.last(), Some("linklast".to_owned()));
    }

    #[test]
    fn default_state() {
        let default: State = Default::default();
        assert_eq!(default, State::Open)
    }

    #[test]
    fn default_sort_direction() {
        let default: SortDirection = Default::default();
        assert_eq!(default, SortDirection::Asc)
    }

    #[test]
    fn default_credentials() {
        let default: Credentials = Default::default();
        assert_eq!(default, Credentials::None)
    }
}
<|endoftext|>