<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use std::convert::TryInto;

use seccomp::{
    allow_syscall, allow_syscall_if, BpfProgram, Error, SeccompAction, SeccompCmpArgLen as ArgLen,
    SeccompCmpOp::Eq, SeccompCondition as Cond, SeccompError, SeccompFilter, SeccompLevel,
    SeccompRule,
};
use utils::signal::sigrtmin;

/// The default filter containing the white listed syscall rules required by `Firecracker` to
/// function.
/// Any non-trivial modification to this allow list needs a proper comment to specify its source
/// or why the sycall/condition is needed.
pub fn default_filter() -> Result<SeccompFilter, Error> {
    Ok(SeccompFilter::new(
        vec![
            // Called by the api thread to receive data on socket
            allow_syscall_if(
                libc::SYS_accept4,
                or![and![Cond::new(
                    3,
                    ArgLen::DWORD,
                    Eq,
                    libc::SOCK_CLOEXEC as u64
                )?],],
            ),
            // Called for expanding the heap
            allow_syscall(libc::SYS_brk),
            // Used for metrics, via the helpers in utils/src/time.rs
            allow_syscall_if(
                libc::SYS_clock_gettime,
                or![and![Cond::new(
                    0,
                    ArgLen::DWORD,
                    Eq,
                    libc::CLOCK_PROCESS_CPUTIME_ID as u64
                )?],],
            ),
            allow_syscall(libc::SYS_close),
            // Needed for vsock
            allow_syscall(libc::SYS_connect),
            allow_syscall(libc::SYS_epoll_ctl),
            allow_syscall(libc::SYS_epoll_pwait),
            #[cfg(all(target_env = "gnu", target_arch = "x86_64"))]
            allow_syscall(libc::SYS_epoll_wait),
            allow_syscall(libc::SYS_exit),
            allow_syscall(libc::SYS_exit_group),
            // Used by snapshotting, drive patching and rescanning
            allow_syscall_if(
                libc::SYS_fcntl,
                or![and![
                    Cond::new(1, ArgLen::DWORD, Eq, super::FCNTL_F_SETFD)?,
                    Cond::new(2, ArgLen::DWORD, Eq, super::FCNTL_FD_CLOEXEC)?,
                ],],
            ),
            // Used for drive patching & rescanning, for reading the local timezone
            allow_syscall(libc::SYS_fstat),
            // Used for snapshotting
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_ftruncate),
            // Used for synchronization
            allow_syscall_if(
                libc::SYS_futex,
                or![
                    and![Cond::new(1, ArgLen::DWORD, Eq, super::FUTEX_WAIT_PRIVATE)?],
                    and![Cond::new(1, ArgLen::DWORD, Eq, super::FUTEX_WAKE_PRIVATE)?],
                    #[cfg(target_env = "gnu")]
                    and![Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        super::FUTEX_CMP_REQUEUE_PRIVATE
                    )?],
                ],
            ),
            // Used by glibc's tgkill
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_getpid),
            allow_syscall_if(libc::SYS_ioctl, super::create_ioctl_seccomp_rule()?),
            // Used by the block device
            allow_syscall(libc::SYS_lseek),
            // Triggered by musl for some customer workloads
            #[cfg(target_env = "musl")]
            allow_syscall_if(
                libc::SYS_madvise,
                or![and![Cond::new(
                    2,
                    ArgLen::DWORD,
                    Eq,
                    libc::MADV_DONTNEED as u64
                )?],],
            ),
            // Used for re-allocating large memory regions, for example vectors
            allow_syscall(libc::SYS_mremap),
            // Used for freeing memory
            allow_syscall(libc::SYS_munmap),
            // Used for reading the timezone in LocalTime::now()
            allow_syscall_if(
                libc::SYS_mmap,
                or![and![Cond::new(
                    3,
                    ArgLen::DWORD,
                    Eq,
                    libc::MAP_SHARED as u64
                )?],],
            ),
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_open),
            #[cfg(target_arch = "aarch64")]
            allow_syscall(libc::SYS_openat),
            allow_syscall(libc::SYS_read),
            // Used by the API thread and vsock
            allow_syscall(libc::SYS_recvfrom),
            // SYS_rt_sigreturn is needed in case a fault does occur, so that the signal handler
            // can return. Otherwise we get stuck in a fault loop.
            allow_syscall(libc::SYS_rt_sigreturn),
            // Used by the API thread and vsock
            allow_syscall_if(
                libc::SYS_socket,
                or![and![
                    Cond::new(0, ArgLen::DWORD, Eq, libc::AF_UNIX as u64)?,
                    Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        (libc::SOCK_STREAM as u64) | (libc::SOCK_CLOEXEC as u64)
                    )?,
                    Cond::new(2, ArgLen::DWORD, Eq, 0u64)?
                ],],
            ),
            // Used to kick vcpus
            allow_syscall_if(
                libc::SYS_tkill,
                or![and![Cond::new(
                    1,
                    ArgLen::DWORD,
                    Eq,
                    (sigrtmin() + super::super::vstate::vcpu::VCPU_RTSIG_OFFSET) as u64
                )?]],
            ),
            // Used to kick vcpus, on gnu
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_tgkill),
            // Needed for rate limiting
            allow_syscall_if(
                libc::SYS_timerfd_create,
                or![and![
                    Cond::new(0, ArgLen::DWORD, Eq, libc::CLOCK_MONOTONIC as u64)?,
                    Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        (libc::TFD_CLOEXEC as u64) | (libc::TFD_NONBLOCK as u64)
                    )?,
                ],],
            ),
            // Needed for rate limiting
            allow_syscall_if(
                libc::SYS_timerfd_settime,
                or![and![Cond::new(1, ArgLen::DWORD, Eq, 0u64)?],],
            ),
            allow_syscall(libc::SYS_write),
        ]
        .into_iter()
        .collect(),
        SeccompAction::Trap,
    )?)
}

/// Generate a BPF program based on a seccomp level value.
pub fn get_seccomp_filter(seccomp_level: SeccompLevel) -> Result<BpfProgram, SeccompError> {
    match seccomp_level {
        SeccompLevel::None => Ok(vec![]),
        SeccompLevel::Basic => default_filter()
            .and_then(|filter| Ok(filter.allow_all()))
            .and_then(|filter| filter.try_into())
            .map_err(SeccompError::SeccompFilter),
        SeccompLevel::Advanced => default_filter()
            .and_then(|filter| filter.try_into())
            .map_err(SeccompError::SeccompFilter),
    }
}

#[cfg(test)]
mod tests {
    use super::get_seccomp_filter;
    use seccomp::SeccompLevel;

    #[test]
    fn test_get_seccomp_filter() {
        assert!(get_seccomp_filter(SeccompLevel::None).is_ok());
        assert!(get_seccomp_filter(SeccompLevel::Basic).is_ok());
        assert!(get_seccomp_filter(SeccompLevel::Advanced).is_ok());
    }
}
<commit_msg>balloon: add mmap to seccomp rules<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use std::convert::TryInto;

use seccomp::{
    allow_syscall, allow_syscall_if, BpfProgram, Error, SeccompAction, SeccompCmpArgLen as ArgLen,
    SeccompCmpOp::Eq, SeccompCondition as Cond, SeccompError, SeccompFilter, SeccompLevel,
    SeccompRule,
};
use utils::signal::sigrtmin;

/// The default filter containing the white listed syscall rules required by `Firecracker` to
/// function.
/// Any non-trivial modification to this allow list needs a proper comment to specify its source
/// or why the sycall/condition is needed.
pub fn default_filter() -> Result<SeccompFilter, Error> {
    Ok(SeccompFilter::new(
        vec![
            // Called by the api thread to receive data on socket
            allow_syscall_if(
                libc::SYS_accept4,
                or![and![Cond::new(
                    3,
                    ArgLen::DWORD,
                    Eq,
                    libc::SOCK_CLOEXEC as u64
                )?],],
            ),
            // Called for expanding the heap
            allow_syscall(libc::SYS_brk),
            // Used for metrics, via the helpers in utils/src/time.rs
            allow_syscall_if(
                libc::SYS_clock_gettime,
                or![and![Cond::new(
                    0,
                    ArgLen::DWORD,
                    Eq,
                    libc::CLOCK_PROCESS_CPUTIME_ID as u64
                )?],],
            ),
            allow_syscall(libc::SYS_close),
            // Needed for vsock
            allow_syscall(libc::SYS_connect),
            allow_syscall(libc::SYS_epoll_ctl),
            allow_syscall(libc::SYS_epoll_pwait),
            #[cfg(all(target_env = "gnu", target_arch = "x86_64"))]
            allow_syscall(libc::SYS_epoll_wait),
            allow_syscall(libc::SYS_exit),
            allow_syscall(libc::SYS_exit_group),
            // Used by snapshotting, drive patching and rescanning
            allow_syscall_if(
                libc::SYS_fcntl,
                or![and![
                    Cond::new(1, ArgLen::DWORD, Eq, super::FCNTL_F_SETFD)?,
                    Cond::new(2, ArgLen::DWORD, Eq, super::FCNTL_FD_CLOEXEC)?,
                ],],
            ),
            // Used for drive patching & rescanning, for reading the local timezone
            allow_syscall(libc::SYS_fstat),
            // Used for snapshotting
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_ftruncate),
            // Used for synchronization
            allow_syscall_if(
                libc::SYS_futex,
                or![
                    and![Cond::new(1, ArgLen::DWORD, Eq, super::FUTEX_WAIT_PRIVATE)?],
                    and![Cond::new(1, ArgLen::DWORD, Eq, super::FUTEX_WAKE_PRIVATE)?],
                    #[cfg(target_env = "gnu")]
                    and![Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        super::FUTEX_CMP_REQUEUE_PRIVATE
                    )?],
                ],
            ),
            // Used by glibc's tgkill
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_getpid),
            allow_syscall_if(libc::SYS_ioctl, super::create_ioctl_seccomp_rule()?),
            // Used by the block device
            allow_syscall(libc::SYS_lseek),
            // Triggered by musl for some customer workloads
            #[cfg(target_env = "musl")]
            allow_syscall_if(
                libc::SYS_madvise,
                or![and![Cond::new(
                    2,
                    ArgLen::DWORD,
                    Eq,
                    libc::MADV_DONTNEED as u64
                )?],],
            ),
            // Used for re-allocating large memory regions, for example vectors
            allow_syscall(libc::SYS_mremap),
            // Used for freeing memory
            allow_syscall(libc::SYS_munmap),
            // Used for reading the timezone in LocalTime::now()
            allow_syscall_if(
                libc::SYS_mmap,
                or![
                    and![Cond::new(3, ArgLen::DWORD, Eq, libc::MAP_SHARED as u64)?],
                    and![Cond::new(
                        3,
                        ArgLen::DWORD,
                        Eq,
                        (libc::MAP_FIXED | libc::MAP_ANONYMOUS | libc::MAP_PRIVATE) as u64
                    )?],
                ],
            ),
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_open),
            #[cfg(target_arch = "aarch64")]
            allow_syscall(libc::SYS_openat),
            allow_syscall(libc::SYS_read),
            // Used by the API thread and vsock
            allow_syscall(libc::SYS_recvfrom),
            // SYS_rt_sigreturn is needed in case a fault does occur, so that the signal handler
            // can return. Otherwise we get stuck in a fault loop.
            allow_syscall(libc::SYS_rt_sigreturn),
            // Used by the API thread and vsock
            allow_syscall_if(
                libc::SYS_socket,
                or![and![
                    Cond::new(0, ArgLen::DWORD, Eq, libc::AF_UNIX as u64)?,
                    Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        (libc::SOCK_STREAM as u64) | (libc::SOCK_CLOEXEC as u64)
                    )?,
                    Cond::new(2, ArgLen::DWORD, Eq, 0u64)?
                ],],
            ),
            // Used to kick vcpus
            allow_syscall_if(
                libc::SYS_tkill,
                or![and![Cond::new(
                    1,
                    ArgLen::DWORD,
                    Eq,
                    (sigrtmin() + super::super::vstate::vcpu::VCPU_RTSIG_OFFSET) as u64
                )?]],
            ),
            // Used to kick vcpus, on gnu
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_tgkill),
            // Needed for rate limiting
            allow_syscall_if(
                libc::SYS_timerfd_create,
                or![and![
                    Cond::new(0, ArgLen::DWORD, Eq, libc::CLOCK_MONOTONIC as u64)?,
                    Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        (libc::TFD_CLOEXEC as u64) | (libc::TFD_NONBLOCK as u64)
                    )?,
                ],],
            ),
            // Needed for rate limiting
            allow_syscall_if(
                libc::SYS_timerfd_settime,
                or![and![Cond::new(1, ArgLen::DWORD, Eq, 0u64)?],],
            ),
            allow_syscall(libc::SYS_write),
        ]
        .into_iter()
        .collect(),
        SeccompAction::Trap,
    )?)
}

/// Generate a BPF program based on a seccomp level value.
pub fn get_seccomp_filter(seccomp_level: SeccompLevel) -> Result<BpfProgram, SeccompError> {
    match seccomp_level {
        SeccompLevel::None => Ok(vec![]),
        SeccompLevel::Basic => default_filter()
            .and_then(|filter| Ok(filter.allow_all()))
            .and_then(|filter| filter.try_into())
            .map_err(SeccompError::SeccompFilter),
        SeccompLevel::Advanced => default_filter()
            .and_then(|filter| filter.try_into())
            .map_err(SeccompError::SeccompFilter),
    }
}

#[cfg(test)]
mod tests {
    use super::get_seccomp_filter;
    use seccomp::SeccompLevel;

    #[test]
    fn test_get_seccomp_filter() {
        assert!(get_seccomp_filter(SeccompLevel::None).is_ok());
        assert!(get_seccomp_filter(SeccompLevel::Basic).is_ok());
        assert!(get_seccomp_filter(SeccompLevel::Advanced).is_ok());
    }
}
<|endoftext|>


<commit_before><commit_msg>cdgparse: mark palette commands as HEADER<commit_after><|endoftext|>


<commit_before>//! The `expressionparser` module parse every expression
//! to an ast (abstract syntaxtree)
//! the idea is explained here: http://programmers.stackexchange.com/questions/254074/

use frontend::ast::{ASTNode, NodeDefault};
use frontend::lexer::Token;
use frontend::lexer::Token::*;

pub struct ExpressionParser {
    expr_stack: Vec<ASTNode>,
    oper_stack: Vec<Token>,
}

impl ExpressionParser {
    pub fn parse(node: &mut NodeDefault) {
        let mut expr_parser = ExpressionParser {
            expr_stack: Vec::new(),
            oper_stack: Vec::new(),
        };
        expr_parser.parse_expressions(node);
    }

    /// parse the expression node and creates mutliple ast nodes
    fn parse_expressions(&mut self, node: &mut NodeDefault) {

        node.childs.reverse();
        while let Some(top) = node.childs.pop() {
            match top.category() {
                tok @ TokBoolean  { .. } |
                tok @ TokInt      { .. } |
                tok @ TokFunction { .. } |
                tok @ TokVariable { .. } => {
                    let childs_copy = top.as_default().childs.to_vec();
                    self.expr_stack.push( ASTNode::Default(NodeDefault { category: tok.clone(), childs: childs_copy }) );
                },
                tok @ TokNumOp  { .. } |
                tok @ TokCompOp { .. } |
                tok @ TokLogOp  { .. } => {
                    let length = self.oper_stack.len();

                    // cycle through the oper_stack stack backwards
                    // if the rank of the current operator is <= the top of the
                    // stack, we create a new node
                    for i in 0..length {
                        let i_rev = length - i - 1;
                        let token: Token = self.oper_stack.get(i_rev).unwrap().clone();
                        if is_ranking_not_higher(token, tok.clone()) {
                            self.new_operator_node();
                        }
                    }

                    self.oper_stack.push(tok.clone());
                },
                _ => ()
            }
        }

        // parse the last elements of the stack
        // to avoid endless loop we try max expr_stack.len()
        for _ in 0..self.expr_stack.len() {
            if self.expr_stack.len() > 0 {
                self.new_operator_node();
            }
        }

        // finished. so add the root of the expressions as child.
        assert!{self.expr_stack.len() == 1, "Only one expression can be the root. But there are {:?}.", self.expr_stack.len()};
        if let Some(root) = self.expr_stack.pop() {
            node.childs.push(root);
        }
    }

    /// creates a node with an operator on top
    fn new_operator_node(&mut self) {
        if let Some(top_op) = self.oper_stack.pop() {
            let e2: ASTNode = self.expr_stack.pop().unwrap();
            let e1: ASTNode = self.expr_stack.pop().unwrap();

            let new_node = ASTNode::Default(NodeDefault { category: top_op.clone(), childs: vec![e1, e2] });
            self.expr_stack.push( new_node );
        }
    }
}

/// checks the operatores of two tokens returns true if operator of token1
/// is more important then operator of token2
/// the ranking is set in "operator_precedence"
fn is_ranking_not_higher(token1: Token, token2: Token) -> bool {
    let mut op1: String = "".to_string();
    let mut op2: String = "".to_string();
    match token1 {
        TokNumOp  { op_name, .. } |
        TokCompOp { op_name, .. } |
        TokLogOp  { op_name, .. } => {
            op1 = op_name.clone();
        },
        _ => ()
    }
    match token2 {
        TokNumOp  { op_name, .. } |
        TokCompOp { op_name, .. } |
        TokLogOp  { op_name, .. } => {
            op2 = op_name.clone();
        },
        _ => ()
    }

    if operator_rank(op1) >= operator_rank(op2) {
        return true
    }

    false
}

/// ranking of the operators
fn operator_rank(op: String) -> u8 {
    match op.as_ref() {
        "or"                => 1,
        "and"               => 2,
        "is" | "==" | "eq" | "neq" | ">" | "gt" | ">=" | "gte" | "<" | "lt" | "<=" | "lte"
                            => 3,
        "+" | "-"           => 4,
        "*" | "/" | "%"     => 5,
        "not"               => 6,
        _                   => panic!{"This operator is not implemented"}
    }
}
<commit_msg>Fix typos in expressionparser.rs docs<commit_after>//! The `expressionparser` module parses every expression
//! to an AST (abstract syntax tree).
//! The idea is explained here: http://programmers.stackexchange.com/questions/254074/

use frontend::ast::{ASTNode, NodeDefault};
use frontend::lexer::Token;
use frontend::lexer::Token::*;

pub struct ExpressionParser {
    expr_stack: Vec<ASTNode>,
    oper_stack: Vec<Token>,
}

impl ExpressionParser {
    pub fn parse(node: &mut NodeDefault) {
        let mut expr_parser = ExpressionParser {
            expr_stack: Vec::new(),
            oper_stack: Vec::new(),
        };
        expr_parser.parse_expressions(node);
    }

    /// parse the expression node and creates mutliple ast nodes
    fn parse_expressions(&mut self, node: &mut NodeDefault) {

        node.childs.reverse();
        while let Some(top) = node.childs.pop() {
            match top.category() {
                tok @ TokBoolean  { .. } |
                tok @ TokInt      { .. } |
                tok @ TokFunction { .. } |
                tok @ TokVariable { .. } => {
                    let childs_copy = top.as_default().childs.to_vec();
                    self.expr_stack.push( ASTNode::Default(NodeDefault { category: tok.clone(), childs: childs_copy }) );
                },
                tok @ TokNumOp  { .. } |
                tok @ TokCompOp { .. } |
                tok @ TokLogOp  { .. } => {
                    let length = self.oper_stack.len();

                    // cycle through the oper_stack stack backwards
                    // if the rank of the current operator is <= the top of the
                    // stack, we create a new node
                    for i in 0..length {
                        let i_rev = length - i - 1;
                        let token: Token = self.oper_stack.get(i_rev).unwrap().clone();
                        if is_ranking_not_higher(token, tok.clone()) {
                            self.new_operator_node();
                        }
                    }

                    self.oper_stack.push(tok.clone());
                },
                _ => ()
            }
        }

        // parse the last elements of the stack
        // to avoid endless loop we try max expr_stack.len()
        for _ in 0..self.expr_stack.len() {
            if self.expr_stack.len() > 0 {
                self.new_operator_node();
            }
        }

        // finished. so add the root of the expressions as child.
        assert!{self.expr_stack.len() == 1, "Only one expression can be the root. But there are {:?}.", self.expr_stack.len()};
        if let Some(root) = self.expr_stack.pop() {
            node.childs.push(root);
        }
    }

    /// creates a node with an operator on top
    fn new_operator_node(&mut self) {
        if let Some(top_op) = self.oper_stack.pop() {
            let e2: ASTNode = self.expr_stack.pop().unwrap();
            let e1: ASTNode = self.expr_stack.pop().unwrap();

            let new_node = ASTNode::Default(NodeDefault { category: top_op.clone(), childs: vec![e1, e2] });
            self.expr_stack.push( new_node );
        }
    }
}

/// checks the operatores of two tokens returns true if operator of token1
/// is more important then operator of token2
/// the ranking is set in "operator_precedence"
fn is_ranking_not_higher(token1: Token, token2: Token) -> bool {
    let mut op1: String = "".to_string();
    let mut op2: String = "".to_string();
    match token1 {
        TokNumOp  { op_name, .. } |
        TokCompOp { op_name, .. } |
        TokLogOp  { op_name, .. } => {
            op1 = op_name.clone();
        },
        _ => ()
    }
    match token2 {
        TokNumOp  { op_name, .. } |
        TokCompOp { op_name, .. } |
        TokLogOp  { op_name, .. } => {
            op2 = op_name.clone();
        },
        _ => ()
    }

    if operator_rank(op1) >= operator_rank(op2) {
        return true
    }

    false
}

/// ranking of the operators
fn operator_rank(op: String) -> u8 {
    match op.as_ref() {
        "or"                => 1,
        "and"               => 2,
        "is" | "==" | "eq" | "neq" | ">" | "gt" | ">=" | "gte" | "<" | "lt" | "<=" | "lte"
                            => 3,
        "+" | "-"           => 4,
        "*" | "/" | "%"     => 5,
        "not"               => 6,
        _                   => panic!{"This operator is not implemented"}
    }
}
<|endoftext|>


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

extern crate glob;
extern crate libloading;

use self::glob::glob;
use self::libloading::{Library, Symbol};

use std::vec::Vec;

/*================================================================================================*/
/*------PLUGINTYPE ENUM---------------------------------------------------------------------------*/
/*================================================================================================*/

/// The Plugin Type enum.
#[derive (Copy, Clone, PartialEq, Debug)]
pub enum PluginType {

    /// Used by audio backends.
    AudioBackend,
    /// Used by rendering backends.
    RenderBackend
}

/*================================================================================================*/
/*------PLUGIN STRUCT-----------------------------------------------------------------------------*/
/*================================================================================================*/

/// Stores the details of a plugin.
#[derive (Clone)]
pub struct Plugin {

    // Public
    /// The name of the plugin.
    pub name: String,
    /// The author of the plugin.
    pub author: String,
    /// A brief description of the plugin.
    pub description: String,
    /// The path to the plugin
    pub path: String,
    /// The type of plugin
    pub plugin_type: PluginType,
}

/*================================================================================================*/
/*------PLUGINMANAGER STRUCT----------------------------------------------------------------------*/
/*================================================================================================*/

/// Manages the finding and loading of plugins.
#[derive (Clone)]
pub struct PluginManager {

    // Public
    /// The list of plugins
    pub plugin_list: Vec<Plugin>,
    /// The plugin directory
    pub plugin_dir: String,

    // Private
    _plugin_ext: String
}

/*================================================================================================*/
/*------PLUGINMANAGER PUBLIC MEMBERS--------------------------------------------------------------*/
/*================================================================================================*/

impl PluginManager {

    /// Returns a new plugin manager.
    ///
    /// # Arguments
    /// * `plugin_dir` - The location of the plugin directory.
    ///
    /// # Return value
    /// A new instance of the plugin manager.
    pub fn new () -> PluginManager {

        // Set the platform extension
        let plug_ext = if cfg! (target_os = "windows") {".dll"}
                       else if cfg! (target_os = "linux") {".so"}
                       else if cfg! (target_os = "macos") {".dylib"}
                       else {panic! ("Platform unsupported")};

        PluginManager {plugin_list: Vec::new (),
                       plugin_dir: String::new (),
                       _plugin_ext: plug_ext.to_owned ()}
    }

    /// Queries the plugin directory, and stores a list of plugins.
    ///
    /// # Return value
    /// An immutable reference to the list of plugins.
    pub fn query_plugins (&mut self) -> &Vec<Plugin> {

        // Clear the old plugin list
        self.plugin_list.clear ();

        info! ("Searching for plugins...");

        // Recurse through all items in the plugin directory
        for path in glob (&format! ("{}/*{}", &self.plugin_dir, &self._plugin_ext)).unwrap ().filter_map (Result::ok) {

            // Load the library, and get function symbols
            let lib = Library::new (&path).unwrap ();

            let get_name: Symbol <unsafe extern fn () -> String> = unsafe {
                lib.get (b"get_name\0").unwrap ()
            };

            let get_author: Symbol <unsafe extern fn () -> String> = unsafe {
                lib.get (b"get_author\0").unwrap ()
            };

            let get_description: Symbol <unsafe extern fn () -> String> = unsafe {
                lib.get (b"get_description\0").unwrap ()
            };

            let get_type: Symbol <unsafe extern fn () -> PluginType> = unsafe {
                lib.get (b"get_type\0").unwrap ()
            };

            unsafe {

                // Add the plugin to the list
                self.plugin_list.push (Plugin {name: get_name (),
                                               author: get_author (),
                                               description: get_description (),
                                               path: path.to_str ().unwrap ().to_owned (),
                                               plugin_type: get_type ()});

                info! ("Found: {:?}", &path);
            }
        }

        info! ("Plugin searching complete.");
        &self.plugin_list
    }
}
<commit_msg>Added a function for getting a reference to a plugin<commit_after>/*================================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*================================================================================================*/

extern crate glob;
extern crate libloading;

use self::glob::glob;
use self::libloading::{Library, Symbol};

use std::vec::Vec;

/*================================================================================================*/
/*------PLUGINTYPE ENUM---------------------------------------------------------------------------*/
/*================================================================================================*/

/// The Plugin Type enum.
#[derive (Copy, Clone, PartialEq, Debug)]
pub enum PluginType {

    /// Used by audio backends.
    AudioBackend,
    /// Used by rendering backends.
    RenderBackend
}

/*================================================================================================*/
/*------PLUGIN STRUCT-----------------------------------------------------------------------------*/
/*================================================================================================*/

/// Stores the details of a plugin.
#[derive (Clone)]
pub struct Plugin {

    // Public
    /// The name of the plugin.
    pub name: String,
    /// The author of the plugin.
    pub author: String,
    /// A brief description of the plugin.
    pub description: String,
    /// The path to the plugin
    pub path: String,
    /// The type of plugin
    pub plugin_type: PluginType,
}

/*================================================================================================*/
/*------PLUGINMANAGER STRUCT----------------------------------------------------------------------*/
/*================================================================================================*/

/// Manages the finding and loading of plugins.
#[derive (Clone)]
pub struct PluginManager {

    // Public
    /// The list of plugins
    pub plugin_list: Vec<Plugin>,
    /// The plugin directory
    pub plugin_dir: String,

    // Private
    _plugin_ext: String
}

/*================================================================================================*/
/*------PLUGINMANAGER PUBLIC MEMBERS--------------------------------------------------------------*/
/*================================================================================================*/

impl PluginManager {

    /// Returns a new plugin manager.
    ///
    /// # Arguments
    /// * `plugin_dir` - The location of the plugin directory.
    ///
    /// # Return value
    /// A new instance of the plugin manager.
    pub fn new () -> PluginManager {

        // Set the platform extension
        let plug_ext = if cfg! (target_os = "windows") {".dll"}
                       else if cfg! (target_os = "linux") {".so"}
                       else if cfg! (target_os = "macos") {".dylib"}
                       else {panic! ("Platform unsupported")};

        PluginManager {plugin_list: Vec::new (),
                       plugin_dir: String::new (),
                       _plugin_ext: plug_ext.to_owned ()}
    }

    /// Queries the plugin directory, and stores a list of plugins.
    ///
    /// # Return value
    /// An immutable reference to the list of plugins.
    pub fn query_plugins (&mut self) -> &Vec<Plugin> {

        // Clear the old plugin list
        self.plugin_list.clear ();

        info! ("Searching for plugins...");

        // Recurse through all items in the plugin directory
        for path in glob (&format! ("{}/*{}", &self.plugin_dir, &self._plugin_ext)).unwrap ().filter_map (Result::ok) {

            // Load the library, and get function symbols
            let lib = Library::new (&path).unwrap ();

            let get_name: Symbol <unsafe extern fn () -> String> = unsafe {
                lib.get (b"get_name\0").unwrap ()
            };

            let get_author: Symbol <unsafe extern fn () -> String> = unsafe {
                lib.get (b"get_author\0").unwrap ()
            };

            let get_description: Symbol <unsafe extern fn () -> String> = unsafe {
                lib.get (b"get_description\0").unwrap ()
            };

            let get_type: Symbol <unsafe extern fn () -> PluginType> = unsafe {
                lib.get (b"get_type\0").unwrap ()
            };

            unsafe {

                // Add the plugin to the list
                self.plugin_list.push (Plugin {name: get_name (),
                                               author: get_author (),
                                               description: get_description (),
                                               path: path.to_str ().unwrap ().to_owned (),
                                               plugin_type: get_type ()});

                info! ("Found: {:?}", &path);
            }
        }

        info! ("Plugin searching complete.");
        &self.plugin_list
    }

    /// Returns an instance of a plugin
    ///
    /// # Arguments
    /// * `name` - The name of the plugin.
    ///
    /// # Return value
    /// A result contaning a reference the plugin.
    pub fn get_plugin (&self, name: &str) -> Result <&Plugin, ()> {

        let mut index = 0;

        // Loop through all plugins
        for p in &self.plugin_list {

            if p.name == name {
                return Ok (&self.plugin_list [index]);
            }

            index += 1;
        }

        Err (())
    }
}
<|endoftext|>


<commit_before>use basetypes::*;
use chess_move::MoveStack;
use tt::*;
use position::Position;

/// Represents a terminated search condition.
pub struct TerminatedSearch;

pub fn search(tt: &TranspositionTable,
              p: &mut Position,
              moves: &mut MoveStack,
              nc: &mut NodeCount,
              report: &Fn(NodeCount) -> Result<(), TerminatedSearch>,
              mut alpha: Value, // lower bound
              beta: Value, // upper bound
              depth: u8)
              -> Result<Value, TerminatedSearch> {
    assert!(alpha < beta);
    if depth == 0 {
        // On leaf nodes, do quiescence search.
        let (value, nodes) = p.evaluate_quiescence(alpha, beta);
        *nc += nodes;
        Ok(value)
    } else {
        moves.save();
        p.generate_moves(moves);
        let mut bound_type = BOUND_UPPER;
        let mut move16 = 0;
        let mut no_moves_yet = true;
        while let Some(m) = moves.remove_best_move() {
            if p.do_move(m) {
                // From time to time, we report how many nodes had
                // been searched since the last report. This also
                // gives an opportunity for the search to be
                // terminated.
                *nc += 1;
                if *nc > NODE_COUNT_REPORT_INTERVAL {
                    try!(report(*nc));
                    *nc = 0;
                }

                let value = if no_moves_yet {
                    // The first move we analyze with a fully open
                    // window (alpha, beta).
                    -try!(search(tt, p, moves, nc, report, -beta, -alpha, depth - 1))
                } else {
                    // For the next moves we first try to prove that
                    // they are not better than our current best
                    // move. For this purpose we analyze them with a
                    // null window (alpha, alpha + 1). This is faster
                    // than a full window search. Only when we are
                    // certain that the move is better than our
                    // current best move, we do a full-window search.
                    match -try!(search(tt, p, moves, nc, report, -alpha - 1, -alpha, depth - 1)) {
                        x if x <= alpha => x,
                        _ => -try!(search(tt, p, moves, nc, report, -beta, -alpha, depth - 1)),
                    }
                };
                no_moves_yet = false;
                p.undo_move();

                if value >= beta {
                    // This move is too good, so that the opponent
                    // will not allow this line of play to
                    // happen. Therefore we can stop here.
                    alpha = beta;
                    bound_type = BOUND_LOWER;
                    move16 = m.move16();
                    break;
                }
                if value > alpha {
                    // We found ourselves a new best move.
                    alpha = value;
                    bound_type = BOUND_EXACT;
                    move16 = m.move16();
                }
            }
        }
        moves.restore();
        if no_moves_yet {
            // No legal moves -- this is a final position.
            alpha = p.evaluate_final();
        }
        tt.store(p.hash(), EntryData::new(alpha, bound_type, depth, move16, 0));
        Ok(alpha)
    }
}

const NODE_COUNT_REPORT_INTERVAL: NodeCount = 10000;
<commit_msg>added todos<commit_after>use basetypes::*;
use chess_move::MoveStack;
use tt::*;
use position::Position;

/// Represents a terminated search condition.
pub struct TerminatedSearch;

pub fn search(tt: &TranspositionTable,
              p: &mut Position,
              moves: &mut MoveStack,
              nc: &mut NodeCount,
              report: &Fn(NodeCount) -> Result<(), TerminatedSearch>,
              mut alpha: Value, // lower bound
              beta: Value, // upper bound
              depth: u8)
              -> Result<Value, TerminatedSearch> {
    assert!(alpha < beta);
    if depth == 0 {
        // On leaf nodes, do quiescence search.
        let (value, nodes) = p.evaluate_quiescence(alpha, beta);
        *nc += nodes;
        Ok(value)
    } else {
        moves.save();
        p.generate_moves(moves);
        // TODO: Consult `tt` here.

        let mut bound_type = BOUND_UPPER;
        let mut move16 = 0;
        let mut no_moves_yet = true;
        while let Some(m) = moves.remove_best_move() {
            if p.do_move(m) {
                // From time to time, we report how many nodes had
                // been searched since the last report. This also
                // gives an opportunity for the search to be
                // terminated.
                *nc += 1;
                if *nc > NODE_COUNT_REPORT_INTERVAL {
                    try!(report(*nc));
                    *nc = 0;
                }

                let value = if no_moves_yet {
                    // The first move we analyze with a fully open
                    // window (alpha, beta).
                    -try!(search(tt, p, moves, nc, report, -beta, -alpha, depth - 1))
                } else {
                    // For the next moves we first try to prove that
                    // they are not better than our current best
                    // move. For this purpose we analyze them with a
                    // null window (alpha, alpha + 1). This is faster
                    // than a full window search. Only when we are
                    // certain that the move is better than our
                    // current best move, we do a full-window search.
                    match -try!(search(tt, p, moves, nc, report, -alpha - 1, -alpha, depth - 1)) {
                        x if x <= alpha => x,
                        _ => -try!(search(tt, p, moves, nc, report, -beta, -alpha, depth - 1)),
                    }
                };
                no_moves_yet = false;
                p.undo_move();

                if value >= beta {
                    // This move is too good, so that the opponent
                    // will not allow this line of play to
                    // happen. Therefore we can stop here.
                    alpha = beta;
                    bound_type = BOUND_LOWER;
                    move16 = m.move16();
                    break;
                }
                if value > alpha {
                    // We found ourselves a new best move.
                    alpha = value;
                    bound_type = BOUND_EXACT;
                    move16 = m.move16();
                }
            }
        }
        moves.restore();
        if no_moves_yet {
            // No legal moves -- this is a final position.
            alpha = p.evaluate_final();
        }
        // TODO: Do not store values with too small `depth`.
        tt.store(p.hash(),
                 EntryData::new(alpha, bound_type, depth, move16, 0));
        Ok(alpha)
    }
}

const NODE_COUNT_REPORT_INTERVAL: NodeCount = 10000;
<|endoftext|>


<commit_before>
use std::cmp::Ordering;
use std::path::{ Path, PathBuf };
use std::fs;
use std::fs::{ PathExt, File };
use std::io::{ Write };

use rustc_serialize::json;
use rustc_serialize::json::{ ToJson, Json };

use ::file_type::{ create_parent_links, Link, read_file, FileType };

static TYPE_STR: &'static str = "dir";

pub struct DirFactory;

impl ::file_type::FileTypeFactory for DirFactory {
    fn try_create(&self, path: &Path) -> Option<Box<FileType>> {
        if path.is_dir() {
            Some(Box::new(Dir {
                path: PathBuf::from(path),
                type_str: TYPE_STR,
                file_type_manager: ::file_type::FileTypeManager::new()
            }))
        } else { None }
    }

    fn initialize(&self, app_context: &mut ::AppContext) -> Result<(), &'static str> {

        // Validate generic stuff
        let header_hbs_path = app_context.root_source.join("partials/header.hbs");
        if !header_hbs_path.exists() {
            return Err("Missing partials/header.hbs");
        }

        let footer_hbs_path = app_context.root_source.join("partials/footer.hbs");
        if !footer_hbs_path.exists() {
            return Err("Missing partials/footer.hbs");
        }

        // Validate Dir
        let dir_hbs_path = app_context.root_source.join("layouts/dir.hbs");
        if !dir_hbs_path.exists() {
            return Err("Missing /layouts/dir.hbs");
        }

        // Grab generic stuff
        let header_hbs_contents = try!(read_file(header_hbs_path));
        let footer_hbs_contents = try!(read_file(footer_hbs_path));

        // Create Dir
        let dir_template_name = TYPE_STR;
        let dir_hbs_contents = try!(read_file(&dir_hbs_path));

        app_context.handlebars.register_template_string(dir_template_name, format!("{}\n{}\n{}", header_hbs_contents, dir_hbs_contents, footer_hbs_contents))
            .ok().expect("Error registering header|dir|footer template");

        Ok(())
    }
}

pub struct Dir {
    path: PathBuf,
    type_str: &'static str,
    file_type_manager: ::file_type::FileTypeManager
}

impl Dir {
    fn get_children(&self, context: &::AppContext) -> Vec<Child> {
        let mut result: Vec<Child> = Vec::new();

            match fs::read_dir(&self.path) {
                Ok(items) => {
                    for item in items {
                        let item = item.unwrap().path();
                        let child = self.file_type_manager.create_file_type(&item);
                        result.push(Child {
                            name: String::from_str(item.file_stem().unwrap().to_str().unwrap()),
                            url: child.get_url(context),
                            file_type: String::from_str(child.get_type_str())
                        });
                    }
                },
                Err(_) => ()
            }

        (&mut result).sort_by(|a, b| {
            if a.file_type == String::from_str(TYPE_STR) && b.file_type != String::from_str(TYPE_STR) {
                Ordering::Less
            } else {
                a.file_type.cmp(&b.file_type)
            }

        });

        result
    }
}

impl FileType for Dir {
    fn get_url(&self, context: &::AppContext) -> String {
        let relative = self.path.relative_from(&context.root_notes).expect("Problem parsing relative url");
        let relative = if relative.to_str().unwrap() == "." { String::new() } else {
            format!("{}/", relative.to_str().unwrap())
        };
        format!("{}{}", context.base_url, relative)
    }

    fn convert(&self, context: &::AppContext) {
        let relative = self.path.relative_from(&context.root_notes).expect("Problem parsing relative url");
        let new_dir = context.root_dest.join(&relative);
        let new_dir_index = new_dir.join("index.html");
        if !new_dir.exists() {
            fs::create_dir(&new_dir).ok().expect("Cannot create destination subdir");
        }
        let children = self.get_children(context);
        let name = match relative.file_name() {
            Some(_) => String::from_str(relative.file_name().unwrap().to_str().unwrap()),
            None => String::from_str("root")
        };
        let parents = create_parent_links(&context.base_url, &relative, true);
        let dir_model = DirModel {
            name: name,
            parents: parents,
            children: children,
            base_url: context.base_url.clone()
        };
        match context.handlebars.render(TYPE_STR, &dir_model) {
            Ok(rendered) => {
                // Create File
                let mut file = File::create(&new_dir_index).ok().expect("Could not create dir index.html file");
                //fs::chmod(&new_dir_index, USER_FILE).ok().expect("Couldn't chmod new file");
                file.write_all(rendered.as_bytes())
                    .ok().expect("Could not write html to file");
            },
            Err(why) => panic!("Error rendering markdown: {:?}", why)
        }
    }

    fn get_type_str(&self) -> &'static str {
        self.type_str
    }
}

#[derive(RustcEncodable, PartialEq)]
struct Child {
    name: String,
    url: String,
    file_type: String
}

#[derive(RustcEncodable)]
struct DirModel {
    name: String,
    parents: Vec<Link>,
    children: Vec<Child>,
    base_url: String
}

impl ToJson for DirModel {
    fn to_json(&self) -> Json {
        Json::from_str(&json::encode(&self).unwrap()).unwrap()
    }
}
<commit_msg>sort by file name not file type<commit_after>
use std::cmp::Ordering;
use std::path::{ Path, PathBuf };
use std::fs;
use std::fs::{ PathExt, File };
use std::io::{ Write };

use rustc_serialize::json;
use rustc_serialize::json::{ ToJson, Json };

use ::file_type::{ create_parent_links, Link, read_file, FileType };

static TYPE_STR: &'static str = "dir";

pub struct DirFactory;

impl ::file_type::FileTypeFactory for DirFactory {
    fn try_create(&self, path: &Path) -> Option<Box<FileType>> {
        if path.is_dir() {
            Some(Box::new(Dir {
                path: PathBuf::from(path),
                type_str: TYPE_STR,
                file_type_manager: ::file_type::FileTypeManager::new()
            }))
        } else { None }
    }

    fn initialize(&self, app_context: &mut ::AppContext) -> Result<(), &'static str> {

        // Validate generic stuff
        let header_hbs_path = app_context.root_source.join("partials/header.hbs");
        if !header_hbs_path.exists() {
            return Err("Missing partials/header.hbs");
        }

        let footer_hbs_path = app_context.root_source.join("partials/footer.hbs");
        if !footer_hbs_path.exists() {
            return Err("Missing partials/footer.hbs");
        }

        // Validate Dir
        let dir_hbs_path = app_context.root_source.join("layouts/dir.hbs");
        if !dir_hbs_path.exists() {
            return Err("Missing /layouts/dir.hbs");
        }

        // Grab generic stuff
        let header_hbs_contents = try!(read_file(header_hbs_path));
        let footer_hbs_contents = try!(read_file(footer_hbs_path));

        // Create Dir
        let dir_template_name = TYPE_STR;
        let dir_hbs_contents = try!(read_file(&dir_hbs_path));

        app_context.handlebars.register_template_string(dir_template_name, format!("{}\n{}\n{}", header_hbs_contents, dir_hbs_contents, footer_hbs_contents))
            .ok().expect("Error registering header|dir|footer template");

        Ok(())
    }
}

pub struct Dir {
    path: PathBuf,
    type_str: &'static str,
    file_type_manager: ::file_type::FileTypeManager
}

impl Dir {
    fn get_children(&self, context: &::AppContext) -> Vec<Child> {
        let mut result: Vec<Child> = Vec::new();

            match fs::read_dir(&self.path) {
                Ok(items) => {
                    for item in items {
                        let item = item.unwrap().path();
                        let child = self.file_type_manager.create_file_type(&item);
                        result.push(Child {
                            name: String::from_str(item.file_stem().unwrap().to_str().unwrap()),
                            url: child.get_url(context),
                            file_type: String::from_str(child.get_type_str())
                        });
                    }
                },
                Err(_) => ()
            }

        (&mut result).sort_by(|a, b| {
            if a.file_type == String::from_str(TYPE_STR) && b.file_type != String::from_str(TYPE_STR) {
                Ordering::Less
            } else {
                a.name.cmp(&b.name)
            }

        });

        result
    }
}

impl FileType for Dir {
    fn get_url(&self, context: &::AppContext) -> String {
        let relative = self.path.relative_from(&context.root_notes).expect("Problem parsing relative url");
        let relative = if relative.to_str().unwrap() == "." { String::new() } else {
            format!("{}/", relative.to_str().unwrap())
        };
        format!("{}{}", context.base_url, relative)
    }

    fn convert(&self, context: &::AppContext) {
        let relative = self.path.relative_from(&context.root_notes).expect("Problem parsing relative url");
        let new_dir = context.root_dest.join(&relative);
        let new_dir_index = new_dir.join("index.html");
        if !new_dir.exists() {
            fs::create_dir(&new_dir).ok().expect("Cannot create destination subdir");
        }
        let children = self.get_children(context);
        let name = match relative.file_name() {
            Some(_) => String::from_str(relative.file_name().unwrap().to_str().unwrap()),
            None => String::from_str("root")
        };
        let parents = create_parent_links(&context.base_url, &relative, true);
        let dir_model = DirModel {
            name: name,
            parents: parents,
            children: children,
            base_url: context.base_url.clone()
        };
        match context.handlebars.render(TYPE_STR, &dir_model) {
            Ok(rendered) => {
                // Create File
                let mut file = File::create(&new_dir_index).ok().expect("Could not create dir index.html file");
                //fs::chmod(&new_dir_index, USER_FILE).ok().expect("Couldn't chmod new file");
                file.write_all(rendered.as_bytes())
                    .ok().expect("Could not write html to file");
            },
            Err(why) => panic!("Error rendering markdown: {:?}", why)
        }
    }

    fn get_type_str(&self) -> &'static str {
        self.type_str
    }
}

#[derive(RustcEncodable, PartialEq)]
struct Child {
    name: String,
    url: String,
    file_type: String
}

#[derive(RustcEncodable)]
struct DirModel {
    name: String,
    parents: Vec<Link>,
    children: Vec<Child>,
    base_url: String
}

impl ToJson for DirModel {
    fn to_json(&self) -> Json {
        Json::from_str(&json::encode(&self).unwrap()).unwrap()
    }
}
<|endoftext|>


<commit_before>use frame::ChannelAssignment;

pub fn decode_left_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let left = buffer[i];
    let side = buffer[i + block_size];

    // right channel
    buffer[i + block_size] = left - side;
  }
}

pub fn decode_right_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let side  = buffer[i];
    let right = buffer[i + block_size];

    // left channel
    buffer[i] = side + right;
  }
}

pub fn decode_middle_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let mut middle = buffer[i];
    let side       = buffer[i + block_size];

    middle = (middle << 1) | (side & 1);

    // left and right channel
    buffer[i]              = (middle + side) >> 1;
    buffer[i + block_size] = (middle - side) >> 1;
  }
}

pub fn decode(channel_assignment: ChannelAssignment, buffer: &mut [i32]) {
  match channel_assignment {
    ChannelAssignment::Independent => return,
    ChannelAssignment::LeftSide    => decode_left_side(buffer),
    ChannelAssignment::RightSide   => decode_right_side(buffer),
    ChannelAssignment::MiddleSide  => decode_middle_side(buffer),
  }
}

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

  #[test]
  fn test_decode_left_side() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let result       = [-5, -33, -59, -125, 127, 89, 7, 3];

    decode_left_side(&mut channels);

    assert_eq!(&channels[8..16], &result);
  }

  #[test]
  fn test_decode_right_side() {
    let mut channels = [ 7, 38, 142, 238, 0, -152, -52, -18
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];
    let result       = [2, 5, 83, 113, 127, -63, -45, -15];

    decode_right_side(&mut channels);

    assert_eq!(&channels[0..8], &result);
  }

  #[test]
  fn test_decode_middle_side() {
    let mut channels = [ -2, -14, 12, -6, 127, 13, -19, -6
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let results      = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];

    decode_middle_side(&mut channels);

    assert_eq!(&channels, &results);
  }

  #[test]
  fn test_decode() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];

    let results = [ [ 2, 5, 83, 113, 127, -63, -45, -15
                    , 7, 38, 142, 238, 0, -152, -52, -18
                    ],
                    [ 2, 5, 83, 113, 127, -63, -45, -15
                    ,-5, -33, -59, -125, 127, 89, 7, 3
                    ]
                  ];

    decode(ChannelAssignment::Independent, &mut channels);
    assert_eq!(&channels, &results[0]);

    channels = [ 2, 5, 83, 113, 127, -63, -45, -15
               , 7, 38, 142, 238, 0, -152, -52, -18
               ];

    decode(ChannelAssignment::LeftSide, &mut channels);
    assert_eq!(&channels, &results[1]);

    channels = [ 7, 38, 142, 238, 0, -152, -52, -18
               , -5, -33, -59, -125, 127, 89, 7, 3
               ];

    decode(ChannelAssignment::RightSide, &mut channels);
    assert_eq!(&channels, &results[1]);
  }
}
<commit_msg>Add `MiddleSide` test for frame decode<commit_after>use frame::ChannelAssignment;

pub fn decode_left_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let left = buffer[i];
    let side = buffer[i + block_size];

    // right channel
    buffer[i + block_size] = left - side;
  }
}

pub fn decode_right_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let side  = buffer[i];
    let right = buffer[i + block_size];

    // left channel
    buffer[i] = side + right;
  }
}

pub fn decode_middle_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let mut middle = buffer[i];
    let side       = buffer[i + block_size];

    middle = (middle << 1) | (side & 1);

    // left and right channel
    buffer[i]              = (middle + side) >> 1;
    buffer[i + block_size] = (middle - side) >> 1;
  }
}

pub fn decode(channel_assignment: ChannelAssignment, buffer: &mut [i32]) {
  match channel_assignment {
    ChannelAssignment::Independent => return,
    ChannelAssignment::LeftSide    => decode_left_side(buffer),
    ChannelAssignment::RightSide   => decode_right_side(buffer),
    ChannelAssignment::MiddleSide  => decode_middle_side(buffer),
  }
}

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

  #[test]
  fn test_decode_left_side() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let result       = [-5, -33, -59, -125, 127, 89, 7, 3];

    decode_left_side(&mut channels);

    assert_eq!(&channels[8..16], &result);
  }

  #[test]
  fn test_decode_right_side() {
    let mut channels = [ 7, 38, 142, 238, 0, -152, -52, -18
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];
    let result       = [2, 5, 83, 113, 127, -63, -45, -15];

    decode_right_side(&mut channels);

    assert_eq!(&channels[0..8], &result);
  }

  #[test]
  fn test_decode_middle_side() {
    let mut channels = [ -2, -14, 12, -6, 127, 13, -19, -6
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let results      = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];

    decode_middle_side(&mut channels);

    assert_eq!(&channels, &results);
  }

  #[test]
  fn test_decode() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];

    let results = [ [ 2, 5, 83, 113, 127, -63, -45, -15
                    , 7, 38, 142, 238, 0, -152, -52, -18
                    ],
                    [ 2, 5, 83, 113, 127, -63, -45, -15
                    ,-5, -33, -59, -125, 127, 89, 7, 3
                    ]
                  ];

    decode(ChannelAssignment::Independent, &mut channels);
    assert_eq!(&channels, &results[0]);

    channels = [ 2, 5, 83, 113, 127, -63, -45, -15
               , 7, 38, 142, 238, 0, -152, -52, -18
               ];

    decode(ChannelAssignment::LeftSide, &mut channels);
    assert_eq!(&channels, &results[1]);

    channels = [ 7, 38, 142, 238, 0, -152, -52, -18
               , -5, -33, -59, -125, 127, 89, 7, 3
               ];

    decode(ChannelAssignment::RightSide, &mut channels);
    assert_eq!(&channels, &results[1]);

    channels = [ -2, -14, 12, -6, 127, 13, -19, -6
               , 7, 38, 142, 238, 0, -152, -52, -18
               ];

    decode(ChannelAssignment::MiddleSide, &mut channels);
    assert_eq!(&channels, &results[1]);
  }
}
<|endoftext|>


<commit_before>extern crate chrono;
extern crate fuse;
extern crate libc;
extern crate regex;
extern crate rustc_serialize;
extern crate time;
extern crate users;

use libc::ENOSYS;
use chrono::*;
use fuse::{Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyDirectory, ReplyEmpty};
use rustc_serialize::json;
use std::path::Path;

use std::ffi::OsStr;

use fs;
use fs::inode;
use gd;
use object;

use fs::helpers::{create_inode_directory_attributes, create_inode_file_attributes};
use helpers;

pub struct GoodDataFS {
    pub client: gd::GoodDataClient,
    pub users_cache: users::UsersCache,
}

impl Drop for GoodDataFS {
    fn drop(&mut self) {
        info!("Unmounting GoodData Filesystem");
    }
}

#[allow(dead_code)]
impl GoodDataFS {
    pub fn client(&self) -> &gd::GoodDataClient {
        &self.client
    }

    pub fn get_projects_dir_attributes(&self) -> fuse::FileAttr {
        create_inode_directory_attributes(fs::constants::INODE_PROJECTS)
    }

    pub fn get_root_dir_attributes(&self) -> fuse::FileAttr {
        create_inode_directory_attributes(fs::constants::INODE_ROOT)
    }

    pub fn get_user_json_attributes(&self) -> fuse::FileAttr {
        let json = format!("{}\n",
                           json::as_pretty_json(&self.client.user()).to_string());

        let user = json::decode::<object::AccountSetting>(&json);

        let ts = UTC.datetime_from_str(&user.unwrap().accountSetting.updated.unwrap()[..],
                               "%Y-%m-%d %H:%M:%S")
            .unwrap()
            .timestamp();

        let updated = time::Timespec::new(ts, 0);

        create_inode_file_attributes(fs::constants::INODE_USER, json.len() as u64, updated)
    }

    pub fn get_projects_json_attributes(&self) -> fuse::FileAttr {
        let json = format!("{}\n",
                           json::as_pretty_json(&self.client.projects()).to_string());

        create_inode_file_attributes(fs::constants::INODE_PROJECTS_JSON,
                                     json.len() as u64,
                                     fs::constants::DEFAULT_CREATE_TIME)
    }
}

impl Filesystem for GoodDataFS {
    fn getattr(&mut self, req: &Request, ino: u64, reply: ReplyAttr) {
        let inode = inode::Inode::deserialize(ino);
        info!("GoodDataFS::getattr() - Getting attributes {} - {:?}",
              ino,
              inode);

        match ino {
            fs::constants::INODE_ROOT => fs::root::getattr(self, req, ino, reply),
            fs::constants::INODE_PROJECTS => fs::projects::getattr(self, req, ino, reply),
            fs::constants::INODE_PROJECTS_JSON => {
                reply.attr(&fs::constants::DEFAULT_TTL,
                           &self.get_projects_json_attributes())
            }
            fs::constants::INODE_USER => {
                reply.attr(&fs::constants::DEFAULT_TTL,
                           &self.get_user_json_attributes())
            }
            _ => {
                if inode.project > 0 && inode.category == fs::constants::Category::Internal as u8 &&
                   inode.reserved == 0 {
                    fs::projects::getattr(self, req, ino, reply)
                } else if inode.project > 0 {
                    fs::project::getattr(self, req, ino, reply)
                } else {
                    error!("getattr() - HAPR")
                }
            }
        }
    }

    fn lookup(&mut self, req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        let parent_inode = inode::Inode::deserialize(parent);
        info!("GoodDataFS::lookup() - Looking up parent {} - {:?}, path: {}",
              parent,
              parent_inode,
              name.to_str().unwrap());

        match parent {
            fs::constants::INODE_ROOT => fs::root::lookup(self, req, parent, name, reply),
            fs::constants::INODE_PROJECTS => fs::projects::lookup(self, req, parent, name, reply),
            _ => {
                if parent_inode.project > 0 {
                    fs::project::lookup(self, req, parent, name, reply)
                }
            }
        }
    }

    fn read(&mut self,
            req: &Request,
            ino: u64,
            fh: u64,
            offset: u64,
            size: u32,
            reply: ReplyData) {

        let inode = inode::Inode::deserialize(ino);
        info!("GoodDataFS::read() - Reading inode {} - {:?}, fh: {}, offset: {}, size: {}",
              ino,
              inode,
              fh,
              offset,
              size);

        match ino {
            fs::constants::INODE_PROJECTS_JSON => {
                debug!("off: {}, size {}", offset, size);
                let json = format!("{}\n",
                                   json::as_pretty_json(&self.client.projects_fetch_if_none())
                                       .to_string());
                // let json: String = fs.client.projects().clone().unwrap().into();
                reply.data(helpers::read_bytes(&json, offset, size));
            }
            fs::constants::INODE_USER => {
                let json: String = self.client.user().clone().unwrap().into();
                reply.data(helpers::read_bytes(&json, offset, size));
            }
            _ => {
                let inode = inode::Inode::deserialize(ino);
                if inode.project > 0 {
                    fs::project::read(self, req, ino, fh, offset, size, reply);
                } else {
                    warn!("read() - HAPR")
                }
            }
        }
    }

    fn readdir(&mut self, req: &Request, ino: u64, fh: u64, offset: u64, reply: ReplyDirectory) {
        let inode = inode::Inode::deserialize(ino);
        info!("GoodDataFS::readdir() - Reading inode {} - {:?}, fh: {}, offset: {}",
              ino,
              inode,
              fh,
              offset);

        match ino {
            fs::constants::INODE_ROOT => {
                if offset == 0 {
                    fs::root::readdir(self, req, ino, fh, offset, reply)
                } else {
                    reply.ok();
                }
            }
            fs::constants::INODE_PROJECTS => {
                if offset == 0 {
                    fs::projects::readdir(self, req, ino, fh, offset, reply)
                } else {
                    reply.ok();
                }
            }
            _ => {
                let inode: fs::inode::Inode = fs::inode::Inode::deserialize(ino);
                if inode.project > 0 {
                    fs::project::readdir(self, req, ino, fh, offset, reply)
                }
            }
        }
    }

    fn mkdir(&mut self, _req: &Request, parent: u64, name: &Path, _mode: u32, reply: ReplyEntry) {
        let parent_inode = inode::Inode::deserialize(parent);
        info!("GoodDataFS::mkdir() - Making dir in parent {} - {:?}, path: {}",
              parent,
              parent_inode,
              name.to_str().unwrap());
        match parent {
            fs::constants::INODE_PROJECTS => fs::projects::create(self, name, reply),
            _ => reply.error(ENOSYS),
        }
    }

    fn rmdir(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEmpty) {
        let parent_inode = inode::Inode::deserialize(parent);
        info!("GoodDataFS::rmdir() - Removing dir in parent {} - {:?}, path: {}",
              parent,
              parent_inode,
              name.to_str().unwrap());
        match parent {
            fs::constants::INODE_PROJECTS => fs::projects::rmdir(self, name, reply),
            _ => {
                warn!("GoodDataFS::rmdir() - not implemented!");
                reply.ok()
                // reply.error(ENOSYS)
            }
        }
    }

    fn unlink(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEmpty) {
        let parent_inode = inode::Inode::deserialize(parent);
        info!("GoodDataFS::unlinl() - Removing file in parent {} - {:?}, path: {}",
              parent,
              parent_inode,
              name.to_str().unwrap());
        warn!("GoodDataFS::unlink() - not implemented!");
        reply.ok()
        // reply.error(ENOSYS);
    }
}

impl GoodDataFS {
    pub fn mount(self, mountpoint: String) {
        const VERSION: &'static str = env!("CARGO_PKG_VERSION");
        info!("Mounting GoodData as Filesystem ({}), mountpoint: {}",
              VERSION,
              mountpoint);

        // See https://github.com/osxfuse/osxfuse/wiki/Mount-options
        fuse::mount(self,
                    &mountpoint,
                    &[
                        // &OsStr::new("debug"),
                        // &OsStr::new("nolocalcaches"),
                        // &OsStr::new("allow_other"),
                    ]);
    }
}
<commit_msg>Remove name of file from log messages<commit_after>extern crate chrono;
extern crate fuse;
extern crate libc;
extern crate regex;
extern crate rustc_serialize;
extern crate time;
extern crate users;

use libc::ENOSYS;
use chrono::*;
use fuse::{Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyDirectory, ReplyEmpty};
use rustc_serialize::json;
use std::path::Path;

use std::ffi::OsStr;

use fs;
use fs::inode;
use gd;
use object;

use fs::helpers::{create_inode_directory_attributes, create_inode_file_attributes};
use helpers;

pub struct GoodDataFS {
    pub client: gd::GoodDataClient,
    pub users_cache: users::UsersCache,
}

impl Drop for GoodDataFS {
    fn drop(&mut self) {
        info!("Unmounting GoodData Filesystem");
    }
}

#[allow(dead_code)]
impl GoodDataFS {
    pub fn client(&self) -> &gd::GoodDataClient {
        &self.client
    }

    pub fn get_projects_dir_attributes(&self) -> fuse::FileAttr {
        create_inode_directory_attributes(fs::constants::INODE_PROJECTS)
    }

    pub fn get_root_dir_attributes(&self) -> fuse::FileAttr {
        create_inode_directory_attributes(fs::constants::INODE_ROOT)
    }

    pub fn get_user_json_attributes(&self) -> fuse::FileAttr {
        let json = format!("{}\n",
                           json::as_pretty_json(&self.client.user()).to_string());

        let user = json::decode::<object::AccountSetting>(&json);

        let ts = UTC.datetime_from_str(&user.unwrap().accountSetting.updated.unwrap()[..],
                               "%Y-%m-%d %H:%M:%S")
            .unwrap()
            .timestamp();

        let updated = time::Timespec::new(ts, 0);

        create_inode_file_attributes(fs::constants::INODE_USER, json.len() as u64, updated)
    }

    pub fn get_projects_json_attributes(&self) -> fuse::FileAttr {
        let json = format!("{}\n",
                           json::as_pretty_json(&self.client.projects()).to_string());

        create_inode_file_attributes(fs::constants::INODE_PROJECTS_JSON,
                                     json.len() as u64,
                                     fs::constants::DEFAULT_CREATE_TIME)
    }
}

impl Filesystem for GoodDataFS {
    fn getattr(&mut self, req: &Request, ino: u64, reply: ReplyAttr) {
        let inode = inode::Inode::deserialize(ino);
        info!("getattr() - Getting attributes {} - {:?}", ino, inode);

        match ino {
            fs::constants::INODE_ROOT => fs::root::getattr(self, req, ino, reply),
            fs::constants::INODE_PROJECTS => fs::projects::getattr(self, req, ino, reply),
            fs::constants::INODE_PROJECTS_JSON => {
                reply.attr(&fs::constants::DEFAULT_TTL,
                           &self.get_projects_json_attributes())
            }
            fs::constants::INODE_USER => {
                reply.attr(&fs::constants::DEFAULT_TTL,
                           &self.get_user_json_attributes())
            }
            _ => {
                if inode.project > 0 && inode.category == fs::constants::Category::Internal as u8 &&
                   inode.reserved == 0 {
                    fs::projects::getattr(self, req, ino, reply)
                } else if inode.project > 0 {
                    fs::project::getattr(self, req, ino, reply)
                } else {
                    error!("getattr() - HAPR")
                }
            }
        }
    }

    fn lookup(&mut self, req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        let parent_inode = inode::Inode::deserialize(parent);
        info!("lookup() - Looking up parent {} - {:?}, path: {}",
              parent,
              parent_inode,
              name.to_str().unwrap());

        match parent {
            fs::constants::INODE_ROOT => fs::root::lookup(self, req, parent, name, reply),
            fs::constants::INODE_PROJECTS => fs::projects::lookup(self, req, parent, name, reply),
            _ => {
                if parent_inode.project > 0 {
                    fs::project::lookup(self, req, parent, name, reply)
                }
            }
        }
    }

    fn read(&mut self,
            req: &Request,
            ino: u64,
            fh: u64,
            offset: u64,
            size: u32,
            reply: ReplyData) {

        let inode = inode::Inode::deserialize(ino);
        info!("read() - Reading inode {} - {:?}, fh: {}, offset: {}, size: {}",
              ino,
              inode,
              fh,
              offset,
              size);

        match ino {
            fs::constants::INODE_PROJECTS_JSON => {
                debug!("off: {}, size {}", offset, size);
                let json = format!("{}\n",
                                   json::as_pretty_json(&self.client.projects_fetch_if_none())
                                       .to_string());
                // let json: String = fs.client.projects().clone().unwrap().into();
                reply.data(helpers::read_bytes(&json, offset, size));
            }
            fs::constants::INODE_USER => {
                let json: String = self.client.user().clone().unwrap().into();
                reply.data(helpers::read_bytes(&json, offset, size));
            }
            _ => {
                let inode = inode::Inode::deserialize(ino);
                if inode.project > 0 {
                    fs::project::read(self, req, ino, fh, offset, size, reply);
                } else {
                    warn!("read() - HAPR")
                }
            }
        }
    }

    fn readdir(&mut self, req: &Request, ino: u64, fh: u64, offset: u64, reply: ReplyDirectory) {
        let inode = inode::Inode::deserialize(ino);
        info!("readdir() - Reading inode {} - {:?}, fh: {}, offset: {}",
              ino,
              inode,
              fh,
              offset);

        match ino {
            fs::constants::INODE_ROOT => {
                if offset == 0 {
                    fs::root::readdir(self, req, ino, fh, offset, reply)
                } else {
                    reply.ok();
                }
            }
            fs::constants::INODE_PROJECTS => {
                if offset == 0 {
                    fs::projects::readdir(self, req, ino, fh, offset, reply)
                } else {
                    reply.ok();
                }
            }
            _ => {
                let inode: fs::inode::Inode = fs::inode::Inode::deserialize(ino);
                if inode.project > 0 {
                    fs::project::readdir(self, req, ino, fh, offset, reply)
                }
            }
        }
    }

    fn mkdir(&mut self, _req: &Request, parent: u64, name: &Path, _mode: u32, reply: ReplyEntry) {
        let parent_inode = inode::Inode::deserialize(parent);
        info!("mkdir() - Making dir in parent {} - {:?}, path: {}",
              parent,
              parent_inode,
              name.to_str().unwrap());
        match parent {
            fs::constants::INODE_PROJECTS => fs::projects::create(self, name, reply),
            _ => reply.error(ENOSYS),
        }
    }

    fn rmdir(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEmpty) {
        let parent_inode = inode::Inode::deserialize(parent);
        info!("rmdir() - Removing dir in parent {} - {:?}, path: {}",
              parent,
              parent_inode,
              name.to_str().unwrap());
        match parent {
            fs::constants::INODE_PROJECTS => fs::projects::rmdir(self, name, reply),
            _ => {
                warn!("rmdir() - not implemented!");
                reply.ok()
                // reply.error(ENOSYS)
            }
        }
    }

    fn unlink(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEmpty) {
        let parent_inode = inode::Inode::deserialize(parent);
        info!("unlink() - Removing file in parent {} - {:?}, path: {}",
              parent,
              parent_inode,
              name.to_str().unwrap());
        warn!("unlink() - not implemented!");
        reply.ok()
        // reply.error(ENOSYS);
    }
}

impl GoodDataFS {
    pub fn mount(self, mountpoint: String) {
        const VERSION: &'static str = env!("CARGO_PKG_VERSION");
        info!("Mounting GoodData as Filesystem ({}), mountpoint: {}",
              VERSION,
              mountpoint);

        // See https://github.com/osxfuse/osxfuse/wiki/Mount-options
        fuse::mount(self,
                    &mountpoint,
                    &[// &OsStr::new("debug"),
                      // &OsStr::new("nolocalcaches"),
                      // &OsStr::new("allow_other"),
                      &OsStr::new("noappledouble")]);
    }
}
<|endoftext|>


<commit_before>
extern crate mprovision;
extern crate docopt;
#[macro_use(version)]
extern crate version;
extern crate chrono;

use std::io::{self, Write};
use std::process;
use std::path::Path;
use std::error;
use std::fmt;
use docopt::Docopt;
use mprovision as mp;

const USAGE: &'static str = "
mprovision
A tool that helps iOS developers to manage mobileprovision files.

Usage:
  mprovision search <text> [<directory>]
  mprovision remove <uuid> [<directory>]
  mprovision show-xml <uuid> [<directory>]
  mprovision show-expired --days <days> [<directory>]
  mprovision remove-expired [<directory>]
  mprovision (-h | --help)
  mprovision --version

Options:
  -h --help     Show this help message.
  --version     Show version.
";

fn main() {
    let args = Docopt::new(USAGE)
        .and_then(|d| d.version(Some(format!("mprovision {}", version!()))).parse())
        .unwrap_or_else(|e| e.exit());

    match Command::from_args(&args).execute() {
        Ok(_) => process::exit(0),
        Err(e) => {
            writeln!(&mut io::stderr(), "{}", e).unwrap();
            process::exit(1);
        }
    }
}

struct Command<'a> {
    args: &'a ::docopt::ArgvMap,
}

impl<'a> Command<'a> {
    fn from_args(args: &'a ::docopt::ArgvMap) -> Self {
        Command { args: args }
    }

    fn execute(&self) -> CliResult {
        if self.args.get_bool("search") {
            search(self.args)
        } else if self.args.get_bool("remove") {
            remove(self.args)
        } else if self.args.get_bool("show-xml") {
            show_xml(self.args)
        } else if self.args.get_bool("show-expired") {
            show_expired(self.args)
        } else if self.args.get_bool("remove-expired") {
            remove_expired(self.args)
        } else {
            Err(CliError::Custom("Command is not implemented".to_string()))
        }
    }
}

type CliResult = std::result::Result<(), CliError>;

#[derive(Debug)]
enum CliError {
    Lib(mp::Error),
    Custom(String),
    EmptyParameter(&'static str),
}

impl error::Error for CliError {
    fn description(&self) -> &str {
        match *self {
            CliError::Lib(ref e) => e.description(),
            CliError::Custom(ref e) => e,
            CliError::EmptyParameter(_) => "parameter is empty",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        if let CliError::Lib(ref e) = *self {
            Some(e)
        } else {
            None
        }
    }
}

impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CliError::Lib(ref e) => error::Error::description(e).fmt(f),
            CliError::Custom(ref e) => e.fmt(f),
            CliError::EmptyParameter(p) => write!(f, "{} should not be empty.", p),
        }
    }
}

impl From<mp::Error> for CliError {
    fn from(e: mp::Error) -> Self {
        CliError::Lib(e)
    }
}

fn search(args: &::docopt::ArgvMap) -> CliResult {
    let text = args.get_str("<text>");
    if text.is_empty() {
        return Err(CliError::EmptyParameter("<text>"));
    }

    let info = try!(mp::with_dir(directory(args), |dir| mp::search(dir, text)));
    if info.profiles.is_empty() {
        println!("Nothing found for '{}'", text);
    } else {
        for profile in &info.profiles {
            println!("\n{}", profile.description());
        }
        println!("\nFound {} of {}", info.profiles.len(), info.total);
    }
    Ok(())
}

fn remove(args: &::docopt::ArgvMap) -> CliResult {
    let uuid = args.get_str("<uuid>");
    if uuid.is_empty() {
        return Err(CliError::EmptyParameter("<uuid>"));
    }

    try!(mp::with_dir(directory(args), |dir| mp::remove(dir, uuid)));
    println!("'{}' was removed", uuid);
    Ok(())
}

fn show_xml(args: &::docopt::ArgvMap) -> CliResult {
    let uuid = args.get_str("<uuid>");
    if uuid.is_empty() {
        return Err(CliError::EmptyParameter("<uuid>"));
    }

    let xml = try!(mp::with_dir(directory(args), |dir| mp::xml(dir, uuid)));
    println!("{}", xml);
    Ok(())
}

fn show_expired(args: &::docopt::ArgvMap) -> CliResult {
    use chrono::*;

    let mut date = UTC::now();
    if let Some(days) = args.get_str("<days>").parse::<i64>().ok() {
        if days < 0 || days > 365 {
            return Err(CliError::Custom("<days> should be between 0 and 365".to_string()));
        }
        date = date + Duration::days(days);
    }

    let info = try!(mp::with_dir(directory(args), |dir| mp::expired_profiles(dir, date)));
    if info.profiles.is_empty() {
        println!("All provisioning profiles are valid");
    } else {
        for profile in &info.profiles {
            println!("\n{}", profile.description());
        }
        println!("\nFound {} of {}", info.profiles.len(), info.total);
    }
    Ok(())
}

fn remove_expired(args: &::docopt::ArgvMap) -> CliResult {
    use chrono::*;

    let info = try!(mp::with_dir(directory(args), |dir| mp::expired_profiles(dir, UTC::now())));
    if info.profiles.is_empty() {
        println!("All provisioning profiles are valid");
    } else {
        let mut errors_counter = 0;
        let mut removals_counter = 0;
        for profile in info.profiles {
            match std::fs::remove_file(&profile.path) {
                Ok(_) => {
                    removals_counter += 1;
                    println!("'{}' was removed", profile.uuid)
                }
                Err(e) => {
                    errors_counter += 1;
                    println!("Error while trying to remove '{}'", profile.uuid);
                    println!("{}", e);
                }
            }
        }
        println!("Removed {} of {}", removals_counter, info.total);
        if errors_counter > 0 {
            println!("Errors: {}", errors_counter);
        }
    }
    Ok(())
}

fn directory(args: &::docopt::ArgvMap) -> Option<&Path> {
    let dir_name = args.get_str("<directory>");
    if dir_name.is_empty() {
        None
    } else {
        Some(dir_name.as_ref())
    }
}
<commit_msg>Update CLI to new '?' mark syntax.<commit_after>
extern crate mprovision;
extern crate docopt;
#[macro_use(version)]
extern crate version;
extern crate chrono;

use std::io::{self, Write};
use std::process;
use std::path::Path;
use std::error;
use std::fmt;
use docopt::Docopt;
use mprovision as mp;

const USAGE: &'static str = "
mprovision
A tool that helps iOS developers to manage mobileprovision files.

Usage:
  mprovision search <text> [<directory>]
  mprovision remove <uuid> [<directory>]
  mprovision show-xml <uuid> [<directory>]
  mprovision show-expired --days <days> [<directory>]
  mprovision remove-expired [<directory>]
  mprovision (-h | --help)
  mprovision --version

Options:
  -h --help     Show this help message.
  --version     Show version.
";

fn main() {
    let args = Docopt::new(USAGE)
        .and_then(|d| d.version(Some(format!("mprovision {}", version!()))).parse())
        .unwrap_or_else(|e| e.exit());

    match Command::from_args(&args).execute() {
        Ok(_) => process::exit(0),
        Err(e) => {
            writeln!(&mut io::stderr(), "{}", e).unwrap();
            process::exit(1);
        }
    }
}

struct Command<'a> {
    args: &'a ::docopt::ArgvMap,
}

impl<'a> Command<'a> {
    fn from_args(args: &'a ::docopt::ArgvMap) -> Self {
        Command { args: args }
    }

    fn execute(&self) -> CliResult {
        if self.args.get_bool("search") {
            search(self.args)
        } else if self.args.get_bool("remove") {
            remove(self.args)
        } else if self.args.get_bool("show-xml") {
            show_xml(self.args)
        } else if self.args.get_bool("show-expired") {
            show_expired(self.args)
        } else if self.args.get_bool("remove-expired") {
            remove_expired(self.args)
        } else {
            Err(CliError::Custom("Command is not implemented".to_string()))
        }
    }
}

type CliResult = std::result::Result<(), CliError>;

#[derive(Debug)]
enum CliError {
    Lib(mp::Error),
    Custom(String),
    EmptyParameter(&'static str),
}

impl error::Error for CliError {
    fn description(&self) -> &str {
        match *self {
            CliError::Lib(ref e) => e.description(),
            CliError::Custom(ref e) => e,
            CliError::EmptyParameter(_) => "parameter is empty",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        if let CliError::Lib(ref e) = *self {
            Some(e)
        } else {
            None
        }
    }
}

impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CliError::Lib(ref e) => error::Error::description(e).fmt(f),
            CliError::Custom(ref e) => e.fmt(f),
            CliError::EmptyParameter(p) => write!(f, "{} should not be empty.", p),
        }
    }
}

impl From<mp::Error> for CliError {
    fn from(e: mp::Error) -> Self {
        CliError::Lib(e)
    }
}

fn search(args: &::docopt::ArgvMap) -> CliResult {
    let text = args.get_str("<text>");
    if text.is_empty() {
        return Err(CliError::EmptyParameter("<text>"));
    }

    let info = mp::with_dir(directory(args), |dir| mp::search(dir, text))?;
    if info.profiles.is_empty() {
        println!("Nothing found for '{}'", text);
    } else {
        for profile in &info.profiles {
            println!("\n{}", profile.description());
        }
        println!("\nFound {} of {}", info.profiles.len(), info.total);
    }
    Ok(())
}

fn remove(args: &::docopt::ArgvMap) -> CliResult {
    let uuid = args.get_str("<uuid>");
    if uuid.is_empty() {
        return Err(CliError::EmptyParameter("<uuid>"));
    }

    mp::with_dir(directory(args), |dir| mp::remove(dir, uuid))?;
    println!("'{}' was removed", uuid);
    Ok(())
}

fn show_xml(args: &::docopt::ArgvMap) -> CliResult {
    let uuid = args.get_str("<uuid>");
    if uuid.is_empty() {
        return Err(CliError::EmptyParameter("<uuid>"));
    }

    let xml = mp::with_dir(directory(args), |dir| mp::xml(dir, uuid))?;
    println!("{}", xml);
    Ok(())
}

fn show_expired(args: &::docopt::ArgvMap) -> CliResult {
    use chrono::*;

    let mut date = UTC::now();
    if let Some(days) = args.get_str("<days>").parse::<i64>().ok() {
        if days < 0 || days > 365 {
            return Err(CliError::Custom("<days> should be between 0 and 365".to_string()));
        }
        date = date + Duration::days(days);
    }

    let info = mp::with_dir(directory(args), |dir| mp::expired_profiles(dir, date))?;
    if info.profiles.is_empty() {
        println!("All provisioning profiles are valid");
    } else {
        for profile in &info.profiles {
            println!("\n{}", profile.description());
        }
        println!("\nFound {} of {}", info.profiles.len(), info.total);
    }
    Ok(())
}

fn remove_expired(args: &::docopt::ArgvMap) -> CliResult {
    use chrono::*;

    let info = mp::with_dir(directory(args), |dir| mp::expired_profiles(dir, UTC::now()))?;
    if info.profiles.is_empty() {
        println!("All provisioning profiles are valid");
    } else {
        let mut errors_counter = 0;
        let mut removals_counter = 0;
        for profile in info.profiles {
            match std::fs::remove_file(&profile.path) {
                Ok(_) => {
                    removals_counter += 1;
                    println!("'{}' was removed", profile.uuid)
                }
                Err(e) => {
                    errors_counter += 1;
                    println!("Error while trying to remove '{}'", profile.uuid);
                    println!("{}", e);
                }
            }
        }
        println!("Removed {} of {}", removals_counter, info.total);
        if errors_counter > 0 {
            println!("Errors: {}", errors_counter);
        }
    }
    Ok(())
}

fn directory(args: &::docopt::ArgvMap) -> Option<&Path> {
    let dir_name = args.get_str("<directory>");
    if dir_name.is_empty() {
        None
    } else {
        Some(dir_name.as_ref())
    }
}
<|endoftext|>