<commit_before>extern crate ini;

use ini::Ini;
use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::BufferedReader;

fn handle_request(host: &str, mut client: TcpStream) {
    println!("handling request for {}", host);
    client.write(b"127.0.0.1:9001\n");
}

fn handle_new_client(mut stream: TcpStream) {
    let mut reader = BufferedReader::new(stream);
    let req = reader.read_line();
    stream = reader.unwrap();
    match req {
        Ok(host) => handle_request(host.as_slice(), stream),
        Err(msg) => {
            stream.write(b"error");
        }
    };
}

fn main() {

    let mut config = Ini::load_from_file("config.ini");

    config.begin_section("config");
    let port: u16 = match from_str(config.get("port").as_slice()) {
        Some(p) => p,
        None => 41144
    };

    let host = config.get("hostname").as_slice();

    let socket = TcpListener::bind(host, port);
    let mut acceptor = socket.listen();

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => {
                println!("connection failed: {}", e);
            },
            Ok(stream) => spawn(proc() {
                // connection succeeded
                handle_new_client(stream)
            })
        }
    }

    drop(acceptor);
}
<commit_msg>using asynchronus backends works! yay<commit_after>extern crate ini;

use ini::Ini;
use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::BufferedReader;

use std::comm::{Sender, Receiver};

use std::io::Timer;
use std::time::Duration;

fn start_random_backend(rx: Receiver<(String, Sender<Option<String>>)>) {
    loop {
        let (host, answer) = rx.recv();
        let mut timer = Timer::new().unwrap();
        timer.sleep(Duration::milliseconds(1000));
        answer.send(Some(host + " found"));
    }
}

fn handle_new_client(mut stream: TcpStream, tx: Sender<(String, Sender<Option<String>>)>) {
    let mut reader = BufferedReader::new(stream);
    let req = reader.read_line();
    stream = reader.unwrap();
    let result = match req {
        Ok(host) => {
            let thost = host.as_slice().trim().to_string();
            let (mytx, myrx) = channel();
            tx.send((thost, mytx));
            let answer = myrx.recv();
            println!("answer: {}", answer);
            match answer {
                Some(address) => {
                    stream.write(address.as_bytes())
                },
                None => {
                    stream.write(b"404")
                }
            }

        },
        Err(msg) => {
            stream.write(format!("error: {}", msg).as_bytes())
        }
    };
    match result {
        Err(msg) => {
            println!("ERROR: {}", msg);
        }
        _ => ()
    };
}

fn main() {

    let mut config = Ini::load_from_file("config.ini");

    config.begin_section("config");
    let port: u16 = match from_str(config.get("port").as_slice()) {
        Some(p) => p,
        None => 41144
    };

    let host = config.get("hostname").as_slice();

    // start backend
    let (tx, rx) = channel();

    spawn(proc() {
        start_random_backend(rx);
    });

    let socket = TcpListener::bind(host, port);
    let mut acceptor = socket.listen();

    for stream in acceptor.incoming() {
        let ptx = tx.clone();
        match stream {
            Err(e) => {
                println!("connection failed: {}", e);
            },
            Ok(stream) => spawn(proc() {
                // connection succeeded
                handle_new_client(stream, ptx)
            })
        }
    }

    drop(acceptor);
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::str::FromStr;
use std::fmt;

use rocket::fairing::AdHoc;
use toml;
use serde::de::{self, Deserialize, Deserializer, Visitor};

/// This struct is used to hold meta data for contexts to be passed to [`Template::render`]
///
/// [`Template::render`]: https://api.rocket.rs/rocket_contrib/struct.Template.html#method.render
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct Metadata {
    title: String,
    description: String,
    authors: Vec<Author>,
    // TODO add more fields
}

impl Metadata {
    pub fn fairing() -> AdHoc {
        AdHoc::on_attach(|rocket| {
            let mut input = String::new();
            File::open("Satellite.toml").and_then(|mut f| {
                f.read_to_string(&mut input)
            }).unwrap();

            let metadata: Result<Metadata, _> = toml::from_str(input.as_str());

            match metadata {
                Ok(metadata) => Ok(rocket.manage(metadata)),
                Err(e) => {
                    println!("{}", e);
                    Err(rocket)
                },
            }
        })
    }
}

/// Holds the name and email address of one author.
/// Used in [`Metadata`]: struct.Metadata.html
#[derive(Debug, Serialize, Clone, PartialEq)]
pub struct Author {
    name: String,
    email: String,
}

impl FromStr for Author {
    type Err = AuthorParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use regex::Regex;
        let re = Regex::new(r"(.*) <([a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*)>").unwrap();

        let cap = re.captures_iter(s).next().ok_or(AuthorParseError)?;
        let name = cap.get(1).map(|m| m.as_str().to_string()).unwrap_or_default();
        let email = cap.get(2).map(|m| m.as_str().to_string()).unwrap_or_default();

        Ok(Author { name, email })
    }
}

impl<'de> Deserialize<'de> for Author {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        struct AuthorStringVisitor;

        impl<'de> Visitor<'de> for AuthorStringVisitor {
            type Value = Author;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(formatter, "a string in the format 'Name <email@example.com>'")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
                where E: de::Error
            {
                Author::from_str(v).map_err(|_| E::custom(format!("'{}' is not in the format 'Name <email@example.com>'", v)))
            }
        }

        deserializer.deserialize_str(AuthorStringVisitor)
    }
}

struct AuthorParseError;

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

    #[test]
    fn deserialize_author() {
        assert_eq!(Ok(Author {
            name: "Random Name".to_string(),
            email: "random@mail.tld".to_string(),
        }), "Random Name <random@mail.tld>".parse());

        assert!("".parse::<Author>().is_err());
        assert!("<>".parse::<Author>().is_err());
        assert!("<random@mail.tld>".parse::<Author>().is_err());
        assert!("Random Name".parse::<Author>().is_err());
    }

    #[test]
    fn deserialize_metadata() {
        let data = r#"
            title = "Some Title"
            description = "Some description"
            authors = [
                "Name <email@author.com>",
                "Another <another@author.net>"
            ]
        "#;

        let meta: Metadata = toml::from_str(data).unwrap();

        assert_eq!(meta, Metadata {
            title: "Some Title".to_string(),
            description: "Some description".to_string(),
            authors: vec![
                Author {
                    name: "Name".to_string(),
                    email: "email@author.com".to_string(),
                },
                Author {
                    name: "Another".to_string(),
                    email: "another@author.net".to_string(),
                }
            ],
        });
    }

}<commit_msg>Corrected mistakes with AuthorParseError<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::str::FromStr;
use std::fmt;

use rocket::fairing::AdHoc;
use toml;
use serde::de::{self, Deserialize, Deserializer, Visitor};

/// This struct is used to hold meta data for contexts to be passed to [`Template::render`]
///
/// [`Template::render`]: https://api.rocket.rs/rocket_contrib/struct.Template.html#method.render
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct Metadata {
    title: String,
    description: String,
    authors: Vec<Author>,
    // TODO add more fields
}

impl Metadata {
    pub fn fairing() -> AdHoc {
        AdHoc::on_attach(|rocket| {
            let mut input = String::new();
            File::open("Satellite.toml").and_then(|mut f| {
                f.read_to_string(&mut input)
            }).unwrap();

            let metadata: Result<Metadata, _> = toml::from_str(input.as_str());

            match metadata {
                Ok(metadata) => Ok(rocket.manage(metadata)),
                Err(e) => {
                    println!("{}", e);
                    Err(rocket)
                },
            }
        })
    }
}

/// Holds the name and email address of one author.
/// Used in [`Metadata`]: struct.Metadata.html
#[derive(Debug, Serialize, Clone, PartialEq)]
pub struct Author {
    name: String,
    email: String,
}

impl FromStr for Author {
    type Err = AuthorParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use regex::Regex;
        let re = Regex::new(r"(.*) <([a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*)>").unwrap();

        let cap = re.captures_iter(s).next().ok_or(AuthorParseError)?;
        let name = cap.get(1).map(|m| m.as_str().to_string()).unwrap_or_default();
        let email = cap.get(2).map(|m| m.as_str().to_string()).unwrap_or_default();

        Ok(Author { name, email })
    }
}

impl<'de> Deserialize<'de> for Author {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        struct AuthorStringVisitor;

        impl<'de> Visitor<'de> for AuthorStringVisitor {
            type Value = Author;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(formatter, "a string in the format 'Name <email@example.com>'")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
                where E: de::Error
            {
                Author::from_str(v).map_err(|_| E::custom(format!("'{}' is not in the format 'Name <email@example.com>'", v)))
            }
        }

        deserializer.deserialize_str(AuthorStringVisitor)
    }
}

/// Represents a parse error for Author.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct AuthorParseError;

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

    #[test]
    fn deserialize_author() {
        assert_eq!(Ok(Author {
            name: "Random Name".to_string(),
            email: "random@mail.tld".to_string(),
        }), "Random Name <random@mail.tld>".parse());

        assert!("".parse::<Author>().is_err());
        assert!("<>".parse::<Author>().is_err());
        assert!("<random@mail.tld>".parse::<Author>().is_err());
        assert!("Random Name".parse::<Author>().is_err());
    }

    #[test]
    fn deserialize_metadata() {
        let data = r#"
            title = "Some Title"
            description = "Some description"
            authors = [
                "Name <email@author.com>",
                "Another <another@author.net>"
            ]
        "#;

        let meta: Metadata = toml::from_str(data).unwrap();

        assert_eq!(meta, Metadata {
            title: "Some Title".to_string(),
            description: "Some description".to_string(),
            authors: vec![
                Author {
                    name: "Name".to_string(),
                    email: "email@author.com".to_string(),
                },
                Author {
                    name: "Another".to_string(),
                    email: "another@author.net".to_string(),
                }
            ],
        });
    }

}<|endoftext|>


<commit_before>// TODO: Move into grammar

use std::io::{self, Write};

use shell::{status::*, variables::Variables};
use types::*;

fn print_list(list: &VariableContext) {
    let stdout = io::stdout();
    let stdout = &mut stdout.lock();

    for (key, value) in list {
        let _ = stdout
            .write(key.as_bytes())
            .and_then(|_| stdout.write_all(b" = "))
            .and_then(|_| stdout.write_all(value.as_bytes()))
            .and_then(|_| stdout.write_all(b"\n"));
    }
}

enum Binding {
    InvalidKey(Identifier),
    ListEntries,
    KeyOnly(Identifier),
    KeyValue(Identifier, Value),
    Math(Identifier, Operator, f32),
    MathInvalid(Value),
}

enum Operator {
    Plus,
    Minus,
    Divide,
    Multiply,
}

/// Parses alias as a `(key, value)` tuple.
fn parse_alias(args: &str) -> Binding {
    // Write all the arguments into a single `String`
    let mut char_iter = args.chars();

    // Find the key and advance the iterator until the equals operator is found.
    let mut key = "".to_owned();
    let mut found_key = false;
    let mut operator = None;

    // Scans through characters until the key is found, then continues to scan until
    // the equals operator is found.
    while let Some(character) = char_iter.next() {
        match character {
            ' ' if key.is_empty() => (),
            ' ' => found_key = true,
            '+' => {
                if char_iter.next() == Some('=') {
                    operator = Some(Operator::Plus);
                    found_key = true;
                }
                break;
            }
            '-' => {
                if char_iter.next() == Some('=') {
                    operator = Some(Operator::Minus);
                    found_key = true;
                }
                break;
            }
            '*' => {
                if char_iter.next() == Some('=') {
                    operator = Some(Operator::Multiply);
                    found_key = true;
                }
                break;
            }
            '/' => {
                if char_iter.next() == Some('=') {
                    operator = Some(Operator::Divide);
                    found_key = true;
                }
                break;
            }
            '=' => {
                found_key = true;
                break;
            }
            _ if !found_key => key.push(character),
            _ => (),
        }
    }

    let key: Identifier = key.into();

    if !found_key && key.is_empty() {
        Binding::ListEntries
    } else {
        let value: Value = char_iter.skip_while(|&x| x == ' ').collect();
        if value.is_empty() {
            Binding::KeyOnly(key)
        } else if !Variables::is_valid_variable_name(&key) {
            Binding::InvalidKey(key)
        } else {
            match operator {
                Some(operator) => match value.parse::<f32>() {
                    Ok(value) => Binding::Math(key, operator, value),
                    Err(_) => Binding::MathInvalid(value),
                },
                None => Binding::KeyValue(key, value),
            }
        }
    }
}

/// The `alias` command will define an alias for another command, and thus may be used as a
/// command itself.
pub(crate) fn alias(vars: &mut Variables, args: &str) -> i32 {
    match parse_alias(args) {
        Binding::InvalidKey(key) => {
            eprintln!("ion: alias name, '{}', is invalid", key);
            return FAILURE;
        }
        Binding::KeyValue(key, value) => {
            vars.aliases.insert(key, value);
        }
        Binding::ListEntries => print_list(&vars.aliases),
        Binding::KeyOnly(key) => {
            eprintln!("ion: please provide value for alias '{}'", key);
            return FAILURE;
        }
        _ => {
            eprintln!("ion: invalid alias syntax");
            return FAILURE;
        }
    }
    SUCCESS
}

/// Dropping an alias will erase it from the shell.
pub(crate) fn drop_alias<S: AsRef<str>>(vars: &mut Variables, args: &[S]) -> i32 {
    if args.len() <= 1 {
        eprintln!("ion: you must specify an alias name");
        return FAILURE;
    }
    for alias in args.iter().skip(1) {
        if vars.aliases.remove(alias.as_ref()).is_none() {
            eprintln!("ion: undefined alias: {}", alias.as_ref());
            return FAILURE;
        }
    }
    SUCCESS
}

/// Dropping an array will erase it from the shell.
pub(crate) fn drop_array<S: AsRef<str>>(vars: &mut Variables, args: &[S]) -> i32 {
    if args.len() <= 2 {
        eprintln!("ion: you must specify an array name");
        return FAILURE;
    }

    if args[1].as_ref() != "-a" {
        eprintln!("ion: drop_array must be used with -a option");
        return FAILURE;
    }

    for array in args.iter().skip(2) {
        if vars.unset_array(array.as_ref()).is_none() {
            eprintln!("ion: undefined array: {}", array.as_ref());
            return FAILURE;
        }
    }
    SUCCESS
}

/// Dropping a variable will erase it from the shell.
pub(crate) fn drop_variable<S: AsRef<str>>(vars: &mut Variables, args: &[S]) -> i32 {
    if args.len() <= 1 {
        eprintln!("ion: you must specify a variable name");
        return FAILURE;
    }

    for variable in args.iter().skip(1) {
        if vars.unset_var(variable.as_ref()).is_none() {
            eprintln!("ion: undefined variable: {}", variable.as_ref());
            return FAILURE;
        }
    }

    SUCCESS
}

#[cfg(test)]
mod test {
    use super::*;
    use parser::{expand_string, Expander};
    use shell::status::{FAILURE, SUCCESS};

    struct VariableExpander(pub Variables);

    impl Expander for VariableExpander {
        fn variable(&self, var: &str, _: bool) -> Option<Value> { self.0.get_var(var) }
    }

    // TODO: Rewrite tests now that let is part of the grammar.
    // #[test]
    // fn let_and_expand_a_variable() {
    //     let mut variables = Variables::default();
    //     let dir_stack = new_dir_stack();
    //     let_(&mut variables, vec!["let", "FOO", "=", "BAR"]);
    // let expanded = expand_string("$FOO", &variables, &dir_stack,
    // false).join("");     assert_eq!("BAR", &expanded);
    // }
    //
    // #[test]
    // fn let_fails_if_no_value() {
    //     let mut variables = Variables::default();
    //     let return_status = let_(&mut variables, vec!["let", "FOO"]);
    //     assert_eq!(FAILURE, return_status);
    // }
    //
    // #[test]
    // fn let_checks_variable_name() {
    //     let mut variables = Variables::default();
    // let return_status = let_(&mut variables, vec!["let", ",;!:", "=",
    // "FOO"]);     assert_eq!(FAILURE, return_status);
    // }

    #[test]
    fn drop_deletes_variable() {
        let mut variables = Variables::default();
        variables.set_var("FOO", "BAR");
        let return_status = drop_variable(&mut variables, vec!["drop", "FOO"]);
        assert_eq!(SUCCESS, return_status);
        let expanded = expand_string("$FOO", &VariableExpander(variables), false).join("");
        assert_eq!("", expanded);
    }

    #[test]
    fn drop_fails_with_no_arguments() {
        let mut variables = Variables::default();
        let return_status = drop_variable(&mut variables, vec!["drop"]);
        assert_eq!(FAILURE, return_status);
    }

    #[test]
    fn drop_fails_with_undefined_variable() {
        let mut variables = Variables::default();
        let return_status = drop_variable(&mut variables, vec!["drop", "FOO"]);
        assert_eq!(FAILURE, return_status);
    }

    #[test]
    fn drop_deletes_array() {
        let mut variables = Variables::default();
        variables.set_array("FOO", array!["BAR"]);
        let return_status = drop_array(&mut variables, vec!["drop", "-a", "FOO"]);
        assert_eq!(SUCCESS, return_status);
        let expanded = expand_string("@FOO", &VariableExpander(variables), false).join("");
        assert_eq!("", expanded);
    }

    #[test]
    fn drop_array_fails_with_no_arguments() {
        let mut variables = Variables::default();
        let return_status = drop_array(&mut variables, vec!["drop", "-a"]);
        assert_eq!(FAILURE, return_status);
    }

    #[test]
    fn drop_array_fails_with_undefined_array() {
        let mut variables = Variables::default();
        let return_status = drop_array(&mut variables, vec!["drop", "FOO"]);
        assert_eq!(FAILURE, return_status);
    }
}
<commit_msg>Fix tests<commit_after>// TODO: Move into grammar

use std::io::{self, Write};

use shell::{status::*, variables::Variables};
use types::*;

fn print_list(list: &VariableContext) {
    let stdout = io::stdout();
    let stdout = &mut stdout.lock();

    for (key, value) in list {
        let _ = stdout
            .write(key.as_bytes())
            .and_then(|_| stdout.write_all(b" = "))
            .and_then(|_| stdout.write_all(value.as_bytes()))
            .and_then(|_| stdout.write_all(b"\n"));
    }
}

enum Binding {
    InvalidKey(Identifier),
    ListEntries,
    KeyOnly(Identifier),
    KeyValue(Identifier, Value),
    Math(Identifier, Operator, f32),
    MathInvalid(Value),
}

enum Operator {
    Plus,
    Minus,
    Divide,
    Multiply,
}

/// Parses alias as a `(key, value)` tuple.
fn parse_alias(args: &str) -> Binding {
    // Write all the arguments into a single `String`
    let mut char_iter = args.chars();

    // Find the key and advance the iterator until the equals operator is found.
    let mut key = "".to_owned();
    let mut found_key = false;
    let mut operator = None;

    // Scans through characters until the key is found, then continues to scan until
    // the equals operator is found.
    while let Some(character) = char_iter.next() {
        match character {
            ' ' if key.is_empty() => (),
            ' ' => found_key = true,
            '+' => {
                if char_iter.next() == Some('=') {
                    operator = Some(Operator::Plus);
                    found_key = true;
                }
                break;
            }
            '-' => {
                if char_iter.next() == Some('=') {
                    operator = Some(Operator::Minus);
                    found_key = true;
                }
                break;
            }
            '*' => {
                if char_iter.next() == Some('=') {
                    operator = Some(Operator::Multiply);
                    found_key = true;
                }
                break;
            }
            '/' => {
                if char_iter.next() == Some('=') {
                    operator = Some(Operator::Divide);
                    found_key = true;
                }
                break;
            }
            '=' => {
                found_key = true;
                break;
            }
            _ if !found_key => key.push(character),
            _ => (),
        }
    }

    let key: Identifier = key.into();

    if !found_key && key.is_empty() {
        Binding::ListEntries
    } else {
        let value: Value = char_iter.skip_while(|&x| x == ' ').collect();
        if value.is_empty() {
            Binding::KeyOnly(key)
        } else if !Variables::is_valid_variable_name(&key) {
            Binding::InvalidKey(key)
        } else {
            match operator {
                Some(operator) => match value.parse::<f32>() {
                    Ok(value) => Binding::Math(key, operator, value),
                    Err(_) => Binding::MathInvalid(value),
                },
                None => Binding::KeyValue(key, value),
            }
        }
    }
}

/// The `alias` command will define an alias for another command, and thus may be used as a
/// command itself.
pub(crate) fn alias(vars: &mut Variables, args: &str) -> i32 {
    match parse_alias(args) {
        Binding::InvalidKey(key) => {
            eprintln!("ion: alias name, '{}', is invalid", key);
            return FAILURE;
        }
        Binding::KeyValue(key, value) => {
            vars.aliases.insert(key, value);
        }
        Binding::ListEntries => print_list(&vars.aliases),
        Binding::KeyOnly(key) => {
            eprintln!("ion: please provide value for alias '{}'", key);
            return FAILURE;
        }
        _ => {
            eprintln!("ion: invalid alias syntax");
            return FAILURE;
        }
    }
    SUCCESS
}

/// Dropping an alias will erase it from the shell.
pub(crate) fn drop_alias<S: AsRef<str>>(vars: &mut Variables, args: &[S]) -> i32 {
    if args.len() <= 1 {
        eprintln!("ion: you must specify an alias name");
        return FAILURE;
    }
    for alias in args.iter().skip(1) {
        if vars.aliases.remove(alias.as_ref()).is_none() {
            eprintln!("ion: undefined alias: {}", alias.as_ref());
            return FAILURE;
        }
    }
    SUCCESS
}

/// Dropping an array will erase it from the shell.
pub(crate) fn drop_array<S: AsRef<str>>(vars: &mut Variables, args: &[S]) -> i32 {
    if args.len() <= 2 {
        eprintln!("ion: you must specify an array name");
        return FAILURE;
    }

    if args[1].as_ref() != "-a" {
        eprintln!("ion: drop_array must be used with -a option");
        return FAILURE;
    }

    for array in args.iter().skip(2) {
        if vars.unset_array(array.as_ref()).is_none() {
            eprintln!("ion: undefined array: {}", array.as_ref());
            return FAILURE;
        }
    }
    SUCCESS
}

/// Dropping a variable will erase it from the shell.
pub(crate) fn drop_variable<S: AsRef<str>>(vars: &mut Variables, args: &[S]) -> i32 {
    if args.len() <= 1 {
        eprintln!("ion: you must specify a variable name");
        return FAILURE;
    }

    for variable in args.iter().skip(1) {
        if vars.unset_var(variable.as_ref()).is_none() {
            eprintln!("ion: undefined variable: {}", variable.as_ref());
            return FAILURE;
        }
    }

    SUCCESS
}

#[cfg(test)]
mod test {
    use super::*;
    use parser::{expand_string, Expander};
    use shell::status::{FAILURE, SUCCESS};

    struct VariableExpander(pub Variables);

    impl Expander for VariableExpander {
        fn variable(&self, var: &str, _: bool) -> Option<Value> { self.0.get_var(var) }
    }

    // TODO: Rewrite tests now that let is part of the grammar.
    // #[test]
    // fn let_and_expand_a_variable() {
    //     let mut variables = Variables::default();
    //     let dir_stack = new_dir_stack();
    //     let_(&mut variables, vec!["let", "FOO", "=", "BAR"]);
    // let expanded = expand_string("$FOO", &variables, &dir_stack,
    // false).join("");     assert_eq!("BAR", &expanded);
    // }
    //
    // #[test]
    // fn let_fails_if_no_value() {
    //     let mut variables = Variables::default();
    //     let return_status = let_(&mut variables, vec!["let", "FOO"]);
    //     assert_eq!(FAILURE, return_status);
    // }
    //
    // #[test]
    // fn let_checks_variable_name() {
    //     let mut variables = Variables::default();
    // let return_status = let_(&mut variables, vec!["let", ",;!:", "=",
    // "FOO"]);     assert_eq!(FAILURE, return_status);
    // }

    #[test]
    fn drop_deletes_variable() {
        let mut variables = Variables::default();
        variables.set_var("FOO", "BAR");
        let return_status = drop_variable(&mut variables, &["drop", "FOO"]);
        assert_eq!(SUCCESS, return_status);
        let expanded = expand_string("$FOO", &VariableExpander(variables), false).join("");
        assert_eq!("", expanded);
    }

    #[test]
    fn drop_fails_with_no_arguments() {
        let mut variables = Variables::default();
        let return_status = drop_variable(&mut variables, &["drop"]);
        assert_eq!(FAILURE, return_status);
    }

    #[test]
    fn drop_fails_with_undefined_variable() {
        let mut variables = Variables::default();
        let return_status = drop_variable(&mut variables, &["drop", "FOO"]);
        assert_eq!(FAILURE, return_status);
    }

    #[test]
    fn drop_deletes_array() {
        let mut variables = Variables::default();
        variables.set_array("FOO", array!["BAR"]);
        let return_status = drop_array(&mut variables, &["drop", "-a", "FOO"]);
        assert_eq!(SUCCESS, return_status);
        let expanded = expand_string("@FOO", &VariableExpander(variables), false).join("");
        assert_eq!("", expanded);
    }

    #[test]
    fn drop_array_fails_with_no_arguments() {
        let mut variables = Variables::default();
        let return_status = drop_array(&mut variables, &["drop", "-a"]);
        assert_eq!(FAILURE, return_status);
    }

    #[test]
    fn drop_array_fails_with_undefined_array() {
        let mut variables = Variables::default();
        let return_status = drop_array(&mut variables, &["drop", "FOO"]);
        assert_eq!(FAILURE, return_status);
    }
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/number-of-zero-filled-subarrays/
pub fn zero_filled_subarray(nums: Vec<i32>) -> i64 {
    todo!()
}

fn main() {
    println!("{}", zero_filled_subarray(vec![1, 3, 0, 0, 2, 0, 0, 4])); // 6
    println!("{}", zero_filled_subarray(vec![0, 0, 0, 2, 0, 0])); // 9
    println!("{}", zero_filled_subarray(vec![2, 10, 2019])); // 0
}
<commit_msg>Solve problem 2348<commit_after>// https://leetcode.com/problems/number-of-zero-filled-subarrays/
pub fn zero_filled_subarray(nums: Vec<i32>) -> i64 {
    fn sum(n: i32) -> i64 {
        // Arithmetic series formula: (n / 2) * (a1 + a2)
        ((n as f64 / 2.0) * (1 + n) as f64) as i64
    }

    let mut answer: i64 = 0;
    let mut i = 0;
    while i < nums.len() {
        if nums[i] == 0 {
            let mut count = 0;
            while i < nums.len() && nums[i] == 0 {
                count += 1;
                i += 1;
            }
            answer += sum(count)
        }
        i += 1;
    }
    answer
}

fn main() {
    println!("{}", zero_filled_subarray(vec![1, 3, 0, 0, 2, 0, 0, 4])); // 6
    println!("{}", zero_filled_subarray(vec![0, 0, 0, 2, 0, 0])); // 9
    println!("{}", zero_filled_subarray(vec![2, 10, 2019])); // 0
    println!("{}", zero_filled_subarray(vec![0, 0, 0, 0, 0])); // 15
}
<|endoftext|>


<commit_before>use autograd::{Function, FuncIntf, FuncDelegate, Variable, VarKindList, FIWrap};
use macros::*;
use tensor::TensorKindList;
use ::*;

pub struct Threshold {
    delegate: Function,
    threshold: f32,
    value: f32,
    inplace: bool,
}

impl Threshold {
    pub fn new(threshold: f32, value: f32, inplace: bool) -> FIWrap<Self> {
        FIWrap::new(Threshold {
                        delegate: Function::new(),
                        threshold: threshold,
                        value: value,
                        inplace: inplace,
                    })
    }
}

impl_func_delegate!(Threshold);

impl FuncIntf for Threshold {
    fn forward(&mut self, mut input: &mut TensorKindList) -> TensorKindList {
        unimplemented!()
    }
    fn backward(&mut self, mut input: &mut TensorKindList) -> TensorKindList {
        unimplemented!()
    }
}
<commit_msg>remove gratuitous mut<commit_after>use autograd::{Function, FuncIntf, FuncDelegate, Variable, VarKindList, FIWrap};
use macros::*;
use tensor::TensorKindList;
use ::*;

pub struct Threshold {
    delegate: Function,
    threshold: f32,
    value: f32,
    inplace: bool,
}

impl Threshold {
    pub fn new(threshold: f32, value: f32, inplace: bool) -> FIWrap<Self> {
        FIWrap::new(Threshold {
                        delegate: Function::new(),
                        threshold: threshold,
                        value: value,
                        inplace: inplace,
                    })
    }
}

impl_func_delegate!(Threshold);

impl FuncIntf for Threshold {
    fn forward(&mut self, input: &mut TensorKindList) -> TensorKindList {
        unimplemented!()
    }
    fn backward(&mut self, input: &mut TensorKindList) -> TensorKindList {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>#![recursion_limit="512"]

extern crate proc_macro;

use proc_macro2::TokenStream;
use quote::TokenStreamExt;

mod input;
mod vec;
mod refs;
mod ptr;
mod slice;
mod iter;

#[proc_macro_derive(StructOfArray, attributes(soa_derive))]
pub fn soa_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let ast = syn::parse(input).unwrap();
    let input = input::Input::new(ast);

    let mut generated = TokenStream::new();
    generated.append_all(vec::derive(&input));
    generated.append_all(refs::derive(&input));
    generated.append_all(ptr::derive(&input));
    generated.append_all(slice::derive_slice(&input));
    generated.append_all(slice::derive_slice_mut(&input));
    generated.append_all(iter::derive(&input));
    generated.into()
}
<commit_msg>Parametrize clippy<commit_after>#![recursion_limit="512"]

#![warn(clippy::all, clippy::pedantic)]
#![allow(clippy::needless_return, clippy::redundant_field_names)]
#![allow(clippy::stutter, clippy::use_self)]
// TODO: improve the code and make it simpler to read
#![allow(clippy::cyclomatic_complexity)]

extern crate proc_macro;

use proc_macro2::TokenStream;
use quote::TokenStreamExt;

mod input;
mod vec;
mod refs;
mod ptr;
mod slice;
mod iter;

#[proc_macro_derive(StructOfArray, attributes(soa_derive))]
pub fn soa_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let ast = syn::parse(input).unwrap();
    let input = input::Input::new(ast);

    let mut generated = TokenStream::new();
    generated.append_all(vec::derive(&input));
    generated.append_all(refs::derive(&input));
    generated.append_all(ptr::derive(&input));
    generated.append_all(slice::derive_slice(&input));
    generated.append_all(slice::derive_slice_mut(&input));
    generated.append_all(iter::derive(&input));
    generated.into()
}
<|endoftext|>


<commit_before>// Copyright 2015 The Gfx-rs 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.

#[deny(missing_docs)]

extern crate gfx_core as core;
extern crate gfx_device_gl as device_gl;
extern crate glutin;

use core::{format, handle, texture};
use core::memory::Typed;
use device_gl::Resources as R;

/// Initialize with a window builder.
/// Generically parametrized version over the main framebuffer format.
///
/// # Example
///
/// ```no_run
/// extern crate gfx_core;
/// extern crate gfx_device_gl;
/// extern crate gfx_window_glutin;
/// extern crate glutin;
///
/// use gfx_core::format::{DepthStencil, Rgba8};
///
/// fn main() {
///     let builder = glutin::WindowBuilder::new().with_title("Example".to_string());
///     let (window, device, factory, rtv, stv) =
///         gfx_window_glutin::init::<Rgba8, DepthStencil>(builder);
///
///     // your code
/// }
/// ```
pub fn init<Cf, Df>(builder: glutin::WindowBuilder) ->
            (glutin::Window, device_gl::Device, device_gl::Factory,
            handle::RenderTargetView<R, Cf>, handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let (window, device, factory, color_view, ds_view) = init_raw(builder, Cf::get_format(), Df::get_format());
    (window, device, factory, Typed::new(color_view), Typed::new(ds_view))
}

/// Initialize with an existing Glutin window.
/// Generically parametrized version over the main framebuffer format.
///
/// # Example (using Piston to create the window)
///
/// let settings = piston::window::WindowSettings::new("Example", [800, 600]);
/// let mut glutin_window = glutin_window::GlutinWindow::new(&settings).unwrap();
///
/// let (mut device, mut factory, main_color, main_depth) =
///     gfx_window_glutin::init_existing::<ColorFormat, DepthFormat>(&glutin_window.window);
///
/// let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
pub fn init_existing<Cf, Df>(window: &glutin::Window) ->
            (device_gl::Device, device_gl::Factory,
            handle::RenderTargetView<R, Cf>, handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let (device, factory, color_view, ds_view) = init_existing_raw(window, Cf::get_format(), Df::get_format());
    (device, factory, Typed::new(color_view), Typed::new(ds_view))
}

fn get_window_dimensions(window: &glutin::Window) -> texture::Dimensions {
    let (width, height) = window.get_inner_size().unwrap();
    let aa = window.get_pixel_format().multisampling
                   .unwrap_or(0) as texture::NumSamples;
    ((width as f32 * window.hidpi_factor()) as texture::Size, (height as f32 * window.hidpi_factor()) as texture::Size, 1, aa.into())
}

/// Initialize with a window builder. Raw version.
pub fn init_raw(builder: glutin::WindowBuilder,
                color_format: format::Format, ds_format: format::Format) ->
                (glutin::Window, device_gl::Device, device_gl::Factory,
                handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)
{
    let window = {
        let color_total_bits = color_format.0.get_total_bits();
        let alpha_bits = color_format.0.get_alpha_stencil_bits();
        let depth_total_bits = ds_format.0.get_total_bits();
        let stencil_bits = ds_format.0.get_alpha_stencil_bits();
        builder
            .with_depth_buffer(depth_total_bits - stencil_bits)
            .with_stencil_buffer(stencil_bits)
            .with_pixel_format(color_total_bits - alpha_bits, alpha_bits)
            .with_srgb(Some(color_format.1 == format::ChannelType::Srgb))
            .build()
    }.unwrap();

    let (device, factory, color_view, ds_view) = init_existing_raw(&window, color_format, ds_format);

    (window, device, factory, color_view, ds_view)
}

/// Initialize with an existing Glutin window. Raw version.
pub fn init_existing_raw(window: &glutin::Window,
                color_format: format::Format, ds_format: format::Format) ->
                (device_gl::Device, device_gl::Factory,
                handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)
{
    unsafe { window.make_current().unwrap() };
    let (device, factory) = device_gl::create(|s|
        window.get_proc_address(s) as *const std::os::raw::c_void);

    // create the main color/depth targets
    let dim = get_window_dimensions(window);
    let (color_view, ds_view) = device_gl::create_main_targets_raw(dim, color_format.0, ds_format.0);

    // done
    (device, factory, color_view, ds_view)
}

/// Update the internal dimensions of the main framebuffer targets. Generic version over the format.
pub fn update_views<Cf, Df>(window: &glutin::Window, color_view: &mut handle::RenderTargetView<R, Cf>,
                    ds_view: &mut handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let dim = color_view.get_dimensions();
    assert_eq!(dim, ds_view.get_dimensions());
    if let Some((cv, dv)) = update_views_raw(window, dim, Cf::get_format(), Df::get_format()) {
        *color_view = Typed::new(cv);
        *ds_view = Typed::new(dv);
    }
}

/// Return new main target views if the window resolution has changed from the old dimensions.
pub fn update_views_raw(window: &glutin::Window, old_dimensions: texture::Dimensions,
                        color_format: format::Format, ds_format: format::Format)
                        -> Option<(handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)>
{
    let dim = get_window_dimensions(window);
    if dim != old_dimensions {
        Some(device_gl::create_main_targets_raw(dim, color_format.0, ds_format.0))
    }else {
        None
    }
}
<commit_msg>Auto merge of #1061 - AnthIste:docs, r=kvark<commit_after>// Copyright 2015 The Gfx-rs 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.

#[deny(missing_docs)]

extern crate gfx_core as core;
extern crate gfx_device_gl as device_gl;
extern crate glutin;

use core::{format, handle, texture};
use core::memory::Typed;
use device_gl::Resources as R;

/// Initialize with a window builder.
/// Generically parametrized version over the main framebuffer format.
///
/// # Example
///
/// ```no_run
/// extern crate gfx_core;
/// extern crate gfx_device_gl;
/// extern crate gfx_window_glutin;
/// extern crate glutin;
///
/// use gfx_core::format::{DepthStencil, Rgba8};
///
/// fn main() {
///     let builder = glutin::WindowBuilder::new().with_title("Example".to_string());
///     let (window, device, factory, rtv, stv) =
///         gfx_window_glutin::init::<Rgba8, DepthStencil>(builder);
///
///     // your code
/// }
/// ```
pub fn init<Cf, Df>(builder: glutin::WindowBuilder) ->
            (glutin::Window, device_gl::Device, device_gl::Factory,
            handle::RenderTargetView<R, Cf>, handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let (window, device, factory, color_view, ds_view) = init_raw(builder, Cf::get_format(), Df::get_format());
    (window, device, factory, Typed::new(color_view), Typed::new(ds_view))
}

/// Initialize with an existing Glutin window.
/// Generically parametrized version over the main framebuffer format.
///
/// # Example (using Piston to create the window)
///
/// ```rust,ignore
/// extern crate piston;
/// extern crate glutin_window;
/// extern crate gfx_window_glutin;
///
/// // Create window with Piston
/// let settings = piston::window::WindowSettings::new("Example", [800, 600]);
/// let mut glutin_window = glutin_window::GlutinWindow::new(&settings).unwrap();
///
/// // Initialise gfx
/// let (mut device, mut factory, main_color, main_depth) =
///     gfx_window_glutin::init_existing::<ColorFormat, DepthFormat>(&glutin_window.window);
///
/// let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
/// ```
pub fn init_existing<Cf, Df>(window: &glutin::Window) ->
            (device_gl::Device, device_gl::Factory,
            handle::RenderTargetView<R, Cf>, handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let (device, factory, color_view, ds_view) = init_existing_raw(window, Cf::get_format(), Df::get_format());
    (device, factory, Typed::new(color_view), Typed::new(ds_view))
}

fn get_window_dimensions(window: &glutin::Window) -> texture::Dimensions {
    let (width, height) = window.get_inner_size().unwrap();
    let aa = window.get_pixel_format().multisampling
                   .unwrap_or(0) as texture::NumSamples;
    ((width as f32 * window.hidpi_factor()) as texture::Size, (height as f32 * window.hidpi_factor()) as texture::Size, 1, aa.into())
}

/// Initialize with a window builder. Raw version.
pub fn init_raw(builder: glutin::WindowBuilder,
                color_format: format::Format, ds_format: format::Format) ->
                (glutin::Window, device_gl::Device, device_gl::Factory,
                handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)
{
    let window = {
        let color_total_bits = color_format.0.get_total_bits();
        let alpha_bits = color_format.0.get_alpha_stencil_bits();
        let depth_total_bits = ds_format.0.get_total_bits();
        let stencil_bits = ds_format.0.get_alpha_stencil_bits();
        builder
            .with_depth_buffer(depth_total_bits - stencil_bits)
            .with_stencil_buffer(stencil_bits)
            .with_pixel_format(color_total_bits - alpha_bits, alpha_bits)
            .with_srgb(Some(color_format.1 == format::ChannelType::Srgb))
            .build()
    }.unwrap();

    let (device, factory, color_view, ds_view) = init_existing_raw(&window, color_format, ds_format);

    (window, device, factory, color_view, ds_view)
}

/// Initialize with an existing Glutin window. Raw version.
pub fn init_existing_raw(window: &glutin::Window,
                color_format: format::Format, ds_format: format::Format) ->
                (device_gl::Device, device_gl::Factory,
                handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)
{
    unsafe { window.make_current().unwrap() };
    let (device, factory) = device_gl::create(|s|
        window.get_proc_address(s) as *const std::os::raw::c_void);

    // create the main color/depth targets
    let dim = get_window_dimensions(window);
    let (color_view, ds_view) = device_gl::create_main_targets_raw(dim, color_format.0, ds_format.0);

    // done
    (device, factory, color_view, ds_view)
}

/// Update the internal dimensions of the main framebuffer targets. Generic version over the format.
pub fn update_views<Cf, Df>(window: &glutin::Window, color_view: &mut handle::RenderTargetView<R, Cf>,
                    ds_view: &mut handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let dim = color_view.get_dimensions();
    assert_eq!(dim, ds_view.get_dimensions());
    if let Some((cv, dv)) = update_views_raw(window, dim, Cf::get_format(), Df::get_format()) {
        *color_view = Typed::new(cv);
        *ds_view = Typed::new(dv);
    }
}

/// Return new main target views if the window resolution has changed from the old dimensions.
pub fn update_views_raw(window: &glutin::Window, old_dimensions: texture::Dimensions,
                        color_format: format::Format, ds_format: format::Format)
                        -> Option<(handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)>
{
    let dim = get_window_dimensions(window);
    if dim != old_dimensions {
        Some(device_gl::create_main_targets_raw(dim, color_format.0, ds_format.0))
    }else {
        None
    }
}
<|endoftext|>


<commit_before>use command_prelude::*;

use cargo::core::{GitReference, SourceId};
use cargo::ops;
use cargo::util::ToUrl;

pub fn cli() -> App {
    subcommand("install")
        .about("Install a Rust binary")
        .arg(Arg::with_name("crate").empty_values(false).multiple(true))
        .arg(
            opt("version", "Specify a version to install from crates.io")
                .alias("vers")
                .value_name("VERSION"),
        )
        .arg(opt("git", "Git URL to install the specified crate from").value_name("URL"))
        .arg(opt("branch", "Branch to use when installing from git").value_name("BRANCH"))
        .arg(opt("tag", "Tag to use when installing from git").value_name("TAG"))
        .arg(opt("rev", "Specific commit to use when installing from git").value_name("SHA"))
        .arg(opt("path", "Filesystem path to local crate to install").value_name("PATH"))
        .arg(opt(
            "list",
            "list all installed packages and their versions",
        ))
        .arg_jobs()
        .arg(opt("force", "Force overwriting existing crates or binaries").short("f"))
        .arg_features()
        .arg(opt("debug", "Build in debug mode instead of release mode"))
        .arg_targets_bins_examples(
            "Install only the specified binary",
            "Install all binaries",
            "Install only the specified example",
            "Install all examples",
        )
        .arg_target_triple("Build for the target triple")
        .arg(opt("root", "Directory to install packages into").value_name("DIR"))
        .after_help(
            "\
This command manages Cargo's local set of installed binary crates. Only packages
which have [[bin]] targets can be installed, and all binaries are installed into
the installation root's `bin` folder. The installation root is determined, in
order of precedence, by `--root`, `$CARGO_INSTALL_ROOT`, the `install.root`
configuration key, and finally the home directory (which is either
`$CARGO_HOME` if set or `$HOME/.cargo` by default).

There are multiple sources from which a crate can be installed. The default
location is crates.io but the `--git` and `--path` flags can change this source.
If the source contains more than one package (such as crates.io or a git
repository with multiple crates) the `<crate>` argument is required to indicate
which crate should be installed.

Crates from crates.io can optionally specify the version they wish to install
via the `--vers` flags, and similarly packages from git repositories can
optionally specify the branch, tag, or revision that should be installed. If a
crate has multiple binaries, the `--bin` argument can selectively install only
one of them, and if you'd rather install examples the `--example` argument can
be used as well.

By default cargo will refuse to overwrite existing binaries. The `--force` flag
enables overwriting existing binaries. Thus you can reinstall a crate with
`cargo install --force <crate>`.

Omitting the <crate> specification entirely will
install the crate in the current directory. That is, `install` is equivalent to
the more explicit `install --path .`.  This behaviour is deprecated, and no
longer supported as of the Rust 2018 edition.

If the source is crates.io or `--git` then by default the crate will be built
in a temporary target directory.  To avoid this, the target directory can be
specified by setting the `CARGO_TARGET_DIR` environment variable to a relative
path.  In particular, this can be useful for caching build artifacts on
continuous integration systems.",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    config.reload_rooted_at_cargo_home()?;
    let mut compile_opts = args.compile_options(config, CompileMode::Build)?;

    compile_opts.build_config.release = !args.is_present("debug");

    let krates = args.values_of("crate")
        .unwrap_or_default()
        .collect::<Vec<_>>();

    let mut from_cwd = false;

    let source = if let Some(url) = args.value_of("git") {
        let url = url.to_url()?;
        let gitref = if let Some(branch) = args.value_of("branch") {
            GitReference::Branch(branch.to_string())
        } else if let Some(tag) = args.value_of("tag") {
            GitReference::Tag(tag.to_string())
        } else if let Some(rev) = args.value_of("rev") {
            GitReference::Rev(rev.to_string())
        } else {
            GitReference::Branch("master".to_string())
        };
        SourceId::for_git(&url, gitref)?
    } else if let Some(path) = args.value_of_path("path", config) {
        SourceId::for_path(&path)?
    } else if krates.is_empty() {
        from_cwd = true;
        SourceId::for_path(config.cwd())?
    } else {
        SourceId::crates_io(config)?
    };

    let version = args.value_of("version");
    let root = args.value_of("root");

    if args.is_present("list") {
        ops::install_list(root, config)?;
    } else {
        ops::install(
            root,
            krates,
            &source,
            from_cwd,
            version,
            &compile_opts,
            args.is_present("force"),
        )?;
    }
    Ok(())
}
<commit_msg>Auto merge of #6128 - cswindle:install-registry, r=alexcrichton<commit_after>use command_prelude::*;

use cargo::core::{GitReference, SourceId};
use cargo::ops;
use cargo::util::ToUrl;

pub fn cli() -> App {
    subcommand("install")
        .about("Install a Rust binary")
        .arg(Arg::with_name("crate").empty_values(false).multiple(true))
        .arg(
            opt("version", "Specify a version to install from crates.io")
                .alias("vers")
                .value_name("VERSION"),
        )
        .arg(opt("git", "Git URL to install the specified crate from").value_name("URL"))
        .arg(opt("branch", "Branch to use when installing from git").value_name("BRANCH"))
        .arg(opt("tag", "Tag to use when installing from git").value_name("TAG"))
        .arg(opt("rev", "Specific commit to use when installing from git").value_name("SHA"))
        .arg(opt("path", "Filesystem path to local crate to install").value_name("PATH"))
        .arg(opt(
            "list",
            "list all installed packages and their versions",
        ))
        .arg_jobs()
        .arg(opt("force", "Force overwriting existing crates or binaries").short("f"))
        .arg_features()
        .arg(opt("debug", "Build in debug mode instead of release mode"))
        .arg_targets_bins_examples(
            "Install only the specified binary",
            "Install all binaries",
            "Install only the specified example",
            "Install all examples",
        )
        .arg_target_triple("Build for the target triple")
        .arg(opt("root", "Directory to install packages into").value_name("DIR"))
        .arg(opt("registry", "Registry to use").value_name("REGISTRY"))
        .after_help(
            "\
This command manages Cargo's local set of installed binary crates. Only packages
which have [[bin]] targets can be installed, and all binaries are installed into
the installation root's `bin` folder. The installation root is determined, in
order of precedence, by `--root`, `$CARGO_INSTALL_ROOT`, the `install.root`
configuration key, and finally the home directory (which is either
`$CARGO_HOME` if set or `$HOME/.cargo` by default).

There are multiple sources from which a crate can be installed. The default
location is crates.io but the `--git` and `--path` flags can change this source.
If the source contains more than one package (such as crates.io or a git
repository with multiple crates) the `<crate>` argument is required to indicate
which crate should be installed.

Crates from crates.io can optionally specify the version they wish to install
via the `--vers` flags, and similarly packages from git repositories can
optionally specify the branch, tag, or revision that should be installed. If a
crate has multiple binaries, the `--bin` argument can selectively install only
one of them, and if you'd rather install examples the `--example` argument can
be used as well.

By default cargo will refuse to overwrite existing binaries. The `--force` flag
enables overwriting existing binaries. Thus you can reinstall a crate with
`cargo install --force <crate>`.

Omitting the <crate> specification entirely will
install the crate in the current directory. That is, `install` is equivalent to
the more explicit `install --path .`.  This behaviour is deprecated, and no
longer supported as of the Rust 2018 edition.

If the source is crates.io or `--git` then by default the crate will be built
in a temporary target directory.  To avoid this, the target directory can be
specified by setting the `CARGO_TARGET_DIR` environment variable to a relative
path.  In particular, this can be useful for caching build artifacts on
continuous integration systems.",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let registry = args.registry(config)?;

    config.reload_rooted_at_cargo_home()?;
    let mut compile_opts = args.compile_options(config, CompileMode::Build)?;

    compile_opts.build_config.release = !args.is_present("debug");

    let krates = args.values_of("crate")
        .unwrap_or_default()
        .collect::<Vec<_>>();

    let mut from_cwd = false;

    let source = if let Some(url) = args.value_of("git") {
        let url = url.to_url()?;
        let gitref = if let Some(branch) = args.value_of("branch") {
            GitReference::Branch(branch.to_string())
        } else if let Some(tag) = args.value_of("tag") {
            GitReference::Tag(tag.to_string())
        } else if let Some(rev) = args.value_of("rev") {
            GitReference::Rev(rev.to_string())
        } else {
            GitReference::Branch("master".to_string())
        };
        SourceId::for_git(&url, gitref)?
    } else if let Some(path) = args.value_of_path("path", config) {
        SourceId::for_path(&path)?
    } else if krates.is_empty() {
        from_cwd = true;
        SourceId::for_path(config.cwd())?
    } else if let Some(registry) = registry {
        SourceId::alt_registry(config, &registry)?
    } else {
        SourceId::crates_io(config)?
    };

    let version = args.value_of("version");
    let root = args.value_of("root");

    if args.is_present("list") {
        ops::install_list(root, config)?;
    } else {
        ops::install(
            root,
            krates,
            &source,
            from_cwd,
            version,
            &compile_opts,
            args.is_present("force"),
        )?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// revisions: ast mir
//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir

enum Sexpression {
    Num(()),
    Cons(&'static mut Sexpression)
}

fn causes_ice(mut l: &mut Sexpression) {
    loop { match l {
        &mut Sexpression::Num(ref mut n) => {}, //[mir]~ ERROR (Mir) [E0384]
        &mut Sexpression::Cons(ref mut expr) => { //[ast]~ ERROR [E0499]
                                                  //[mir]~^ ERROR (Ast) [E0499]
                                                  //[mir]~| ERROR (Mir) [E0506]
                                                  //[mir]~| ERROR (Mir) [E0384]
                                                  //[mir]~| ERROR (Mir) [E0499]
            l = &mut **expr; //[ast]~ ERROR [E0506]
                             //[mir]~^ ERROR (Ast) [E0506]
                             //[mir]~| ERROR (Mir) [E0506]
                             //[mir]~| ERROR (Mir) [E0506]
                             //[mir]~| ERROR (Mir) [E0499]
                             //[mir]~| ERROR (Mir) [E0499]
        }
    }}
}

fn main() {
}
<commit_msg>fix test<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// revisions: ast mir
//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir

enum Sexpression {
    Num(()),
    Cons(&'static mut Sexpression)
}

fn causes_ice(mut l: &mut Sexpression) {
    loop { match l {
        &mut Sexpression::Num(ref mut n) => {},
        &mut Sexpression::Cons(ref mut expr) => { //[ast]~ ERROR [E0499]
                                                  //[mir]~^ ERROR (Ast) [E0499]
                                                  //[mir]~| ERROR (Mir) [E0506]
                                                  //[mir]~| ERROR (Mir) [E0499]
            l = &mut **expr; //[ast]~ ERROR [E0506]
                             //[mir]~^ ERROR (Ast) [E0506]
                             //[mir]~| ERROR (Mir) [E0506]
                             //[mir]~| ERROR (Mir) [E0506]
                             //[mir]~| ERROR (Mir) [E0499]
                             //[mir]~| ERROR (Mir) [E0499]
        }
    }}
}

fn main() {
}
<|endoftext|>


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

use std::{
    clone::Clone,
    collections::HashMap,
    path::{Path, PathBuf},
};

use libudev;

use devicemapper::{Device, DmNameBuf};

#[cfg(test)]
use crate::engine::strat_engine::cleanup::teardown_pools;

use crate::{
    engine::{
        engine::Eventable,
        event::get_engine_listener_list,
        shared::create_pool_idempotent_or_err,
        strat_engine::{
            backstore::{find_all, get_metadata, identify_block_device},
            cmd::verify_binaries,
            devlinks,
            dm::{get_dm, get_dm_init},
            names::validate_name,
            pool::StratPool,
        },
        structures::Table,
        types::{CreateAction, DeleteAction, RenameAction},
        Engine, EngineEvent, Name, Pool, PoolUuid,
    },
    stratis::{ErrorEnum, StratisError, StratisResult},
};

const REQUIRED_DM_MINOR_VERSION: u32 = 37;

#[derive(Debug)]
pub struct StratEngine {
    pools: Table<StratPool>,

    // Map of stratis devices that have been found but one or more stratis block devices are missing
    // which prevents the associated pools from being setup.
    incomplete_pools: HashMap<PoolUuid, HashMap<Device, PathBuf>>,

    // Maps name of DM devices we are watching to the most recent event number
    // we've handled for each
    watched_dev_last_event_nrs: HashMap<DmNameBuf, u32>,
}

impl StratEngine {
    /// Setup a StratEngine.
    /// 1. Verify the existence of Stratis /dev directory.
    /// 2. Setup all the pools belonging to the engine.
    ///    a. Places any devices which belong to a pool, but are not complete
    ///       in the incomplete pools data structure.
    ///
    /// Returns an error if the kernel doesn't support required DM features.
    /// Returns an error if there was an error reading device nodes.
    /// Returns an error if the binaries on which it depends can not be found.
    pub fn initialize() -> StratisResult<StratEngine> {
        let dm = get_dm_init()?;
        verify_binaries()?;
        let minor_dm_version = dm.version()?.1;
        if minor_dm_version < REQUIRED_DM_MINOR_VERSION {
            let err_msg = format!(
                "Requires DM minor version {} but kernel only supports {}",
                REQUIRED_DM_MINOR_VERSION, minor_dm_version
            );
            return Err(StratisError::Engine(ErrorEnum::Error, err_msg));
        }

        devlinks::setup_dev_path()?;

        let mut engine = StratEngine {
            pools: Table::default(),
            incomplete_pools: HashMap::new(),
            watched_dev_last_event_nrs: HashMap::new(),
        };

        for (pool_uuid, devices) in find_all()? {
            engine.try_setup_pool(pool_uuid, devices);
        }

        devlinks::cleanup_devlinks(engine.pools().iter());

        Ok(engine)
    }

    // Given a set of devices, try to set up a pool. If the setup fails,
    // insert the devices into incomplete_pools.
    fn try_setup_pool(&mut self, pool_uuid: PoolUuid, devices: HashMap<Device, PathBuf>) {
        /// Setup a pool from constituent devices in the context of some already
        /// setup pools. Return an error on anything that prevents the pool
        /// being set up.
        /// Precondition: every device in devices has already been determined to belong
        /// to the pool with pool_uuid.
        fn setup_pool(
            pool_uuid: PoolUuid,
            devices: &HashMap<Device, PathBuf>,
            pools: &Table<StratPool>,
        ) -> StratisResult<(Name, StratPool)> {
            // FIXME: In this method, various errors are assembled from various
            // sources and combined into strings, so that they
            // can be printed as log messages if necessary. Instead, some kind of
            // error-chaining should be used here and if it is necessary
            // to log the error, the log code should be able to reduce the error
            // chain to something that can be sensibly logged.
            let info_string = || {
                let dev_paths = devices
                    .values()
                    .map(|p| p.to_str().expect("Unix is utf-8"))
                    .collect::<Vec<&str>>()
                    .join(" ,");
                format!("(pool UUID: {}, devnodes: {})", pool_uuid, dev_paths)
            };

            let (timestamp, metadata) = get_metadata(pool_uuid, devices)?.ok_or_else(|| {
                let err_msg = format!("no metadata found for {}", info_string());
                StratisError::Engine(ErrorEnum::NotFound, err_msg)
            })?;

            if pools.contains_name(&metadata.name) {
                let err_msg = format!(
                    "pool with name \"{}\" set up; metadata specifies same name for {}",
                    &metadata.name,
                    info_string()
                );
                return Err(StratisError::Engine(ErrorEnum::AlreadyExists, err_msg));
            }

            StratPool::setup(pool_uuid, devices, timestamp, &metadata)
                .or_else(|e| {
                    let err_msg = format!(
                        "failed to set up pool for {}: reason: {:?}",
                        info_string(),
                        e
                    );
                    Err(StratisError::Engine(ErrorEnum::Error, err_msg))
                })
                .and_then(|(pool_name, pool)| {
                    devlinks::setup_pool_devlinks(&pool_name, &pool);
                    Ok((pool_name, pool))
                })
        }

        match setup_pool(pool_uuid, &devices, &self.pools) {
            Ok((pool_name, pool)) => {
                self.pools.insert(pool_name, pool_uuid, pool);
            }
            Err(err) => {
                warn!("no pool set up, reason: {:?}", err);
                self.incomplete_pools.insert(pool_uuid, devices);
            }
        }
    }

    /// Teardown Stratis, preparatory to a shutdown.
    #[cfg(test)]
    pub fn teardown(self) -> StratisResult<()> {
        teardown_pools(self.pools)
    }

    /// Given a udev database entry, process the entry.
    ///
    /// If all the devices are present in the pool and the pool isn't already
    /// up and running, it will get setup and the newly created pool and UUID
    /// will be returned.
    ///
    /// Logs a warning if the block devices appears to be a Stratis block
    /// device and no pool is set up.
    fn block_evaluate(&mut self, device: &libudev::Device) -> Option<(PoolUuid, &mut dyn Pool)> {
        identify_block_device(device).and_then(move |(pool_uuid, _, device, dev_node)| {
            if self.pools.contains_uuid(pool_uuid) {
                None
            } else {
                let mut devices = self
                    .incomplete_pools
                    .remove(&pool_uuid)
                    .unwrap_or_else(HashMap::new);
                devices.insert(device, dev_node);
                self.try_setup_pool(pool_uuid, devices);
                self.pools
                    .get_mut_by_uuid(pool_uuid)
                    .map(|(_, pool)| (pool_uuid, pool as &mut dyn Pool))
            }
        })
    }
}

impl Engine for StratEngine {
    fn handle_event(&mut self, event: &libudev::Event) -> Option<(PoolUuid, &mut dyn Pool)> {
        let event_type = event.event_type();
        if event_type == libudev::EventType::Add || event_type == libudev::EventType::Change {
            self.block_evaluate(event.device())
        } else {
            None
        }
    }

    fn create_pool(
        &mut self,
        name: &str,
        blockdev_paths: &[&Path],
        redundancy: Option<u16>,
    ) -> StratisResult<CreateAction<PoolUuid>> {
        let redundancy = calculate_redundancy!(redundancy);

        validate_name(name)?;

        match self.pools.get_by_name(name) {
            Some((_, pool)) => create_pool_idempotent_or_err(pool, name, blockdev_paths),
            None => {
                let (uuid, pool) = StratPool::initialize(name, blockdev_paths, redundancy)?;

                let name = Name::new(name.to_owned());
                devlinks::pool_added(&name);
                self.pools.insert(name, uuid, pool);
                Ok(CreateAction::Created(uuid))
            }
        }
    }

    fn destroy_pool(&mut self, uuid: PoolUuid) -> StratisResult<DeleteAction<PoolUuid>> {
        if let Some((_, pool)) = self.pools.get_by_uuid(uuid) {
            if pool.has_filesystems() {
                return Err(StratisError::Engine(
                    ErrorEnum::Busy,
                    "filesystems remaining on pool".into(),
                ));
            };
        } else {
            return Ok(DeleteAction::Identity);
        }

        let (pool_name, mut pool) = self
            .pools
            .remove_by_uuid(uuid)
            .expect("Must succeed since self.pools.get_by_uuid() returned a value");

        if let Err(err) = pool.destroy() {
            self.pools.insert(pool_name, uuid, pool);
            Err(err)
        } else {
            devlinks::pool_removed(&pool_name);
            Ok(DeleteAction::Deleted(uuid))
        }
    }

    fn rename_pool(
        &mut self,
        uuid: PoolUuid,
        new_name: &str,
    ) -> StratisResult<RenameAction<PoolUuid>> {
        validate_name(new_name)?;
        let old_name = rename_pool_pre_idem!(self; uuid; new_name);

        let (_, mut pool) = self
            .pools
            .remove_by_uuid(uuid)
            .expect("Must succeed since self.pools.get_by_uuid() returned a value");

        let new_name = Name::new(new_name.to_owned());
        if let Err(err) = pool.write_metadata(&new_name) {
            self.pools.insert(old_name, uuid, pool);
            Err(err)
        } else {
            get_engine_listener_list().notify(&EngineEvent::PoolRenamed {
                dbus_path: pool.get_dbus_path(),
                from: &*old_name,
                to: &*new_name,
            });

            self.pools.insert(new_name.clone(), uuid, pool);
            devlinks::pool_renamed(&old_name, &new_name);
            Ok(RenameAction::Renamed(uuid))
        }
    }

    fn get_pool(&self, uuid: PoolUuid) -> Option<(Name, &dyn Pool)> {
        get_pool!(self; uuid)
    }

    fn get_mut_pool(&mut self, uuid: PoolUuid) -> Option<(Name, &mut dyn Pool)> {
        get_mut_pool!(self; uuid)
    }

    fn configure_simulator(&mut self, _denominator: u32) -> StratisResult<()> {
        Ok(()) // we're not the simulator and not configurable, so just say ok
    }

    fn pools(&self) -> Vec<(Name, PoolUuid, &dyn Pool)> {
        self.pools
            .iter()
            .map(|(name, uuid, pool)| (name.clone(), *uuid, pool as &dyn Pool))
            .collect()
    }

    fn pools_mut(&mut self) -> Vec<(Name, PoolUuid, &mut dyn Pool)> {
        self.pools
            .iter_mut()
            .map(|(name, uuid, pool)| (name.clone(), *uuid, pool as &mut dyn Pool))
            .collect()
    }

    fn get_eventable(&self) -> Option<&'static dyn Eventable> {
        Some(get_dm())
    }

    fn evented(&mut self) -> StratisResult<()> {
        let device_list: HashMap<_, _> = get_dm()
            .list_devices()?
            .into_iter()
            .map(|(dm_name, _, event_nr)| {
                (
                    dm_name,
                    event_nr.expect("Supported DM versions always provide a value"),
                )
            })
            .collect();

        for (pool_name, pool_uuid, pool) in &mut self.pools {
            for dm_name in pool.get_eventing_dev_names(*pool_uuid) {
                if device_list.get(&dm_name) > self.watched_dev_last_event_nrs.get(&dm_name) {
                    pool.event_on(*pool_uuid, pool_name, &dm_name)?;
                }
            }
        }

        self.watched_dev_last_event_nrs = device_list;

        Ok(())
    }
}

#[cfg(test)]
mod test {
    use std::fs::remove_dir_all;

    use crate::engine::engine::DEV_PATH;

    use crate::engine::strat_engine::tests::{loopbacked, real};

    use crate::engine::types::EngineAction;

    use super::*;

    /// Verify that a pool rename causes the pool metadata to get the new name.
    fn test_pool_rename(paths: &[&Path]) {
        let mut engine = StratEngine::initialize().unwrap();

        let name1 = "name1";
        let uuid1 = engine
            .create_pool(name1, paths, None)
            .unwrap()
            .changed()
            .unwrap();

        let name2 = "name2";
        let action = engine.rename_pool(uuid1, name2).unwrap();

        assert_eq!(action, RenameAction::Renamed(uuid1));
        engine.teardown().unwrap();

        let engine = StratEngine::initialize().unwrap();
        let pool_name: String = engine.get_pool(uuid1).unwrap().0.to_owned();
        assert_eq!(pool_name, name2);
    }

    #[test]
    pub fn loop_test_pool_rename() {
        loopbacked::test_with_spec(
            &loopbacked::DeviceLimits::Range(1, 3, None),
            test_pool_rename,
        );
    }

    #[test]
    pub fn real_test_pool_rename() {
        real::test_with_spec(
            &real::DeviceLimits::AtLeast(1, None, None),
            test_pool_rename,
        );
    }

    /// Test engine setup.
    /// 1. Create two pools.
    /// 2. Verify that both exist.
    /// 3. Teardown the engine.
    /// 4. Initialize the engine.
    /// 5. Verify that pools can be found again.
    /// 6. Teardown the engine and remove "/stratis".
    /// 7. Initialize the engine one more time.
    /// 8. Verify that both pools are found and that there are no incomplete pools.
    fn test_setup(paths: &[&Path]) {
        assert!(paths.len() > 1);

        let (paths1, paths2) = paths.split_at(paths.len() / 2);

        let mut engine = StratEngine::initialize().unwrap();

        let name1 = "name1";
        let uuid1 = engine
            .create_pool(name1, paths1, None)
            .unwrap()
            .changed()
            .unwrap();

        let name2 = "name2";
        let uuid2 = engine
            .create_pool(name2, paths2, None)
            .unwrap()
            .changed()
            .unwrap();

        assert!(engine.get_pool(uuid1).is_some());
        assert!(engine.get_pool(uuid2).is_some());

        engine.teardown().unwrap();

        let engine = StratEngine::initialize().unwrap();

        assert!(engine.get_pool(uuid1).is_some());
        assert!(engine.get_pool(uuid2).is_some());

        engine.teardown().unwrap();
        remove_dir_all(DEV_PATH).unwrap();

        let engine = StratEngine::initialize().unwrap();
        assert_eq!(engine.incomplete_pools, HashMap::new());

        assert!(engine.get_pool(uuid1).is_some());
        assert!(engine.get_pool(uuid2).is_some());

        engine.teardown().unwrap();
    }

    #[test]
    pub fn loop_test_setup() {
        loopbacked::test_with_spec(&loopbacked::DeviceLimits::Range(2, 3, None), test_setup);
    }

    #[test]
    pub fn real_test_setup() {
        real::test_with_spec(&real::DeviceLimits::AtLeast(2, None, None), test_setup);
    }
}
<commit_msg>Move devlinks setup to the part where the action is done<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::{
    clone::Clone,
    collections::HashMap,
    path::{Path, PathBuf},
};

use libudev;

use devicemapper::{Device, DmNameBuf};

#[cfg(test)]
use crate::engine::strat_engine::cleanup::teardown_pools;

use crate::{
    engine::{
        engine::Eventable,
        event::get_engine_listener_list,
        shared::create_pool_idempotent_or_err,
        strat_engine::{
            backstore::{find_all, get_metadata, identify_block_device},
            cmd::verify_binaries,
            devlinks,
            dm::{get_dm, get_dm_init},
            names::validate_name,
            pool::StratPool,
        },
        structures::Table,
        types::{CreateAction, DeleteAction, RenameAction},
        Engine, EngineEvent, Name, Pool, PoolUuid,
    },
    stratis::{ErrorEnum, StratisError, StratisResult},
};

const REQUIRED_DM_MINOR_VERSION: u32 = 37;

#[derive(Debug)]
pub struct StratEngine {
    pools: Table<StratPool>,

    // Map of stratis devices that have been found but one or more stratis block devices are missing
    // which prevents the associated pools from being setup.
    incomplete_pools: HashMap<PoolUuid, HashMap<Device, PathBuf>>,

    // Maps name of DM devices we are watching to the most recent event number
    // we've handled for each
    watched_dev_last_event_nrs: HashMap<DmNameBuf, u32>,
}

impl StratEngine {
    /// Setup a StratEngine.
    /// 1. Verify the existence of Stratis /dev directory.
    /// 2. Setup all the pools belonging to the engine.
    ///    a. Places any devices which belong to a pool, but are not complete
    ///       in the incomplete pools data structure.
    ///
    /// Returns an error if the kernel doesn't support required DM features.
    /// Returns an error if there was an error reading device nodes.
    /// Returns an error if the binaries on which it depends can not be found.
    pub fn initialize() -> StratisResult<StratEngine> {
        let dm = get_dm_init()?;
        verify_binaries()?;
        let minor_dm_version = dm.version()?.1;
        if minor_dm_version < REQUIRED_DM_MINOR_VERSION {
            let err_msg = format!(
                "Requires DM minor version {} but kernel only supports {}",
                REQUIRED_DM_MINOR_VERSION, minor_dm_version
            );
            return Err(StratisError::Engine(ErrorEnum::Error, err_msg));
        }

        devlinks::setup_dev_path()?;

        let mut engine = StratEngine {
            pools: Table::default(),
            incomplete_pools: HashMap::new(),
            watched_dev_last_event_nrs: HashMap::new(),
        };

        for (pool_uuid, devices) in find_all()? {
            engine.try_setup_pool(pool_uuid, devices);
        }

        devlinks::cleanup_devlinks(engine.pools().iter());

        Ok(engine)
    }

    // Given a set of devices, try to set up a pool. If the setup fails,
    // insert the devices into incomplete_pools.
    fn try_setup_pool(&mut self, pool_uuid: PoolUuid, devices: HashMap<Device, PathBuf>) {
        /// Setup a pool from constituent devices in the context of some already
        /// setup pools. Return an error on anything that prevents the pool
        /// being set up.
        /// Precondition: every device in devices has already been determined to belong
        /// to the pool with pool_uuid.
        fn setup_pool(
            pool_uuid: PoolUuid,
            devices: &HashMap<Device, PathBuf>,
            pools: &Table<StratPool>,
        ) -> StratisResult<(Name, StratPool)> {
            // FIXME: In this method, various errors are assembled from various
            // sources and combined into strings, so that they
            // can be printed as log messages if necessary. Instead, some kind of
            // error-chaining should be used here and if it is necessary
            // to log the error, the log code should be able to reduce the error
            // chain to something that can be sensibly logged.
            let info_string = || {
                let dev_paths = devices
                    .values()
                    .map(|p| p.to_str().expect("Unix is utf-8"))
                    .collect::<Vec<&str>>()
                    .join(" ,");
                format!("(pool UUID: {}, devnodes: {})", pool_uuid, dev_paths)
            };

            let (timestamp, metadata) = get_metadata(pool_uuid, devices)?.ok_or_else(|| {
                let err_msg = format!("no metadata found for {}", info_string());
                StratisError::Engine(ErrorEnum::NotFound, err_msg)
            })?;

            if pools.contains_name(&metadata.name) {
                let err_msg = format!(
                    "pool with name \"{}\" set up; metadata specifies same name for {}",
                    &metadata.name,
                    info_string()
                );
                return Err(StratisError::Engine(ErrorEnum::AlreadyExists, err_msg));
            }

            StratPool::setup(pool_uuid, devices, timestamp, &metadata).or_else(|e| {
                let err_msg = format!(
                    "failed to set up pool for {}: reason: {:?}",
                    info_string(),
                    e
                );
                Err(StratisError::Engine(ErrorEnum::Error, err_msg))
            })
        }

        match setup_pool(pool_uuid, &devices, &self.pools) {
            Ok((pool_name, pool)) => {
                devlinks::setup_pool_devlinks(&pool_name, &pool);
                self.pools.insert(pool_name, pool_uuid, pool);
            }
            Err(err) => {
                warn!("no pool set up, reason: {:?}", err);
                self.incomplete_pools.insert(pool_uuid, devices);
            }
        }
    }

    /// Teardown Stratis, preparatory to a shutdown.
    #[cfg(test)]
    pub fn teardown(self) -> StratisResult<()> {
        teardown_pools(self.pools)
    }

    /// Given a udev database entry, process the entry.
    ///
    /// If all the devices are present in the pool and the pool isn't already
    /// up and running, it will get setup and the newly created pool and UUID
    /// will be returned.
    ///
    /// Logs a warning if the block devices appears to be a Stratis block
    /// device and no pool is set up.
    fn block_evaluate(&mut self, device: &libudev::Device) -> Option<(PoolUuid, &mut dyn Pool)> {
        identify_block_device(device).and_then(move |(pool_uuid, _, device, dev_node)| {
            if self.pools.contains_uuid(pool_uuid) {
                None
            } else {
                let mut devices = self
                    .incomplete_pools
                    .remove(&pool_uuid)
                    .unwrap_or_else(HashMap::new);
                devices.insert(device, dev_node);
                self.try_setup_pool(pool_uuid, devices);
                self.pools
                    .get_mut_by_uuid(pool_uuid)
                    .map(|(_, pool)| (pool_uuid, pool as &mut dyn Pool))
            }
        })
    }
}

impl Engine for StratEngine {
    fn handle_event(&mut self, event: &libudev::Event) -> Option<(PoolUuid, &mut dyn Pool)> {
        let event_type = event.event_type();
        if event_type == libudev::EventType::Add || event_type == libudev::EventType::Change {
            self.block_evaluate(event.device())
        } else {
            None
        }
    }

    fn create_pool(
        &mut self,
        name: &str,
        blockdev_paths: &[&Path],
        redundancy: Option<u16>,
    ) -> StratisResult<CreateAction<PoolUuid>> {
        let redundancy = calculate_redundancy!(redundancy);

        validate_name(name)?;

        match self.pools.get_by_name(name) {
            Some((_, pool)) => create_pool_idempotent_or_err(pool, name, blockdev_paths),
            None => {
                let (uuid, pool) = StratPool::initialize(name, blockdev_paths, redundancy)?;

                let name = Name::new(name.to_owned());
                devlinks::pool_added(&name);
                self.pools.insert(name, uuid, pool);
                Ok(CreateAction::Created(uuid))
            }
        }
    }

    fn destroy_pool(&mut self, uuid: PoolUuid) -> StratisResult<DeleteAction<PoolUuid>> {
        if let Some((_, pool)) = self.pools.get_by_uuid(uuid) {
            if pool.has_filesystems() {
                return Err(StratisError::Engine(
                    ErrorEnum::Busy,
                    "filesystems remaining on pool".into(),
                ));
            };
        } else {
            return Ok(DeleteAction::Identity);
        }

        let (pool_name, mut pool) = self
            .pools
            .remove_by_uuid(uuid)
            .expect("Must succeed since self.pools.get_by_uuid() returned a value");

        if let Err(err) = pool.destroy() {
            self.pools.insert(pool_name, uuid, pool);
            Err(err)
        } else {
            devlinks::pool_removed(&pool_name);
            Ok(DeleteAction::Deleted(uuid))
        }
    }

    fn rename_pool(
        &mut self,
        uuid: PoolUuid,
        new_name: &str,
    ) -> StratisResult<RenameAction<PoolUuid>> {
        validate_name(new_name)?;
        let old_name = rename_pool_pre_idem!(self; uuid; new_name);

        let (_, mut pool) = self
            .pools
            .remove_by_uuid(uuid)
            .expect("Must succeed since self.pools.get_by_uuid() returned a value");

        let new_name = Name::new(new_name.to_owned());
        if let Err(err) = pool.write_metadata(&new_name) {
            self.pools.insert(old_name, uuid, pool);
            Err(err)
        } else {
            get_engine_listener_list().notify(&EngineEvent::PoolRenamed {
                dbus_path: pool.get_dbus_path(),
                from: &*old_name,
                to: &*new_name,
            });

            self.pools.insert(new_name.clone(), uuid, pool);
            devlinks::pool_renamed(&old_name, &new_name);
            Ok(RenameAction::Renamed(uuid))
        }
    }

    fn get_pool(&self, uuid: PoolUuid) -> Option<(Name, &dyn Pool)> {
        get_pool!(self; uuid)
    }

    fn get_mut_pool(&mut self, uuid: PoolUuid) -> Option<(Name, &mut dyn Pool)> {
        get_mut_pool!(self; uuid)
    }

    fn configure_simulator(&mut self, _denominator: u32) -> StratisResult<()> {
        Ok(()) // we're not the simulator and not configurable, so just say ok
    }

    fn pools(&self) -> Vec<(Name, PoolUuid, &dyn Pool)> {
        self.pools
            .iter()
            .map(|(name, uuid, pool)| (name.clone(), *uuid, pool as &dyn Pool))
            .collect()
    }

    fn pools_mut(&mut self) -> Vec<(Name, PoolUuid, &mut dyn Pool)> {
        self.pools
            .iter_mut()
            .map(|(name, uuid, pool)| (name.clone(), *uuid, pool as &mut dyn Pool))
            .collect()
    }

    fn get_eventable(&self) -> Option<&'static dyn Eventable> {
        Some(get_dm())
    }

    fn evented(&mut self) -> StratisResult<()> {
        let device_list: HashMap<_, _> = get_dm()
            .list_devices()?
            .into_iter()
            .map(|(dm_name, _, event_nr)| {
                (
                    dm_name,
                    event_nr.expect("Supported DM versions always provide a value"),
                )
            })
            .collect();

        for (pool_name, pool_uuid, pool) in &mut self.pools {
            for dm_name in pool.get_eventing_dev_names(*pool_uuid) {
                if device_list.get(&dm_name) > self.watched_dev_last_event_nrs.get(&dm_name) {
                    pool.event_on(*pool_uuid, pool_name, &dm_name)?;
                }
            }
        }

        self.watched_dev_last_event_nrs = device_list;

        Ok(())
    }
}

#[cfg(test)]
mod test {
    use std::fs::remove_dir_all;

    use crate::engine::engine::DEV_PATH;

    use crate::engine::strat_engine::tests::{loopbacked, real};

    use crate::engine::types::EngineAction;

    use super::*;

    /// Verify that a pool rename causes the pool metadata to get the new name.
    fn test_pool_rename(paths: &[&Path]) {
        let mut engine = StratEngine::initialize().unwrap();

        let name1 = "name1";
        let uuid1 = engine
            .create_pool(name1, paths, None)
            .unwrap()
            .changed()
            .unwrap();

        let name2 = "name2";
        let action = engine.rename_pool(uuid1, name2).unwrap();

        assert_eq!(action, RenameAction::Renamed(uuid1));
        engine.teardown().unwrap();

        let engine = StratEngine::initialize().unwrap();
        let pool_name: String = engine.get_pool(uuid1).unwrap().0.to_owned();
        assert_eq!(pool_name, name2);
    }

    #[test]
    pub fn loop_test_pool_rename() {
        loopbacked::test_with_spec(
            &loopbacked::DeviceLimits::Range(1, 3, None),
            test_pool_rename,
        );
    }

    #[test]
    pub fn real_test_pool_rename() {
        real::test_with_spec(
            &real::DeviceLimits::AtLeast(1, None, None),
            test_pool_rename,
        );
    }

    /// Test engine setup.
    /// 1. Create two pools.
    /// 2. Verify that both exist.
    /// 3. Teardown the engine.
    /// 4. Initialize the engine.
    /// 5. Verify that pools can be found again.
    /// 6. Teardown the engine and remove "/stratis".
    /// 7. Initialize the engine one more time.
    /// 8. Verify that both pools are found and that there are no incomplete pools.
    fn test_setup(paths: &[&Path]) {
        assert!(paths.len() > 1);

        let (paths1, paths2) = paths.split_at(paths.len() / 2);

        let mut engine = StratEngine::initialize().unwrap();

        let name1 = "name1";
        let uuid1 = engine
            .create_pool(name1, paths1, None)
            .unwrap()
            .changed()
            .unwrap();

        let name2 = "name2";
        let uuid2 = engine
            .create_pool(name2, paths2, None)
            .unwrap()
            .changed()
            .unwrap();

        assert!(engine.get_pool(uuid1).is_some());
        assert!(engine.get_pool(uuid2).is_some());

        engine.teardown().unwrap();

        let engine = StratEngine::initialize().unwrap();

        assert!(engine.get_pool(uuid1).is_some());
        assert!(engine.get_pool(uuid2).is_some());

        engine.teardown().unwrap();
        remove_dir_all(DEV_PATH).unwrap();

        let engine = StratEngine::initialize().unwrap();
        assert_eq!(engine.incomplete_pools, HashMap::new());

        assert!(engine.get_pool(uuid1).is_some());
        assert!(engine.get_pool(uuid2).is_some());

        engine.teardown().unwrap();
    }

    #[test]
    pub fn loop_test_setup() {
        loopbacked::test_with_spec(&loopbacked::DeviceLimits::Range(2, 3, None), test_setup);
    }

    #[test]
    pub fn real_test_setup() {
        real::test_with_spec(&real::DeviceLimits::AtLeast(2, None, None), test_setup);
    }
}
<|endoftext|>


<commit_before>use ::quote::Tokens;
use ::syn::Ident;
use ::yaml_rust::Yaml;

use infer::datatype;
use infer::TokensResult;

const UNKNOWN_ERR_CODE: u16 = 520;

fn parse_response_key(key: &Yaml) -> (u16, String) {
    match key.as_i64() {
        Some(code) => (code as u16, format!("Status{}", code)),
        None => (UNKNOWN_ERR_CODE, format!("Status{}", UNKNOWN_ERR_CODE)),
    }
}

pub(super) fn infer_v3(enum_idents: &(Ident, Ident), schema: &Yaml) -> TokensResult {
    let (ref success_en, ref error_en) = *enum_idents;
    let borrow = quote!(#[serde(borrow)]);

    let mut error_variants: Vec<Ident> = Vec::new();
    let mut error_models: Vec<Tokens> = Vec::new();
    let mut error_lifetime = quote!();
    let mut success_variants: Vec<Ident> = Vec::new();
    let mut success_models: Vec<Tokens> = Vec::new();
    let mut success_lifetime = quote!();
    let mut additional_types: Vec<Tokens> = Vec::new();

    for (code, schema) in schema.as_hash()
        .expect("Responses must be a map.")
    {
        let schema = &schema["content"]["application/json"]["schema"];
        schema.as_hash().expect("Only application/json responses are supported.");

        let (status_code, status_str) = parse_response_key(&code);
        let variant_ident = Ident::new(status_str);
        let (inferred_type, has_lifetime, additional_type) = datatype::infer_v3(&schema)?;

        if let Some(t) = additional_type {
            additional_types.push(t);
        }

        if status_code < 400 {
            success_variants.push(variant_ident);

            if has_lifetime {
                success_lifetime = quote!('a);
                success_models.push(quote!{ #borrow #inferred_type });
            } else {
                success_models.push(inferred_type);
            }
        } else {
            error_variants.push(variant_ident);

            if has_lifetime {
                error_lifetime = quote!('a);
                error_models.push(quote!{ #borrow #inferred_type });
            } else {
                error_models.push(inferred_type);
            }
        }
    }

    Ok(quote! {
        #(
            #[derive(Deserialize)]
            #additional_types
        )*

        #[derive(Deserialize)]
        enum #error_en<#error_lifetime> {
            #(#error_variants(#error_models)),*
        }

        #[derive(Deserialize)]
        enum #success_en<#success_lifetime> {
            #(#success_variants(#success_models)),*
        }
    })
}
<commit_msg>Support contentless responses<commit_after>use ::quote::Tokens;
use ::syn::Ident;
use ::yaml_rust::Yaml;

use infer::datatype;
use infer::TokensResult;

const UNKNOWN_ERR_CODE: u16 = 520;

fn parse_response_key(key: &Yaml) -> (u16, String) {
    match key.as_i64() {
        Some(code) => (code as u16, format!("Status{}", code)),
        None => (UNKNOWN_ERR_CODE, format!("Status{}", UNKNOWN_ERR_CODE)),
    }
}

pub(super) fn infer_v3(enum_idents: &(Ident, Ident), schema: &Yaml) -> TokensResult {
    let (ref success_en, ref error_en) = *enum_idents;
    let borrow = quote!(#[serde(borrow)]);

    let mut error_variants: Vec<Ident> = Vec::new();
    let mut error_models: Vec<Tokens> = Vec::new();
    let mut error_lifetime = quote!();
    let mut success_variants: Vec<Ident> = Vec::new();
    let mut success_models: Vec<Tokens> = Vec::new();
    let mut success_lifetime = quote!();
    let mut additional_types: Vec<Tokens> = Vec::new();

    for (code, schema) in schema.as_hash().expect("Responses must be a map.") {
        let (status_code, status_str) = parse_response_key(&code);
        let variant_ident = Ident::new(status_str);

        let mut inferred_type: Tokens;
        let mut has_lifetime: bool;
        let mut additional_type: Option<Tokens>;

        let schema = &schema["content"]["application/json"]["schema"];
        if let None = schema.as_hash() {
            inferred_type = quote!{ () };
            has_lifetime = false;
            additional_type = None;
        } else {
            let (ty, lt, at) = datatype::infer_v3(&schema)?;
            inferred_type = ty;
            has_lifetime = lt;
            additional_type = at;
        }

        if let Some(t) = additional_type {
            additional_types.push(t);
        }

        if status_code < 400 {
            success_variants.push(variant_ident);

            if has_lifetime {
                success_lifetime = quote!('a);
                success_models.push(quote!{ #borrow #inferred_type });
            } else {
                success_models.push(inferred_type);
            }
        } else {
            error_variants.push(variant_ident);

            if has_lifetime {
                error_lifetime = quote!('a);
                error_models.push(quote!{ #borrow #inferred_type });
            } else {
                error_models.push(inferred_type);
            }
        }
    }

    Ok(quote! {
        #(
            #[derive(Deserialize)]
            #additional_types
        )*

        #[derive(Deserialize)]
        enum #error_en<#error_lifetime> {
            #(#error_variants(#error_models)),*
        }

        #[derive(Deserialize)]
        enum #success_en<#success_lifetime> {
            #(#success_variants(#success_models)),*
        }
    })
}
<|endoftext|>


<commit_before>use itertools::Itertools;

struct PanickingCounter {
    curr: usize,
    max: usize,
}

impl Iterator for PanickingCounter {
    type Item = ();

    fn next(&mut self) -> Option<Self::Item> {
        self.curr += 1;

        if self.curr == self.max {
            panic!(
                "Input iterator reached maximum of {} suggesting collection by adaptor",
                self.max
            );
        }

        Some(())
    }
}

fn no_collect_test<A, T>(to_adaptor: T)
    where A: Iterator, T: Fn(PanickingCounter) -> A
{
    let counter = PanickingCounter { curr: 0, max: 10_000 };
    let adaptor = to_adaptor(counter);

    for _ in adaptor.take(5) {}
}

#[test]
fn permutations_no_collect() {
    no_collect_test(|iter| iter.permutations(5))
}

#[test]
fn combinations_no_collect() {
    no_collect_test(|iter| iter.combinations(5))
}

#[test]
fn combinations_with_replacement_no_collect() {
    no_collect_test(|iter| iter.combinations_with_replacement(5))
}<commit_msg>fix clippy::manual_assert in tests<commit_after>use itertools::Itertools;

struct PanickingCounter {
    curr: usize,
    max: usize,
}

impl Iterator for PanickingCounter {
    type Item = ();

    fn next(&mut self) -> Option<Self::Item> {
        self.curr += 1;

        assert_ne!(
            self.curr, self.max,
            "Input iterator reached maximum of {} suggesting collection by adaptor",
            self.max
        );

        Some(())
    }
}

fn no_collect_test<A, T>(to_adaptor: T)
    where A: Iterator, T: Fn(PanickingCounter) -> A
{
    let counter = PanickingCounter { curr: 0, max: 10_000 };
    let adaptor = to_adaptor(counter);

    for _ in adaptor.take(5) {}
}

#[test]
fn permutations_no_collect() {
    no_collect_test(|iter| iter.permutations(5))
}

#[test]
fn combinations_no_collect() {
    no_collect_test(|iter| iter.combinations(5))
}

#[test]
fn combinations_with_replacement_no_collect() {
    no_collect_test(|iter| iter.combinations_with_replacement(5))
}<|endoftext|>