<commit_before>#![doc(html_root_url = "https://matthiasbeyer.github.io/task-hookrs/")]
#![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 chrono;
#[macro_use] extern crate log;
extern crate serde;
extern crate serde_json;
extern crate uuid;

pub mod annotation;
pub mod date;
pub mod error;
pub mod import;
pub mod priority;
pub mod project;
pub mod result;
pub mod status;
pub mod tag;
pub mod task;

<commit_msg>Enable lint: dead_code<commit_after>#![doc(html_root_url = "https://matthiasbeyer.github.io/task-hookrs/")]
#![deny(
    dead_code,
    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 chrono;
#[macro_use] extern crate log;
extern crate serde;
extern crate serde_json;
extern crate uuid;

pub mod annotation;
pub mod date;
pub mod error;
pub mod import;
pub mod priority;
pub mod project;
pub mod result;
pub mod status;
pub mod tag;
pub mod task;

<|endoftext|>


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

//#![deny(missing_docs)]
//#![deny(warnings)]
#![doc(test(attr(allow(unused_variables), deny(warnings))))]

// TODO: Remove this
#![allow(unused_macros, unused_imports)]

#[macro_use]
extern crate nom;

#[cfg(feature="graphviz")]
extern crate dot;

#[cfg(test)]
#[macro_use]
extern crate quickcheck;

// this is going to be usefull when looking at this crate
// https://www.lua.org/manual/5.3/manual.html#9

use function::parse_block;
pub use ast::ASTNode;
use std::io::Read;

#[macro_use]
mod macros;

pub mod lexer;
pub mod ast;
pub mod op;
pub mod number;
pub mod exp;
pub mod string;
pub mod name;
pub mod var;
pub mod field;
pub mod statement;
pub mod function;

pub use nom::IResult;

//named!(pub parse_chunk<ASTNode>, ws!(parse_block));
use exp::parse_exp;
named!(pub parse_chunk<ASTNode>, dbg_dmp!(ws!(parse_exp)));

// TODO: Implement our own Error type
pub fn parse_string<'a, T: Into<&'a [u8]>>(s: T) -> Option<ASTNode> {
    match parse_chunk(s.into()) {
        IResult::Done(_, a) => Some(a),
        _ => None
    }
}

pub fn parse<T: Read>(mut s: T) -> Option<ASTNode> {
    let mut buf = vec![];
    s.read_to_end(&mut buf);
    buf.pop(); //Remove EOF
    match parse_chunk(&buf) {
        IResult::Done(_, a) => Some(a),
        _ => None
    }
}
<commit_msg>Remove lexer<commit_after>// Copyright 2017 The nom-lua project developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//#![deny(missing_docs)]
//#![deny(warnings)]
#![doc(test(attr(allow(unused_variables), deny(warnings))))]

// TODO: Remove this
#![allow(unused_macros, unused_imports)]

#[macro_use]
extern crate nom;

#[cfg(feature="graphviz")]
extern crate dot;

#[cfg(test)]
#[macro_use]
extern crate quickcheck;

// this is going to be usefull when looking at this crate
// https://www.lua.org/manual/5.3/manual.html#9

use function::parse_block;
pub use ast::ASTNode;
use std::io::Read;

#[macro_use]
mod macros;

pub mod ast;
pub mod op;
pub mod number;
pub mod exp;
pub mod string;
pub mod name;
pub mod var;
pub mod field;
pub mod statement;
pub mod function;

pub use nom::IResult;

//named!(pub parse_chunk<ASTNode>, ws!(parse_block));
use exp::parse_exp;
named!(pub parse_chunk<ASTNode>, dbg_dmp!(ws!(parse_exp)));

// TODO: Implement our own Error type
pub fn parse_string<'a, T: Into<&'a [u8]>>(s: T) -> Option<ASTNode> {
    match parse_chunk(s.into()) {
        IResult::Done(_, a) => Some(a),
        _ => None
    }
}

pub fn parse<T: Read>(mut s: T) -> Option<ASTNode> {
    let mut buf = vec![];
    s.read_to_end(&mut buf);
    buf.pop(); //Remove EOF
    match parse_chunk(&buf) {
        IResult::Done(_, a) => Some(a),
        _ => None
    }
}
<|endoftext|>


<commit_before>//! Solvent is a dependency resolver library written in rust.
//!
//! Solvent helps you to resolve dependency orderings by building up a dependency
//! graph and then resolving the dependences of some target node in an order such
//! that each output depends only upon the previous outputs.
//!
//! It is currently quite simple, but is still useful.
//!
//! #Example
//!
//! ```rust
//! extern crate solvent;
//!
//! use solvent::DepGraph;
//!
//! fn main() {
//!     // Create a new empty DepGraph.  Must be `mut` or else it cannot
//!     // be used by the rest of the library.
//!     let mut depgraph: DepGraph = DepGraph::new();
//!
//!     // You can register a dependency like this.  Solvent will
//!     // automatically create nodes for any term it has not seen before.
//!     // This means 'b' depends on 'd'
//!     depgraph.register_dependency("b","d");
//!
//!     // You can also register multiple dependencies at once
//!     depgraph.register_dependencies("a",&["b","c","d"]);
//!     depgraph.register_dependencies("c",&["e"]);
//!
//!     // Iterate through each dependency of "a".  The dependencies will be
//!     // returned in an order such that each output only depends on the
//!     // previous outputs (or nothing).  The target itself will be output
//!     // last.
//!     for node in depgraph.dependencies_of("a") {
//!         print!("{} ", node.unwrap());
//!     }
//! }
//! ```
//!
//! The above will output:  `d b e c a` or `e c d b a` or some other valid
//! dependency order.
//!
//! The algorithm is not deterministic, and may give a different answer each
//! time it is run.  Beware.
//!
//! The iterator dependencies_of() returns an Option<Result<String,SolventError>>.
//! The for loop handles the Option part for you, but you may want to check the
//! result for SolventErrors.  Once an error is returned, all subsequent calls to
//! the iterator next() will yield None.
//!
//! You can also mark some elements as already satisfied, and the iterator
//! will take that into account:
//!
//! ```ignore
//! depgraph.mark_as_satisfied(["e","c"]);
//! ```
//!
//! Dependency cycles are detected and will return SolventError::CycleDetected.

#![crate_name = "solvent"]
#![crate_type = "lib"]

// Required for log and rustdoc:
#![feature(phase)]
#[phase(plugin, link)]

extern crate log;

use std::collections::{HashMap,HashSet};
use std::collections::hash_map::Entry;
use std::iter::{Iterator};
#[allow(unused_imports)]
use std::task;
use std::borrow::ToOwned;

/// This is the dependency graph.
#[derive(Clone)]
pub struct DepGraph {
    /// List of dependencies.  Key is the element, values are the
    /// other elements that the key element depends upon.
    pub dependencies: HashMap<String,HashSet<String>>,

    /// Nodes already satisfied.  dependencies_of() will prune
    /// dependency searches at these nodes, and not output nodes
    /// registered here.
    pub satisfied: HashSet<String>,
}

#[derive(Copy,Show,PartialEq)]
pub enum SolventError {
    CycleDetected,
    // TODO once we implement conflicts: Conflict(String)
}

/// This iterates through the dependencies of the DepGraph's target
pub struct DepGraphIterator<'a> {
    depgraph: &'a DepGraph,

    // Target we are trying to satisfy
    target: String,

    // Elements already satisfied during this iterator's walk
    satisfied: HashSet<String>,

    // Current path, for cycle detection
    curpath: HashSet<String>,

    // Halted.  Used so that it can return None after an Err is returned.
    halted: bool,
}

impl DepGraph {

    /// Create an empty DepGraph.
    pub fn new() -> DepGraph
    {
        DepGraph {
            dependencies: HashMap::new(),
            satisfied: HashSet::new(),
        }
    }

    /// Add a dependency to a DepGraph.  The node does not need
    /// to pre-exist, nor do the dependency nodes.  But if the
    /// node does pre-exist, the depends_on will be added to its
    /// existing dependency list.
    pub fn register_dependency<'a>( &mut self,
                                node: &'a str,
                                depends_on: &'a str )
    {
        match self.dependencies.entry( String::from_str(node) ) {
            Entry::Vacant(entry) => {
                let mut deps = HashSet::with_capacity(1);
                deps.insert( String::from_str(depends_on) );
                entry.set( deps );
            },
            Entry::Occupied(mut entry) => {
                (*entry.get_mut()).insert(String::from_str(depends_on));
            },
        }
    }

    /// Add multiple dependencies of one node to a DepGraph.  The
    /// node does not need to pre-exist, nor do the dependency elements.
    /// But if the node does pre-exist, the depends_on will be added
    /// to its existing dependency list.
    pub fn register_dependencies<'a>( &mut self,
                                  node: &'a str,
                                  depends_on: &'a[&'a str] )
    {
        match self.dependencies.entry( String::from_str(node) ) {
            Entry::Vacant(entry) => {
                let mut deps = HashSet::with_capacity( depends_on.len() );
                for s in depends_on.iter() {
                    deps.insert( String::from_str(*s) );
                }
                entry.set( deps );
            },
            Entry::Occupied(mut entry) => {
                for s in depends_on.iter() {
                    (*entry.get_mut()).insert( String::from_str(*s) );
                }
            },
        }
    }

    /// This marks a node as satisfied.  Iterators will not output
    /// such nodes.
    pub fn mark_as_satisfied<'a>( &mut self,
                                   nodes: &'a[&'a str] )
    {
        for node in nodes.iter() {
            self.satisfied.insert(String::from_str(*node));
        }
    }

    /// Get an iterator to iterate through the dependencies of
    /// the target node.
    pub fn dependencies_of<'a>(&'a self, target: &str) -> DepGraphIterator<'a>
    {
        // TODO: iterator's satisfied could start empty, and all checks
        //       could separately check depgraph's and iterator's.  That
        //       would avoid the copy.
        DepGraphIterator {
            depgraph: self,
            target: target.to_owned(),
            satisfied: self.satisfied.clone(),
            curpath: HashSet::new(),
            halted: false,
        }
    }
}

impl<'a> DepGraphIterator<'a> {

    fn get_next_dependency(&mut self, node: &String) -> Result<String,SolventError>
    {
        if self.curpath.contains(node) {
            return Err(SolventError::CycleDetected);
        }
        self.curpath.insert(node.clone());

        let deplist = match self.depgraph.dependencies.get(node) {
            None => return Ok(node.clone()),
            Some(deplist) => deplist.clone() // ouch
        };

        for n in deplist.iter() {
            // Prune satisfied nodes
            if self.satisfied.contains(n) {
                continue;
            }

            return self.get_next_dependency(n);
        }
        // nodes dependencies are satisfied
        Ok(node.clone())
    }
}

impl<'a> Iterator< Result<String,SolventError> > for DepGraphIterator<'a> {
    /// Get next dependency.  Returns None when finished.  If
    /// Some(Err(SolventError)) occurs, all subsequent calls will
    /// return None.
    fn next(&mut self) -> Option< Result<String,SolventError> >
    {
        if self.halted {
            return None;
        }

        let node = self.target.clone();
        if self.satisfied.contains(&node) {
            return None;
        }

        self.curpath.clear();
        let next = match self.get_next_dependency(&node) {
            Ok(d) => d,
            Err(e) => {
                self.halted = true;
                return Some(Err(e));
            }
        };
        self.satisfied.insert(next.clone());
        Some(Ok(next))
    }
}

#[test]
fn solvent_test_branching() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.register_dependencies("a",&["b","c","d"]);
    depgraph.register_dependency("b","d");
    depgraph.register_dependencies("c",&["e","m","g"]);
    depgraph.register_dependency("e","f");
    depgraph.register_dependency("g","h");
    depgraph.register_dependency("h","i");
    depgraph.register_dependencies("i",&["j","k"]);
    depgraph.register_dependencies("k",&["l","m"]);
    depgraph.register_dependency("m","n");

    let mut results: Vec<String> = Vec::new();

    for node in depgraph.dependencies_of("a") {
        // detect infinite looping bugs
        assert!(results.len() < 30);

        let n = node.unwrap();

        // Check that all of that nodes dependencies have already been output
        let deps: Option<&HashSet<String>> = depgraph.dependencies.get(&n);
        if deps.is_some() {
            for dep in deps.unwrap().iter() {
                assert!( results.contains(dep) );
            }
        }

        results.push(n.clone());
    }

    // Be sure we actually output enough stuff
    assert!(results.len() == 14);

    // Be sure each output is unique
    for result in results.iter() {
        let mut count = 0u;
        for result2 in results.iter() {
            if result == result2 { count = count + 1; }
        }
        assert!(count == 1);
    }
}

#[test]
fn solvent_test_updating_dependencies() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.register_dependencies("a",&["b","c"]);
    depgraph.register_dependency("a","d");
    assert!(depgraph.dependencies.get("a").unwrap().contains("b"));
    assert!(depgraph.dependencies.get("a").unwrap().contains("c"));
    assert!(depgraph.dependencies.get("a").unwrap().contains("d"));
}

#[test]
fn solvent_test_circular() {

    let mut depgraph: DepGraph = DepGraph::new();
    depgraph.register_dependency("a","b");
    depgraph.register_dependency("b","c");
    depgraph.register_dependency("c","a");

    for node in depgraph.dependencies_of("a") {
        assert!(node.is_err());
        assert!(node.unwrap_err() == SolventError::CycleDetected);
    }
}

#[test]
fn solvent_test_satisfied_stoppage() {

    let mut depgraph: DepGraph = DepGraph::new();
    depgraph.register_dependencies("superconn", &[]);
    depgraph.register_dependencies("owneruser", &["superconn"]);
    depgraph.register_dependencies("appuser", &["superconn"]);
    depgraph.register_dependencies("database", &["owneruser"]);
    depgraph.register_dependencies("ownerconn", &["database","owneruser"]);
    depgraph.register_dependencies("adminconn", &["database"]);
    depgraph.register_dependencies("extensions", &["database","adminconn"]);
    depgraph.register_dependencies("schema_table", &["database","ownerconn"]);
    depgraph.register_dependencies("schemas", &["ownerconn","extensions","schema_table","appuser"]);
    depgraph.register_dependencies("appconn", &["database","appuser","schemas"]);

    depgraph.mark_as_satisfied(&["owneruser","appuser"]);

    let mut results: Vec<String> = Vec::new();

    for node in depgraph.dependencies_of("appconn") {
        assert!(results.len() < 30);
        results.push(node.unwrap());
    }

    // Be sure we did not depend on these
    assert!( !results.contains(&String::from_str("appuser")) );
    assert!( !results.contains(&String::from_str("owneruser")) );
    assert!( !results.contains(&String::from_str("superconn")) );

    // Be sure we actually output enough stuff
    assert!(results.len() == 7);

    // Be sure each output is unique
    for result in results.iter() {
        let mut count = 0u;
        for result2 in results.iter() {
            if result == result2 { count = count + 1; }
        }
        assert!(count == 1);
    }
}

<commit_msg>upstream rust: fallout of Iterator associated type<commit_after>//! Solvent is a dependency resolver library written in rust.
//!
//! Solvent helps you to resolve dependency orderings by building up a dependency
//! graph and then resolving the dependences of some target node in an order such
//! that each output depends only upon the previous outputs.
//!
//! It is currently quite simple, but is still useful.
//!
//! #Example
//!
//! ```rust
//! extern crate solvent;
//!
//! use solvent::DepGraph;
//!
//! fn main() {
//!     // Create a new empty DepGraph.  Must be `mut` or else it cannot
//!     // be used by the rest of the library.
//!     let mut depgraph: DepGraph = DepGraph::new();
//!
//!     // You can register a dependency like this.  Solvent will
//!     // automatically create nodes for any term it has not seen before.
//!     // This means 'b' depends on 'd'
//!     depgraph.register_dependency("b","d");
//!
//!     // You can also register multiple dependencies at once
//!     depgraph.register_dependencies("a",&["b","c","d"]);
//!     depgraph.register_dependencies("c",&["e"]);
//!
//!     // Iterate through each dependency of "a".  The dependencies will be
//!     // returned in an order such that each output only depends on the
//!     // previous outputs (or nothing).  The target itself will be output
//!     // last.
//!     for node in depgraph.dependencies_of("a") {
//!         print!("{} ", node.unwrap());
//!     }
//! }
//! ```
//!
//! The above will output:  `d b e c a` or `e c d b a` or some other valid
//! dependency order.
//!
//! The algorithm is not deterministic, and may give a different answer each
//! time it is run.  Beware.
//!
//! The iterator dependencies_of() returns an Option<Result<String,SolventError>>.
//! The for loop handles the Option part for you, but you may want to check the
//! result for SolventErrors.  Once an error is returned, all subsequent calls to
//! the iterator next() will yield None.
//!
//! You can also mark some elements as already satisfied, and the iterator
//! will take that into account:
//!
//! ```ignore
//! depgraph.mark_as_satisfied(["e","c"]);
//! ```
//!
//! Dependency cycles are detected and will return SolventError::CycleDetected.

#![crate_name = "solvent"]
#![crate_type = "lib"]

// Required for log and rustdoc:
#![feature(phase)]
#![feature(associated_types)]
#[phase(plugin, link)]

extern crate log;

use std::collections::{HashMap,HashSet};
use std::collections::hash_map::Entry;
use std::iter::{Iterator};
#[allow(unused_imports)]
use std::task;
use std::borrow::ToOwned;

/// This is the dependency graph.
#[derive(Clone)]
pub struct DepGraph {
    /// List of dependencies.  Key is the element, values are the
    /// other elements that the key element depends upon.
    pub dependencies: HashMap<String,HashSet<String>>,

    /// Nodes already satisfied.  dependencies_of() will prune
    /// dependency searches at these nodes, and not output nodes
    /// registered here.
    pub satisfied: HashSet<String>,
}

#[derive(Copy,Show,PartialEq)]
pub enum SolventError {
    CycleDetected,
    // TODO once we implement conflicts: Conflict(String)
}

/// This iterates through the dependencies of the DepGraph's target
pub struct DepGraphIterator<'a> {
    depgraph: &'a DepGraph,

    // Target we are trying to satisfy
    target: String,

    // Elements already satisfied during this iterator's walk
    satisfied: HashSet<String>,

    // Current path, for cycle detection
    curpath: HashSet<String>,

    // Halted.  Used so that it can return None after an Err is returned.
    halted: bool,
}

impl DepGraph {

    /// Create an empty DepGraph.
    pub fn new() -> DepGraph
    {
        DepGraph {
            dependencies: HashMap::new(),
            satisfied: HashSet::new(),
        }
    }

    /// Add a dependency to a DepGraph.  The node does not need
    /// to pre-exist, nor do the dependency nodes.  But if the
    /// node does pre-exist, the depends_on will be added to its
    /// existing dependency list.
    pub fn register_dependency<'a>( &mut self,
                                node: &'a str,
                                depends_on: &'a str )
    {
        match self.dependencies.entry( String::from_str(node) ) {
            Entry::Vacant(entry) => {
                let mut deps = HashSet::with_capacity(1);
                deps.insert( String::from_str(depends_on) );
                entry.set( deps );
            },
            Entry::Occupied(mut entry) => {
                (*entry.get_mut()).insert(String::from_str(depends_on));
            },
        }
    }

    /// Add multiple dependencies of one node to a DepGraph.  The
    /// node does not need to pre-exist, nor do the dependency elements.
    /// But if the node does pre-exist, the depends_on will be added
    /// to its existing dependency list.
    pub fn register_dependencies<'a>( &mut self,
                                  node: &'a str,
                                  depends_on: &'a[&'a str] )
    {
        match self.dependencies.entry( String::from_str(node) ) {
            Entry::Vacant(entry) => {
                let mut deps = HashSet::with_capacity( depends_on.len() );
                for s in depends_on.iter() {
                    deps.insert( String::from_str(*s) );
                }
                entry.set( deps );
            },
            Entry::Occupied(mut entry) => {
                for s in depends_on.iter() {
                    (*entry.get_mut()).insert( String::from_str(*s) );
                }
            },
        }
    }

    /// This marks a node as satisfied.  Iterators will not output
    /// such nodes.
    pub fn mark_as_satisfied<'a>( &mut self,
                                   nodes: &'a[&'a str] )
    {
        for node in nodes.iter() {
            self.satisfied.insert(String::from_str(*node));
        }
    }

    /// Get an iterator to iterate through the dependencies of
    /// the target node.
    pub fn dependencies_of<'a>(&'a self, target: &str) -> DepGraphIterator<'a>
    {
        // TODO: iterator's satisfied could start empty, and all checks
        //       could separately check depgraph's and iterator's.  That
        //       would avoid the copy.
        DepGraphIterator {
            depgraph: self,
            target: target.to_owned(),
            satisfied: self.satisfied.clone(),
            curpath: HashSet::new(),
            halted: false,
        }
    }
}

impl<'a> DepGraphIterator<'a> {

    fn get_next_dependency(&mut self, node: &String) -> Result<String,SolventError>
    {
        if self.curpath.contains(node) {
            return Err(SolventError::CycleDetected);
        }
        self.curpath.insert(node.clone());

        let deplist = match self.depgraph.dependencies.get(node) {
            None => return Ok(node.clone()),
            Some(deplist) => deplist.clone() // ouch
        };

        for n in deplist.iter() {
            // Prune satisfied nodes
            if self.satisfied.contains(n) {
                continue;
            }

            return self.get_next_dependency(n);
        }
        // nodes dependencies are satisfied
        Ok(node.clone())
    }
}

impl<'a> Iterator for DepGraphIterator<'a> {
    type Item = Result<String,SolventError>;

    /// Get next dependency.  Returns None when finished.  If
    /// Some(Err(SolventError)) occurs, all subsequent calls will
    /// return None.
    fn next(&mut self) -> Option< Result<String,SolventError> >
    {
        if self.halted {
            return None;
        }

        let node = self.target.clone();
        if self.satisfied.contains(&node) {
            return None;
        }

        self.curpath.clear();
        let next = match self.get_next_dependency(&node) {
            Ok(d) => d,
            Err(e) => {
                self.halted = true;
                return Some(Err(e));
            }
        };
        self.satisfied.insert(next.clone());
        Some(Ok(next))
    }
}

#[test]
fn solvent_test_branching() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.register_dependencies("a",&["b","c","d"]);
    depgraph.register_dependency("b","d");
    depgraph.register_dependencies("c",&["e","m","g"]);
    depgraph.register_dependency("e","f");
    depgraph.register_dependency("g","h");
    depgraph.register_dependency("h","i");
    depgraph.register_dependencies("i",&["j","k"]);
    depgraph.register_dependencies("k",&["l","m"]);
    depgraph.register_dependency("m","n");

    let mut results: Vec<String> = Vec::new();

    for node in depgraph.dependencies_of("a") {
        // detect infinite looping bugs
        assert!(results.len() < 30);

        let n = node.unwrap();

        // Check that all of that nodes dependencies have already been output
        let deps: Option<&HashSet<String>> = depgraph.dependencies.get(&n);
        if deps.is_some() {
            for dep in deps.unwrap().iter() {
                assert!( results.contains(dep) );
            }
        }

        results.push(n.clone());
    }

    // Be sure we actually output enough stuff
    assert!(results.len() == 14);

    // Be sure each output is unique
    for result in results.iter() {
        let mut count = 0u;
        for result2 in results.iter() {
            if result == result2 { count = count + 1; }
        }
        assert!(count == 1);
    }
}

#[test]
fn solvent_test_updating_dependencies() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.register_dependencies("a",&["b","c"]);
    depgraph.register_dependency("a","d");
    assert!(depgraph.dependencies.get("a").unwrap().contains("b"));
    assert!(depgraph.dependencies.get("a").unwrap().contains("c"));
    assert!(depgraph.dependencies.get("a").unwrap().contains("d"));
}

#[test]
fn solvent_test_circular() {

    let mut depgraph: DepGraph = DepGraph::new();
    depgraph.register_dependency("a","b");
    depgraph.register_dependency("b","c");
    depgraph.register_dependency("c","a");

    for node in depgraph.dependencies_of("a") {
        assert!(node.is_err());
        assert!(node.unwrap_err() == SolventError::CycleDetected);
    }
}

#[test]
fn solvent_test_satisfied_stoppage() {

    let mut depgraph: DepGraph = DepGraph::new();
    depgraph.register_dependencies("superconn", &[]);
    depgraph.register_dependencies("owneruser", &["superconn"]);
    depgraph.register_dependencies("appuser", &["superconn"]);
    depgraph.register_dependencies("database", &["owneruser"]);
    depgraph.register_dependencies("ownerconn", &["database","owneruser"]);
    depgraph.register_dependencies("adminconn", &["database"]);
    depgraph.register_dependencies("extensions", &["database","adminconn"]);
    depgraph.register_dependencies("schema_table", &["database","ownerconn"]);
    depgraph.register_dependencies("schemas", &["ownerconn","extensions","schema_table","appuser"]);
    depgraph.register_dependencies("appconn", &["database","appuser","schemas"]);

    depgraph.mark_as_satisfied(&["owneruser","appuser"]);

    let mut results: Vec<String> = Vec::new();

    for node in depgraph.dependencies_of("appconn") {
        assert!(results.len() < 30);
        results.push(node.unwrap());
    }

    // Be sure we did not depend on these
    assert!( !results.contains(&String::from_str("appuser")) );
    assert!( !results.contains(&String::from_str("owneruser")) );
    assert!( !results.contains(&String::from_str("superconn")) );

    // Be sure we actually output enough stuff
    assert!(results.len() == 7);

    // Be sure each output is unique
    for result in results.iter() {
        let mut count = 0u;
        for result2 in results.iter() {
            if result == result2 { count = count + 1; }
        }
        assert!(count == 1);
    }
}

<|endoftext|>


<commit_before>//! Parsers for wavefront's `.obj` and `.mtl` file format for loading meshes.
#![crate_type = "lib"]
#![deny(warnings)]
#![deny(missing_docs)]
#![feature(collections, core, hash)]

pub use lex::ParseError;

mod lex;
mod util;

pub mod mtl;
pub mod obj;
<commit_msg>deny unsafe blocks<commit_after>//! Parsers for wavefront's `.obj` and `.mtl` file format for loading meshes.
#![crate_type = "lib"]
#![deny(unsafe_blocks)]
#![deny(warnings)]
#![deny(missing_docs)]
#![feature(collections, core, hash)]

pub use lex::ParseError;

mod lex;
mod util;

pub mod mtl;
pub mod obj;
<|endoftext|>


<commit_before>// Copyright 2014-2015 The GeoRust Developers
//
// 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.

#![allow(unstable)]

use std::ascii::AsciiExt;

use tokenizer::{PeekableTokens, Token, Tokens};
use types::FromTokens;
use types::linestring::LineString;
use types::point::Point;
use types::polygon::Polygon;

mod tokenizer;
mod types;

pub enum WktItem {
    Point(Point),
    LineString(LineString),
    Polygon(Polygon),
}

impl WktItem {
    fn from_word_and_tokens(word: &str, tokens: &mut PeekableTokens)-> Result<Self, &'static str> {
        match word {
            "POINT" => {
                let x: Result<Point, _> = FromTokens::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "LINESTRING" => {
                let x: Result<LineString, _> = FromTokens::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "POLYGON" => {
                let x: Result<Polygon, _> = FromTokens::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            _ => Err("Invalid type encountered"),
        }
    }
}

pub struct Wkt {
    items: Vec<WktItem>
}

impl Wkt {
    fn new() -> Self {
        Wkt {items: vec![]}
    }

    fn add_item(&mut self, item: WktItem) {
        self.items.push(item);
    }

    fn from_str(wkt_str: &str) -> Result<Self, &'static str> {
        let tokens = Tokens::from_str(wkt_str);
        Wkt::from_tokens(tokens)
    }

    fn from_tokens(tokens: Tokens) -> Result<Self, &'static str> {
        let mut wkt = Wkt::new();
        let mut tokens = tokens.peekable();
        let word = match tokens.next() {
            Some(Token::Word(word)) => {
                if !word.is_ascii() {
                    return Err("Encountered non-ascii word");
                }
                word.to_ascii_uppercase()
            },
            None => return Ok(wkt),
            _ => return Err("Invalid WKT format"),
        };
        match WktItem::from_word_and_tokens(word.as_slice(), &mut tokens) {
            Ok(item) => wkt.add_item(item),
            Err(s) => return Err(s),
        }
        Ok(wkt)
    }
}

#[cfg(test)]
mod tests {
    use super::{Wkt, WktItem};

    #[test]
    fn empty_string() {
        let wkt = Wkt::from_str("").ok().unwrap();
        assert_eq!(0, wkt.items.len());
    }

    #[test]
    fn basic_point() {
        let mut wkt = Wkt::from_str("POINT (10 -20)").ok().unwrap();
        assert_eq!(1, wkt.items.len());
        let point = match wkt.items.pop().unwrap() {
            WktItem::Point(point) => point,
            _ => unreachable!(),
        };
        assert_eq!(10.0, point.coord.x);
        assert_eq!(-20.0, point.coord.y);
        assert_eq!(None, point.coord.z);
        assert_eq!(None, point.coord.m);
    }

    #[test]
    fn basic_linestring() {
        let mut wkt = Wkt::from_str("LINESTRING (10 -20, -0 -0.5)").ok().unwrap();
        assert_eq!(1, wkt.items.len());
        let linestring = match wkt.items.pop().unwrap() {
            WktItem::LineString(linestring) => linestring,
            _ => unreachable!(),
        };
        assert_eq!(2, linestring.coords.len());

        assert_eq!(10.0, linestring.coords[0].x);
        assert_eq!(-20.0, linestring.coords[0].y);
        assert_eq!(None, linestring.coords[0].z);
        assert_eq!(None, linestring.coords[0].m);

        assert_eq!(0.0, linestring.coords[1].x);
        assert_eq!(-0.5, linestring.coords[1].y);
        assert_eq!(None, linestring.coords[1].z);
        assert_eq!(None, linestring.coords[1].m);
    }

    #[test]
    fn basic_polygon() {
        let mut wkt = Wkt::from_str("POLYGON ((8 4, 4 0, 0 4, 8 4), (7 3, 4 1, 1 4, 7 3))").ok().unwrap();
        assert_eq!(1, wkt.items.len());
        let linestring = match wkt.items.pop().unwrap() {
            WktItem::Polygon(linestring) => linestring,
            _ => unreachable!(),
        };
        assert_eq!(2, linestring.lines.len());
    }

    #[test]
    fn invalid_points() {
        Wkt::from_str("POINT ()").err().unwrap();
        Wkt::from_str("POINT (10)").err().unwrap();
        Wkt::from_str("POINT 10").err().unwrap();
        Wkt::from_str("POINT (10 -20 40)").err().unwrap();
    }
}
<commit_msg>Add test excessive whitespace<commit_after>// Copyright 2014-2015 The GeoRust Developers
//
// 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.

#![allow(unstable)]

use std::ascii::AsciiExt;

use tokenizer::{PeekableTokens, Token, Tokens};
use types::FromTokens;
use types::linestring::LineString;
use types::point::Point;
use types::polygon::Polygon;

mod tokenizer;
mod types;

pub enum WktItem {
    Point(Point),
    LineString(LineString),
    Polygon(Polygon),
}

impl WktItem {
    fn from_word_and_tokens(word: &str, tokens: &mut PeekableTokens)-> Result<Self, &'static str> {
        match word {
            "POINT" => {
                let x: Result<Point, _> = FromTokens::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "LINESTRING" => {
                let x: Result<LineString, _> = FromTokens::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "POLYGON" => {
                let x: Result<Polygon, _> = FromTokens::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            _ => Err("Invalid type encountered"),
        }
    }
}

pub struct Wkt {
    items: Vec<WktItem>
}

impl Wkt {
    fn new() -> Self {
        Wkt {items: vec![]}
    }

    fn add_item(&mut self, item: WktItem) {
        self.items.push(item);
    }

    fn from_str(wkt_str: &str) -> Result<Self, &'static str> {
        let tokens = Tokens::from_str(wkt_str);
        Wkt::from_tokens(tokens)
    }

    fn from_tokens(tokens: Tokens) -> Result<Self, &'static str> {
        let mut wkt = Wkt::new();
        let mut tokens = tokens.peekable();
        let word = match tokens.next() {
            Some(Token::Word(word)) => {
                if !word.is_ascii() {
                    return Err("Encountered non-ascii word");
                }
                word.to_ascii_uppercase()
            },
            None => return Ok(wkt),
            _ => return Err("Invalid WKT format"),
        };
        match WktItem::from_word_and_tokens(word.as_slice(), &mut tokens) {
            Ok(item) => wkt.add_item(item),
            Err(s) => return Err(s),
        }
        Ok(wkt)
    }
}

#[cfg(test)]
mod tests {
    use super::{Wkt, WktItem};

    #[test]
    fn empty_string() {
        let wkt = Wkt::from_str("").ok().unwrap();
        assert_eq!(0, wkt.items.len());
    }

    #[test]
    fn basic_point() {
        let mut wkt = Wkt::from_str("POINT (10 -20)").ok().unwrap();
        assert_eq!(1, wkt.items.len());
        let point = match wkt.items.pop().unwrap() {
            WktItem::Point(point) => point,
            _ => unreachable!(),
        };
        assert_eq!(10.0, point.coord.x);
        assert_eq!(-20.0, point.coord.y);
        assert_eq!(None, point.coord.z);
        assert_eq!(None, point.coord.m);
    }

    #[test]
    fn basic_point_whitespace() {
        let mut wkt = Wkt::from_str(" \n\t\rPOINT \n\t\r( \n\r\t10 \n\t\r-20 \n\t\r) \n\t\r").ok().unwrap();
        assert_eq!(1, wkt.items.len());
        let point = match wkt.items.pop().unwrap() {
            WktItem::Point(point) => point,
            _ => unreachable!(),
        };
        assert_eq!(10.0, point.coord.x);
        assert_eq!(-20.0, point.coord.y);
        assert_eq!(None, point.coord.z);
        assert_eq!(None, point.coord.m);
    }

    #[test]
    fn basic_linestring() {
        let mut wkt = Wkt::from_str("LINESTRING (10 -20, -0 -0.5)").ok().unwrap();
        assert_eq!(1, wkt.items.len());
        let linestring = match wkt.items.pop().unwrap() {
            WktItem::LineString(linestring) => linestring,
            _ => unreachable!(),
        };
        assert_eq!(2, linestring.coords.len());

        assert_eq!(10.0, linestring.coords[0].x);
        assert_eq!(-20.0, linestring.coords[0].y);
        assert_eq!(None, linestring.coords[0].z);
        assert_eq!(None, linestring.coords[0].m);

        assert_eq!(0.0, linestring.coords[1].x);
        assert_eq!(-0.5, linestring.coords[1].y);
        assert_eq!(None, linestring.coords[1].z);
        assert_eq!(None, linestring.coords[1].m);
    }

    #[test]
    fn basic_polygon() {
        let mut wkt = Wkt::from_str("POLYGON ((8 4, 4 0, 0 4, 8 4), (7 3, 4 1, 1 4, 7 3))").ok().unwrap();
        assert_eq!(1, wkt.items.len());
        let linestring = match wkt.items.pop().unwrap() {
            WktItem::Polygon(linestring) => linestring,
            _ => unreachable!(),
        };
        assert_eq!(2, linestring.lines.len());
    }

    #[test]
    fn invalid_points() {
        Wkt::from_str("POINT ()").err().unwrap();
        Wkt::from_str("POINT (10)").err().unwrap();
        Wkt::from_str("POINT 10").err().unwrap();
        Wkt::from_str("POINT (10 -20 40)").err().unwrap();
    }
}
<|endoftext|>


<commit_before>use std::io::Write;
use std::thread;

use time;

use Request;

/// RAII guard that ensures that a log entry corresponding to a request will be written.
///
/// # Example
///
/// ```no_run
/// rouille::start_server("localhost:80", move |request| {
///     let _entry = rouille::LogEntry::start(std::io::stdout(), request);
///
///     // process the request here
///
/// # panic!()
/// }); // <-- the log entry is written at the end of this block
/// ```
///
pub struct LogEntry<W> where W: Write {
    line: String,
    output: W,
    start_time: u64,
}

impl<'a, W> LogEntry<W> where W: Write {
    /// Starts a `LogEntry`.
    pub fn start(output: W, rq: &Request) -> LogEntry<W> {
        LogEntry {
            line: format!("GET {}", rq.url()),       // TODO:
            output: output,
            start_time: time::precise_time_ns(),
        }
    }
}

impl<W> Drop for LogEntry<W> where W: Write {
    fn drop(&mut self) {
        write!(self.output, "{} - ", self.line).unwrap();

        if thread::panicking() {
            write!(self.output, " - PANIC!").unwrap();

        } else {
            let elapsed = time::precise_time_ns() - self.start_time;
            format_time(self.output.by_ref(), elapsed);
        }

        writeln!(self.output, "").unwrap();
    }
}

fn format_time<W>(mut out: W, time: u64) where W: Write {
    if time < 1_000 {
        write!(out, "{}ns", time).unwrap()
    } else if time < 1_000_000 {
        write!(out, "{:.1}us", time as f64 / 1_000.0).unwrap()
    } else if time < 1_000_000_000 {
        write!(out, "{:.1}ms", time as f64 / 1_000_000.0).unwrap()
    } else {
        write!(out, "{:.1}s", time as f64 / 1_000_000_000.0).unwrap()
    }
}
<commit_msg>Fix method name in LogEntry<commit_after>use std::io::Write;
use std::thread;

use time;

use Request;

/// RAII guard that ensures that a log entry corresponding to a request will be written.
///
/// # Example
///
/// ```no_run
/// rouille::start_server("localhost:80", move |request| {
///     let _entry = rouille::LogEntry::start(std::io::stdout(), request);
///
///     // process the request here
///
/// # panic!()
/// }); // <-- the log entry is written at the end of this block
/// ```
///
pub struct LogEntry<W> where W: Write {
    line: String,
    output: W,
    start_time: u64,
}

impl<'a, W> LogEntry<W> where W: Write {
    /// Starts a `LogEntry`.
    pub fn start(output: W, rq: &Request) -> LogEntry<W> {
        LogEntry {
            line: format!("{} {}", rq.method(), rq.url()),
            output: output,
            start_time: time::precise_time_ns(),
        }
    }
}

impl<W> Drop for LogEntry<W> where W: Write {
    fn drop(&mut self) {
        write!(self.output, "{} - ", self.line).unwrap();

        if thread::panicking() {
            write!(self.output, " - PANIC!").unwrap();

        } else {
            let elapsed = time::precise_time_ns() - self.start_time;
            format_time(self.output.by_ref(), elapsed);
        }

        writeln!(self.output, "").unwrap();
    }
}

fn format_time<W>(mut out: W, time: u64) where W: Write {
    if time < 1_000 {
        write!(out, "{}ns", time).unwrap()
    } else if time < 1_000_000 {
        write!(out, "{:.1}us", time as f64 / 1_000.0).unwrap()
    } else if time < 1_000_000_000 {
        write!(out, "{:.1}ms", time as f64 / 1_000_000.0).unwrap()
    } else {
        write!(out, "{:.1}s", time as f64 / 1_000_000_000.0).unwrap()
    }
}
<|endoftext|>


<commit_before> #![feature(test)]

#[macro_use] extern crate nom;
#[macro_use] extern crate lazy_static;

extern crate regex;
extern crate colored;

pub mod test;
pub mod types;
pub mod error;
pub mod cli_helpers;
pub mod gitignore;

pub mod prelude {

    use std::fs;
    use std::path::PathBuf;
    use regex::{Regex, RegexSet};
    use types::*;
    use colored::*;
    use gitignore::*;
    use std::io::prelude::*;
    use std::process::exit;
    use std::fs::{Metadata, File};

    #[cfg(not(target_os = "windows"))]
    use std::os::unix::fs::PermissionsExt;

    pub use cli_helpers::*;
    pub use error::*;

    /// Helper function to determine whether a path points
    ///
    /// Rules:
    /// - if the file extension of that is that of an artifact, return true
    /// - if the file is executable and included in the .gitignore, return true
    /// - if the file looks like a configuration file and is in the .gitignore, return true
    /// (\.cache.*, \.conf
    /// - return false otherwise
    ///
    /// # Examples
    ///
    /// ```
    /// use libsniff::prelude::*;
    /// use std::path::PathBuf;
    ///
    /// let path_buf: PathBuf = PathBuf::from("lib.so");
    /// assert_eq!(is_artifact(&path_buf, None), true);
    /// ```
    #[cfg(not(target_os = "windows"))]
    pub fn is_artifact(p: &PathBuf, re: Option<&Regex>, metadata: Metadata, gitignore: &Option<RegexSet>) -> bool {

        // get path as a string so we can match against it
        let path_str = p.clone().into_os_string().into_string().expect("OS string invalid.");

        // match on the user's expression if it exists
        if let Some(r) = re {
            r.is_match(&path_str)
        }

        // otherwise, use builtin expressions
        else {
            lazy_static! {
                static ref REGEX: Regex =
                    Regex::new(r".*?\.(a|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|js_o|so.*|dump-.*|vba|crx)$")
                    .unwrap();
            }
            lazy_static! {
                static ref REGEX_GITIGNORE: Regex =
                    Regex::new(r".*?\.(a|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|js_o|so.*|dump-.*|vba|crx|cache|conf|h|cache.*)$")
                    .unwrap();
            }
            if REGEX.is_match(&path_str) { true }

            else if let &Some(ref x) = gitignore {
                if metadata.permissions().mode() == 0o755 || REGEX_GITIGNORE.is_match(&path_str)
                    { x.is_match(&path_str) }
                else { false }
            }
            else { false }
        }
    }

    #[cfg(target_os = "windows")]
    pub fn is_artifact(p: &PathBuf, re: Option<&Regex>, _: Metadata, gitignore:&Option<RegexSet>) -> bool {
        let path_str = &p.into_os_string().into_string().expect("OS String invalid.");
        if let Some(r) = re {
            r.is_match(path_str)
        }
        else {
            lazy_static! {
                static ref REGEX: Regex =
                    Regex::new(r".*?\.(exe|a|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|js_o|so.*|dump-.*|vba|crx)$")
                    .unwrap();
            }
            lazy_static! {
                static ref REGEX_GITIGNORE: Regex =
                    Regex::new(r".*?\.(exe|a|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|js_o|so.*|dump-.*|vba|crx|cache|conf|h|cache.*)$")
                    .unwrap();
            }
            if REGEX.is_match(&path_str) { true }

            else if let &Some(ref x) = gitignore {
                if REGEX_GITIGNORE.is_match(&path_str) {
                    if x.is_match(&path_str) { true } else { false }
                } else { false }
            }
            else { false }
        }
    }

    // how depth/recursion SHOULD work for artifacts: if e.g. .stack-work/ has *multiple* subdirs
    // with artifacts, then list it in place of all of them. Basically find "root nodes" of these
    // places - hard but potentially very nice? look in .gitignore?
    /// Function to process directory contents and return a `FileTree` struct.
    ///
    /// # Examples
    ///
    /// ```
    /// use libsniff::prelude::*;
    /// use std::path::PathBuf;
    ///
    /// let path = PathBuf::from("src");
    /// let file_tree = read_all(&path, 2, None, None, None, false, true);
    /// ```
    pub fn read_all(in_paths: &PathBuf,
                          depth: u8,
                          min_bytes: Option<u64>,
                          artifact_regex: Option<&Regex>,
                          excludes: Option<&Regex>,
                          silent: bool,
                          maybe_gitignore: &Option<RegexSet>,
                          artifacts_only: bool) -> FileTree {

        // attempt to read the .gitignore
        let mut tree = FileTree::new();
        let min_size = min_bytes.map(FileSize::new);
        let gitignore = if let &Some(ref gitignore) = maybe_gitignore { Some(gitignore.to_owned()) }
            else {
                let mut gitignore_path = in_paths.clone();
                gitignore_path.push(".gitignore");
                if let Ok(mut file) = File::open(gitignore_path) {
                    let mut contents = String::new();
                    file.read_to_string(&mut contents)
                        .expect("File read failed. Is your system configured to use unix?");
                    Some(file_contents_to_regex(&contents))
                } else { None }
            };

        // try to read directory contents
        if let Ok(paths) = fs::read_dir(in_paths) {

            // iterate over all the entries in the directory
            for p in paths {
                let path = p.unwrap().path(); // TODO no unwraps; idk what this error would be though.
                let path_string = path.clone().into_os_string().into_string().expect("OS String invalid."); // TODO nicer error message, mention windows/utf-8?
                let bool_loop = match excludes {
                    Some(ex) => !ex.is_match(&path_string),
                    _ => true,
                };

                // only consider path if we're not using regex excludes or if they don't match the
                // exclusion regex
                if bool_loop {

                    // if this fails, it's probably because `path` is a broken symlink
                    if let Ok(metadata) = fs::metadata(&path) {

                        // append file size/name for a file
                        if metadata.is_file() {
                            if !artifacts_only || is_artifact(&path, artifact_regex, metadata.clone(), &gitignore) {
                                let file_size = FileSize::new(metadata.len());
                                if let Some(b) = min_bytes {
                                    if file_size >= FileSize::new(b) {
                                            tree.push(path_string, file_size, None, depth + 1, min_size);
                                        }
                                    }
                                else {
                                    tree.push(path_string, file_size, None, depth + 1, min_size);
                                }
                            }
                        }

                        // otherwise, go deeper

                        else if metadata.is_dir() {
                            let mut subtree = read_all(&path, depth + 1, min_bytes, artifact_regex, excludes, silent, &gitignore, artifacts_only);
                            let dir_size = subtree.file_size;
                            if let Some(b) = min_bytes {
                                if dir_size >= FileSize::new(b) {
                                    tree.push(path_string, dir_size, Some(&mut subtree), depth + 1, min_size);
                                }
                            }
                            else { tree.push(path_string, dir_size, Some(&mut subtree), depth + 1, min_size); }
                        }
                    }
                    else if !silent { eprintln!("{}: ignoring symlink at {}", "Warning".yellow(), path.display()); }
                }
            }
        }

        // if we can't read the directory contents, figure out why
        // 1: check the path exists
        else if !in_paths.exists() {
            eprintln!("{}: path '{}' does not exist.", "Error".red(), &in_paths.display()); // FIXME check it is a directory too
            exit(0x0001);
        }
        // 2: check the path is actually a directory
        else if !in_paths.is_dir() {
            eprintln!("{}: {} is not a directory.", "Error".red(), &in_paths.display());
            exit(0x0001);
        }
        // 3: otherwise, give a warning about permissions
        else if !silent {
            eprintln!("{}: permission denied for directory: {}", "Warning".yellow(), &in_paths.display());
        }

        tree
    }
}
<commit_msg>for commit<commit_after> #![feature(test)]

#[macro_use] extern crate nom;
#[macro_use] extern crate lazy_static;

extern crate regex;
extern crate colored;

pub mod test;
pub mod types;
pub mod error;
pub mod cli_helpers;
pub mod gitignore;

pub mod prelude {

    use std::fs;
    use std::path::PathBuf;
    use regex::{Regex, RegexSet};
    use types::*;
    use colored::*;
    use gitignore::*;
    use std::io::prelude::*;
    use std::process::exit;
    use std::fs::{Metadata, File};

    #[cfg(not(target_os = "windows"))]
    use std::os::unix::fs::PermissionsExt;

    pub use cli_helpers::*;
    pub use error::*;

    /// Helper function to determine whether a path points
    ///
    /// Rules:
    /// - if the file extension of that is that of an artifact, return true
    /// - if the file is executable and included in the .gitignore, return true
    /// - if the file looks like a configuration file and is in the .gitignore, return true
    /// (\.cache.*, \.conf
    /// - return false otherwise
    ///
    /// # Examples
    ///
    /// ```
    /// use libsniff::prelude::*;
    /// use std::path::PathBuf;
    ///
    /// let path_buf: PathBuf = PathBuf::from("lib.so");
    /// assert_eq!(is_artifact(&path_buf, None), true);
    /// ```
    #[cfg(not(target_os = "windows"))]
    pub fn is_artifact(p: &PathBuf, re: Option<&Regex>, metadata: Metadata, gitignore: &Option<RegexSet>) -> bool {

        // get path as a string so we can match against it
        let path_str = p.clone().into_os_string().into_string().expect("OS string invalid.");

        // match on the user's expression if it exists
        if let Some(r) = re {
            r.is_match(&path_str)
        }

        // otherwise, use builtin expressions
        else {
            lazy_static! {
                static ref REGEX: Regex =
                    Regex::new(r".*?\.(a|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|js_o|so.*|dump-.*|vba|crx)$")
                    .unwrap();
            }
            lazy_static! {
                static ref REGEX_GITIGNORE: Regex =
                    Regex::new(r".*?\.(a|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|js_o|so.*|dump-.*|vba|crx|cache|conf|h|cache.*)$")
                    .unwrap();
            }
            if REGEX.is_match(&path_str) { true }

            else if let &Some(ref x) = gitignore {
                if metadata.permissions().mode() == 0o755 || REGEX_GITIGNORE.is_match(&path_str)
                    { x.is_match(&path_str) }
                else { false }
            }
            else { false }
        }
    }

    #[cfg(target_os = "windows")]
    pub fn is_artifact(p: &PathBuf, re: Option<&Regex>, _: Metadata, gitignore:&Option<RegexSet>) -> bool {
        let path_str = p.clone().into_os_string().into_string().expect("OS String invalid.");
        if let Some(r) = re {
            r.is_match(&path_str)
        }
        else {
            lazy_static! {
                static ref REGEX: Regex =
                    Regex::new(r".*?\.(exe|a|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|js_o|so.*|dump-.*|vba|crx)$")
                    .unwrap();
            }
            lazy_static! {
                static ref REGEX_GITIGNORE: Regex =
                    Regex::new(r".*?\.(exe|a|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|js_o|so.*|dump-.*|vba|crx|conf|h|cache.*)$")
                    .unwrap();
            }
            if REGEX.is_match(&path_str) { true }

            else if let &Some(ref x) = gitignore {
                if REGEX_GITIGNORE.is_match(&path_str) {
                    if x.is_match(&path_str) { true } else { false }
                } else { false }
            }
            else { false }
        }
    }

    // how depth/recursion SHOULD work for artifacts: if e.g. .stack-work/ has *multiple* subdirs
    // with artifacts, then list it in place of all of them. Basically find "root nodes" of these
    // places - hard but potentially very nice? look in .gitignore?
    /// Function to process directory contents and return a `FileTree` struct.
    ///
    /// # Examples
    ///
    /// ```
    /// use libsniff::prelude::*;
    /// use std::path::PathBuf;
    ///
    /// let path = PathBuf::from("src");
    /// let file_tree = read_all(&path, 2, None, None, None, false, true);
    /// ```
    pub fn read_all(in_paths: &PathBuf,
                          depth: u8,
                          min_bytes: Option<u64>,
                          artifact_regex: Option<&Regex>,
                          excludes: Option<&Regex>,
                          silent: bool,
                          maybe_gitignore: &Option<RegexSet>,
                          artifacts_only: bool) -> FileTree {

        // attempt to read the .gitignore
        let mut tree = FileTree::new();
        let min_size = min_bytes.map(FileSize::new);
        let gitignore = if let &Some(ref gitignore) = maybe_gitignore { Some(gitignore.to_owned()) }
            else {
                let mut gitignore_path = in_paths.clone();
                gitignore_path.push(".gitignore");
                if let Ok(mut file) = File::open(gitignore_path) {
                    let mut contents = String::new();
                    file.read_to_string(&mut contents)
                        .expect("File read failed. Is your system configured to use unix?");
                    Some(file_contents_to_regex(&contents))
                } else { None }
            };

        // try to read directory contents
        if let Ok(paths) = fs::read_dir(in_paths) {

            // iterate over all the entries in the directory
            for p in paths {
                let path = p.unwrap().path(); // TODO no unwraps; idk what this error would be though.
                let path_string = path.clone().into_os_string().into_string().expect("OS String invalid."); // TODO nicer error message, mention windows/utf-8?
                let bool_loop = match excludes {
                    Some(ex) => !ex.is_match(&path_string),
                    _ => true,
                };

                // only consider path if we're not using regex excludes or if they don't match the
                // exclusion regex
                if bool_loop {

                    // if this fails, it's probably because `path` is a broken symlink
                    if let Ok(metadata) = fs::metadata(&path) {

                        // append file size/name for a file
                        if metadata.is_file() {
                            if !artifacts_only || is_artifact(&path, artifact_regex, metadata.clone(), &gitignore) {
                                let file_size = FileSize::new(metadata.len());
                                if let Some(b) = min_bytes {
                                    if file_size >= FileSize::new(b) {
                                            tree.push(path_string, file_size, None, depth + 1, min_size);
                                        }
                                    }
                                else {
                                    tree.push(path_string, file_size, None, depth + 1, min_size);
                                }
                            }
                        }

                        // otherwise, go deeper

                        else if metadata.is_dir() {
                            let mut subtree = read_all(&path, depth + 1, min_bytes, artifact_regex, excludes, silent, &gitignore, artifacts_only);
                            let dir_size = subtree.file_size;
                            if let Some(b) = min_bytes {
                                if dir_size >= FileSize::new(b) {
                                    tree.push(path_string, dir_size, Some(&mut subtree), depth + 1, min_size);
                                }
                            }
                            else { tree.push(path_string, dir_size, Some(&mut subtree), depth + 1, min_size); }
                        }
                    }
                    else if !silent { eprintln!("{}: ignoring symlink at {}", "Warning".yellow(), path.display()); }
                }
            }
        }

        // if we can't read the directory contents, figure out why
        // 1: check the path exists
        else if !in_paths.exists() {
            eprintln!("{}: path '{}' does not exist.", "Error".red(), &in_paths.display()); // FIXME check it is a directory too
            exit(0x0001);
        }
        // 2: check the path is actually a directory
        else if !in_paths.is_dir() {
            eprintln!("{}: {} is not a directory.", "Error".red(), &in_paths.display());
            exit(0x0001);
        }
        // 3: otherwise, give a warning about permissions
        else if !silent {
            eprintln!("{}: permission denied for directory: {}", "Warning".yellow(), &in_paths.display());
        }

        tree
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::convert::From;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::path::Path;

const PATHS: [&'static str; 2] = ["/etc/os-release", "/usr/lib/os-release"];
const QUOTES: [&'static str; 2] = ["\"", "'"];

#[derive(Debug, PartialEq)]
pub enum OsReleaseError {
    Io,
    NoFile,
    ParseError,
}

impl From<std::io::Error> for OsReleaseError {
    fn from(_: std::io::Error) -> OsReleaseError {
        OsReleaseError::Io
    }
}

pub type Result<T> = std::result::Result<T, OsReleaseError>;

fn trim_quotes(s: &str) -> &str {
    // TODO: is it malformed if we have only one quote?
    let is_quoted = |s: &str, q: &str| s.starts_with(q) && s.ends_with(q);
    if QUOTES.iter().find(|q| is_quoted(s, q)).is_some() {
        &s[1..s.len() - 1]
    } else {
        s
    }
}

fn extract_variable_and_value(s: &str) -> Result<(String, String)> {
    if let Some(equal) = s.chars().position(|c| c == '=') {
        let var = &s[..equal];
        let val = &s[equal + 1..];
        let val = trim_quotes(val.trim()).to_string();
        Ok((var.trim().to_string(), val))
    } else {
        Err(OsReleaseError::ParseError)
    }
}

pub fn parse_os_release<P: AsRef<Path>>(path: P) -> Result<HashMap<String, String>> {
    let mut os_release = HashMap::new();
    let file = try!(File::open(path));
    let reader = BufReader::new(file);
    for line in reader.lines() {
        let line = try!(line);
        let line = line.trim();

        if line.starts_with('#') {
            continue;
        }
        let var_val = try!(extract_variable_and_value(line));
        os_release.insert(var_val.0, var_val.1);
    }
    Ok(os_release)
}

pub fn get_os_release() -> Result<HashMap<String, String>> {
    for file in &PATHS {
        if let Ok(os_release) = parse_os_release(file) {
            return Ok(os_release);
        }
    }
    Err(OsReleaseError::NoFile)
}
<commit_msg>lib: Simplify even more with Iterator::any. Thanks, clippy!<commit_after>use std::collections::HashMap;
use std::convert::From;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::path::Path;

const PATHS: [&'static str; 2] = ["/etc/os-release", "/usr/lib/os-release"];
const QUOTES: [&'static str; 2] = ["\"", "'"];

#[derive(Debug, PartialEq)]
pub enum OsReleaseError {
    Io,
    NoFile,
    ParseError,
}

impl From<std::io::Error> for OsReleaseError {
    fn from(_: std::io::Error) -> OsReleaseError {
        OsReleaseError::Io
    }
}

pub type Result<T> = std::result::Result<T, OsReleaseError>;

fn trim_quotes(s: &str) -> &str {
    // TODO: is it malformed if we have only one quote?
    if QUOTES.iter().any(|q| s.starts_with(q) && s.ends_with(q)) {
        &s[1..s.len() - 1]
    } else {
        s
    }
}

fn extract_variable_and_value(s: &str) -> Result<(String, String)> {
    if let Some(equal) = s.chars().position(|c| c == '=') {
        let var = &s[..equal];
        let val = &s[equal + 1..];
        let val = trim_quotes(val.trim()).to_string();
        Ok((var.trim().to_string(), val))
    } else {
        Err(OsReleaseError::ParseError)
    }
}

pub fn parse_os_release<P: AsRef<Path>>(path: P) -> Result<HashMap<String, String>> {
    let mut os_release = HashMap::new();
    let file = try!(File::open(path));
    let reader = BufReader::new(file);
    for line in reader.lines() {
        let line = try!(line);
        let line = line.trim();

        if line.starts_with('#') {
            continue;
        }
        let var_val = try!(extract_variable_and_value(line));
        os_release.insert(var_val.0, var_val.1);
    }
    Ok(os_release)
}

pub fn get_os_release() -> Result<HashMap<String, String>> {
    for file in &PATHS {
        if let Ok(os_release) = parse_os_release(file) {
            return Ok(os_release);
        }
    }
    Err(OsReleaseError::NoFile)
}
<|endoftext|>


<commit_before>//! Crate for accessing MS Windows registry
#![feature(std_misc)]
#![cfg_attr(test, feature(collections))]
extern crate winapi;
extern crate advapi32;
use std::path::Path;
use std::ptr;
use std::ffi::AsOsStr;
use std::os::windows::ffi::OsStrExt;
use types::{FromReg, ToReg};

pub mod types;

#[derive(Debug)]
pub struct RegError {
    err: winapi::LONG,
}

pub type RegResult<T> = std::result::Result<T, RegError>;

#[derive(Debug)]
pub struct RegKey {
    hkey: winapi::HKEY,
}

impl RegKey {
    pub fn predef(hkey: winapi::HKEY) -> RegKey {
        RegKey{ hkey: hkey }
    }

    pub fn open_subkey(&self, path: &Path, perms: winapi::REGSAM) -> RegResult<RegKey> {
        let c_path = to_utf16(path);
        let mut new_hkey: winapi::HKEY = ptr::null_mut();
        match unsafe{
            advapi32::RegOpenKeyExW(
                self.hkey,
                c_path.as_ptr(),
                0,
                perms,
                &mut new_hkey,
            )
        } {
            0 => Ok(RegKey{ hkey: new_hkey }),
            err => Err(RegError{ err: err })
        }
    }

    /// Will also create all missing parent keys. Will open key if it already exists.
    pub fn create_subkey(&self, path: &Path, perms: winapi::REGSAM) -> RegResult<RegKey> {
        let c_path = to_utf16(path);
        let mut new_hkey: winapi::HKEY = ptr::null_mut();
        let mut disp: winapi::DWORD = 0;
        match unsafe{
            advapi32::RegCreateKeyExW(
                self.hkey,
                c_path.as_ptr(),
                0,
                ptr::null(),
                winapi::REG_OPTION_NON_VOLATILE,
                perms,
                ptr::null_mut(),
                &mut new_hkey,
                &mut disp // TODO: return this somehow
            )
        } {
            0 => Ok(RegKey{ hkey: new_hkey }),
            err => Err(RegError{ err: err })
        }
    }

    pub fn get_value<T: FromReg>(&self, name: &Path) -> RegResult<T> {
        let c_name = to_utf16(name);
        let mut buf_len: winapi::DWORD = winapi::MAX_PATH as winapi::DWORD;
        let mut buf: Vec<u16> = Vec::with_capacity(buf_len as usize);
        match unsafe{
            advapi32::RegQueryValueExW(
                self.hkey,
                c_name.as_ptr() as *const u16,
                ptr::null_mut(),
                ptr::null_mut(),
                buf.as_mut_ptr() as winapi::LPBYTE,
                &mut buf_len
            )
        } {
            0 => {
                // set length to wchars count - 1 (trailing \0)
                unsafe{ buf.set_len(((buf_len >> 1) - 1) as usize); }
                Ok(FromReg::convert_from_bytes(buf))
            },
            err => Err(RegError{ err: err })
        }
    }

    pub fn set_value<T: ToReg>(&self, name: &Path, value: &T) -> RegResult<()> {
        let c_name = to_utf16(name);
        let c_value = value.convert_to_bytes();
        let v_type = value.get_val_type();
        match unsafe{
            advapi32::RegSetValueExW(
                self.hkey,
                c_name.as_ptr(),
                0,
                v_type,
                c_value.as_ptr() as *const winapi::BYTE,
                (c_value.len()*2) as u32
            )
        } {
            0 => {
                Ok(())
            },
            err => Err(RegError{ err: err })
        }
    }

    fn close_(&mut self) -> RegResult<()> {
        match unsafe{
            advapi32::RegCloseKey(self.hkey)
        } {
            0 => Ok(()),
            err => Err(RegError{ err: err })
        }
    }
}

impl Drop for RegKey {
    fn drop(&mut self) {
        self.close_().unwrap();
    }
}

fn to_utf16<T: AsOsStr>(s: T) -> Vec<u16> {
    s.as_os_str().encode_wide().chain(Some(0).into_iter()).collect()
}

#[cfg(test)]
mod test {
    use super::*;
    use super::types::*;
    use std::path::Path;

    #[test]
    fn test_key_open() {
        let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
        let win = hklm.open_subkey(Path::new("Software\\Microsoft\\Windows"), KEY_READ);
        assert!(win.is_ok());
        assert!(win.unwrap().open_subkey(Path::new("CurrentVersion\\"), KEY_READ).is_ok());
        assert!(hklm.open_subkey(Path::new("i\\just\\hope\\nobody\\created\\that\\key"), KEY_READ).is_err());
    }

    #[test]
    fn test_string_value() {
        let hkcu = RegKey::predef(HKEY_CURRENT_USER);
        let sw = hkcu.create_subkey(Path::new("Software\\WinregRsTestKey"), KEY_ALL_ACCESS).unwrap();
        let name = Path::new("WinregRsTestVal");
        let val1 = String::from_str("Test123 $%^&|+-*/\\()");
        assert!(sw.set_value(name, &val1).is_ok());
        let val2: String = sw.get_value(name).unwrap();
        assert_eq!(val1, val2);
    }
}
<commit_msg>Add key deletion<commit_after>//! Crate for accessing MS Windows registry
#![feature(std_misc)]
#![cfg_attr(test, feature(collections))]
extern crate winapi;
extern crate advapi32;
use std::path::Path;
use std::ptr;
use std::ffi::AsOsStr;
use std::os::windows::ffi::OsStrExt;
use types::{FromReg, ToReg};

pub mod types;

#[derive(Debug)]
pub struct RegError {
    err: winapi::LONG,
}

pub type RegResult<T> = std::result::Result<T, RegError>;

#[derive(Debug)]
pub struct RegKey {
    hkey: winapi::HKEY,
}

impl RegKey {
    pub fn predef(hkey: winapi::HKEY) -> RegKey {
        RegKey{ hkey: hkey }
    }

    pub fn open_subkey(&self, path: &Path, perms: winapi::REGSAM) -> RegResult<RegKey> {
        let c_path = to_utf16(path);
        let mut new_hkey: winapi::HKEY = ptr::null_mut();
        match unsafe{
            advapi32::RegOpenKeyExW(
                self.hkey,
                c_path.as_ptr(),
                0,
                perms,
                &mut new_hkey,
            )
        } {
            0 => Ok(RegKey{ hkey: new_hkey }),
            err => Err(RegError{ err: err })
        }
    }

    /// Will also create all missing parent keys. Will open key if it already exists.
    pub fn create_subkey(&self, path: &Path, perms: winapi::REGSAM) -> RegResult<RegKey> {
        let c_path = to_utf16(path);
        let mut new_hkey: winapi::HKEY = ptr::null_mut();
        let mut disp: winapi::DWORD = 0;
        match unsafe{
            advapi32::RegCreateKeyExW(
                self.hkey,
                c_path.as_ptr(),
                0,
                ptr::null(),
                winapi::REG_OPTION_NON_VOLATILE,
                perms,
                ptr::null_mut(),
                &mut new_hkey,
                &mut disp // TODO: return this somehow
            )
        } {
            0 => Ok(RegKey{ hkey: new_hkey }),
            err => Err(RegError{ err: err })
        }
    }

    pub fn delete_subkey(&self, path: &Path) -> RegResult<()> {
        let c_path = to_utf16(path);
        match unsafe{
            advapi32::RegDeleteKeyW(
                self.hkey,
                c_path.as_ptr(),
            )
        } {
            0 => Ok(()),
            err => Err(RegError{ err: err })
        }
    }

    pub fn get_value<T: FromReg>(&self, name: &Path) -> RegResult<T> {
        let c_name = to_utf16(name);
        let mut buf_len: winapi::DWORD = winapi::MAX_PATH as winapi::DWORD;
        let mut buf: Vec<u16> = Vec::with_capacity(buf_len as usize);
        match unsafe{
            advapi32::RegQueryValueExW(
                self.hkey,
                c_name.as_ptr() as *const u16,
                ptr::null_mut(),
                ptr::null_mut(),
                buf.as_mut_ptr() as winapi::LPBYTE,
                &mut buf_len
            )
        } {
            0 => {
                // set length to wchars count - 1 (trailing \0)
                unsafe{ buf.set_len(((buf_len >> 1) - 1) as usize); }
                Ok(FromReg::convert_from_bytes(buf))
            },
            err => Err(RegError{ err: err })
        }
    }

    pub fn set_value<T: ToReg>(&self, name: &Path, value: &T) -> RegResult<()> {
        let c_name = to_utf16(name);
        let c_value = value.convert_to_bytes();
        let v_type = value.get_val_type();
        match unsafe{
            advapi32::RegSetValueExW(
                self.hkey,
                c_name.as_ptr(),
                0,
                v_type,
                c_value.as_ptr() as *const winapi::BYTE,
                (c_value.len()*2) as u32
            )
        } {
            0 => {
                Ok(())
            },
            err => Err(RegError{ err: err })
        }
    }

    fn close_(&mut self) -> RegResult<()> {
        match unsafe{
            advapi32::RegCloseKey(self.hkey)
        } {
            0 => Ok(()),
            err => Err(RegError{ err: err })
        }
    }
}

impl Drop for RegKey {
    fn drop(&mut self) {
        self.close_().unwrap();
    }
}

fn to_utf16<T: AsOsStr>(s: T) -> Vec<u16> {
    s.as_os_str().encode_wide().chain(Some(0).into_iter()).collect()
}

#[cfg(test)]
mod test {
    use super::*;
    use super::types::*;
    use std::path::Path;

    #[test]
    fn test_key_open() {
        let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
        let win = hklm.open_subkey(Path::new("Software\\Microsoft\\Windows"), KEY_READ);
        assert!(win.is_ok());
        assert!(win.unwrap().open_subkey(Path::new("CurrentVersion\\"), KEY_READ).is_ok());
        assert!(hklm.open_subkey(Path::new("i\\just\\hope\\nobody\\created\\that\\key"), KEY_READ).is_err());
    }

    #[test]
    fn test_string_value() {
        let hkcu = RegKey::predef(HKEY_CURRENT_USER);
        let path = Path::new("Software\\WinregRsTestKey");
        let name = Path::new("WinregRsTestVal");
        let val1 = String::from_str("Test123 $%^&|+-*/\\()");

        let sw = hkcu.create_subkey(path, KEY_ALL_ACCESS).unwrap();
        assert!(sw.set_value(name, &val1).is_ok());
        let val2: String = sw.get_value(name).unwrap();
        assert_eq!(val1, val2);
        assert!(hkcu.delete_subkey(path).is_ok());
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

pub fn test() {
    println!("Hello from lib.rs");
}

#[derive(Debug)]
enum Steps {
    Echo,
    Run,
    Shell,
    SetEnv,
}

fn parse_toml(filename: &str) -> Vec<Steps> {

    println!("Reading toml file: {}", filename);

    unimplemented!();
}

pub fn execute_steps(filename: &str) {
    println!("Reading file {:?}", filename);

    let steps = parse_toml(filename);

    println!("Steps: {:?}", steps);
}
<commit_msg>Read and parse toml file<commit_after>extern crate toml;

// Import traits
use std::io::prelude::Read;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

pub fn test() {
    println!("Hello from lib.rs");
}

#[derive(Debug)]
enum Steps {
    Echo,
    Run,
    Shell,
    SetEnv,
}

fn parse_toml(filename: &str) -> Vec<Steps> {

    println!("Reading toml file {}", filename);

    // Read toml file content
    let mut input = String::new();
    std::fs::File::open(&filename).and_then(|mut f| {
        f.read_to_string(&mut input)
    }).unwrap();

    // Pase toml file
    let mut parser = toml::Parser::new(&input);

    let toml = parser.parse().unwrap_or_else(|| {
        for err in &parser.errors {
            let (loline, locol) = parser.to_linecol(err.lo);
            let (hiline, hicol) = parser.to_linecol(err.hi);
            println!("{}:{}:{}-{}:{} error: {}",
                     filename, loline, locol, hiline, hicol, err.desc);
        }
        panic!("Error parsing toml file.");
    });

    // toml
    unimplemented!();
}

pub fn execute_steps(filename: &str) {

    let steps = parse_toml(filename);

    println!("Steps: {:?}", steps);
}
<|endoftext|>


<commit_before>// (c) 2016 Productize SPRL <joost@productize.be>

#![cfg_attr(feature = "use_clippy", feature(plugin))]
#![cfg_attr(feature = "use_clippy", plugin(clippy))]

extern crate rustc_serialize;
extern crate symbolic_expressions;

use std::fmt;

pub use symbolic_expressions::Sexp;
pub use error::*;

pub trait FromSexp {
    fn from_sexp(&Sexp) -> Self;
}

pub use util::read_file;

pub fn parse_split_quote_aware(s:&str) -> Vec<String> {
    let mut v:Vec<String> = vec![];
    let mut in_q:bool = false;
    let mut q_seen:bool = false;
    let mut s2:String = String::from("");
    for c in s.chars() {
        if !in_q && c == '\"' {
            in_q = true;
            //s2.push(c);
            continue
        }
        if in_q && c == '\"' {
            in_q = false;
            //s2.push(c);
            q_seen = true;
            continue
        }
        if !in_q && c == ' ' {
            if !s2.is_empty() || q_seen {
                v.push(s2.clone());
                s2.clear();
            }
            q_seen = false;
            continue;
        }
        s2.push(c);
    }
    if !s2.is_empty() || q_seen {
        v.push(s2.clone())
    }
    v
}

pub fn parse_split_quote_aware_n(n:usize, s:&str) -> Result<Vec<String>> {
    let mut i = 0;
    let mut v:Vec<String> = vec![];
    let mut in_q:bool = false;
    let mut q_seen:bool = false;
    let mut s2:String = String::from("");
    for c in s.chars() {
        if i == n { // if we're in the nth. just keep collecting in current string
            s2.push(c);
            continue;
        }
        if !in_q && c == '\"' {
            in_q = true;
            //s2.push(c);
            continue
        }
        if in_q && c == '\"' {
            in_q = false;
            //s2.push(c);
            q_seen = true;
            continue
        }
        if !in_q && c == ' ' {
            if !s2.is_empty() || q_seen {
                i += 1;
                v.push(s2.clone());
                s2.clear();
            }
            q_seen = false;
            continue;
        }
        s2.push(c);
    }
    if !s2.is_empty() || q_seen {
        v.push(s2.clone())
    }
    if v.len() < n {
        return str_error(format!("expecting {} elements in {}", n, s))
    }
    Ok(v)
}

#[derive(Debug)]
pub enum KicadFile {
    Unknown(String),
    Module(footprint::Module),
    Schematic(schematic::Schematic),
    Layout(layout::Layout),
    SymbolLib(symbol_lib::SymbolLib),
    Project(project::Project),
}

#[derive(PartialEq)]
pub enum Expected {
    Module,
    Schematic,
    Layout,
    SymbolLib,
    Project,
    Any,
}

impl fmt::Display for KicadFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
        match *self {
            KicadFile::Unknown(ref x)   => write!(f, "unknown: {}", x),
            KicadFile::Module(_)    => write!(f, "module"),
            KicadFile::Schematic(_) => write!(f, "schematic"),
            KicadFile::Layout(_)    => write!(f, "layout"),
            KicadFile::SymbolLib(_) => write!(f, "symbollib"),
            KicadFile::Project(_)   => write!(f, "project"),
        }
    }
}

pub fn read_kicad_file(name: &str, expected:Expected) -> Result<KicadFile> {
    let pb = std::path::PathBuf::from(name);
    let data = try!(read_file(name));
    let mut msg = String::new();
    match footprint::parse(&data) {
        Ok(module) => return Ok(KicadFile::Module(module)),
        Err(x) => { if expected == Expected::Module { msg = format!("{}", x) } },
    }
    match schematic::parse(Some(pb), &data) {
        Ok(sch) => return Ok(KicadFile::Schematic(sch)),
        Err(x) => { if expected == Expected::Schematic { msg = format!("{}", x) } },
    }
    match layout::parse(&data) {
        Ok(layout) => return Ok(KicadFile::Layout(layout)),
        Err(x) => { if expected == Expected::Layout { msg = format!("{}", x) } },
    }
    match symbol_lib::parse_str(&data) {
        Ok(sl) => return Ok(KicadFile::SymbolLib(sl)),
        Err(x) => { if expected == Expected::SymbolLib { msg = format!("{}", x) } },
    }
    match project::parse_str(&data) {
        Ok(p) => return Ok(KicadFile::Project(p)),
        Err(x) => { if expected == Expected::Project { msg = format!("{}", x) } },
    }
    Ok(KicadFile::Unknown(format!("{}: {}", name, msg)))
}

pub fn read_module(name: &str) -> Result<footprint::Module> {
    match try!(read_kicad_file(name, Expected::Module)) {
        KicadFile::Module(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name)),
    }
}

pub fn read_schematic(name: &str) -> Result<schematic::Schematic> {
    match try!(read_kicad_file(name, Expected::Schematic)) {
        KicadFile::Schematic(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name)),
    }
}

pub fn read_layout(name: &str) -> Result<layout::Layout> {
    match try!(read_kicad_file(name, Expected::Layout)) {
        KicadFile::Layout(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name)),
    }
}

pub fn read_symbol_lib(name: &str) -> Result<symbol_lib::SymbolLib> {
    match try!(read_kicad_file(name, Expected::SymbolLib)) {
        KicadFile::SymbolLib(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name)),
    }
}

pub fn read_project(name: &str) -> Result<project::Project> {
    match try!(read_kicad_file(name, Expected::Project)) {
        KicadFile::Project(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name)),
    }
}

pub mod error;
pub mod footprint;
pub mod schematic;
pub mod layout;
pub mod symbol_lib;
pub mod project;
pub mod util;
mod formatter;
<commit_msg>write file pub<commit_after>// (c) 2016 Productize SPRL <joost@productize.be>

#![cfg_attr(feature = "use_clippy", feature(plugin))]
#![cfg_attr(feature = "use_clippy", plugin(clippy))]

extern crate rustc_serialize;
extern crate symbolic_expressions;

use std::fmt;

pub use symbolic_expressions::Sexp;
pub use error::*;

pub trait FromSexp {
    fn from_sexp(&Sexp) -> Self;
}

pub use util::read_file;
pub use util::write_file;

pub fn parse_split_quote_aware(s:&str) -> Vec<String> {
    let mut v:Vec<String> = vec![];
    let mut in_q:bool = false;
    let mut q_seen:bool = false;
    let mut s2:String = String::from("");
    for c in s.chars() {
        if !in_q && c == '\"' {
            in_q = true;
            //s2.push(c);
            continue
        }
        if in_q && c == '\"' {
            in_q = false;
            //s2.push(c);
            q_seen = true;
            continue
        }
        if !in_q && c == ' ' {
            if !s2.is_empty() || q_seen {
                v.push(s2.clone());
                s2.clear();
            }
            q_seen = false;
            continue;
        }
        s2.push(c);
    }
    if !s2.is_empty() || q_seen {
        v.push(s2.clone())
    }
    v
}

pub fn parse_split_quote_aware_n(n:usize, s:&str) -> Result<Vec<String>> {
    let mut i = 0;
    let mut v:Vec<String> = vec![];
    let mut in_q:bool = false;
    let mut q_seen:bool = false;
    let mut s2:String = String::from("");
    for c in s.chars() {
        if i == n { // if we're in the nth. just keep collecting in current string
            s2.push(c);
            continue;
        }
        if !in_q && c == '\"' {
            in_q = true;
            //s2.push(c);
            continue
        }
        if in_q && c == '\"' {
            in_q = false;
            //s2.push(c);
            q_seen = true;
            continue
        }
        if !in_q && c == ' ' {
            if !s2.is_empty() || q_seen {
                i += 1;
                v.push(s2.clone());
                s2.clear();
            }
            q_seen = false;
            continue;
        }
        s2.push(c);
    }
    if !s2.is_empty() || q_seen {
        v.push(s2.clone())
    }
    if v.len() < n {
        return str_error(format!("expecting {} elements in {}", n, s))
    }
    Ok(v)
}

#[derive(Debug)]
pub enum KicadFile {
    Unknown(String),
    Module(footprint::Module),
    Schematic(schematic::Schematic),
    Layout(layout::Layout),
    SymbolLib(symbol_lib::SymbolLib),
    Project(project::Project),
}

#[derive(PartialEq)]
pub enum Expected {
    Module,
    Schematic,
    Layout,
    SymbolLib,
    Project,
    Any,
}

impl fmt::Display for KicadFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
        match *self {
            KicadFile::Unknown(ref x)   => write!(f, "unknown: {}", x),
            KicadFile::Module(_)    => write!(f, "module"),
            KicadFile::Schematic(_) => write!(f, "schematic"),
            KicadFile::Layout(_)    => write!(f, "layout"),
            KicadFile::SymbolLib(_) => write!(f, "symbollib"),
            KicadFile::Project(_)   => write!(f, "project"),
        }
    }
}

pub fn read_kicad_file(name: &str, expected:Expected) -> Result<KicadFile> {
    let pb = std::path::PathBuf::from(name);
    let data = try!(read_file(name));
    let mut msg = String::new();
    match footprint::parse(&data) {
        Ok(module) => return Ok(KicadFile::Module(module)),
        Err(x) => { if expected == Expected::Module { msg = format!("{}", x) } },
    }
    match schematic::parse(Some(pb), &data) {
        Ok(sch) => return Ok(KicadFile::Schematic(sch)),
        Err(x) => { if expected == Expected::Schematic { msg = format!("{}", x) } },
    }
    match layout::parse(&data) {
        Ok(layout) => return Ok(KicadFile::Layout(layout)),
        Err(x) => { if expected == Expected::Layout { msg = format!("{}", x) } },
    }
    match symbol_lib::parse_str(&data) {
        Ok(sl) => return Ok(KicadFile::SymbolLib(sl)),
        Err(x) => { if expected == Expected::SymbolLib { msg = format!("{}", x) } },
    }
    match project::parse_str(&data) {
        Ok(p) => return Ok(KicadFile::Project(p)),
        Err(x) => { if expected == Expected::Project { msg = format!("{}", x) } },
    }
    Ok(KicadFile::Unknown(format!("{}: {}", name, msg)))
}

pub fn read_module(name: &str) -> Result<footprint::Module> {
    match try!(read_kicad_file(name, Expected::Module)) {
        KicadFile::Module(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name)),
    }
}

pub fn read_schematic(name: &str) -> Result<schematic::Schematic> {
    match try!(read_kicad_file(name, Expected::Schematic)) {
        KicadFile::Schematic(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name)),
    }
}

pub fn read_layout(name: &str) -> Result<layout::Layout> {
    match try!(read_kicad_file(name, Expected::Layout)) {
        KicadFile::Layout(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name)),
    }
}

pub fn read_symbol_lib(name: &str) -> Result<symbol_lib::SymbolLib> {
    match try!(read_kicad_file(name, Expected::SymbolLib)) {
        KicadFile::SymbolLib(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name)),
    }
}

pub fn read_project(name: &str) -> Result<project::Project> {
    match try!(read_kicad_file(name, Expected::Project)) {
        KicadFile::Project(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name)),
    }
}

pub mod error;
pub mod footprint;
pub mod schematic;
pub mod layout;
pub mod symbol_lib;
pub mod project;
pub mod util;
mod formatter;
<|endoftext|>