<commit_before>use super::*;
use pact_matching::models::*;
use pact_matching::models::matchingrules::*;
use pact_matching::models::generators::*;
use std::str::FromStr;
use std::error::Error;
use std::collections::hash_map::HashMap;
use hyper::client::Client;
use hyper::{Request as HyperRequest, Response as HyperResponse};
use hyper::http::request::{Builder as RequestBuilder};
use hyper::Body;
use hyper::error::Error as HyperError;
use hyper::Method;
use hyper::http::method::InvalidMethod;
use hyper::http::header::{HeaderMap, HeaderName, HeaderValue, InvalidHeaderName, InvalidHeaderValue};
use hyper::http::header::CONTENT_TYPE;
use futures::future;
use futures::future::Future;
use futures::stream::Stream;

#[derive(Debug)]
pub enum ProviderClientError {
    RequestMethodError(String, InvalidMethod),
    RequestHeaderNameError(String, InvalidHeaderName),
    RequestHeaderValueError(String, InvalidHeaderValue),
    RequestBodyError(String),
    ResponseError(String),
    ResponseStatusCodeError(u16),
}

pub fn join_paths(base: &String, path: String) -> String {
    let mut full_path = s!(base.trim_right_matches("/"));
    full_path.push('/');
    full_path.push_str(path.trim_left_matches("/"));
    full_path
}

fn setup_headers(builder: &mut RequestBuilder, headers: &Option<HashMap<String, String>>) -> Result<(), ProviderClientError> {
    let mut hyper_headers = builder.headers_mut().unwrap();
    match headers {
        Some(header_map) => {
            for (k, v) in header_map {
                // FIXME?: Headers are not sent in "raw" mode.
                // Names are converted to lower case and values are parsed.
                hyper_headers.insert(
                    HeaderName::from_bytes(k.as_bytes())
                        .map_err(|err| ProviderClientError::RequestHeaderNameError(k.clone(), err))?,
                    v.parse::<HeaderValue>()
                        .map_err(|err| ProviderClientError::RequestHeaderValueError(v.clone(), err))?
                );
            }

            if !header_map.keys().any(|k| k.to_lowercase() == "content-type") {
                hyper_headers.insert(CONTENT_TYPE, "application/json".parse().unwrap());
            }
        },
        _ => {}
    }
    Ok(())
}

fn create_hyper_request(base_url: &String, request: &Request) -> Result<HyperRequest<Body>, ProviderClientError> {
    let mut url = join_paths(base_url, request.path.clone());
    if request.query.is_some() {
        url.push('?');
        url.push_str(&build_query_string(request.query.clone().unwrap()));
    }
    debug!("Making request to '{}'", url);
    let mut builder = HyperRequest::builder();
    builder.method(
        Method::from_str(&request.method)
            .map_err(|err| ProviderClientError::RequestMethodError(request.method.clone(), err))?
    );
    builder.uri(url);
    setup_headers(&mut builder, &request.headers())?;

    let hyper_request = builder
        .body(match request.body {
            OptionalBody::Present(ref s) => Body::from(s.clone()),
            OptionalBody::Null => {
                if request.content_type() == "application/json" {
                    Body::from("null")
                } else {
                    Body::empty()
                }
            },
            _ => Body::empty()
        })
        .map_err(|err| ProviderClientError::RequestBodyError(err.description().into()))?;

    Ok(hyper_request)
}

fn extract_headers(headers: &HeaderMap) -> Option<HashMap<String, String>> {
    if headers.len() > 0 {
        Some(headers.iter()
            .map(|(name, value)| {
                (name.as_str().into(), value.to_str().unwrap().into())
            })
            .collect()
        )
    } else {
        None
    }
}

pub fn extract_body(hyper_body: Result<hyper::Chunk, HyperError>) -> Result<OptionalBody, HyperError> {
    match hyper_body {
        Ok(chunk) => {
            let bytes = chunk.into_bytes();
            if bytes.len() > 0 {
                Ok(OptionalBody::Present(bytes.to_vec()))
            } else {
                Ok(OptionalBody::Empty)
            }
        },
        Err(err) => {
            warn!("Failed to read request body: {}", err);
            Ok(OptionalBody::Missing)
        }
    }
}

fn hyper_response_to_pact_response(response: HyperResponse<Body>) -> impl Future<Item = Response, Error = HyperError> {
    debug!("Received response: {:?}", response);

    let status = response.status().as_u16();
    let headers = extract_headers(response.headers());

    response.into_body()
        .concat2()
        .then(extract_body)
        .map(move |body| {
            Response {
                status: status,
                headers: headers,
                body: body,
                matching_rules: MatchingRules::default(),
                generators: Generators::default()
            }
        })
}

fn check_hyper_response_status(result: Result<HyperResponse<Body>, HyperError>) -> Result<(), ProviderClientError> {
    match result {
        Ok(response) => {
            if response.status().is_success() {
                Ok(())
            } else {
                Err(ProviderClientError::ResponseStatusCodeError(response.status().as_u16()))
            }
        },
        Err(err) => Err(ProviderClientError::ResponseError(err.description().into()))
    }
}

pub fn make_provider_request(provider: &ProviderInfo, request: &Request) -> impl Future<Item = Response, Error = ProviderClientError> {
    debug!("Sending {:?} to provider", request);
    let base_url = format!("{}://{}:{}{}", provider.protocol, provider.host, provider.port, provider.path);

    future::done(create_hyper_request(&base_url, request))
        .and_then(|request| {
            Client::new().request(request)
                .and_then(hyper_response_to_pact_response)
                .map_err(|err| ProviderClientError::ResponseError(err.description().into()))
        })
        .map_err(|err| {
            debug!("Request failed: {:?}", err);
            err
        })
}

pub fn make_state_change_request(provider: &ProviderInfo, request: &Request) -> impl Future<Item = (), Error = ProviderClientError> {
    debug!("Sending {:?} to state change handler", request);

    future::done(create_hyper_request(&provider.state_change_url.clone().unwrap(), request))
        .and_then(|request| {
            Client::new().request(request)
                .then(check_hyper_response_status)
        })
}

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

    #[test]
    fn join_paths_test() {
        expect!(join_paths(&s!(""), s!(""))).to(be_equal_to(s!("/")));
        expect!(join_paths(&s!("/"), s!(""))).to(be_equal_to(s!("/")));
        expect!(join_paths(&s!(""), s!("/"))).to(be_equal_to(s!("/")));
        expect!(join_paths(&s!("/"), s!("/"))).to(be_equal_to(s!("/")));
        expect!(join_paths(&s!("/a/b"), s!("/c/d"))).to(be_equal_to(s!("/a/b/c/d")));
    }

}
<commit_msg>Fix a couple of warnings<commit_after>use super::*;
use pact_matching::models::*;
use pact_matching::models::matchingrules::*;
use pact_matching::models::generators::*;
use std::str::FromStr;
use std::error::Error;
use std::collections::hash_map::HashMap;
use hyper::client::Client;
use hyper::{Request as HyperRequest, Response as HyperResponse};
use hyper::http::request::{Builder as RequestBuilder};
use hyper::Body;
use hyper::error::Error as HyperError;
use hyper::Method;
use hyper::http::method::InvalidMethod;
use hyper::http::header::{HeaderMap, HeaderName, HeaderValue, InvalidHeaderName, InvalidHeaderValue};
use hyper::http::header::CONTENT_TYPE;
use futures::future;
use futures::future::Future;
use futures::stream::Stream;

#[derive(Debug)]
pub enum ProviderClientError {
    RequestMethodError(String, InvalidMethod),
    RequestHeaderNameError(String, InvalidHeaderName),
    RequestHeaderValueError(String, InvalidHeaderValue),
    RequestBodyError(String),
    ResponseError(String),
    ResponseStatusCodeError(u16),
}

pub fn join_paths(base: &String, path: String) -> String {
    let mut full_path = s!(base.trim_end_matches("/"));
    full_path.push('/');
    full_path.push_str(path.trim_start_matches("/"));
    full_path
}

fn setup_headers(builder: &mut RequestBuilder, headers: &Option<HashMap<String, String>>) -> Result<(), ProviderClientError> {
    let hyper_headers = builder.headers_mut().unwrap();
    match headers {
        Some(header_map) => {
            for (k, v) in header_map {
                // FIXME?: Headers are not sent in "raw" mode.
                // Names are converted to lower case and values are parsed.
                hyper_headers.insert(
                    HeaderName::from_bytes(k.as_bytes())
                        .map_err(|err| ProviderClientError::RequestHeaderNameError(k.clone(), err))?,
                    v.parse::<HeaderValue>()
                        .map_err(|err| ProviderClientError::RequestHeaderValueError(v.clone(), err))?
                );
            }

            if !header_map.keys().any(|k| k.to_lowercase() == "content-type") {
                hyper_headers.insert(CONTENT_TYPE, "application/json".parse().unwrap());
            }
        },
        _ => {}
    }
    Ok(())
}

fn create_hyper_request(base_url: &String, request: &Request) -> Result<HyperRequest<Body>, ProviderClientError> {
    let mut url = join_paths(base_url, request.path.clone());
    if request.query.is_some() {
        url.push('?');
        url.push_str(&build_query_string(request.query.clone().unwrap()));
    }
    debug!("Making request to '{}'", url);
    let mut builder = HyperRequest::builder();
    builder.method(
        Method::from_str(&request.method)
            .map_err(|err| ProviderClientError::RequestMethodError(request.method.clone(), err))?
    );
    builder.uri(url);
    setup_headers(&mut builder, &request.headers())?;

    let hyper_request = builder
        .body(match request.body {
            OptionalBody::Present(ref s) => Body::from(s.clone()),
            OptionalBody::Null => {
                if request.content_type() == "application/json" {
                    Body::from("null")
                } else {
                    Body::empty()
                }
            },
            _ => Body::empty()
        })
        .map_err(|err| ProviderClientError::RequestBodyError(err.description().into()))?;

    Ok(hyper_request)
}

fn extract_headers(headers: &HeaderMap) -> Option<HashMap<String, String>> {
    if headers.len() > 0 {
        Some(headers.iter()
            .map(|(name, value)| {
                (name.as_str().into(), value.to_str().unwrap().into())
            })
            .collect()
        )
    } else {
        None
    }
}

pub fn extract_body(hyper_body: Result<hyper::Chunk, HyperError>) -> Result<OptionalBody, HyperError> {
    match hyper_body {
        Ok(chunk) => {
            let bytes = chunk.into_bytes();
            if bytes.len() > 0 {
                Ok(OptionalBody::Present(bytes.to_vec()))
            } else {
                Ok(OptionalBody::Empty)
            }
        },
        Err(err) => {
            warn!("Failed to read request body: {}", err);
            Ok(OptionalBody::Missing)
        }
    }
}

fn hyper_response_to_pact_response(response: HyperResponse<Body>) -> impl Future<Item = Response, Error = HyperError> {
    debug!("Received response: {:?}", response);

    let status = response.status().as_u16();
    let headers = extract_headers(response.headers());

    response.into_body()
        .concat2()
        .then(extract_body)
        .map(move |body| {
            Response {
                status: status,
                headers: headers,
                body: body,
                matching_rules: MatchingRules::default(),
                generators: Generators::default()
            }
        })
}

fn check_hyper_response_status(result: Result<HyperResponse<Body>, HyperError>) -> Result<(), ProviderClientError> {
    match result {
        Ok(response) => {
            if response.status().is_success() {
                Ok(())
            } else {
                Err(ProviderClientError::ResponseStatusCodeError(response.status().as_u16()))
            }
        },
        Err(err) => Err(ProviderClientError::ResponseError(err.description().into()))
    }
}

pub fn make_provider_request(provider: &ProviderInfo, request: &Request) -> impl Future<Item = Response, Error = ProviderClientError> {
    debug!("Sending {:?} to provider", request);
    let base_url = format!("{}://{}:{}{}", provider.protocol, provider.host, provider.port, provider.path);

    future::done(create_hyper_request(&base_url, request))
        .and_then(|request| {
            Client::new().request(request)
                .and_then(hyper_response_to_pact_response)
                .map_err(|err| ProviderClientError::ResponseError(err.description().into()))
        })
        .map_err(|err| {
            debug!("Request failed: {:?}", err);
            err
        })
}

pub fn make_state_change_request(provider: &ProviderInfo, request: &Request) -> impl Future<Item = (), Error = ProviderClientError> {
    debug!("Sending {:?} to state change handler", request);

    future::done(create_hyper_request(&provider.state_change_url.clone().unwrap(), request))
        .and_then(|request| {
            Client::new().request(request)
                .then(check_hyper_response_status)
        })
}

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

    #[test]
    fn join_paths_test() {
        expect!(join_paths(&s!(""), s!(""))).to(be_equal_to(s!("/")));
        expect!(join_paths(&s!("/"), s!(""))).to(be_equal_to(s!("/")));
        expect!(join_paths(&s!(""), s!("/"))).to(be_equal_to(s!("/")));
        expect!(join_paths(&s!("/"), s!("/"))).to(be_equal_to(s!("/")));
        expect!(join_paths(&s!("/a/b"), s!("/c/d"))).to(be_equal_to(s!("/a/b/c/d")));
    }

}
<|endoftext|>


<commit_before>//! RAII wrapper for a dynamically allocated CSpace slot.

#![cfg_attr(not(test), no_std)]
#![allow(non_snake_case)]

use slot_allocator::KATA_CSPACE_SLOTS;

use sel4_sys::seL4_CapRights;
use sel4_sys::seL4_CNode_Copy;
use sel4_sys::seL4_CNode_Delete;
use sel4_sys::seL4_CNode_Move;
use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_SetCapReceivePath;
use sel4_sys::seL4_WordBits;

extern "C" {
    static SELF_CNODE: seL4_CPtr;
}

pub struct CSpaceSlot {
    pub slot: seL4_CPtr,
}
impl CSpaceSlot {
    pub fn new() -> Self {
        CSpaceSlot {
            slot: unsafe { KATA_CSPACE_SLOTS.alloc(1) }.expect("CSpaceSlot"),
        }
    }

    // Release ownership of the slot; this inhibits the normal cleanup
    // done by drop.
    pub fn release(&mut self) {
        self.slot = seL4_CPtr::MAX;
    }

    // Returns the (root, index, depth) seL4 path for the slot.
    pub fn get_path(&self) -> (seL4_CPtr, seL4_CPtr, u8) {
        (unsafe { SELF_CNODE }, self.slot, seL4_WordBits as u8)
    }

    // Sets the receive path used for receiving a capability attached
    // to an seL4 IPC message.
    pub fn set_recv_path(&self) {
        unsafe { seL4_SetCapReceivePath(SELF_CNODE, self.slot, seL4_WordBits) };
    }

    // Copies the specified path to our slot.
    pub fn copy_to(
        &self,
        src_root: seL4_CPtr,
        src_index: seL4_CPtr,
        src_depth: u8,
    ) -> seL4_Result {
        let seL4_AllRights = seL4_CapRights::new(
            /*grant_reply=*/ 1, /*grant=*/ 1, /*read=*/ 1, /*write=*/ 1,
        );
        unsafe {
            seL4_CNode_Copy(
                /*dest_root=*/ SELF_CNODE,
                /*dest_index= */ self.slot,
                /*dest_depth=*/ seL4_WordBits as u8,
                src_root,
                src_index,
                src_depth,
                seL4_AllRights,
            )
        }
    }

    // Moves the specified path to our slot.
    pub fn move_to(
        &self,
        src_root: seL4_CPtr,
        src_slot: seL4_CPtr,
        src_depth: u8,
    ) -> seL4_Result {
        unsafe {
            seL4_CNode_Move(
                /*dest_root=*/ SELF_CNODE,
                /*dest_index= */ self.slot,
                /*dest_depth=*/ seL4_WordBits as u8,
                src_root,
                src_slot,
                src_depth,
            )
        }
    }

    // Moves our slot to the specified path.
    pub fn move_from(
        &self,
        dest_root: seL4_CPtr,
        dest_slot: seL4_CPtr,
        dest_depth: u8,
    ) -> seL4_Result {
        unsafe {
            seL4_CNode_Move(
                dest_root,
                dest_slot,
                dest_depth,
                /*src_root=*/ SELF_CNODE,
                /*src_index= */ self.slot,
                /*src_depth=*/ seL4_WordBits as u8,
            )
        }
    }
}
impl Drop for CSpaceSlot {
    fn drop(&mut self) {
        if self.slot != seL4_CPtr::MAX {
            unsafe {
                seL4_CNode_Delete(SELF_CNODE, self.slot, seL4_WordBits as u8)
                    .expect("CSpaceSlot");
                KATA_CSPACE_SLOTS.free(self.slot, 1);
            }
        }
    }
}
<commit_msg>kata-os-common: add delete support to CSpaceSlot.<commit_after>//! RAII wrapper for a dynamically allocated CSpace slot.

#![cfg_attr(not(test), no_std)]
#![allow(non_snake_case)]

use slot_allocator::KATA_CSPACE_SLOTS;

use sel4_sys::seL4_CapRights;
use sel4_sys::seL4_CNode_Copy;
use sel4_sys::seL4_CNode_Delete;
use sel4_sys::seL4_CNode_Move;
use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_SetCapReceivePath;
use sel4_sys::seL4_WordBits;

extern "C" {
    static SELF_CNODE: seL4_CPtr;
}

pub struct CSpaceSlot {
    pub slot: seL4_CPtr,
}
impl CSpaceSlot {
    pub fn new() -> Self {
        CSpaceSlot {
            slot: unsafe { KATA_CSPACE_SLOTS.alloc(1) }.expect("CSpaceSlot"),
        }
    }

    // Release ownership of the slot; this inhibits the normal cleanup
    // done by drop.
    pub fn release(&mut self) {
        self.slot = seL4_CPtr::MAX;
    }

    // Returns the (root, index, depth) seL4 path for the slot.
    pub fn get_path(&self) -> (seL4_CPtr, seL4_CPtr, u8) {
        (unsafe { SELF_CNODE }, self.slot, seL4_WordBits as u8)
    }

    // Sets the receive path used for receiving a capability attached
    // to an seL4 IPC message.
    pub fn set_recv_path(&self) {
        unsafe { seL4_SetCapReceivePath(SELF_CNODE, self.slot, seL4_WordBits) };
    }

    // Copies the specified path to our slot.
    pub fn copy_to(
        &self,
        src_root: seL4_CPtr,
        src_index: seL4_CPtr,
        src_depth: u8,
    ) -> seL4_Result {
        let seL4_AllRights = seL4_CapRights::new(
            /*grant_reply=*/ 1, /*grant=*/ 1, /*read=*/ 1, /*write=*/ 1,
        );
        unsafe {
            seL4_CNode_Copy(
                /*dest_root=*/ SELF_CNODE,
                /*dest_index= */ self.slot,
                /*dest_depth=*/ seL4_WordBits as u8,
                src_root,
                src_index,
                src_depth,
                seL4_AllRights,
            )
        }
    }

    // Moves the specified path to our slot.
    pub fn move_to(
        &self,
        src_root: seL4_CPtr,
        src_slot: seL4_CPtr,
        src_depth: u8,
    ) -> seL4_Result {
        unsafe {
            seL4_CNode_Move(
                /*dest_root=*/ SELF_CNODE,
                /*dest_index= */ self.slot,
                /*dest_depth=*/ seL4_WordBits as u8,
                src_root,
                src_slot,
                src_depth,
            )
        }
    }

    // Moves our slot to the specified path.
    pub fn move_from(
        &self,
        dest_root: seL4_CPtr,
        dest_slot: seL4_CPtr,
        dest_depth: u8,
    ) -> seL4_Result {
        unsafe {
            seL4_CNode_Move(
                dest_root,
                dest_slot,
                dest_depth,
                /*src_root=*/ SELF_CNODE,
                /*src_index= */ self.slot,
                /*src_depth=*/ seL4_WordBits as u8,
            )
        }
    }

    // Delete any cap in our slot.
    // NB: deleting an empty slot is a noop to seL4
    pub fn delete(&self) -> seL4_Result {
        unsafe {
            seL4_CNode_Delete(SELF_CNODE, self.slot, seL4_WordBits as u8)
        }
    }
}
impl Drop for CSpaceSlot {
    fn drop(&mut self) {
        if self.slot != seL4_CPtr::MAX {
            unsafe {
                self.delete().expect("CSpaceSlot");
                KATA_CSPACE_SLOTS.free(self.slot, 1);
            }
        }
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

extern crate clap;
#[macro_use] extern crate log;
#[macro_use] extern crate version;

extern crate libimagbookmark;
extern crate libimagentrylink;
extern crate libimagentrytag;
extern crate libimagrt;
extern crate libimagerror;
extern crate libimagutil;

use std::process::exit;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagbookmark::collection::BookmarkCollection;
use libimagbookmark::link::Link as BookmarkLink;
use libimagerror::trace::{trace_error, trace_error_exit};

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup("imag-bookmark",
                                    &version!()[..],
                                    "Bookmark collection tool",
                                    build_ui);

    rt.cli()
        .subcommand_name()
        .map(|name| {
            debug!("Call {}", name);
            match name {
                "add"        => add(&rt),
                "collection" => collection(&rt),
                "list"       => list(&rt),
                "remove"     => remove(&rt),
                _            => {
                    debug!("Unknown command"); // More error handling
                },
            }
        });
}

fn add(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("add").unwrap();
    let coll = scmd.value_of("collection").unwrap(); // enforced by clap

    BookmarkCollection::get(rt.store(), coll)
        .map(|mut collection| {
            for url in scmd.values_of("urls").unwrap() { // enforced by clap
                collection.add_link(BookmarkLink::from(url)).map_err(|e| trace_error(&e)).ok();
            }
        });
    info!("Ready");
}

fn collection(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("collection").unwrap();

    if scmd.is_present("add") { // adding a new collection
        let name = scmd.value_of("add").unwrap();
        if let Ok(_) = BookmarkCollection::new(rt.store(), name) {
            info!("Created: {}", name);
        } else {
            warn!("Creating collection {} failed", name);
            exit(1);
        }
    }

    if scmd.is_present("remove") { // remove a collection
        let name = scmd.value_of("remove").unwrap();
        if let Ok(_) = BookmarkCollection::delete(rt.store(), name) {
            info!("Deleted: {}", name);
        } else {
            warn!("Deleting collection {} failed", name);
            exit(1);
        }
    }
}

fn list(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("list").unwrap();
    let coll = scmd.value_of("collection").unwrap(); // enforced by clap

    BookmarkCollection::get(rt.store(), coll)
        .map(|collection| {
            match collection.links() {
                Ok(links) => {
                    debug!("Listing...");
                    for (i, link) in links.iter().enumerate() {
                        println!("{: >3}: {}", i, link);
                    };
                    debug!("... ready with listing");
                },
                Err(e) => trace_error_exit(&e, 1),
            }
        })
        .ok();
    info!("Ready");
}

fn remove(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("remove").unwrap();
    let coll = scmd.value_of("collection").unwrap(); // enforced by clap

    BookmarkCollection::get(rt.store(), coll)
        .map(|mut collection| {
            for url in scmd.values_of("urls").unwrap() { // enforced by clap
                collection.remove_link(BookmarkLink::from(url)).map_err(|e| trace_error(&e)).ok();
            }
        })
        .ok();
    info!("Ready");
}

<commit_msg>imag-bookmark: Rewrite add() with iterator helpers<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

extern crate clap;
#[macro_use] extern crate log;
#[macro_use] extern crate version;

extern crate libimagbookmark;
extern crate libimagentrylink;
extern crate libimagentrytag;
extern crate libimagrt;
extern crate libimagerror;
extern crate libimagutil;

use std::process::exit;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagbookmark::collection::BookmarkCollection;
use libimagbookmark::link::Link as BookmarkLink;
use libimagerror::trace::{MapErrTrace, trace_error, trace_error_exit};
use libimagutil::info_result::*;
use libimagutil::iter::*;

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup("imag-bookmark",
                                    &version!()[..],
                                    "Bookmark collection tool",
                                    build_ui);

    rt.cli()
        .subcommand_name()
        .map(|name| {
            debug!("Call {}", name);
            match name {
                "add"        => add(&rt),
                "collection" => collection(&rt),
                "list"       => list(&rt),
                "remove"     => remove(&rt),
                _            => {
                    debug!("Unknown command"); // More error handling
                },
            }
        });
}

fn add(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("add").unwrap();
    let coll = scmd.value_of("collection").unwrap(); // enforced by clap

    BookmarkCollection::get(rt.store(), coll)
        .and_then(|mut collection| {
            scmd.values_of("urls")
                .unwrap() // enforced by clap
                .fold_defresult(|url| collection.add_link(BookmarkLink::from(url)))
        })
        .map_err_trace()
        .map_info_str("Ready")
        .ok();
}

fn collection(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("collection").unwrap();

    if scmd.is_present("add") { // adding a new collection
        let name = scmd.value_of("add").unwrap();
        if let Ok(_) = BookmarkCollection::new(rt.store(), name) {
            info!("Created: {}", name);
        } else {
            warn!("Creating collection {} failed", name);
            exit(1);
        }
    }

    if scmd.is_present("remove") { // remove a collection
        let name = scmd.value_of("remove").unwrap();
        if let Ok(_) = BookmarkCollection::delete(rt.store(), name) {
            info!("Deleted: {}", name);
        } else {
            warn!("Deleting collection {} failed", name);
            exit(1);
        }
    }
}

fn list(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("list").unwrap();
    let coll = scmd.value_of("collection").unwrap(); // enforced by clap

    BookmarkCollection::get(rt.store(), coll)
        .map(|collection| {
            match collection.links() {
                Ok(links) => {
                    debug!("Listing...");
                    for (i, link) in links.iter().enumerate() {
                        println!("{: >3}: {}", i, link);
                    };
                    debug!("... ready with listing");
                },
                Err(e) => trace_error_exit(&e, 1),
            }
        })
        .ok();
    info!("Ready");
}

fn remove(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("remove").unwrap();
    let coll = scmd.value_of("collection").unwrap(); // enforced by clap

    BookmarkCollection::get(rt.store(), coll)
        .map(|mut collection| {
            for url in scmd.values_of("urls").unwrap() { // enforced by clap
                collection.remove_link(BookmarkLink::from(url)).map_err(|e| trace_error(&e)).ok();
            }
        })
        .ok();
    info!("Ready");
}

<|endoftext|>


<commit_before>use std::{
    fmt::Debug,
    os::unix::prelude::AsRawFd,
    sync::{Arc, Mutex},
};

use wayland_protocols_misc::zwp_virtual_keyboard_v1::server::zwp_virtual_keyboard_v1::{
    self, ZwpVirtualKeyboardV1,
};
use wayland_server::{
    backend::{ClientId, ObjectId},
    protocol::wl_keyboard::{KeyState, KeymapFormat},
    Client, DataInit, Dispatch, DisplayHandle,
};
use xkbcommon::xkb;

use crate::{
    input::{Seat, SeatHandler},
    utils::SERIAL_COUNTER,
    wayland::seat::{keyboard::for_each_focused_kbds, WaylandFocus},
};

use super::VirtualKeyboardManagerState;

#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
struct SerializedMods {
    depressed: u32,
    latched: u32,
    locked: u32,
    group: u32,
}

#[derive(Debug, Default)]
pub(crate) struct VirtualKeyboard {
    instances: u8,
    modifiers: Option<SerializedMods>,
    old_keymap: Option<String>,
}

/// Handle to a virtual keyboard instance
#[derive(Debug, Clone, Default)]
pub(crate) struct VirtualKeyboardHandle {
    pub(crate) inner: Arc<Mutex<VirtualKeyboard>>,
}

impl VirtualKeyboardHandle {
    pub(super) fn count_instance(&self) {
        let mut inner = self.inner.lock().unwrap();
        inner.instances += 1;
    }
}

/// User data of ZwpVirtualKeyboardV1 object
pub struct VirtualKeyboardUserData<D: SeatHandler> {
    pub(super) handle: VirtualKeyboardHandle,
    pub(crate) seat: Seat<D>,
}

impl<D: SeatHandler> Debug for VirtualKeyboardUserData<D>
where
    <D as SeatHandler>::KeyboardFocus: Debug,
    <D as SeatHandler>::PointerFocus: Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("VirtualKeyboardUserData")
            .field("handle", &self.handle)
            .field("seat", &self.seat.arc)
            .finish()
    }
}

impl<D> Dispatch<ZwpVirtualKeyboardV1, VirtualKeyboardUserData<D>, D> for VirtualKeyboardManagerState
where
    D: Dispatch<ZwpVirtualKeyboardV1, VirtualKeyboardUserData<D>>,
    D: SeatHandler + 'static,
    <D as SeatHandler>::KeyboardFocus: WaylandFocus,
{
    fn request(
        _data: &mut D,
        _client: &Client,
        _: &ZwpVirtualKeyboardV1,
        request: zwp_virtual_keyboard_v1::Request,
        data: &VirtualKeyboardUserData<D>,
        _dh: &DisplayHandle,
        _data_init: &mut DataInit<'_, D>,
    ) {
        match request {
            zwp_virtual_keyboard_v1::Request::Keymap { format, fd, size } => {
                // This should be wl_keyboard::KeymapFormat::XkbV1,
                // but the protocol does not state the parameter is an enum.
                if format == 1 {
                    let keyboard_handle = data.seat.get_keyboard().unwrap();
                    let internal = keyboard_handle.arc.internal.lock().unwrap();
                    let old_keymap = internal.keymap.get_as_string(xkb::FORMAT_TEXT_V1);
                    let new_keymap = unsafe {
                        xkb::Keymap::new_from_fd(
                            &xkb::Context::new(xkb::CONTEXT_NO_FLAGS),
                            fd.as_raw_fd(),
                            size as usize,
                            format,
                            xkb::KEYMAP_COMPILE_NO_FLAGS,
                        )
                        .unwrap()
                        .unwrap()
                    };
                    if old_keymap != new_keymap.get_as_string(xkb::FORMAT_TEXT_V1) {
                        let mut inner = data.handle.inner.lock().unwrap();
                        inner.old_keymap = Some(old_keymap);
                        keyboard_handle.change_keymap(new_keymap);
                        let known_kbds = &keyboard_handle.arc.known_kbds;
                        for kbd in &*known_kbds.lock().unwrap() {
                            kbd.keymap(KeymapFormat::XkbV1, fd.as_raw_fd(), size);
                        }
                    }
                }
            }
            zwp_virtual_keyboard_v1::Request::Key { time, key, state } => {
                let keyboard_handle = data.seat.get_keyboard().unwrap();
                let internal = keyboard_handle.arc.internal.lock().unwrap();
                let inner = data.handle.inner.lock().unwrap();
                if let Some(focus) = internal.focus.as_ref().and_then(|f| f.0.wl_surface()) {
                    for_each_focused_kbds(&data.seat, focus, |kbd| {
                        // This should be wl_keyboard::KeyState,
                        // but the protocol does not state the parameter is an enum.
                        let key_state = if state == 1 {
                            KeyState::Pressed
                        } else {
                            KeyState::Released
                        };
                        kbd.key(SERIAL_COUNTER.next_serial().0, time, key, key_state);
                        if let Some(mods) = inner.modifiers {
                            kbd.modifiers(
                                SERIAL_COUNTER.next_serial().0,
                                mods.depressed,
                                mods.latched,
                                mods.locked,
                                mods.group,
                            );
                        }
                    });
                }
            }
            zwp_virtual_keyboard_v1::Request::Modifiers {
                mods_depressed,
                mods_latched,
                mods_locked,
                group,
            } => {
                data.handle.inner.lock().unwrap().modifiers = Some(SerializedMods {
                    depressed: mods_depressed,
                    latched: mods_latched,
                    locked: mods_locked,
                    group,
                });
            }
            zwp_virtual_keyboard_v1::Request::Destroy => {
                // Nothing to do
            }
            _ => unreachable!(),
        }
    }

    fn destroyed(
        _state: &mut D,
        _client: ClientId,
        _virtual_keyboard: ObjectId,
        data: &VirtualKeyboardUserData<D>,
    ) {
        let mut inner = data.handle.inner.lock().unwrap();
        inner.instances -= 1;
        if inner.instances == 0 {
            if let Some(old_keymap) = &inner.old_keymap {
                let keyboard_handle = data.seat.get_keyboard().unwrap();
                let old_keymap = xkb::Keymap::new_from_string(
                    &xkb::Context::new(xkb::CONTEXT_NO_FLAGS),
                    old_keymap.to_string(),
                    xkb::KEYMAP_FORMAT_TEXT_V1,
                    xkb::KEYMAP_COMPILE_NO_FLAGS,
                )
                .unwrap();
                keyboard_handle.change_keymap(old_keymap);
                let keymap_file = keyboard_handle.arc.keymap.lock().unwrap();
                keymap_file
                    .with_fd(false, |fd, size| {
                        let known_kbds = &keyboard_handle.arc.known_kbds;
                        for kbd in &*known_kbds.lock().unwrap() {
                            kbd.keymap(KeymapFormat::XkbV1, fd.as_raw_fd(), size as u32);
                        }
                    })
                    .ok(); //TODO: log some kind of error here;
            }
        }
    }
}
<commit_msg>clippy<commit_after>use std::{
    fmt::Debug,
    os::unix::prelude::AsRawFd,
    sync::{Arc, Mutex},
};

use wayland_protocols_misc::zwp_virtual_keyboard_v1::server::zwp_virtual_keyboard_v1::{
    self, ZwpVirtualKeyboardV1,
};
use wayland_server::{
    backend::{ClientId, ObjectId},
    protocol::wl_keyboard::{KeyState, KeymapFormat},
    Client, DataInit, Dispatch, DisplayHandle,
};
use xkbcommon::xkb;

use crate::{
    input::{Seat, SeatHandler},
    utils::SERIAL_COUNTER,
    wayland::seat::{keyboard::for_each_focused_kbds, WaylandFocus},
};

use super::VirtualKeyboardManagerState;

#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
struct SerializedMods {
    depressed: u32,
    latched: u32,
    locked: u32,
    group: u32,
}

#[derive(Debug, Default)]
pub(crate) struct VirtualKeyboard {
    instances: u8,
    modifiers: Option<SerializedMods>,
    old_keymap: Option<String>,
}

/// Handle to a virtual keyboard instance
#[derive(Debug, Clone, Default)]
pub(crate) struct VirtualKeyboardHandle {
    pub(crate) inner: Arc<Mutex<VirtualKeyboard>>,
}

impl VirtualKeyboardHandle {
    pub(super) fn count_instance(&self) {
        let mut inner = self.inner.lock().unwrap();
        inner.instances += 1;
    }
}

/// User data of ZwpVirtualKeyboardV1 object
pub struct VirtualKeyboardUserData<D: SeatHandler> {
    pub(super) handle: VirtualKeyboardHandle,
    pub(crate) seat: Seat<D>,
}

impl<D: SeatHandler> Debug for VirtualKeyboardUserData<D>
where
    <D as SeatHandler>::KeyboardFocus: Debug,
    <D as SeatHandler>::PointerFocus: Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("VirtualKeyboardUserData")
            .field("handle", &self.handle)
            .field("seat", &self.seat.arc)
            .finish()
    }
}

impl<D> Dispatch<ZwpVirtualKeyboardV1, VirtualKeyboardUserData<D>, D> for VirtualKeyboardManagerState
where
    D: Dispatch<ZwpVirtualKeyboardV1, VirtualKeyboardUserData<D>>,
    D: SeatHandler + 'static,
    <D as SeatHandler>::KeyboardFocus: WaylandFocus,
{
    fn request(
        _data: &mut D,
        _client: &Client,
        _: &ZwpVirtualKeyboardV1,
        request: zwp_virtual_keyboard_v1::Request,
        data: &VirtualKeyboardUserData<D>,
        _dh: &DisplayHandle,
        _data_init: &mut DataInit<'_, D>,
    ) {
        match request {
            zwp_virtual_keyboard_v1::Request::Keymap { format, fd, size } => {
                // This should be wl_keyboard::KeymapFormat::XkbV1,
                // but the protocol does not state the parameter is an enum.
                if format == 1 {
                    let keyboard_handle = data.seat.get_keyboard().unwrap();
                    let internal = keyboard_handle.arc.internal.lock().unwrap();
                    let old_keymap = internal.keymap.get_as_string(xkb::FORMAT_TEXT_V1);
                    let new_keymap = unsafe {
                        xkb::Keymap::new_from_fd(
                            &xkb::Context::new(xkb::CONTEXT_NO_FLAGS),
                            fd.as_raw_fd(),
                            size as usize,
                            format,
                            xkb::KEYMAP_COMPILE_NO_FLAGS,
                        )
                        .unwrap()
                        .unwrap()
                    };
                    if old_keymap != new_keymap.get_as_string(xkb::FORMAT_TEXT_V1) {
                        let mut inner = data.handle.inner.lock().unwrap();
                        inner.old_keymap = Some(old_keymap);
                        keyboard_handle.change_keymap(new_keymap);
                        let known_kbds = &keyboard_handle.arc.known_kbds;
                        for kbd in &*known_kbds.lock().unwrap() {
                            kbd.keymap(KeymapFormat::XkbV1, fd.as_raw_fd(), size);
                        }
                    }
                }
            }
            zwp_virtual_keyboard_v1::Request::Key { time, key, state } => {
                let keyboard_handle = data.seat.get_keyboard().unwrap();
                let internal = keyboard_handle.arc.internal.lock().unwrap();
                let inner = data.handle.inner.lock().unwrap();
                if let Some(focus) = internal.focus.as_ref().and_then(|f| f.0.wl_surface()) {
                    for_each_focused_kbds(&data.seat, &focus, |kbd| {
                        // This should be wl_keyboard::KeyState,
                        // but the protocol does not state the parameter is an enum.
                        let key_state = if state == 1 {
                            KeyState::Pressed
                        } else {
                            KeyState::Released
                        };
                        kbd.key(SERIAL_COUNTER.next_serial().0, time, key, key_state);
                        if let Some(mods) = inner.modifiers {
                            kbd.modifiers(
                                SERIAL_COUNTER.next_serial().0,
                                mods.depressed,
                                mods.latched,
                                mods.locked,
                                mods.group,
                            );
                        }
                    });
                }
            }
            zwp_virtual_keyboard_v1::Request::Modifiers {
                mods_depressed,
                mods_latched,
                mods_locked,
                group,
            } => {
                data.handle.inner.lock().unwrap().modifiers = Some(SerializedMods {
                    depressed: mods_depressed,
                    latched: mods_latched,
                    locked: mods_locked,
                    group,
                });
            }
            zwp_virtual_keyboard_v1::Request::Destroy => {
                // Nothing to do
            }
            _ => unreachable!(),
        }
    }

    fn destroyed(
        _state: &mut D,
        _client: ClientId,
        _virtual_keyboard: ObjectId,
        data: &VirtualKeyboardUserData<D>,
    ) {
        let mut inner = data.handle.inner.lock().unwrap();
        inner.instances -= 1;
        if inner.instances == 0 {
            if let Some(old_keymap) = &inner.old_keymap {
                let keyboard_handle = data.seat.get_keyboard().unwrap();
                let old_keymap = xkb::Keymap::new_from_string(
                    &xkb::Context::new(xkb::CONTEXT_NO_FLAGS),
                    old_keymap.to_string(),
                    xkb::KEYMAP_FORMAT_TEXT_V1,
                    xkb::KEYMAP_COMPILE_NO_FLAGS,
                )
                .unwrap();
                keyboard_handle.change_keymap(old_keymap);
                let keymap_file = keyboard_handle.arc.keymap.lock().unwrap();
                keymap_file
                    .with_fd(false, |fd, size| {
                        let known_kbds = &keyboard_handle.arc.known_kbds;
                        for kbd in &*known_kbds.lock().unwrap() {
                            kbd.keymap(KeymapFormat::XkbV1, fd.as_raw_fd(), size as u32);
                        }
                    })
                    .ok(); //TODO: log some kind of error here;
            }
        }
    }
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]
extern crate cql_bindgen;

use std::mem;
use std::ffi::CString;

use cql_bindgen::*;

const CASS_UUID_STRING_LENGTH:usize = 37;

unsafe fn print_keyspace(session:&mut CassSession, keyspace:&str) {
    let schema = cass_session_get_schema(session);
    let keyspace = CString::new(keyspace).unwrap();
    let keyspace_meta = cass_schema_get_keyspace(schema, keyspace.as_ptr());

    if !keyspace_meta.is_null() {
        print_schema_meta(&*keyspace_meta, 0);
    } else {
        println!("Unable to find {:?} keyspace in the schema metadata", keyspace);
    }

    let keyspace_meta = cass_schema_get_keyspace(schema, keyspace.as_ptr());

    if !keyspace_meta.is_null() {
        print_schema_meta(&*keyspace_meta, 0);
    } else {
        println!("Unable to find {:?} keyspace in the schema metadata", keyspace);
    }
    cass_schema_free(schema);
}

unsafe fn print_table(session:&mut CassSession, keyspace:&str, table:&str) {
    let schema = cass_session_get_schema(session);
    let keyspace = CString::new(keyspace).unwrap();
    let keyspace_meta = cass_schema_get_keyspace(schema, keyspace.as_ptr());
    let table = CString::new(table).unwrap();

    if !keyspace_meta.is_null() {
        let table_meta = cass_schema_meta_get_entry(keyspace_meta, table.as_ptr());
        if !table_meta.is_null() {
            print_schema_meta(&*table_meta, 0);
        } else {
            println!("Unable to find {:?} table in the schema metadata", table);
        }
    } else {
        println!("Unable to find {:?} keyspace in the schema metadata", keyspace);
    }
    cass_schema_free(schema);
}

//unsafe fn print_error(future:&mut CassFuture) {
//    let message = cass_future_error_message(future);
//    println!("Error: {:?}", raw2utf8(message.data,message.length));
//}

unsafe fn execute_query(session:&mut CassSession, query:&str) -> u32 {
    let query = CString::new(query).unwrap();
    let statement = cass_statement_new(query.as_ptr(), 0);

    let future = cass_session_execute(session, statement);
    cass_future_wait(future);

    let rc = cass_future_error_code(future);
    if rc != CASS_OK {
       // print_error(&mut *future);
    }

    cass_future_free(future);
    cass_statement_free(statement);

    return rc;
}

fn main() {unsafe{
    let cluster = cass_cluster_new();
    let session = cass_session_new();
    let contact_points = CString::new("127.0.0.1").unwrap();
    cass_cluster_set_contact_points(cluster, contact_points.as_ptr());

    let connect_future = cass_session_connect(session, cluster);

    if cass_future_error_code(connect_future) == CASS_OK {

        execute_query(&mut*session,
                  "CREATE KEYSPACE IF NOT EXISTS examples WITH replication = { \
                  'class': 'SimpleStrategy', 'replication_factor': '3' };");

        print_keyspace(&mut*session, "examples");

        execute_query(&mut*session,
                  "CREATE TABLE IF NOT EXISTS examples.schema_meta (key text, \
                  value bigint, \
                  PRIMARY KEY (key));");

        print_table(&mut *session, "examples", "schema_meta");

        /* Close the session */
        let close_future = cass_session_close(session);
        cass_future_wait(close_future);
        cass_future_free(close_future);
    } else {
        /* Handle error */
        let mut m:*const i8 = mem::zeroed();
        let mut l = mem::zeroed();
        cass_future_error_message(connect_future,&mut m, &mut l);

        println!("Unable to connect: {:?}", raw2utf8(m,l as u64));
    }

    cass_future_free(connect_future);
    cass_cluster_free(cluster);
    cass_session_free(session);
}}

fn print_indent(indent:u32) {
    for _ in 0..indent {
        print!("\t");
    }
}

unsafe fn print_schema_value(value:&CassValue) {
    let mut i:cass_int32_t=mem::zeroed();
    let mut b:cass_bool_t=mem::zeroed();
    let mut d:cass_double_t=mem::zeroed();
    //let mut s:CassString=mem::zeroed();
    let mut u:CassUuid=mem::zeroed();
    let mut us:[i8; CASS_UUID_STRING_LENGTH] = mem::zeroed();

    let cass_type = cass_value_type(value);
    match cass_type {
        CASS_VALUE_TYPE_INT => {
            cass_value_get_int32(value, &mut i);
            print!("{}", i);
        }

        CASS_VALUE_TYPE_BOOLEAN => {
            cass_value_get_bool(value, &mut b);
            print!("{}", if b > 0 {"true"} else {"false"});
        }

        CASS_VALUE_TYPE_DOUBLE => {
            cass_value_get_double(value, &mut d);
            print!("{}", d);
        }

//        CASS_VALUE_TYPE_TEXT|CASS_VALUE_TYPE_ASCII|CASS_VALUE_TYPE_VARCHAR => {
//            cass_value_get_string(value, &mut s);
//
//            print!("{:?}", raw2utf8(s.data,s.length));
//        }

        CASS_VALUE_TYPE_UUID => {
            cass_value_get_uuid(value, &mut u);
            cass_uuid_string(u, &mut*us.as_mut_ptr());
            print!("{:?}", "us - FIXME" /*us*/);
        }

        CASS_VALUE_TYPE_LIST => {
            print_schema_list(value);
        }

        CASS_VALUE_TYPE_MAP => {
            print_schema_map(value);
        }
        _ => {
            if cass_value_is_null(value) > 0 {
                print!("null");
            } else {
                print!("<unhandled type>");
            }
        }
    }
}

unsafe fn print_schema_list(value:&CassValue) {
    let iterator = cass_iterator_from_collection(value);
    let mut is_first = cass_true;

    print!("[ ");
    while cass_iterator_next(iterator) > 0 {
        if !is_first > 0 {print!(", ")};
        print_schema_value(&*cass_iterator_get_value(iterator));
        is_first = cass_false;
    }
    print!(" ]");
    cass_iterator_free(iterator);
}

unsafe fn print_schema_map(value:&CassValue) {
    let iterator = cass_iterator_from_map(value);
    let mut is_first = cass_true;

    print!("[[ ");
    while cass_iterator_next(iterator) > 0 {
        if !is_first > 0 {} print!(", ");
        print_schema_value(&*cass_iterator_get_map_key(iterator));
        print!(" : ");
        print_schema_value(&*cass_iterator_get_map_value(iterator));
        is_first = cass_false;
    }
    print!(" ]]");
    cass_iterator_free(iterator);
}

unsafe fn print_schema_meta_field(field:&Struct_CassSchemaMetaField_, indent:u32) {
    //let name = cass_schema_meta_field_name(field);
    let value = cass_schema_meta_field_value(field);

    print_indent(indent);

   // print!("{:?}", raw2utf8(name.data,name.length));
    print_schema_value(&*value);
    print!("\n");
}

unsafe fn print_schema_meta_fields(meta:&CassSchemaMeta, indent:u32) {
    let fields = cass_iterator_fields_from_schema_meta(meta);

    while cass_iterator_next(fields) > 0 {
        print_schema_meta_field(&*cass_iterator_get_schema_meta_field(fields), indent);
    }
    cass_iterator_free(fields);
}

unsafe fn print_schema_meta_entries(meta:&CassSchemaMeta, indent:u32) {
    let entries = cass_iterator_from_schema_meta(meta);

    while cass_iterator_next(entries) > 0 {
        print_schema_meta(&*cass_iterator_get_schema_meta(entries), indent);
    }
    cass_iterator_free(entries);
}

//pub fn cass_value_get_string(value: *const CassValue,
//                                 output: *mut *const ::libc::c_char,
//                                 output_size: *mut size_t) -> CassError;

unsafe fn print_schema_meta(meta:&CassSchemaMeta, indent:u32) {

    print_indent(indent);
   	let mut output = mem::zeroed();
   	let mut output_size = mem::zeroed();

    match cass_schema_meta_type(meta) {
        CASS_SCHEMA_META_TYPE_KEYSPACE => {
            let KS_NAME = CString::new("keyspace_name").unwrap();
            let field = cass_schema_meta_get_field(meta, KS_NAME.as_ptr());
            cass_value_get_string(cass_schema_meta_field_value(&*field), &mut output, &mut output_size);

            println!("Keyspace {:?}", raw2utf8(output,output_size as u64));
            print_schema_meta_fields(meta, indent + 1);
            println!("");
            print_schema_meta_entries(meta, indent + 1);
        }

        CASS_SCHEMA_META_TYPE_TABLE => {
            let CF_NAME = CString::new("columnfamily_name").unwrap();
            let field = cass_schema_meta_get_field(meta, CF_NAME.as_ptr());
            cass_value_get_string(cass_schema_meta_field_value(field), &mut output, &mut output_size);

            println!("Table {:?}", raw2utf8(output,output_size as u64));
            print_schema_meta_fields(meta, indent + 1);
            println!("");
            print_schema_meta_entries(meta, indent + 1);
        }

        CASS_SCHEMA_META_TYPE_COLUMN => {
            let COLUMN_NAME = CString::new("column_name").unwrap();
            let field = cass_schema_meta_get_field(meta, COLUMN_NAME.as_ptr());
            cass_value_get_string(cass_schema_meta_field_value(field), &mut output, &mut output_size);

            println!("Column {:?}", raw2utf8(output,output_size as u64));
            print_schema_meta_fields(meta, indent + 1);
            println!("");
        }
    _ => {panic!("")}
    }
}
<commit_msg>some improvements to printing out schema. needs some more work<commit_after>#![allow(non_snake_case)]
extern crate cql_bindgen;

use std::mem;
use std::ffi::CString;

use cql_bindgen::*;

const CASS_UUID_STRING_LENGTH:usize = 37;

//unsafe fn print_error(future:&mut CassFuture) {
//    let message = cass_future_error_message(future);
//    println!("Error: {:?}", raw2utf8(message.data,message.length));
//}

unsafe fn execute_query(session:&mut CassSession, query:&str) -> u32 {
    let query = CString::new(query).unwrap();
    let statement = cass_statement_new(query.as_ptr(), 0);

    let future = cass_session_execute(session, statement);
    cass_future_wait(future);

    let rc = cass_future_error_code(future);
    if rc != CASS_OK {
       // print_error(&mut *future);
    }

    cass_future_free(future);
    cass_statement_free(statement);

    return rc;
}

fn main() {unsafe{
    let cluster = cass_cluster_new();
    let session = cass_session_new();
    let contact_points = CString::new("127.0.0.1").unwrap();
    cass_cluster_set_contact_points(cluster, contact_points.as_ptr());

    let connect_future = cass_session_connect(session, cluster);

    if cass_future_error_code(connect_future) == CASS_OK {

        execute_query(&mut*session,
                  "CREATE KEYSPACE IF NOT EXISTS examples WITH replication = { \
                  'class': 'SimpleStrategy', 'replication_factor': '3' };");

        print_keyspace(&mut*session, "examples");

        execute_query(&mut*session,
                  "CREATE TABLE IF NOT EXISTS examples.schema_meta (key text, \
                  value bigint, \
                  PRIMARY KEY (key));");

        print_table(&mut *session, "examples", "schema_meta");

        /* Close the session */
        let close_future = cass_session_close(session);
        cass_future_wait(close_future);
        cass_future_free(close_future);
    } else {
        /* Handle error */
        let mut m:*const i8 = mem::zeroed();
        let mut l = mem::zeroed();
        cass_future_error_message(connect_future,&mut m, &mut l);

        println!("Unable to connect: {:?}", raw2utf8(m,l as u64));
    }

    cass_future_free(connect_future);
    cass_cluster_free(cluster);
    cass_session_free(session);
}}

fn print_indent(indent:u32) {
    for _ in 0..indent {
        print!("\t");
    }
}

unsafe fn print_schema_value(value:&CassValue) {
    let mut i:cass_int32_t=mem::zeroed();
    let mut b:cass_bool_t=mem::zeroed();
    let mut d:cass_double_t=mem::zeroed();
    //let mut s:CassString=mem::zeroed();
    let mut u:CassUuid=mem::zeroed();
    let mut us:[i8; CASS_UUID_STRING_LENGTH] = mem::zeroed();

    match cass_value_type(value) {
        CASS_VALUE_TYPE_INT => {
            cass_value_get_int32(value, &mut i);
            println!("{}", i);
        }

        CASS_VALUE_TYPE_BOOLEAN => {
            cass_value_get_bool(value, &mut b);
            println!("{}", if b > 0 {"true"} else {"false"});
        }

        CASS_VALUE_TYPE_DOUBLE => {
            cass_value_get_double(value, &mut d);
            println!("{}", d);
        }

        CASS_VALUE_TYPE_TEXT|CASS_VALUE_TYPE_ASCII|CASS_VALUE_TYPE_VARCHAR => {
            let mut s:*const i8=mem::zeroed();
            let mut s_size:u64=mem::zeroed();
            cass_value_get_string(value, &mut s, &mut s_size);

            println!("{:?}", raw2utf8(s,s_size));
        }

        CASS_VALUE_TYPE_UUID => {
            cass_value_get_uuid(value, &mut u);
            cass_uuid_string(u, &mut*us.as_mut_ptr());
            println!("{:?}", "us - FIXME" /*us*/);
        }

        CASS_VALUE_TYPE_LIST => {
            print_schema_list(value);
        }

        CASS_VALUE_TYPE_MAP => {
            print_schema_map(value);
        }
        _ => {
            match cass_value_is_null(value) {
                0 => println!("<unhandled type>: {:?}",cass_value_type(value)),
                _ => {/*print!("null")*/}
            }
        }
    }
}

unsafe fn print_schema_list(value:&CassValue) {
    let iterator = cass_iterator_from_collection(value);
    let mut is_first = cass_true;

    print!("[ ");
    while cass_iterator_next(iterator) > 0 {
        if !is_first > 0 {print!(", ")};
        print_schema_value(&*cass_iterator_get_value(iterator));
        is_first = cass_false;
    }
    print!(" ]");
    cass_iterator_free(iterator);
}

unsafe fn print_schema_map(value:&CassValue) {
    let iterator = cass_iterator_from_map(value);
    let mut is_first = cass_true;

    print!("[[ ");
    while cass_iterator_next(iterator) > 0 {
        if !is_first > 0 {} print!(", ");
        print_schema_value(&*cass_iterator_get_map_key(iterator));
        print!(" : ");
        print_schema_value(&*cass_iterator_get_map_value(iterator));
        is_first = cass_false;
    }
    print!(" ]]");
    cass_iterator_free(iterator);
}

unsafe fn print_schema_meta_field(field:&Struct_CassSchemaMetaField_, indent:u32) {
    //let name = cass_schema_meta_field_name(field);
    let value = cass_schema_meta_field_value(field);

    print_indent(indent);

   // print!("{:?}", raw2utf8(name.data,name.length));
    print_schema_value(&*value);
    //print!("\n");
}

unsafe fn print_schema_meta_fields(meta:&CassSchemaMeta, indent:u32) {
    let fields = cass_iterator_fields_from_schema_meta(meta);

    while cass_iterator_next(fields) > 0 {
        print_schema_meta_field(&*cass_iterator_get_schema_meta_field(fields), indent);
    }
    cass_iterator_free(fields);
}

unsafe fn print_schema_meta_entries(meta:&CassSchemaMeta, indent:u32) {
    let entries = cass_iterator_from_schema_meta(meta);

    while cass_iterator_next(entries) > 0 {
        print_schema_meta(&*cass_iterator_get_schema_meta(entries), indent);
    }
    cass_iterator_free(entries);
}

unsafe fn print_schema_meta(meta:&CassSchemaMeta, indent:u32) {

    print_indent(indent);
   	let mut output = mem::zeroed();
   	let mut output_size = mem::zeroed();

    match cass_schema_meta_type(meta) {
        CASS_SCHEMA_META_TYPE_KEYSPACE => {
            let KS_NAME = CString::new("keyspace_name").unwrap();
            let field = cass_schema_meta_get_field(meta, KS_NAME.as_ptr());
            cass_value_get_string(cass_schema_meta_field_value(&*field), &mut output, &mut output_size);

            println!("Keyspace {:?}", raw2utf8(output,output_size as u64));
            print_schema_meta_fields(meta, indent + 1);
            //println!("");
            print_schema_meta_entries(meta, indent + 1);
        }

        CASS_SCHEMA_META_TYPE_TABLE => {
            let CF_NAME = CString::new("columnfamily_name").unwrap();
            let field = cass_schema_meta_get_field(meta, CF_NAME.as_ptr());
            cass_value_get_string(cass_schema_meta_field_value(field), &mut output, &mut output_size);

            println!("Table {:?}", raw2utf8(output,output_size as u64));
            print_schema_meta_fields(meta, indent + 1);
            //println!("");
            print_schema_meta_entries(meta, indent + 1);
        }

        CASS_SCHEMA_META_TYPE_COLUMN => {
            let COLUMN_NAME = CString::new("column_name").unwrap();
            let field = cass_schema_meta_get_field(meta, COLUMN_NAME.as_ptr());
            cass_value_get_string(cass_schema_meta_field_value(field), &mut output, &mut output_size);

            println!("{:?}", raw2utf8(output,output_size as u64));
            print_schema_meta_fields(meta, indent + 1);
            //println!("");
        }
    _ => {panic!("")}
    }
}

unsafe fn print_keyspace(session:&mut CassSession, keyspace:&str) {
    let schema = cass_session_get_schema(session);
    let keyspace = CString::new(keyspace).unwrap();
    let keyspace_meta = cass_schema_get_keyspace(schema, keyspace.as_ptr());

    if !keyspace_meta.is_null() {
        print_schema_meta(&*keyspace_meta, 0);
    } else {
        println!("Unable to find {:?} keyspace in the schema metadata", keyspace);
    }

    let keyspace_meta = cass_schema_get_keyspace(schema, keyspace.as_ptr());

    if !keyspace_meta.is_null() {
        print_schema_meta(&*keyspace_meta, 0);
    } else {
        println!("Unable to find {:?} keyspace in the schema metadata", keyspace);
    }
    cass_schema_free(schema);
}

unsafe fn print_table(session:&mut CassSession, keyspace:&str, table:&str) {
    let schema = cass_session_get_schema(session);
    let keyspace = CString::new(keyspace).unwrap();
    let keyspace_meta = cass_schema_get_keyspace(schema, keyspace.as_ptr());
    let table = CString::new(table).unwrap();

    if !keyspace_meta.is_null() {
        let table_meta = cass_schema_meta_get_entry(keyspace_meta, table.as_ptr());
        if !table_meta.is_null() {
            print_schema_meta(&*table_meta, 0);
        } else {
            println!("Unable to find {:?} table in the schema metadata", table);
        }
    } else {
        println!("Unable to find {:?} keyspace in the schema metadata", keyspace);
    }
    cass_schema_free(schema);
}

<|endoftext|>


<commit_before>use super::*;

pub struct PriceFilter {
    pub locale: String,
}

impl PriceFilter {
    fn currencies(&self) -> &'static str {
        "$¢£¤¥֏؋৲৳৻૱௹฿₠₡₢₣₤₥₦₧₨₩₪₫€₭₮₯₰₱₲₳₴₵₶₷₸₹₺₽﹩＄￠￡￥￦"
    }
}

impl LinterFilter for PriceFilter {
    fn locales(&self) -> Vec<&'static str> {
        vec!("de", "en", "es", "fr")
    }

    fn message(&self) -> &'static str {
        match &self.locale as &str {
            "de" | "es" | "fr" => "The currency sign should be written after the amount and a non-breaking space.",
            "en" => "The currency sign should be written before the amount without space.",
            _ => "",
        }
    }

    fn regex_pattern(&self) -> String {
        match &self.locale as &str {
            // Matches one of the following:
            // - digits followed by a character (or none) other than a non-breaking space followed
            //   by any of currencies() return values (ex: `120€` or `120 $`);
            // - any of currencies() return values followed by any whitespace character (or not)
            //   followed by digits (ex: `€120` or `$ 120`).
            "de" | "es" | "fr" => format!("([\\d]+[^ ]?[{}]{{1}}|[{}]{{1}}[\\s]?[\\d]+)", self.currencies(), self.currencies()),

            // Matches one of the following:
            // - digits followed by any whitespace character (or not) followed by any of
            //   currencies() return values (ex: `120€` or `120 €`)
            // - any of currencies() return values followed by any whitespace character followed by
            //   digits (ex: `€ 120` or `$ 120`).
            "en" => format!("([\\d]+[\\s]?[{}]{{1}}|[{}]{{1}}[\\s][\\d]+)", self.currencies(), self.currencies()),

            _ => "".to_string(),
        }
    }
}

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

    struct ExpectedWarning {
        locale: &'static str,
        text: &'static str,
        start: usize,
        end: usize,
    }

    fn expected_warnings() -> Vec<ExpectedWarning> {
        vec!(
            ExpectedWarning { locale: "de", text: "€120", start: 0, end: 6},
            ExpectedWarning { locale: "de", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "de", text: "120€", start: 0, end: 6},

            ExpectedWarning { locale: "en", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "en", text: "120 €", start: 0, end: 8},
            ExpectedWarning { locale: "en", text: "120€", start: 0, end: 6},
            ExpectedWarning { locale: "en", text: "€ 120", start: 0, end: 7},
            ExpectedWarning { locale: "en", text: "€ 120", start: 0, end: 8},

            ExpectedWarning { locale: "es", text: "€120", start: 0, end: 6},
            ExpectedWarning { locale: "es", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "es", text: "120€", start: 0, end: 6},

            ExpectedWarning { locale: "fr", text: "€120", start: 0, end: 6},
            ExpectedWarning { locale: "fr", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "fr", text: "120€", start: 0, end: 6}
        )
    }

    #[test]
    fn test_filters_when_warnings() {
        for expected_warning in expected_warnings() {
            let filter = PriceFilter { locale: expected_warning.locale.to_string() };

            let result = filter.check(expected_warning.text);

            assert!(result.is_err());

            let warnings = result.err().unwrap();

            assert_eq!(1, warnings.len());
            assert_eq!(expected_warning.start, warnings[0].start);
            assert_eq!(expected_warning.end, warnings[0].end);
        }
    }

    #[test]
    fn test_filter_when_de_and_no_warnings() {
        let filter = PriceFilter { locale: "de".to_string() };

        let result = filter.check("120 €");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }

    #[test]
    fn test_filter_when_en_and_no_warnings() {
        let filter = PriceFilter { locale: "en".to_string() };

        let result = filter.check("€120");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }

    #[test]
    fn test_filter_when_es_and_no_warnings() {
        let filter = PriceFilter { locale: "es".to_string() };

        let result = filter.check("120 €");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }

    #[test]
    fn test_filter_when_fr_and_no_warnings() {
        let filter = PriceFilter { locale: "fr".to_string() };

        let result = filter.check("120 €");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }
}

<commit_msg>Add Italian in PriceFilter<commit_after>use super::*;

pub struct PriceFilter {
    pub locale: String,
}

impl PriceFilter {
    fn currencies(&self) -> &'static str {
        "$¢£¤¥֏؋৲৳৻૱௹฿₠₡₢₣₤₥₦₧₨₩₪₫€₭₮₯₰₱₲₳₴₵₶₷₸₹₺₽﹩＄￠￡￥￦"
    }
}

impl LinterFilter for PriceFilter {
    fn locales(&self) -> Vec<&'static str> {
        vec!("de", "en", "es", "fr")
    }

    fn message(&self) -> &'static str {
        match &self.locale as &str {
            "de" | "es" | "fr" => "The currency sign should be written after the amount and a non-breaking space.",
            "en" => "The currency sign should be written before the amount without space.",
            "it" => "The currency sign should be written before the amount and a non-breaking space.",
            _ => "",
        }
    }

    fn regex_pattern(&self) -> String {
        match &self.locale as &str {
            // Matches one of the following:
            // - digits followed by a character (or none) other than a non-breaking space followed
            //   by any of currencies() return values (ex: `120€` or `120 $`);
            // - any of currencies() return values followed by any whitespace character (or not)
            //   followed by digits (ex: `€120` or `$ 120`).
            "de" | "es" | "fr" => format!("([\\d]+[^ ]?[{}]{{1}}|[{}]{{1}}[\\s]?[\\d]+)", self.currencies(), self.currencies()),

            // Matches one of the following:
            // - digits followed by any whitespace character (or not) followed by any of
            //   currencies() return values (ex: `120€` or `120 €`)
            // - any of currencies() return values followed by any whitespace character followed by
            //   digits (ex: `€ 120` or `$ 120`).
            "en" => format!("([\\d]+[\\s]?[{}]{{1}}|[{}]{{1}}[\\s][\\d]+)", self.currencies(), self.currencies()),

            // Matches one of the following:
            // - digits followed by any whitespace character (or not) followed by any of
            //   currencies() return values (ex: `120€` or `120 €`)
            // - any of currencies() return values followed by a character (or none) other than a
            //   non-breaking space followed by digits (ex: `€ 120` or `$120`).
            "it" => format!("([\\d]+[\\s]?[{}]{{1}}|[{}]{{1}}[^ ]?[\\d]+)", self.currencies(), self.currencies()),

            _ => "".to_string(),
        }
    }
}

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

    struct ExpectedWarning {
        locale: &'static str,
        text: &'static str,
        start: usize,
        end: usize,
    }

    fn expected_warnings() -> Vec<ExpectedWarning> {
        vec!(
            ExpectedWarning { locale: "de", text: "€120", start: 0, end: 6},
            ExpectedWarning { locale: "de", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "de", text: "120€", start: 0, end: 6},

            ExpectedWarning { locale: "en", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "en", text: "120 €", start: 0, end: 8},
            ExpectedWarning { locale: "en", text: "120€", start: 0, end: 6},
            ExpectedWarning { locale: "en", text: "€ 120", start: 0, end: 7},
            ExpectedWarning { locale: "en", text: "€ 120", start: 0, end: 8},

            ExpectedWarning { locale: "es", text: "€120", start: 0, end: 6},
            ExpectedWarning { locale: "es", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "es", text: "120€", start: 0, end: 6},

            ExpectedWarning { locale: "fr", text: "€120", start: 0, end: 6},
            ExpectedWarning { locale: "fr", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "fr", text: "120€", start: 0, end: 6},

            ExpectedWarning { locale: "it", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "it", text: "120 €", start: 0, end: 8},
            ExpectedWarning { locale: "it", text: "120€", start: 0, end: 6},
            ExpectedWarning { locale: "it", text: "€120", start: 0, end: 6},
            ExpectedWarning { locale: "it", text: "€ 120", start: 0, end: 7}
        )
    }

    #[test]
    fn test_filters_when_warnings() {
        for expected_warning in expected_warnings() {
            let filter = PriceFilter { locale: expected_warning.locale.to_string() };

            let result = filter.check(expected_warning.text);

            assert!(result.is_err());

            let warnings = result.err().unwrap();

            assert_eq!(1, warnings.len());
            assert_eq!(expected_warning.start, warnings[0].start);
            assert_eq!(expected_warning.end, warnings[0].end);
        }
    }

    #[test]
    fn test_filter_when_de_and_no_warnings() {
        let filter = PriceFilter { locale: "de".to_string() };

        let result = filter.check("120 €");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }

    #[test]
    fn test_filter_when_en_and_no_warnings() {
        let filter = PriceFilter { locale: "en".to_string() };

        let result = filter.check("€120");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }

    #[test]
    fn test_filter_when_es_and_no_warnings() {
        let filter = PriceFilter { locale: "es".to_string() };

        let result = filter.check("120 €");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }

    #[test]
    fn test_filter_when_it_and_no_warnings() {
        let filter = PriceFilter { locale: "it".to_string() };

        let result = filter.check("€ 120");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }

    #[test]
    fn test_filter_when_fr_and_no_warnings() {
        let filter = PriceFilter { locale: "fr".to_string() };

        let result = filter.check("120 €");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }
}

<|endoftext|>


<commit_before>use filetime::{self, FileTime};
use lazy_static::lazy_static;
use std::cell::RefCell;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::io::{self, ErrorKind};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;
use crate::{basic_manifest, project};

static CARGO_INTEGRATION_TEST_DIR: &str = "cit";

lazy_static! {
    static ref GLOBAL_ROOT: PathBuf = {
        let mut path = t!(env::current_exe());
        path.pop(); // chop off exe name
        path.pop(); // chop off 'debug'

        // If `cargo test` is run manually then our path looks like
        // `target/debug/foo`, in which case our `path` is already pointing at
        // `target`. If, however, `cargo test --target $target` is used then the
        // output is `target/$target/debug/foo`, so our path is pointing at
        // `target/$target`. Here we conditionally pop the `$target` name.
        if path.file_name().and_then(|s| s.to_str()) != Some("target") {
            path.pop();
        }

        path.push(CARGO_INTEGRATION_TEST_DIR);
        path.mkdir_p();
        path
    };

    static ref TEST_ROOTS: Mutex<HashMap<String, PathBuf>> = Default::default();
}

// We need to give each test a unique id. The test name could serve this
// purpose, but the `test` crate doesn't have a way to obtain the current test
// name.[*] Instead, we used the `cargo-test-macro` crate to automatically
// insert an init function for each test that sets the test name in a thread
// local variable.
//
// [*] It does set the thread name, but only when running concurrently. If not
// running concurrently, all tests are run on the main thread.
thread_local! {
    static TEST_ID: RefCell<Option<usize>> = RefCell::new(None);
}

pub struct TestIdGuard {
    _private: (),
}

pub fn init_root() -> TestIdGuard {
    static NEXT_ID: AtomicUsize = AtomicUsize::new(0);

    let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
    TEST_ID.with(|n| *n.borrow_mut() = Some(id));

    let guard = TestIdGuard { _private: () };

    let r = root();
    r.rm_rf();
    r.mkdir_p();

    guard
}

impl Drop for TestIdGuard {
    fn drop(&mut self) {
        TEST_ID.with(|n| *n.borrow_mut() = None);
    }
}

pub fn root() -> PathBuf {
    let id = TEST_ID.with(|n| {
        n.borrow().expect(
            "Tests must use the `#[cargo_test]` attribute in \
             order to be able to use the crate root.",
        )
    });
    GLOBAL_ROOT.join(&format!("t{}", id))
}

pub fn home() -> PathBuf {
    let mut path = root();
    path.push("home");
    path.mkdir_p();
    path
}

pub trait CargoPathExt {
    fn rm_rf(&self);
    fn mkdir_p(&self);

    fn move_into_the_past(&self) {
        self.move_in_time(|sec, nsec| (sec - 3600, nsec))
    }

    fn move_into_the_future(&self) {
        self.move_in_time(|sec, nsec| (sec + 3600, nsec))
    }

    fn move_in_time<F>(&self, travel_amount: F)
    where
        F: Fn(i64, u32) -> (i64, u32);

    fn is_symlink(&self) -> bool;
}

impl CargoPathExt for Path {
    /* Technically there is a potential race condition, but we don't
     * care all that much for our tests
     */
    fn rm_rf(&self) {
        if self.exists() {
            if let Err(e) = remove_dir_all::remove_dir_all(self) {
                panic!("failed to remove {:?}: {:?}", self, e)
            }
        }
    }

    fn mkdir_p(&self) {
        fs::create_dir_all(self)
            .unwrap_or_else(|e| panic!("failed to mkdir_p {}: {}", self.display(), e))
    }

    fn move_in_time<F>(&self, travel_amount: F)
    where
        F: Fn(i64, u32) -> (i64, u32),
    {
        if self.is_file() {
            time_travel(self, &travel_amount);
        } else {
            recurse(self, &self.join("target"), &travel_amount);
        }

        fn recurse<F>(p: &Path, bad: &Path, travel_amount: &F)
        where
            F: Fn(i64, u32) -> (i64, u32),
        {
            if p.is_file() {
                time_travel(p, travel_amount)
            } else if !p.starts_with(bad) {
                for f in t!(fs::read_dir(p)) {
                    let f = t!(f).path();
                    recurse(&f, bad, travel_amount);
                }
            }
        }

        fn time_travel<F>(path: &Path, travel_amount: &F)
        where
            F: Fn(i64, u32) -> (i64, u32),
        {
            let stat = t!(path.symlink_metadata());

            let mtime = FileTime::from_last_modification_time(&stat);

            let (sec, nsec) = travel_amount(mtime.unix_seconds(), mtime.nanoseconds());
            let newtime = FileTime::from_unix_time(sec, nsec);

            // Sadly change_file_times has a failure mode where a readonly file
            // cannot have its times changed on windows.
            do_op(path, "set file times", |path| {
                filetime::set_file_times(path, newtime, newtime)
            });
        }
    }

    fn is_symlink(&self) -> bool {
        fs::symlink_metadata(self)
            .map(|m| m.file_type().is_symlink())
            .unwrap_or(false)
    }
}

fn do_op<F>(path: &Path, desc: &str, mut f: F)
where
    F: FnMut(&Path) -> io::Result<()>,
{
    match f(path) {
        Ok(()) => {}
        Err(ref e) if e.kind() == ErrorKind::PermissionDenied => {
            let mut p = t!(path.metadata()).permissions();
            p.set_readonly(false);
            t!(fs::set_permissions(path, p));

            // Unix also requires the parent to not be readonly for example when
            // removing files
            let parent = path.parent().unwrap();
            let mut p = t!(parent.metadata()).permissions();
            p.set_readonly(false);
            t!(fs::set_permissions(parent, p));

            f(path).unwrap_or_else(|e| {
                panic!("failed to {} {}: {}", desc, path.display(), e);
            })
        }
        Err(e) => {
            panic!("failed to {} {}: {}", desc, path.display(), e);
        }
    }
}

/// Get the filename for a library.
///
/// `kind` should be one of: "lib", "rlib", "staticlib", "dylib", "proc-macro"
///
/// For example, dynamic library named "foo" would return:
/// - macOS: "libfoo.dylib"
/// - Windows: "foo.dll"
/// - Unix: "libfoo.so"
pub fn get_lib_filename(name: &str, kind: &str) -> String {
    let prefix = get_lib_prefix(kind);
    let extension = get_lib_extension(kind);
    format!("{}{}.{}", prefix, name, extension)
}

pub fn get_lib_prefix(kind: &str) -> &str {
    match kind {
        "lib" | "rlib" => "lib",
        "staticlib" | "dylib" | "proc-macro" => {
            if cfg!(windows) {
                ""
            } else {
                "lib"
            }
        }
        _ => unreachable!(),
    }
}

pub fn get_lib_extension(kind: &str) -> &str {
    match kind {
        "lib" | "rlib" => "rlib",
        "staticlib" => {
            if cfg!(windows) {
                "lib"
            } else {
                "a"
            }
        }
        "dylib" | "proc-macro" => {
            if cfg!(windows) {
                "dll"
            } else if cfg!(target_os = "macos") {
                "dylib"
            } else {
                "so"
            }
        }
        _ => unreachable!(),
    }
}

/// Returns the sysroot as queried from rustc.
pub fn sysroot() -> String {
    let output = Command::new("rustc")
        .arg("--print=sysroot")
        .output()
        .expect("rustc to run");
    assert!(output.status.success());
    let sysroot = String::from_utf8(output.stdout).unwrap();
    sysroot.trim().to_string()
}

pub fn echo_wrapper() -> std::path::PathBuf {
    let p = project()
        .at("rustc-echo-wrapper")
        .file("Cargo.toml", &basic_manifest("rustc-echo-wrapper", "1.0.0"))
        .file(
            "src/main.rs",
            r#"
            fn main() {
                let args = std::env::args().collect::<Vec<_>>();
                eprintln!("WRAPPER CALLED: {}", args[1..].join(" "));
                let status = std::process::Command::new(&args[1])
                    .args(&args[2..]).status().unwrap();
                std::process::exit(status.code().unwrap_or(1));
            }
            "#,
        )
        .build();
    p.cargo("build").run();
    p.bin("rustc-echo-wrapper")
}
<commit_msg>rustfmt<commit_after>use crate::{basic_manifest, project};
use filetime::{self, FileTime};
use lazy_static::lazy_static;
use std::cell::RefCell;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::io::{self, ErrorKind};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;

static CARGO_INTEGRATION_TEST_DIR: &str = "cit";

lazy_static! {
    static ref GLOBAL_ROOT: PathBuf = {
        let mut path = t!(env::current_exe());
        path.pop(); // chop off exe name
        path.pop(); // chop off 'debug'

        // If `cargo test` is run manually then our path looks like
        // `target/debug/foo`, in which case our `path` is already pointing at
        // `target`. If, however, `cargo test --target $target` is used then the
        // output is `target/$target/debug/foo`, so our path is pointing at
        // `target/$target`. Here we conditionally pop the `$target` name.
        if path.file_name().and_then(|s| s.to_str()) != Some("target") {
            path.pop();
        }

        path.push(CARGO_INTEGRATION_TEST_DIR);
        path.mkdir_p();
        path
    };

    static ref TEST_ROOTS: Mutex<HashMap<String, PathBuf>> = Default::default();
}

// We need to give each test a unique id. The test name could serve this
// purpose, but the `test` crate doesn't have a way to obtain the current test
// name.[*] Instead, we used the `cargo-test-macro` crate to automatically
// insert an init function for each test that sets the test name in a thread
// local variable.
//
// [*] It does set the thread name, but only when running concurrently. If not
// running concurrently, all tests are run on the main thread.
thread_local! {
    static TEST_ID: RefCell<Option<usize>> = RefCell::new(None);
}

pub struct TestIdGuard {
    _private: (),
}

pub fn init_root() -> TestIdGuard {
    static NEXT_ID: AtomicUsize = AtomicUsize::new(0);

    let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
    TEST_ID.with(|n| *n.borrow_mut() = Some(id));

    let guard = TestIdGuard { _private: () };

    let r = root();
    r.rm_rf();
    r.mkdir_p();

    guard
}

impl Drop for TestIdGuard {
    fn drop(&mut self) {
        TEST_ID.with(|n| *n.borrow_mut() = None);
    }
}

pub fn root() -> PathBuf {
    let id = TEST_ID.with(|n| {
        n.borrow().expect(
            "Tests must use the `#[cargo_test]` attribute in \
             order to be able to use the crate root.",
        )
    });
    GLOBAL_ROOT.join(&format!("t{}", id))
}

pub fn home() -> PathBuf {
    let mut path = root();
    path.push("home");
    path.mkdir_p();
    path
}

pub trait CargoPathExt {
    fn rm_rf(&self);
    fn mkdir_p(&self);

    fn move_into_the_past(&self) {
        self.move_in_time(|sec, nsec| (sec - 3600, nsec))
    }

    fn move_into_the_future(&self) {
        self.move_in_time(|sec, nsec| (sec + 3600, nsec))
    }

    fn move_in_time<F>(&self, travel_amount: F)
    where
        F: Fn(i64, u32) -> (i64, u32);

    fn is_symlink(&self) -> bool;
}

impl CargoPathExt for Path {
    /* Technically there is a potential race condition, but we don't
     * care all that much for our tests
     */
    fn rm_rf(&self) {
        if self.exists() {
            if let Err(e) = remove_dir_all::remove_dir_all(self) {
                panic!("failed to remove {:?}: {:?}", self, e)
            }
        }
    }

    fn mkdir_p(&self) {
        fs::create_dir_all(self)
            .unwrap_or_else(|e| panic!("failed to mkdir_p {}: {}", self.display(), e))
    }

    fn move_in_time<F>(&self, travel_amount: F)
    where
        F: Fn(i64, u32) -> (i64, u32),
    {
        if self.is_file() {
            time_travel(self, &travel_amount);
        } else {
            recurse(self, &self.join("target"), &travel_amount);
        }

        fn recurse<F>(p: &Path, bad: &Path, travel_amount: &F)
        where
            F: Fn(i64, u32) -> (i64, u32),
        {
            if p.is_file() {
                time_travel(p, travel_amount)
            } else if !p.starts_with(bad) {
                for f in t!(fs::read_dir(p)) {
                    let f = t!(f).path();
                    recurse(&f, bad, travel_amount);
                }
            }
        }

        fn time_travel<F>(path: &Path, travel_amount: &F)
        where
            F: Fn(i64, u32) -> (i64, u32),
        {
            let stat = t!(path.symlink_metadata());

            let mtime = FileTime::from_last_modification_time(&stat);

            let (sec, nsec) = travel_amount(mtime.unix_seconds(), mtime.nanoseconds());
            let newtime = FileTime::from_unix_time(sec, nsec);

            // Sadly change_file_times has a failure mode where a readonly file
            // cannot have its times changed on windows.
            do_op(path, "set file times", |path| {
                filetime::set_file_times(path, newtime, newtime)
            });
        }
    }

    fn is_symlink(&self) -> bool {
        fs::symlink_metadata(self)
            .map(|m| m.file_type().is_symlink())
            .unwrap_or(false)
    }
}

fn do_op<F>(path: &Path, desc: &str, mut f: F)
where
    F: FnMut(&Path) -> io::Result<()>,
{
    match f(path) {
        Ok(()) => {}
        Err(ref e) if e.kind() == ErrorKind::PermissionDenied => {
            let mut p = t!(path.metadata()).permissions();
            p.set_readonly(false);
            t!(fs::set_permissions(path, p));

            // Unix also requires the parent to not be readonly for example when
            // removing files
            let parent = path.parent().unwrap();
            let mut p = t!(parent.metadata()).permissions();
            p.set_readonly(false);
            t!(fs::set_permissions(parent, p));

            f(path).unwrap_or_else(|e| {
                panic!("failed to {} {}: {}", desc, path.display(), e);
            })
        }
        Err(e) => {
            panic!("failed to {} {}: {}", desc, path.display(), e);
        }
    }
}

/// Get the filename for a library.
///
/// `kind` should be one of: "lib", "rlib", "staticlib", "dylib", "proc-macro"
///
/// For example, dynamic library named "foo" would return:
/// - macOS: "libfoo.dylib"
/// - Windows: "foo.dll"
/// - Unix: "libfoo.so"
pub fn get_lib_filename(name: &str, kind: &str) -> String {
    let prefix = get_lib_prefix(kind);
    let extension = get_lib_extension(kind);
    format!("{}{}.{}", prefix, name, extension)
}

pub fn get_lib_prefix(kind: &str) -> &str {
    match kind {
        "lib" | "rlib" => "lib",
        "staticlib" | "dylib" | "proc-macro" => {
            if cfg!(windows) {
                ""
            } else {
                "lib"
            }
        }
        _ => unreachable!(),
    }
}

pub fn get_lib_extension(kind: &str) -> &str {
    match kind {
        "lib" | "rlib" => "rlib",
        "staticlib" => {
            if cfg!(windows) {
                "lib"
            } else {
                "a"
            }
        }
        "dylib" | "proc-macro" => {
            if cfg!(windows) {
                "dll"
            } else if cfg!(target_os = "macos") {
                "dylib"
            } else {
                "so"
            }
        }
        _ => unreachable!(),
    }
}

/// Returns the sysroot as queried from rustc.
pub fn sysroot() -> String {
    let output = Command::new("rustc")
        .arg("--print=sysroot")
        .output()
        .expect("rustc to run");
    assert!(output.status.success());
    let sysroot = String::from_utf8(output.stdout).unwrap();
    sysroot.trim().to_string()
}

pub fn echo_wrapper() -> std::path::PathBuf {
    let p = project()
        .at("rustc-echo-wrapper")
        .file("Cargo.toml", &basic_manifest("rustc-echo-wrapper", "1.0.0"))
        .file(
            "src/main.rs",
            r#"
            fn main() {
                let args = std::env::args().collect::<Vec<_>>();
                eprintln!("WRAPPER CALLED: {}", args[1..].join(" "));
                let status = std::process::Command::new(&args[1])
                    .args(&args[2..]).status().unwrap();
                std::process::exit(status.code().unwrap_or(1));
            }
            "#,
        )
        .build();
    p.cargo("build").run();
    p.bin("rustc-echo-wrapper")
}
<|endoftext|>


<commit_before>extern crate curl;
extern crate crypto_hash;

#[cfg(feature = "pi")]
extern crate wiringpi;

use std::path::Path;
use std::fs::File;
use std::error::Error;
use std::io::prelude::*;
use std::{thread, time};
use std::str;

use curl::easy::Easy;

use crypto_hash::{Algorithm, hex_digest};

static CONFIG_FILE_NAME: &'static str = "doorstate.config";

struct API {
    url: String,
    rate_ms: i64,
    pre_shared_key: String
}

struct GPIO {
    pin: i8
}

fn config() -> (API, GPIO)
{
    let path = Path::new(CONFIG_FILE_NAME);
    let path_display = path.display();

    let mut file = match File::open(&path) {
        Err(why) => panic!(
            "Couldn't open {}: {}",
            path_display,
            why.description()),
        Ok(file) => file,
    };

    let mut config = String::new();

    match file.read_to_string(&mut config) {
        Err(why) => panic!(
            "Couldn't read {}: {}",
            path_display,
            why.description()),
        //Ok(_) => print!("{} contains:\n{}", path_display, config),
        Ok(_) => {},
    };

    let mut api = API {
        url: String::new(),
        pre_shared_key: String::new(),
        rate_ms: -1
    };

    let mut gpio = GPIO {
        pin: -1
    };

    for line in config.lines() {
        // Ignore comments (lines starting with '#')
        if !line.trim().starts_with("#") {
            //println!("{}", line);
            let tokens: Vec<&str> = line.splitn(2, "=").collect();

            let key = tokens[0].trim();
            let value = tokens[1].trim();

            match key {
                "api.url" => api.url = value.to_string(),
                "api.rate-ms" => api.rate_ms = value.parse::<i64>().unwrap(),
                "api.pre-shared-key" => api.pre_shared_key = value.to_string(),
                "gpio.pin" => gpio.pin = value.parse::<i8>().unwrap(),
                _ => {},
            }
        }
    }

    (api, gpio)
}

#[cfg(feature = "pi")]
fn read_doorstate() {
}

fn send_doorstate(baseurl: String, pre_shared_key: String, status: String) {
    let mut easy = Easy::new();
    let mut dst = Vec::new();

    easy.url(&baseurl).unwrap();

    // This scope is required to end the borrow of dst
    {
        let mut transfer = easy.transfer();
        transfer.write_function(|data| {
            dst.extend_from_slice(data);
            Ok(data.len())
        }).unwrap();
        transfer.perform().unwrap();
    }

    let challenge = str::from_utf8(&dst).unwrap();
    let mut response = dst.to_vec();

    response.extend_from_slice(pre_shared_key.as_bytes());

    let response_hashed = hex_digest(Algorithm::SHA256, response);
    let url: String = baseurl + "?" +
        "challenge=" + challenge + "&" +
        "response=" + &response_hashed + "&" +
        "status=" + &status;

    println!("{}", url);

    easy.url(&url).unwrap();

    let transfer = easy.transfer();

    transfer.perform().unwrap();
}

#[cfg(feature = "pi")]
fn setup_gpio(pin: i8) -> WiringPi {
    let pi = wiringpi::setup();
    let pin = pi.input_pin(pin);

    pi
}

#[allow(unused_variables)]
fn setup_gpio(pin: i8) {
}

fn main() {
    let (api, gpio) = config();
    let duration;

    let pi = setup_gpio(gpio.pin);

    if api.rate_ms > -1 {
        duration = time::Duration::from_millis(api.rate_ms as u64);
    } else {
        duration = time::Duration::from_millis(0);
    }

    send_doorstate(api.url, api.pre_shared_key, "offen".to_string());

    /*
    loop {
        println!("Test");

        if pi != () {
            println!("pi is not equal to unit type");
        }

        if duration > time::Duration::from_millis(0) {
            thread::sleep(duration);
        }
    }
    */
}
<commit_msg>Read door state from GPIO and send it (not tested)<commit_after>extern crate curl;
extern crate crypto_hash;

#[cfg(feature = "pi")]
extern crate wiringpi;

use std::path::Path;
use std::fs::File;
use std::error::Error;
use std::io::prelude::*;
use std::{thread, time};
use std::str;

use curl::easy::Easy;

use crypto_hash::{Algorithm, hex_digest};

static CONFIG_FILE_NAME: &'static str = "doorstate.config";

struct API {
    url: String,
    rate_ms: i64,
    pre_shared_key: String
}

struct GPIO {
    pin: i8
}

fn config() -> (API, GPIO)
{
    let path = Path::new(CONFIG_FILE_NAME);
    let path_display = path.display();

    let mut file = match File::open(&path) {
        Err(why) => panic!(
            "Couldn't open {}: {}",
            path_display,
            why.description()),
        Ok(file) => file,
    };

    let mut config = String::new();

    match file.read_to_string(&mut config) {
        Err(why) => panic!(
            "Couldn't read {}: {}",
            path_display,
            why.description()),
        //Ok(_) => print!("{} contains:\n{}", path_display, config),
        Ok(_) => {},
    };

    let mut api = API {
        url: String::new(),
        pre_shared_key: String::new(),
        rate_ms: -1
    };

    let mut gpio = GPIO {
        pin: -1
    };

    for line in config.lines() {
        // Ignore comments (lines starting with '#')
        if !line.trim().starts_with("#") {
            //println!("{}", line);
            let tokens: Vec<&str> = line.splitn(2, "=").collect();

            let key = tokens[0].trim();
            let value = tokens[1].trim();

            match key {
                "api.url" => api.url = value.to_string(),
                "api.rate-ms" => api.rate_ms = value.parse::<i64>().unwrap(),
                "api.pre-shared-key" => api.pre_shared_key = value.to_string(),
                "gpio.pin" => gpio.pin = value.parse::<i8>().unwrap(),
                _ => {},
            }
        }
    }

    (api, gpio)
}

#[cfg(feature = "pi")]
fn read_doorstate(pin: InputPin) -> String {
    let mut status: String  = "geschlossen";

    if pin.digital_read() == wiringpi::pin::Value::Low {
        status = "offen";
    }

    return status
}

#[allow(unused_variables)]
fn read_doorstate(pin: ()) -> String {
    return "offen".to_string();
}

fn send_doorstate(baseurl: &String, pre_shared_key: &String, status: &String) {
    let mut easy = Easy::new();
    let mut dst = Vec::new();

    easy.url(&baseurl).unwrap();

    // This scope is required to end the borrow of dst
    {
        let mut transfer = easy.transfer();
        transfer.write_function(|data| {
            dst.extend_from_slice(data);
            Ok(data.len())
        }).unwrap();
        transfer.perform().unwrap();
    }

    let challenge = str::from_utf8(&dst).unwrap();
    let mut response = dst.to_vec();

    response.extend_from_slice(pre_shared_key.as_bytes());

    let response_hashed = hex_digest(Algorithm::SHA256, response);
    let mut url: String = String::new();

    url.push_str(baseurl);
    url.push_str("?");
    url.push_str("challenge=");
    url.push_str(challenge);
    url.push_str("&");
    url.push_str("response=");
    url.push_str(&response_hashed);
    url.push_str("&");
    url.push_str("status=");
    url.push_str(status);

    easy.url(&url).unwrap();

    let transfer = easy.transfer();

    transfer.perform().unwrap();
}

#[cfg(feature = "pi")]
fn setup_gpio(pin: i8) -> InputPin {
    let pi = wiringpi::setup();
    let pin = pi.input_pin(pin);

    return pin
}

#[allow(unused_variables)]
fn setup_gpio(pin: i8) {
}

fn main() {
    let (api, gpio) = config();
    let duration;
    let mut status_last: String = "".to_string();

    let pin = setup_gpio(gpio.pin);

    if api.rate_ms > -1 {
        duration = time::Duration::from_millis(api.rate_ms as u64);
    } else {
        duration = time::Duration::from_millis(0);
    }

    loop {
        let status_new = read_doorstate(pin);

        if status_new != status_last {
            send_doorstate(&api.url, &api.pre_shared_key, &status_new);

            status_last = status_new;
        }

        if duration > time::Duration::from_millis(0) {
            thread::sleep(duration);
        }
    }
}
<|endoftext|>