<commit_before>// Copyright (c) 2019 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! This is the Button server process. It does several things:
//!  1. Watches for file changes to both input and output resources, hashes
//!     them, and holds a set of modified resources ready to go whenever a build
//!     is requested.
//!  2. Holds all of the build state. By holding all of the state in memory, it
//!     doesn't need to be re-read for every build. It should be written to disk
//!     asynchronously after each build to prevent data loss.
//!  3. Produces a stream of events for the client that requested a build. The
//!     client can use this event stream to display the build output.

use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::Duration;

use button::{self, Error, ErrorKind};
use humantime;
use log;
use structopt::StructOpt;

use crate::opts::GlobalOpts;

#[derive(StructOpt, Default, Debug)]
pub struct Server {
    /// Port to use. By default a random, unused port is used.
    #[structopt(long = "port", short = "p", default_value = "0")]
    port: u16,

    /// The amount of time to wait after the server has become idle before
    /// shutting down.
    #[structopt(
        long = "idle-timeout",
        parse(try_from_str = "humantime::parse_duration")
    )]
    idle: Option<Duration>,

    /// Logging level to use.
    #[structopt(long = "log-level")]
    log_level: Option<log::LevelFilter>,

    /// Make this a daemon process.
    #[structopt(long = "--daemon")]
    daemon: bool,

    /// Root directory for the daemon. Defaults to the current working
    /// directory.
    #[structopt(long = "root", parse(from_os_str))]
    root: Option<PathBuf>,

    /// Run the server in the foreground?
    #[structopt(long = "foreground", short = "f")]
    foreground: bool,
}

impl Server {
    pub fn main(self, _global: &GlobalOpts) -> Result<(), Error> {
        if self.daemon {
            button::server::run_daemon(self.port, self.idle, self.log_level)?;
        } else if self.foreground {
            // Can't run in the foreground if there is already a server running.
            if let Some(client) = button::server::try_connect(".")? {
                return Err(ErrorKind::Other(
                    format!(
                        "Server is already running on port {}",
                        client.port()
                    )
                    .into(),
                )
                .into());
            }

            if let Some(dir) = &self.root {
                env::set_current_dir(dir)?;
            }

            button::server::run(self.port, self.idle, self.log_level)?;
        } else {
            let root = self
                .root
                .as_ref()
                .map(PathBuf::as_path)
                .unwrap_or_else(|| Path::new("."));

            let client = button::server::connect_or_spawn(root, || {
                // Run `button server --daemon` in order to spawn the daemon.
                let mut command = Command::new(env::current_exe()?);
                command.arg("server");
                command.arg("--daemon");
                command.args(&["--port", &self.port.to_string()]);

                if let Some(log_level) = &self.log_level {
                    command.args(&["--log-level", &log_level.to_string()]);
                }

                if let Some(idle) = &self.idle {
                    command.args(&[
                        "--idle-timeout",
                        &humantime::format_duration(idle.clone()).to_string(),
                    ]);
                }

                Ok(command)
            })?;

            println!("Server is running at {}.", client.peer_addr().unwrap());
        }

        Ok(())
    }
}
<commit_msg>Fix clippy warning<commit_after>// Copyright (c) 2019 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! This is the Button server process. It does several things:
//!  1. Watches for file changes to both input and output resources, hashes
//!     them, and holds a set of modified resources ready to go whenever a build
//!     is requested.
//!  2. Holds all of the build state. By holding all of the state in memory, it
//!     doesn't need to be re-read for every build. It should be written to disk
//!     asynchronously after each build to prevent data loss.
//!  3. Produces a stream of events for the client that requested a build. The
//!     client can use this event stream to display the build output.

use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::Duration;

use button::{self, Error, ErrorKind};
use humantime;
use log;
use structopt::StructOpt;

use crate::opts::GlobalOpts;

#[derive(StructOpt, Default, Debug)]
pub struct Server {
    /// Port to use. By default a random, unused port is used.
    #[structopt(long = "port", short = "p", default_value = "0")]
    port: u16,

    /// The amount of time to wait after the server has become idle before
    /// shutting down.
    #[structopt(
        long = "idle-timeout",
        parse(try_from_str = "humantime::parse_duration")
    )]
    idle: Option<Duration>,

    /// Logging level to use.
    #[structopt(long = "log-level")]
    log_level: Option<log::LevelFilter>,

    /// Make this a daemon process.
    #[structopt(long = "--daemon")]
    daemon: bool,

    /// Root directory for the daemon. Defaults to the current working
    /// directory.
    #[structopt(long = "root", parse(from_os_str))]
    root: Option<PathBuf>,

    /// Run the server in the foreground?
    #[structopt(long = "foreground", short = "f")]
    foreground: bool,
}

impl Server {
    pub fn main(self, _global: &GlobalOpts) -> Result<(), Error> {
        if self.daemon {
            button::server::run_daemon(self.port, self.idle, self.log_level)?;
        } else if self.foreground {
            // Can't run in the foreground if there is already a server running.
            if let Some(client) = button::server::try_connect(".")? {
                return Err(ErrorKind::Other(
                    format!(
                        "Server is already running on port {}",
                        client.port()
                    )
                    .into(),
                )
                .into());
            }

            if let Some(dir) = &self.root {
                env::set_current_dir(dir)?;
            }

            button::server::run(self.port, self.idle, self.log_level)?;
        } else {
            let root = self
                .root
                .as_ref()
                .map(PathBuf::as_path)
                .unwrap_or_else(|| Path::new("."));

            let client = button::server::connect_or_spawn(root, || {
                // Run `button server --daemon` in order to spawn the daemon.
                let mut command = Command::new(env::current_exe()?);
                command.arg("server");
                command.arg("--daemon");
                command.args(&["--port", &self.port.to_string()]);

                if let Some(log_level) = &self.log_level {
                    command.args(&["--log-level", &log_level.to_string()]);
                }

                if let Some(idle) = &self.idle {
                    command.args(&[
                        "--idle-timeout",
                        &humantime::format_duration(*idle).to_string(),
                    ]);
                }

                Ok(command)
            })?;

            println!("Server is running at {}.", client.peer_addr().unwrap());
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::collections::LinkedList;
use std::path::PathBuf;

use std::result;

use api_server::request::sync::{DriveDescription, DriveError};

type Result<T> = result::Result<T, DriveError>;

/// Use this structure to set up the Block Device before booting the kernel
#[derive(PartialEq, Debug, Clone)]
pub struct BlockDeviceConfig {
    pub drive_id: String,
    pub path_on_host: PathBuf,
    pub is_root_device: bool,
    pub is_read_only: bool,
}

// Wrapper for the collection that holds all the Block Devices Configs
pub struct BlockDeviceConfigs {
    pub config_list: LinkedList<BlockDeviceConfig>,
    has_root_block: bool,
    read_only_root: bool,
}

impl From<DriveDescription> for BlockDeviceConfig {
    fn from(item: DriveDescription) -> Self {
        let is_read_only = item.is_read_only();
        BlockDeviceConfig {
            drive_id: item.drive_id,
            path_on_host: PathBuf::from(item.path_on_host),
            is_root_device: item.is_root_device,
            is_read_only,
        }
    }
}

impl BlockDeviceConfigs {
    pub fn new() -> BlockDeviceConfigs {
        BlockDeviceConfigs {
            config_list: LinkedList::<BlockDeviceConfig>::new(),
            has_root_block: false,
            read_only_root: false,
        }
    }

    pub fn has_root_block_device(&self) -> bool {
        return self.has_root_block;
    }

    pub fn has_read_only_root(&self) -> bool {
        self.read_only_root
    }

    pub fn contains_drive_path(&self, drive_path: PathBuf) -> bool {
        for drive_config in self.config_list.iter() {
            if drive_config.path_on_host == drive_path {
                return true;
            }
        }
        return false;
    }

    pub fn contains_drive_id(&self, drive_id: String) -> bool {
        for drive_config in self.config_list.iter() {
            if drive_config.drive_id == drive_id {
                return true;
            }
        }
        return false;
    }

    /// This function adds a Block Device Config to the list. The root block device is always
    /// added to the beginning of the list. Only one root block device can be added.
    pub fn add(&mut self, block_device_config: BlockDeviceConfig) -> Result<()> {
        // check if the path exists
        if !block_device_config.path_on_host.exists() {
            return Err(DriveError::InvalidBlockDevicePath);
        }

        if self.contains_drive_path(block_device_config.path_on_host.clone()) {
            return Err(DriveError::BlockDevicePathAlreadyExists);
        }

        // check whether the Device Config belongs to a root device
        // we need to satify the condition by which a VMM can only have on root device
        if block_device_config.is_root_device {
            if self.has_root_block {
                return Err(DriveError::RootBlockDeviceAlreadyAdded);
            } else {
                self.has_root_block = true;
                self.read_only_root = block_device_config.is_read_only;
                // Root Device should be the first in the list
                self.config_list.push_front(block_device_config);
            }
        } else {
            self.config_list.push_back(block_device_config);
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs::{self, File};

    // Helper function for creating a dummy file
    // The filename has to be unique among all tests because the tests are run on many threads
    fn create_dummy_path(filename: String) -> PathBuf {
        let _file = File::create(filename.clone());
        return PathBuf::from(filename);
    }

    // Helper function for deleting a dummy file
    fn delete_dummy_path(filename: String) {
        let _rs = fs::remove_file(filename);
    }

    #[test]
    fn test_create_block_devices_configs() {
        let block_devices_configs = BlockDeviceConfigs::new();
        assert_eq!(block_devices_configs.has_root_block_device(), false);
        assert_eq!(block_devices_configs.config_list.len(), 0);
    }

    #[test]
    fn test_add_non_root_block_device() {
        let dummy_filename = String::from("non_root_block_device");
        let dummy_path = create_dummy_path(dummy_filename.clone());

        let dummy_block_device = BlockDeviceConfig {
            path_on_host: dummy_path,
            is_root_device: false,
            is_read_only: false,
            drive_id: String::from("1"),
        };

        let mut block_devices_configs = BlockDeviceConfigs::new();
        assert!(
            block_devices_configs
                .add(dummy_block_device.clone())
                .is_ok()
        );
        assert_eq!(block_devices_configs.has_root_block, false);
        assert_eq!(block_devices_configs.config_list.len(), 1);
        let dev_config = block_devices_configs.config_list.iter().next().unwrap();
        assert_eq!(dev_config, &dummy_block_device);

        delete_dummy_path(dummy_filename);
    }

    #[test]
    fn test_add_one_root_block_device() {
        let dummy_filename = String::from("one_root_block_device");
        let dummy_path = create_dummy_path(dummy_filename.clone());

        let dummy_block_device = BlockDeviceConfig {
            path_on_host: dummy_path,
            is_root_device: true,
            is_read_only: false,
            drive_id: String::from("1"),
        };
        let mut block_devices_configs = BlockDeviceConfigs::new();
        assert!(
            block_devices_configs
                .add(dummy_block_device.clone())
                .is_ok()
        );
        assert_eq!(block_devices_configs.has_root_block, true);
        assert_eq!(block_devices_configs.config_list.len(), 1);
        let dev_config = block_devices_configs.config_list.iter().next().unwrap();
        assert_eq!(dev_config, &dummy_block_device);

        delete_dummy_path(dummy_filename);
    }

    #[test]
    fn test_add_two_root_block_devices_configs() {
        let dummy_filename_1 = String::from("two_root_block_devices_configs_1");
        let dummy_path_1 = create_dummy_path(dummy_filename_1.clone());
        let root_block_device_1 = BlockDeviceConfig {
            path_on_host: dummy_path_1.clone(),
            is_root_device: true,
            is_read_only: false,
            drive_id: String::from("1"),
        };

        let dummy_filename_2 = String::from("two_root_block_devices_configs_2");
        let dummy_path_2 = create_dummy_path(dummy_filename_2.clone());
        let root_block_device_2 = BlockDeviceConfig {
            path_on_host: dummy_path_2.clone(),
            is_root_device: true,
            is_read_only: false,
            drive_id: String::from("2"),
        };

        let mut block_devices_configs = BlockDeviceConfigs::new();
        assert!(block_devices_configs.add(root_block_device_1).is_ok());
        let actual_error = format!(
            "{:?}",
            block_devices_configs.add(root_block_device_2).unwrap_err()
        );
        let expected_error = format!("{:?}", DriveError::RootBlockDeviceAlreadyAdded);
        assert_eq!(expected_error, actual_error);

        delete_dummy_path(dummy_filename_1);
        delete_dummy_path(dummy_filename_2);
    }

    #[test]
    /// Test BlockDevicesConfigs::add when you first add the root device and then the other devices
    fn test_add_root_block_device_first() {
        let dummy_filename_1 = String::from("root_block_device_first_1");
        let dummy_path_1 = create_dummy_path(dummy_filename_1.clone());
        let root_block_device = BlockDeviceConfig {
            path_on_host: dummy_path_1.clone(),
            is_root_device: true,
            is_read_only: false,
            drive_id: String::from("1"),
        };

        let dummy_filename_2 = String::from("root_block_device_first_2");
        let dummy_path_2 = create_dummy_path(dummy_filename_2.clone());
        let dummy_block_device_2 = BlockDeviceConfig {
            path_on_host: dummy_path_2.clone(),
            is_root_device: false,
            is_read_only: false,
            drive_id: String::from("2"),
        };

        let dummy_filename_3 = String::from("root_block_device_first_3");
        let dummy_path_3 = create_dummy_path(dummy_filename_3.clone());
        let dummy_block_device_3 = BlockDeviceConfig {
            path_on_host: dummy_path_3.clone(),
            is_root_device: false,
            is_read_only: false,
            drive_id: String::from("3"),
        };

        let mut block_devices_configs = BlockDeviceConfigs::new();
        assert!(block_devices_configs.add(root_block_device.clone()).is_ok());
        assert!(
            block_devices_configs
                .add(dummy_block_device_2.clone())
                .is_ok()
        );
        assert!(
            block_devices_configs
                .add(dummy_block_device_3.clone())
                .is_ok()
        );

        assert_eq!(block_devices_configs.has_root_block_device(), true);
        assert_eq!(block_devices_configs.config_list.len(), 3);

        let mut block_dev_iter = block_devices_configs.config_list.iter();
        assert_eq!(block_dev_iter.next().unwrap(), &root_block_device);
        assert_eq!(block_dev_iter.next().unwrap(), &dummy_block_device_2);
        assert_eq!(block_dev_iter.next().unwrap(), &dummy_block_device_3);

        delete_dummy_path(dummy_filename_1);
        delete_dummy_path(dummy_filename_2);
        delete_dummy_path(dummy_filename_3);
    }

    #[test]
    /// Test BlockDevicesConfigs::add when you add other devices first and then the root device
    fn test_root_block_device_add_last() {
        let dummy_filename_1 = String::from("root_block_device_first_1");
        let dummy_path_1 = create_dummy_path(dummy_filename_1.clone());
        let root_block_device = BlockDeviceConfig {
            path_on_host: dummy_path_1.clone(),
            is_root_device: true,
            is_read_only: false,
            drive_id: String::from("1"),
        };

        let dummy_filename_2 = String::from("root_block_device_first_2");
        let dummy_path_2 = create_dummy_path(dummy_filename_2.clone());
        let dummy_block_device_2 = BlockDeviceConfig {
            path_on_host: dummy_path_2.clone(),
            is_root_device: false,
            is_read_only: false,
            drive_id: String::from("2"),
        };

        let dummy_filename_3 = String::from("root_block_device_first_3");
        let dummy_path_3 = create_dummy_path(dummy_filename_3.clone());
        let dummy_block_device_3 = BlockDeviceConfig {
            path_on_host: dummy_path_3.clone(),
            is_root_device: false,
            is_read_only: false,
            drive_id: String::from("3"),
        };

        let mut block_devices_configs = BlockDeviceConfigs::new();
        assert!(
            block_devices_configs
                .add(dummy_block_device_2.clone())
                .is_ok()
        );
        assert!(
            block_devices_configs
                .add(dummy_block_device_3.clone())
                .is_ok()
        );
        assert!(block_devices_configs.add(root_block_device.clone()).is_ok());

        assert_eq!(block_devices_configs.has_root_block_device(), true);
        assert_eq!(block_devices_configs.config_list.len(), 3);

        let mut block_dev_iter = block_devices_configs.config_list.iter();
        // The root device should be first in the list no matter of the order in which the devices were added
        assert_eq!(block_dev_iter.next().unwrap(), &root_block_device);
        assert_eq!(block_dev_iter.next().unwrap(), &dummy_block_device_2);
        assert_eq!(block_dev_iter.next().unwrap(), &dummy_block_device_3);

        delete_dummy_path(dummy_filename_1);
        delete_dummy_path(dummy_filename_2);
        delete_dummy_path(dummy_filename_3);
    }
}
<commit_msg>device_config: fix drive unittests sporadic failures<commit_after>use std::collections::LinkedList;
use std::path::PathBuf;

use std::result;

use api_server::request::sync::{DriveDescription, DriveError};

type Result<T> = result::Result<T, DriveError>;

/// Use this structure to set up the Block Device before booting the kernel
#[derive(PartialEq, Debug, Clone)]
pub struct BlockDeviceConfig {
    pub drive_id: String,
    pub path_on_host: PathBuf,
    pub is_root_device: bool,
    pub is_read_only: bool,
}

// Wrapper for the collection that holds all the Block Devices Configs
pub struct BlockDeviceConfigs {
    pub config_list: LinkedList<BlockDeviceConfig>,
    has_root_block: bool,
    read_only_root: bool,
}

impl From<DriveDescription> for BlockDeviceConfig {
    fn from(item: DriveDescription) -> Self {
        let is_read_only = item.is_read_only();
        BlockDeviceConfig {
            drive_id: item.drive_id,
            path_on_host: PathBuf::from(item.path_on_host),
            is_root_device: item.is_root_device,
            is_read_only,
        }
    }
}

impl BlockDeviceConfigs {
    pub fn new() -> BlockDeviceConfigs {
        BlockDeviceConfigs {
            config_list: LinkedList::<BlockDeviceConfig>::new(),
            has_root_block: false,
            read_only_root: false,
        }
    }

    pub fn has_root_block_device(&self) -> bool {
        return self.has_root_block;
    }

    pub fn has_read_only_root(&self) -> bool {
        self.read_only_root
    }

    pub fn contains_drive_path(&self, drive_path: PathBuf) -> bool {
        for drive_config in self.config_list.iter() {
            if drive_config.path_on_host == drive_path {
                return true;
            }
        }
        return false;
    }

    pub fn contains_drive_id(&self, drive_id: String) -> bool {
        for drive_config in self.config_list.iter() {
            if drive_config.drive_id == drive_id {
                return true;
            }
        }
        return false;
    }

    /// This function adds a Block Device Config to the list. The root block device is always
    /// added to the beginning of the list. Only one root block device can be added.
    pub fn add(&mut self, block_device_config: BlockDeviceConfig) -> Result<()> {
        // check if the path exists
        if !block_device_config.path_on_host.exists() {
            return Err(DriveError::InvalidBlockDevicePath);
        }

        if self.contains_drive_path(block_device_config.path_on_host.clone()) {
            return Err(DriveError::BlockDevicePathAlreadyExists);
        }

        // check whether the Device Config belongs to a root device
        // we need to satify the condition by which a VMM can only have on root device
        if block_device_config.is_root_device {
            if self.has_root_block {
                return Err(DriveError::RootBlockDeviceAlreadyAdded);
            } else {
                self.has_root_block = true;
                self.read_only_root = block_device_config.is_read_only;
                // Root Device should be the first in the list
                self.config_list.push_front(block_device_config);
            }
        } else {
            self.config_list.push_back(block_device_config);
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs::{self, File};

    // Helper function for creating a dummy file
    // The filename has to be unique among all tests because the tests are run on many threads
    fn create_dummy_path(filename: String) -> PathBuf {
        let _file = File::create(filename.clone());
        return PathBuf::from(filename);
    }

    // Helper function for deleting a dummy file
    fn delete_dummy_path(filename: String) {
        let _rs = fs::remove_file(filename);
    }

    #[test]
    fn test_create_block_devices_configs() {
        let block_devices_configs = BlockDeviceConfigs::new();
        assert_eq!(block_devices_configs.has_root_block_device(), false);
        assert_eq!(block_devices_configs.config_list.len(), 0);
    }

    #[test]
    fn test_add_non_root_block_device() {
        let dummy_filename = String::from("test_add_non_root_block_device");
        let dummy_path = create_dummy_path(dummy_filename.clone());

        let dummy_block_device = BlockDeviceConfig {
            path_on_host: dummy_path,
            is_root_device: false,
            is_read_only: false,
            drive_id: String::from("1"),
        };

        let mut block_devices_configs = BlockDeviceConfigs::new();
        assert!(
            block_devices_configs
                .add(dummy_block_device.clone())
                .is_ok()
        );
        assert_eq!(block_devices_configs.has_root_block, false);
        assert_eq!(block_devices_configs.config_list.len(), 1);
        let dev_config = block_devices_configs.config_list.iter().next().unwrap();
        assert_eq!(dev_config, &dummy_block_device);

        delete_dummy_path(dummy_filename);
    }

    #[test]
    fn test_add_one_root_block_device() {
        let dummy_filename = String::from("test_add_one_root_block_device");
        let dummy_path = create_dummy_path(dummy_filename.clone());

        let dummy_block_device = BlockDeviceConfig {
            path_on_host: dummy_path,
            is_root_device: true,
            is_read_only: false,
            drive_id: String::from("1"),
        };
        let mut block_devices_configs = BlockDeviceConfigs::new();
        assert!(
            block_devices_configs
                .add(dummy_block_device.clone())
                .is_ok()
        );
        assert_eq!(block_devices_configs.has_root_block, true);
        assert_eq!(block_devices_configs.config_list.len(), 1);
        let dev_config = block_devices_configs.config_list.iter().next().unwrap();
        assert_eq!(dev_config, &dummy_block_device);

        delete_dummy_path(dummy_filename);
    }

    #[test]
    fn test_add_two_root_block_devices_configs() {
        let dummy_filename_1 = String::from("test_add_two_root_block_devices_configs_1");
        let dummy_path_1 = create_dummy_path(dummy_filename_1.clone());
        let root_block_device_1 = BlockDeviceConfig {
            path_on_host: dummy_path_1,
            is_root_device: true,
            is_read_only: false,
            drive_id: String::from("1"),
        };

        let dummy_filename_2 = String::from("test_add_two_root_block_devices_configs_2");
        let dummy_path_2 = create_dummy_path(dummy_filename_2.clone());
        let root_block_device_2 = BlockDeviceConfig {
            path_on_host: dummy_path_2,
            is_root_device: true,
            is_read_only: false,
            drive_id: String::from("2"),
        };

        let mut block_devices_configs = BlockDeviceConfigs::new();
        assert!(block_devices_configs.add(root_block_device_1).is_ok());
        let actual_error = format!(
            "{:?}",
            block_devices_configs.add(root_block_device_2).unwrap_err()
        );
        let expected_error = format!("{:?}", DriveError::RootBlockDeviceAlreadyAdded);
        assert_eq!(expected_error, actual_error);

        delete_dummy_path(dummy_filename_1);
        delete_dummy_path(dummy_filename_2);
    }

    #[test]
    /// Test BlockDevicesConfigs::add when you first add the root device and then the other devices
    fn test_add_root_block_device_first() {
        let dummy_filename_1 = String::from("test_add_root_block_device_first_1");
        let dummy_path_1 = create_dummy_path(dummy_filename_1.clone());
        let root_block_device = BlockDeviceConfig {
            path_on_host: dummy_path_1,
            is_root_device: true,
            is_read_only: false,
            drive_id: String::from("1"),
        };

        let dummy_filename_2 = String::from("test_add_root_block_device_first_2");
        let dummy_path_2 = create_dummy_path(dummy_filename_2.clone());
        let dummy_block_device_2 = BlockDeviceConfig {
            path_on_host: dummy_path_2,
            is_root_device: false,
            is_read_only: false,
            drive_id: String::from("2"),
        };

        let dummy_filename_3 = String::from("test_add_root_block_device_first_3");
        let dummy_path_3 = create_dummy_path(dummy_filename_3.clone());
        let dummy_block_device_3 = BlockDeviceConfig {
            path_on_host: dummy_path_3,
            is_root_device: false,
            is_read_only: false,
            drive_id: String::from("3"),
        };

        let mut block_devices_configs = BlockDeviceConfigs::new();
        assert!(block_devices_configs.add(root_block_device.clone()).is_ok());
        assert!(
            block_devices_configs
                .add(dummy_block_device_2.clone())
                .is_ok()
        );
        assert!(
            block_devices_configs
                .add(dummy_block_device_3.clone())
                .is_ok()
        );

        assert_eq!(block_devices_configs.has_root_block_device(), true);
        assert_eq!(block_devices_configs.config_list.len(), 3);

        let mut block_dev_iter = block_devices_configs.config_list.iter();
        assert_eq!(block_dev_iter.next().unwrap(), &root_block_device);
        assert_eq!(block_dev_iter.next().unwrap(), &dummy_block_device_2);
        assert_eq!(block_dev_iter.next().unwrap(), &dummy_block_device_3);

        delete_dummy_path(dummy_filename_1);
        delete_dummy_path(dummy_filename_2);
        delete_dummy_path(dummy_filename_3);
    }

    #[test]
    /// Test BlockDevicesConfigs::add when you add other devices first and then the root device
    fn test_root_block_device_add_last() {
        let dummy_filename_1 = String::from("test_root_block_device_add_last_1");
        let dummy_path_1 = create_dummy_path(dummy_filename_1.clone());
        let root_block_device = BlockDeviceConfig {
            path_on_host: dummy_path_1,
            is_root_device: true,
            is_read_only: false,
            drive_id: String::from("1"),
        };

        let dummy_filename_2 = String::from("test_root_block_device_add_last_2");
        let dummy_path_2 = create_dummy_path(dummy_filename_2.clone());
        let dummy_block_device_2 = BlockDeviceConfig {
            path_on_host: dummy_path_2,
            is_root_device: false,
            is_read_only: false,
            drive_id: String::from("2"),
        };

        let dummy_filename_3 = String::from("test_root_block_device_add_last_3");
        let dummy_path_3 = create_dummy_path(dummy_filename_3.clone());
        let dummy_block_device_3 = BlockDeviceConfig {
            path_on_host: dummy_path_3,
            is_root_device: false,
            is_read_only: false,
            drive_id: String::from("3"),
        };

        let mut block_devices_configs = BlockDeviceConfigs::new();
        assert!(
            block_devices_configs
                .add(dummy_block_device_2.clone())
                .is_ok()
        );
        assert!(
            block_devices_configs
                .add(dummy_block_device_3.clone())
                .is_ok()
        );
        assert!(block_devices_configs.add(root_block_device.clone()).is_ok());

        assert_eq!(block_devices_configs.has_root_block_device(), true);
        assert_eq!(block_devices_configs.config_list.len(), 3);

        let mut block_dev_iter = block_devices_configs.config_list.iter();
        // The root device should be first in the list no matter of the order in which the devices were added
        assert_eq!(block_dev_iter.next().unwrap(), &root_block_device);
        assert_eq!(block_dev_iter.next().unwrap(), &dummy_block_device_2);
        assert_eq!(block_dev_iter.next().unwrap(), &dummy_block_device_3);

        delete_dummy_path(dummy_filename_1);
        delete_dummy_path(dummy_filename_2);
        delete_dummy_path(dummy_filename_3);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::mem;
use std::ops::Range;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::Weak;

use command_buffer::Submission;
use format::Format;
use image::traits::AccessRange;
use image::traits::GpuAccessResult;
use image::traits::Image;
use image::traits::ImageContent;
use image::traits::ImageView;
use image::traits::Transition;
use image::sys::Dimensions;
use image::sys::Layout;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use swapchain::Swapchain;
use sync::Semaphore;

use OomError;

pub struct SwapchainImage {
    image: UnsafeImage,
    view: UnsafeImageView,
    format: Format,
    swapchain: Arc<Swapchain>,
    id: u32,
    guarded: Mutex<Guarded>,
}

struct Guarded {
    present_layout: bool,
    latest_submission: Option<Weak<Submission>>,    // TODO: can use `Weak::new()` once it's stabilized
}

impl SwapchainImage {
    pub unsafe fn from_raw(image: UnsafeImage, format: Format, swapchain: &Arc<Swapchain>, id: u32)
                           -> Result<Arc<SwapchainImage>, OomError>
    {
        let view = try!(UnsafeImageView::new(&image, 0 .. 1, 0 .. 1));

        Ok(Arc::new(SwapchainImage {
            image: image,
            view: view,
            format: format,
            swapchain: swapchain.clone(),
            id: id,
            guarded: Mutex::new(Guarded {
                present_layout: false,
                latest_submission: None,
            }),
        }))
    }

    #[inline]
    pub fn dimensions(&self) -> Dimensions {
        self.image.dimensions()
    }
}

unsafe impl Image for SwapchainImage {
    #[inline]
    fn inner_image(&self) -> &UnsafeImage {
        &self.image
    }

    #[inline]
    fn blocks(&self, _: Range<u32>, _: Range<u32>) -> Vec<(u32, u32)> {
        vec![(0, 0)]
    }

    #[inline]
    fn block_mipmap_levels_range(&self, block: (u32, u32)) -> Range<u32> {
        0 .. 1
    }

    #[inline]
    fn block_array_layers_range(&self, block: (u32, u32)) -> Range<u32> {
        0 .. 1
    }

    #[inline]
    fn initial_layout(&self, _: (u32, u32), _: Layout) -> (Layout, bool, bool) {
        (Layout::PresentSrc, false, true)
    }

    #[inline]
    fn final_layout(&self, _: (u32, u32), _: Layout) -> (Layout, bool, bool) {
        (Layout::PresentSrc, false, true)
    }

    fn needs_fence(&self, access: &mut Iterator<Item = AccessRange>) -> Option<bool> {
        Some(false)
    }

    unsafe fn gpu_access(&self, access: &mut Iterator<Item = AccessRange>,
                         submission: &Arc<Submission>) -> GpuAccessResult
    {
        let mut guarded = self.guarded.lock().unwrap();

        let dependency = mem::replace(&mut guarded.latest_submission, Some(Arc::downgrade(submission)));
        let dependency = dependency.and_then(|d| d.upgrade());

        let signal = Semaphore::new(submission.queue().device()).unwrap();
        let wait = self.swapchain.image_semaphore(self.id, signal.clone()).expect("Try to render to a swapchain image that was not acquired first");

        if guarded.present_layout {
            return GpuAccessResult {
                dependencies: if let Some(dependency) = dependency {
                    vec![dependency]
                } else {
                    vec![]
                },
                additional_wait_semaphore: Some(wait),
                additional_signal_semaphore: Some(signal),
                before_transitions: vec![],
                after_transitions: vec![],
            };
        }

        guarded.present_layout = true;

        GpuAccessResult {
            dependencies: if let Some(dependency) = dependency {
                vec![dependency]
            } else {
                vec![]
            },
            additional_wait_semaphore: Some(wait),
            additional_signal_semaphore: Some(signal),
            before_transitions: vec![Transition {
                block: (0, 0),
                from: Layout::Undefined,
                to: Layout::PresentSrc,
            }],
            after_transitions: vec![],
        }
    }
}

unsafe impl<P> ImageContent<P> for SwapchainImage {
    #[inline]
    fn matches_format(&self) -> bool {
        true        // FIXME:
    }
}

unsafe impl ImageView for SwapchainImage {
    #[inline]
    fn parent(&self) -> &Image {
        self
    }

    #[inline]
    fn parent_arc(me: &Arc<Self>) -> Arc<Image> where Self: Sized {
        me.clone() as Arc<_>
    }

    #[inline]
    fn blocks(&self) -> Vec<(u32, u32)> {
        vec![(0, 0)]
    }

    #[inline]
    fn inner_view(&self) -> &UnsafeImageView {
        &self.view
    }

    #[inline]
    fn descriptor_set_storage_image_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_sampled_image_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_input_attachment_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn identity_swizzle(&self) -> bool {
        true
    }
}
<commit_msg>SwapchainImage::dimensions() now returns a [u32; 2]<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::mem;
use std::ops::Range;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::Weak;

use command_buffer::Submission;
use format::Format;
use image::traits::AccessRange;
use image::traits::GpuAccessResult;
use image::traits::Image;
use image::traits::ImageContent;
use image::traits::ImageView;
use image::traits::Transition;
use image::sys::Layout;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use swapchain::Swapchain;
use sync::Semaphore;

use OomError;

pub struct SwapchainImage {
    image: UnsafeImage,
    view: UnsafeImageView,
    format: Format,
    swapchain: Arc<Swapchain>,
    id: u32,
    guarded: Mutex<Guarded>,
}

struct Guarded {
    present_layout: bool,
    latest_submission: Option<Weak<Submission>>,    // TODO: can use `Weak::new()` once it's stabilized
}

impl SwapchainImage {
    pub unsafe fn from_raw(image: UnsafeImage, format: Format, swapchain: &Arc<Swapchain>, id: u32)
                           -> Result<Arc<SwapchainImage>, OomError>
    {
        let view = try!(UnsafeImageView::new(&image, 0 .. 1, 0 .. 1));

        Ok(Arc::new(SwapchainImage {
            image: image,
            view: view,
            format: format,
            swapchain: swapchain.clone(),
            id: id,
            guarded: Mutex::new(Guarded {
                present_layout: false,
                latest_submission: None,
            }),
        }))
    }

    /// Returns the dimensions of the image.
    ///
    /// A `SwapchainImage` is always two-dimensional.
    #[inline]
    pub fn dimensions(&self) -> [u32; 2] {
        let dims = self.image.dimensions();
        [dims.width(), dims.height()]
    }
}

unsafe impl Image for SwapchainImage {
    #[inline]
    fn inner_image(&self) -> &UnsafeImage {
        &self.image
    }

    #[inline]
    fn blocks(&self, _: Range<u32>, _: Range<u32>) -> Vec<(u32, u32)> {
        vec![(0, 0)]
    }

    #[inline]
    fn block_mipmap_levels_range(&self, block: (u32, u32)) -> Range<u32> {
        0 .. 1
    }

    #[inline]
    fn block_array_layers_range(&self, block: (u32, u32)) -> Range<u32> {
        0 .. 1
    }

    #[inline]
    fn initial_layout(&self, _: (u32, u32), _: Layout) -> (Layout, bool, bool) {
        (Layout::PresentSrc, false, true)
    }

    #[inline]
    fn final_layout(&self, _: (u32, u32), _: Layout) -> (Layout, bool, bool) {
        (Layout::PresentSrc, false, true)
    }

    fn needs_fence(&self, access: &mut Iterator<Item = AccessRange>) -> Option<bool> {
        Some(false)
    }

    unsafe fn gpu_access(&self, access: &mut Iterator<Item = AccessRange>,
                         submission: &Arc<Submission>) -> GpuAccessResult
    {
        let mut guarded = self.guarded.lock().unwrap();

        let dependency = mem::replace(&mut guarded.latest_submission, Some(Arc::downgrade(submission)));
        let dependency = dependency.and_then(|d| d.upgrade());

        let signal = Semaphore::new(submission.queue().device()).unwrap();
        let wait = self.swapchain.image_semaphore(self.id, signal.clone()).expect("Try to render to a swapchain image that was not acquired first");

        if guarded.present_layout {
            return GpuAccessResult {
                dependencies: if let Some(dependency) = dependency {
                    vec![dependency]
                } else {
                    vec![]
                },
                additional_wait_semaphore: Some(wait),
                additional_signal_semaphore: Some(signal),
                before_transitions: vec![],
                after_transitions: vec![],
            };
        }

        guarded.present_layout = true;

        GpuAccessResult {
            dependencies: if let Some(dependency) = dependency {
                vec![dependency]
            } else {
                vec![]
            },
            additional_wait_semaphore: Some(wait),
            additional_signal_semaphore: Some(signal),
            before_transitions: vec![Transition {
                block: (0, 0),
                from: Layout::Undefined,
                to: Layout::PresentSrc,
            }],
            after_transitions: vec![],
        }
    }
}

unsafe impl<P> ImageContent<P> for SwapchainImage {
    #[inline]
    fn matches_format(&self) -> bool {
        true        // FIXME:
    }
}

unsafe impl ImageView for SwapchainImage {
    #[inline]
    fn parent(&self) -> &Image {
        self
    }

    #[inline]
    fn parent_arc(me: &Arc<Self>) -> Arc<Image> where Self: Sized {
        me.clone() as Arc<_>
    }

    #[inline]
    fn blocks(&self) -> Vec<(u32, u32)> {
        vec![(0, 0)]
    }

    #[inline]
    fn inner_view(&self) -> &UnsafeImageView {
        &self.view
    }

    #[inline]
    fn descriptor_set_storage_image_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_sampled_image_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_input_attachment_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn identity_swizzle(&self) -> bool {
        true
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The rust-pcre authors.
//
// 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.
#![allow(unused_must_use)]
#![feature(phase)]

#[phase(plugin, link)] extern crate log;
extern crate rustc;

use rustc::driver::driver::host_triple;
use std::from_str::{from_str};
use std::io;
use std::io::{Command, FilePermission};
use std::io::fs::{mkdir, File};
use std::option::{Option};
use std::os;
use std::str;

#[deriving(Eq, PartialEq)]
struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl std::fmt::Show for Version {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{:u}.{:u}", self.major, self.minor)
    }
}

impl PartialOrd for Version {
    fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Version {
    fn cmp(&self, other: &Version) -> Ordering {
        (self.major, self.minor).cmp(&(other.major, other.minor))
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail!("Package script error: Failed to `cd` into `{}`", path.display());
    }
}

fn main() {
    let pcre_libdir = match os::getenv("PCRE_LIBDIR") {
        None            => {
            let pcre_config_output = match Command::new("pcre-config").arg("--prefix").output() {
                Err(e) => {
                    match e.kind {
                        io::FileNotFound => fail!("Package script error: Could not run `pcre-config` because no such executable is in the executable search PATH. Make sure that you have installed a dev package for libpcre and/or make sure that libpcre's bindir is added to your PATH (currently \"{}\").", os::getenv("PATH").unwrap_or(String::from_str(""))),
                        _ => fail!("Package script error: Could not run `pcre-config`: {}", e)
                    }
                },
                Ok(pcre_config_output) => pcre_config_output
            };
            if !pcre_config_output.status.success() {
                fail!("Package script error: `pcre-config --prefix` failed");
            }
            let output_ptr = pcre_config_output.output.as_ptr();
            let output_len = pcre_config_output.output.len();
            let prefix_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            // `pcre-config` adds a newline to the end, which we need to trim away.
            String::from_str(prefix_str.as_slice().trim()).append("/lib")
        },
        Some(pcre_libdir) => pcre_libdir
    };
    let pcre_lib_path = Path::new(pcre_libdir);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.join("build").join(host_triple());
    if !target_build_path.exists() {
        if mkdir(&target_build_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create target build directory `{}`", target_build_path.display());
        }
    }
    let out_path = target_build_path.join("pcre");
    if !out_path.exists() {
        if mkdir(&out_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create output directory `{}`", out_path.display());
        }
    }

    let versioncheck_rs_path = out_path.join("versioncheck.rs");
    {
        let mut f = match File::create(&versioncheck_rs_path) {
            Err(e) => fail!("Package script error: Failed to open `{}` for writing: {}", versioncheck_rs_path.display(), e),
            Ok(f) => f
        };
        let contents = format!("\
extern crate libc;

use std::c_str::{{CString}};
use libc::{{c_char, c_int, c_uchar, c_void}};
use std::ptr;
use std::ptr::{{RawPtr}};
use std::slice;

type options = c_int;
struct pcre;
struct pcre_extra;

#[link(name = \"pcre\")]
extern {{
    static pcre_free: extern \"C\" fn(ptr: *const c_void);

    fn pcre_compile(pattern: *const c_char, options: options, errptr: *mut *const c_char, erroffset: *mut c_int, tableptr: *const c_uchar) -> *const pcre;
    fn pcre_exec(code: *const pcre, extra: *const pcre_extra, subject: *const c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *const c_char;
}}

fn main () {{
    unsafe {{
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_string();

        let pattern = \"^\\\\d+\\\\.\\\\d+\";
        pattern.with_c_str(|pattern_c_str| {{
            let mut err: *const c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if code.is_null() {{
                if code.is_null() {{
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() {{
                        None          => fail!(\"pcre_compile() failed at offset {{}}\", erroffset as uint),
                        Some(err_str) => fail!(\"pcre_compile() failed at offset {{}}: {{}}\", erroffset as uint, err_str)
                    }}
                }}
            }}
            assert!(code.is_not_null());

            let ovecsize = 1 * 3;
            let mut ovector = Vec::from_elem(ovecsize, 0 as c_int);
            version_str.with_c_str_unchecked(|version_c_str| {{
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, ovector.as_mut_ptr(), ovecsize as c_int);
                if rc < 0 {{
                    fail!(\"pcre_exec() failed\");
                }}

                print!(\"{{}}\", version_str.as_slice().slice_to(*ovector.get(1) as uint));
            }});

            pcre_free(code as *const c_void);
        }});
    }}
}}
");
        f.write_str(contents.as_slice()).map_err(|e| -> () {
            fail!("Package script error: Failed to write to `{}`: {}", versioncheck_rs_path.display(), e);
        });
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rustc_output = match Command::new("rustc").arg("versioncheck.rs").arg("-L").arg(pcre_lib_path).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {}", e),
        Ok(rustc_output) => rustc_output
    };
    if !rustc_output.status.success() {
        println!("{}", str::from_utf8(rustc_output.output.as_slice()));
        println!("{}", str::from_utf8(rustc_output.error.as_slice()));
        fail!("Package script error: `rustc versioncheck.rs` failed: {}", rustc_output.status);
    }
    let versioncheck_output = match Command::new("./versioncheck").output() {
        Err(e) => fail!("Package script error: Failed to run `./versioncheck`: {}", e),
        Ok(versioncheck_output) => versioncheck_output
    };
    if !versioncheck_output.status.success() {
        println!("{}", str::from_utf8(versioncheck_output.output.as_slice()));
        println!("{}", str::from_utf8(versioncheck_output.error.as_slice()));
        fail!("versioncheck error: {}", versioncheck_output.status);
    }
    cd(&workspace_path);

    let output_ptr = versioncheck_output.output.as_ptr();
    let output_len = versioncheck_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
    debug!("output_str = `{}`", output_str);

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.as_slice().split('\n').rev();
    let version_str: String = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_string()
    };

    debug!("libpcre version {:s}", version_str.as_slice());

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str.as_slice()) {
        None               => fail!("Package script error: Failed to parse version string '{}'", version_str.as_slice()),
        Some(pcre_version) => pcre_version
    };

    if pcre_version < min_required_version {
        fail!("Package script error: Found libpcre version {}, but at least version {} is required", version_str.as_slice(), min_required_version);
    }

    // Create directories `bin` and `lib`
    let bin_path = workspace_path.join("bin");
    if !bin_path.exists() {
        if mkdir(&bin_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create the `bin` directory");
        }
    }
    let lib_path = workspace_path.join("lib");
    if !lib_path.exists() {
        if mkdir(&lib_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create the `lib` directory");
        }
    }

    // Compile libpcre-*.rlib
    match Command::new("rustc").arg("--out-dir").arg(lib_path).arg("src/pcre/mod.rs").arg("-L").arg(pcre_lib_path).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {}", e),
        Ok(rustc_output) => {
            if !rustc_output.status.success() {
                println!("{}", str::from_utf8(rustc_output.output.as_slice()));
                println!("{}", str::from_utf8(rustc_output.error.as_slice()));
                fail!("Package script error: `rustc src/pcre/mod.rs` failed: {}", rustc_output.status);
            }
        }
    }

    match Command::new("rustc").arg("-o").arg(bin_path.join("pcredemo")).arg("src/pcredemo/main.rs").arg("-L").arg("lib").arg("-L").arg(pcre_lib_path).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {}", e),
        Ok(rustc_output) => {
            if !rustc_output.status.success() {
                println!("{}", str::from_utf8(rustc_output.output.as_slice()));
                println!("{}", str::from_utf8(rustc_output.error.as_slice()));
                fail!("Package script error: `rustc src/pcredemo/main.rs` failed: {}", rustc_output.status);
            }
        }
    }
}
<commit_msg>Fix error: use of moved value: `pcre_lib_path`<commit_after>// Copyright 2014 The rust-pcre authors.
//
// 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.
#![allow(unused_must_use)]
#![feature(phase)]

#[phase(plugin, link)] extern crate log;
extern crate rustc;

use rustc::driver::driver::host_triple;
use std::from_str::{from_str};
use std::io;
use std::io::{Command, FilePermission};
use std::io::fs::{mkdir, File};
use std::option::{Option};
use std::os;
use std::str;

#[deriving(Eq, PartialEq)]
struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl std::fmt::Show for Version {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{:u}.{:u}", self.major, self.minor)
    }
}

impl PartialOrd for Version {
    fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Version {
    fn cmp(&self, other: &Version) -> Ordering {
        (self.major, self.minor).cmp(&(other.major, other.minor))
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail!("Package script error: Failed to `cd` into `{}`", path.display());
    }
}

fn main() {
    let pcre_libdir = match os::getenv("PCRE_LIBDIR") {
        None            => {
            let pcre_config_output = match Command::new("pcre-config").arg("--prefix").output() {
                Err(e) => {
                    match e.kind {
                        io::FileNotFound => fail!("Package script error: Could not run `pcre-config` because no such executable is in the executable search PATH. Make sure that you have installed a dev package for libpcre and/or make sure that libpcre's bindir is added to your PATH (currently \"{}\").", os::getenv("PATH").unwrap_or(String::from_str(""))),
                        _ => fail!("Package script error: Could not run `pcre-config`: {}", e)
                    }
                },
                Ok(pcre_config_output) => pcre_config_output
            };
            if !pcre_config_output.status.success() {
                fail!("Package script error: `pcre-config --prefix` failed");
            }
            let output_ptr = pcre_config_output.output.as_ptr();
            let output_len = pcre_config_output.output.len();
            let prefix_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            // `pcre-config` adds a newline to the end, which we need to trim away.
            String::from_str(prefix_str.as_slice().trim()).append("/lib")
        },
        Some(pcre_libdir) => pcre_libdir
    };
    let pcre_lib_path = Path::new(pcre_libdir);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.join("build").join(host_triple());
    if !target_build_path.exists() {
        if mkdir(&target_build_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create target build directory `{}`", target_build_path.display());
        }
    }
    let out_path = target_build_path.join("pcre");
    if !out_path.exists() {
        if mkdir(&out_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create output directory `{}`", out_path.display());
        }
    }

    let versioncheck_rs_path = out_path.join("versioncheck.rs");
    {
        let mut f = match File::create(&versioncheck_rs_path) {
            Err(e) => fail!("Package script error: Failed to open `{}` for writing: {}", versioncheck_rs_path.display(), e),
            Ok(f) => f
        };
        let contents = format!("\
extern crate libc;

use std::c_str::{{CString}};
use libc::{{c_char, c_int, c_uchar, c_void}};
use std::ptr;
use std::ptr::{{RawPtr}};
use std::slice;

type options = c_int;
struct pcre;
struct pcre_extra;

#[link(name = \"pcre\")]
extern {{
    static pcre_free: extern \"C\" fn(ptr: *const c_void);

    fn pcre_compile(pattern: *const c_char, options: options, errptr: *mut *const c_char, erroffset: *mut c_int, tableptr: *const c_uchar) -> *const pcre;
    fn pcre_exec(code: *const pcre, extra: *const pcre_extra, subject: *const c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *const c_char;
}}

fn main () {{
    unsafe {{
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_string();

        let pattern = \"^\\\\d+\\\\.\\\\d+\";
        pattern.with_c_str(|pattern_c_str| {{
            let mut err: *const c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if code.is_null() {{
                if code.is_null() {{
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() {{
                        None          => fail!(\"pcre_compile() failed at offset {{}}\", erroffset as uint),
                        Some(err_str) => fail!(\"pcre_compile() failed at offset {{}}: {{}}\", erroffset as uint, err_str)
                    }}
                }}
            }}
            assert!(code.is_not_null());

            let ovecsize = 1 * 3;
            let mut ovector = Vec::from_elem(ovecsize, 0 as c_int);
            version_str.with_c_str_unchecked(|version_c_str| {{
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, ovector.as_mut_ptr(), ovecsize as c_int);
                if rc < 0 {{
                    fail!(\"pcre_exec() failed\");
                }}

                print!(\"{{}}\", version_str.as_slice().slice_to(*ovector.get(1) as uint));
            }});

            pcre_free(code as *const c_void);
        }});
    }}
}}
");
        f.write_str(contents.as_slice()).map_err(|e| -> () {
            fail!("Package script error: Failed to write to `{}`: {}", versioncheck_rs_path.display(), e);
        });
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rustc_output = match Command::new("rustc").arg("versioncheck.rs").arg("-L").arg(pcre_lib_path.clone()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {}", e),
        Ok(rustc_output) => rustc_output
    };
    if !rustc_output.status.success() {
        println!("{}", str::from_utf8(rustc_output.output.as_slice()));
        println!("{}", str::from_utf8(rustc_output.error.as_slice()));
        fail!("Package script error: `rustc versioncheck.rs` failed: {}", rustc_output.status);
    }
    let versioncheck_output = match Command::new("./versioncheck").output() {
        Err(e) => fail!("Package script error: Failed to run `./versioncheck`: {}", e),
        Ok(versioncheck_output) => versioncheck_output
    };
    if !versioncheck_output.status.success() {
        println!("{}", str::from_utf8(versioncheck_output.output.as_slice()));
        println!("{}", str::from_utf8(versioncheck_output.error.as_slice()));
        fail!("versioncheck error: {}", versioncheck_output.status);
    }
    cd(&workspace_path);

    let output_ptr = versioncheck_output.output.as_ptr();
    let output_len = versioncheck_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
    debug!("output_str = `{}`", output_str);

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.as_slice().split('\n').rev();
    let version_str: String = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_string()
    };

    debug!("libpcre version {:s}", version_str.as_slice());

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str.as_slice()) {
        None               => fail!("Package script error: Failed to parse version string '{}'", version_str.as_slice()),
        Some(pcre_version) => pcre_version
    };

    if pcre_version < min_required_version {
        fail!("Package script error: Found libpcre version {}, but at least version {} is required", version_str.as_slice(), min_required_version);
    }

    // Create directories `bin` and `lib`
    let bin_path = workspace_path.join("bin");
    if !bin_path.exists() {
        if mkdir(&bin_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create the `bin` directory");
        }
    }
    let lib_path = workspace_path.join("lib");
    if !lib_path.exists() {
        if mkdir(&lib_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create the `lib` directory");
        }
    }

    // Compile libpcre-*.rlib
    match Command::new("rustc").arg("--out-dir").arg(lib_path).arg("src/pcre/mod.rs").arg("-L").arg(pcre_lib_path.clone()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {}", e),
        Ok(rustc_output) => {
            if !rustc_output.status.success() {
                println!("{}", str::from_utf8(rustc_output.output.as_slice()));
                println!("{}", str::from_utf8(rustc_output.error.as_slice()));
                fail!("Package script error: `rustc src/pcre/mod.rs` failed: {}", rustc_output.status);
            }
        }
    }

    match Command::new("rustc").arg("-o").arg(bin_path.join("pcredemo")).arg("src/pcredemo/main.rs").arg("-L").arg("lib").arg("-L").arg(pcre_lib_path.clone()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {}", e),
        Ok(rustc_output) => {
            if !rustc_output.status.success() {
                println!("{}", str::from_utf8(rustc_output.output.as_slice()));
                println!("{}", str::from_utf8(rustc_output.error.as_slice()));
                fail!("Package script error: `rustc src/pcredemo/main.rs` failed: {}", rustc_output.status);
            }
        }
    }
}
<|endoftext|>


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

use std::io::Write;
use std::io::stderr;

use log::{Log, LogLevel, LogRecord, LogMetadata};

use ansi_term::Style;
use ansi_term::Colour;
use ansi_term::ANSIString;

pub struct ImagLogger {
    prefix: String,
    lvl: LogLevel,
    color_enabled: bool,
}

impl ImagLogger {

    pub fn new(lvl: LogLevel) -> ImagLogger {
        ImagLogger {
            prefix: "[imag]".to_owned(),
            lvl: lvl,
            color_enabled: true
        }
    }

    pub fn with_prefix(mut self, pref: String) -> ImagLogger {
        self.prefix = pref;
        self
    }

    pub fn with_color(mut self, b: bool) -> ImagLogger {
        self.color_enabled = b;
        self
    }

    fn style_or_not(&self, c: Style, s: String) -> ANSIString {
        if self.color_enabled {
            c.paint(s)
        } else {
            ANSIString::from(s)
        }
    }

    fn color_or_not(&self, c: Colour, s: String) -> ANSIString {
        if self.color_enabled {
            c.paint(s)
        } else {
            ANSIString::from(s)
        }
    }

}

impl Log for ImagLogger {

    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.lvl
    }

    fn log(&self, record: &LogRecord) {
        use ansi_term::Colour::Red;
        use ansi_term::Colour::Yellow;
        use ansi_term::Colour::Cyan;

        if self.enabled(record.metadata()) {
            // TODO: This is just simple logging. Maybe we can enhance this lateron
            let loc = record.location();
            match record.metadata().level() {
                LogLevel::Debug => {
                    let lvl  = self.color_or_not(Cyan, format!("{}", record.level()));
                    let file = self.color_or_not(Cyan, format!("{}", loc.file()));
                    let ln   = self.color_or_not(Cyan, format!("{}", loc.line()));
                    let args = self.color_or_not(Cyan, format!("{}", record.args()));

                    writeln!(stderr(), "{}[{: <5}][{}][{: >5}]: {}", self.prefix, lvl, file, ln, args).ok();
                },
                LogLevel::Warn | LogLevel::Error => {
                    let lvl  = self.style_or_not(Red.blink(), format!("{}", record.level()));
                    let args = self.color_or_not(Red, format!("{}", record.args()));

                    writeln!(stderr(), "{}[{: <5}]: {}", self.prefix, lvl, args).ok();
                },
                LogLevel::Info => {
                    let lvl  = self.color_or_not(Yellow, format!("{}", record.level()));
                    let args = self.color_or_not(Yellow, format!("{}", record.args()));

                    writeln!(stderr(), "{}[{: <5}]: {}", self.prefix, lvl, args).ok();
                },
                _ => {
                    writeln!(stderr(), "{}[{: <5}]: {}", self.prefix, record.level(), record.args()).ok();
                },
            }
        }
    }
}

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

use std::io::Write;
use std::io::stderr;

use log::{Log, LogLevel, LogRecord, LogMetadata};

use ansi_term::Style;
use ansi_term::Colour;
use ansi_term::ANSIString;

pub struct ImagLogger {
    prefix: String,
    dbg_fileline: bool,
    lvl: LogLevel,
    color_enabled: bool,
}

impl ImagLogger {

    pub fn new(lvl: LogLevel) -> ImagLogger {
        ImagLogger {
            prefix: "[imag]".to_owned(),
            dbg_fileline: true,
            lvl: lvl,
            color_enabled: true
        }
    }

    pub fn with_dbg_file_and_line(mut self, b: bool) -> ImagLogger {
        self.dbg_fileline = b;
        self
    }

    pub fn with_prefix(mut self, pref: String) -> ImagLogger {
        self.prefix = pref;
        self
    }

    pub fn with_color(mut self, b: bool) -> ImagLogger {
        self.color_enabled = b;
        self
    }

    fn style_or_not(&self, c: Style, s: String) -> ANSIString {
        if self.color_enabled {
            c.paint(s)
        } else {
            ANSIString::from(s)
        }
    }

    fn color_or_not(&self, c: Colour, s: String) -> ANSIString {
        if self.color_enabled {
            c.paint(s)
        } else {
            ANSIString::from(s)
        }
    }

}

impl Log for ImagLogger {

    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.lvl
    }

    fn log(&self, record: &LogRecord) {
        use ansi_term::Colour::Red;
        use ansi_term::Colour::Yellow;
        use ansi_term::Colour::Cyan;

        if self.enabled(record.metadata()) {
            // TODO: This is just simple logging. Maybe we can enhance this lateron
            let loc = record.location();
            match record.metadata().level() {
                LogLevel::Debug => {
                    let lvl  = self.color_or_not(Cyan, format!("{}", record.level()));
                    let args = self.color_or_not(Cyan, format!("{}", record.args()));
                    if self.dbg_fileline {
                        let file = self.color_or_not(Cyan, format!("{}", loc.file()));
                        let ln   = self.color_or_not(Cyan, format!("{}", loc.line()));

                        writeln!(stderr(), "{}[{: <5}][{}][{: >5}]: {}", self.prefix, lvl, file, ln, args).ok();
                    } else {
                        writeln!(stderr(), "{}[{: <5}]: {}", self.prefix, lvl, args).ok();
                    }
                },
                LogLevel::Warn | LogLevel::Error => {
                    let lvl  = self.style_or_not(Red.blink(), format!("{}", record.level()));
                    let args = self.color_or_not(Red, format!("{}", record.args()));

                    writeln!(stderr(), "{}[{: <5}]: {}", self.prefix, lvl, args).ok();
                },
                LogLevel::Info => {
                    let lvl  = self.color_or_not(Yellow, format!("{}", record.level()));
                    let args = self.color_or_not(Yellow, format!("{}", record.args()));

                    writeln!(stderr(), "{}[{: <5}]: {}", self.prefix, lvl, args).ok();
                },
                _ => {
                    writeln!(stderr(), "{}[{: <5}]: {}", self.prefix, record.level(), record.args()).ok();
                },
            }
        }
    }
}

<|endoftext|>


<commit_before>use crate::schema::Value;
use serde::Serialize;
use std::collections::BTreeMap;

/// Internal representation of a document used for JSON
/// serialization.
///
/// A `NamedFieldDocument` is a simple representation of a document
/// as a `BTreeMap<String, Vec<Value>>`.
///
#[derive(Serialize)]
pub struct NamedFieldDocument(pub BTreeMap<String, Vec<Value>>);
<commit_msg>Make NamedFieldDocument deserializable<commit_after>use crate::schema::Value;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;

/// Internal representation of a document used for JSON
/// serialization.
///
/// A `NamedFieldDocument` is a simple representation of a document
/// as a `BTreeMap<String, Vec<Value>>`.
///
#[derive(Debug, Deserialize, Serialize)]
pub struct NamedFieldDocument(pub BTreeMap<String, Vec<Value>>);
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::iter::FromIterator;
use std::time::Duration;

use serialport as sp;
use errors::*;

/// Struct for containing Port information
struct OpenPort {
  /// The opened serial port
  /// SerialPort is not Sized, so it makes hashmap mad
  /// and so we deal with these shennanigans
  port: Box<sp::SerialPort>,
}

impl OpenPort {
  /// Write data to the serial port
  pub fn write_port(&mut self, data: &[u8]) -> Result<()> {
    self
      .port
      .write_all(data)
      .map_err(|err| ErrorKind::Io(err).into())
  }

  /// Read data from the serial port
  pub fn read_port(&mut self, buff: &mut [u8]) -> Result<usize> {
    self
      .port
      .read(buff)
      .map_err(|err| ErrorKind::Io(err).into())
  }
}

/// Manages ports and their locks
pub struct PortManager {
  /// Maintains list of ports
  open_ports: HashMap<String, OpenPort>,
}

impl PortManager {
  /// Create a new PortManager instance
  pub fn new() -> PortManager {
    PortManager { open_ports: HashMap::new() }
  }

  /// Has the port been opened
  pub fn is_port_open(&self, port_name: &String) -> bool {
    self.open_ports.contains_key(port_name)
  }

  /// List all serial ports
  pub fn list_ports(&self) -> Result<Vec<sp::SerialPortInfo>> {
    sp::available_ports().map_err(|e| ErrorKind::Serialport(e).into())
  }

  /// Open a port
  pub fn open_port(&mut self, port_name: &String) -> Result<()> {

    if self.is_port_open(port_name) {
      Ok(())
    } else {

      let sp_settings = sp::SerialPortSettings {
        baud_rate: sp::BaudRate::Baud115200,
        data_bits: sp::DataBits::Eight,
        flow_control: sp::FlowControl::None,
        parity: sp::Parity::None,
        // Bug: serialport 1.0.1 has One and Two mixed up
        // FIXME: Will be fixed in next release
        // So here we use Two to select One stop bit
        stop_bits: sp::StopBits::One,
        timeout: Duration::from_millis(1),
      };

      match sp::open_with_settings(&port_name, &sp_settings) {
        Ok(serial_port) => {
          let open_port = OpenPort { port: serial_port };
          self.open_ports.insert(port_name.to_string(), open_port);
          Ok(())
        }
        Err(e) => Err(ErrorKind::Serialport(e).into()),
      }
    }
  }

  pub fn close_port(&mut self, port_name: &String) {
    // This drops the underlying serial port and box
    self.open_ports.remove(port_name);
  }

  /// Write data to the port
  /// To write data to a port the port must have been previously locked by sub_id
  pub fn write_port(&mut self, port_name: &String, data: &[u8]) -> Result<()> {
    match self.open_ports.get_mut(port_name) {
      None => Err(ErrorKind::OpenPortNotFound(port_name.to_string()).into()),
      Some(p) => p.write_port(data),
    }
  }

  /// Read data from a port into the buffer buff
  /// If successful, returns Ok(usize) which is the number of
  /// bytes read
  pub fn read_port(&mut self, port_name: &String, buff: &mut [u8]) -> Result<usize> {
    match self.open_ports.get_mut(port_name) {
      None => Err(ErrorKind::OpenPortNotFound(port_name.to_string()).into()),
      Some(p) => p.read_port(buff),
    }
  }

  /// Read all currently open ports, return a hashmap of
  /// ports to Result<Vec<u8>>
  pub fn read_all_ports(&mut self) -> HashMap<String, Result<Vec<u8>>> {
    let mut buffer = vec![0; 4096];
    let mut map = HashMap::new();
    for (port_name, open_port) in self.open_ports.iter_mut() {
      match open_port.read_port(buffer.as_mut_slice()) {
        Ok(bytes_read) => {
          if bytes_read == 0 {
            // EOF
            info!("Received EOF reading from port {}", port_name);
            map.insert(
              port_name.to_string(),
              Err(ErrorKind::PortEOFError(port_name.clone()).into()),
            );
          } else {
            let bytes = buffer[0..bytes_read].to_vec();
            map.insert(port_name.to_string(), Ok(bytes));
          }
        }
        Err(e) => {
          // debug!("Error {} reading from port {}", e, port_name);
          match e.description() {
            "Operation timed out" => {}
            _ => {
              map.insert(port_name.to_string(), Err(e.into()));
            }
          }

        }
      }
    }
    map
  }

  /// Get a vec of open ports
  pub fn open_ports(&self) -> HashSet<String> {
    HashSet::<String>::from_iter(self.open_ports.keys().map(|k| k.clone()))
  }
}
<commit_msg>Remove FIXME<commit_after>use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::iter::FromIterator;
use std::time::Duration;

use serialport as sp;
use errors::*;

/// Struct for containing Port information
struct OpenPort {
  /// The opened serial port
  /// SerialPort is not Sized, so it makes hashmap mad
  /// and so we deal with these shennanigans
  port: Box<sp::SerialPort>,
}

impl OpenPort {
  /// Write data to the serial port
  pub fn write_port(&mut self, data: &[u8]) -> Result<()> {
    self
      .port
      .write_all(data)
      .map_err(|err| ErrorKind::Io(err).into())
  }

  /// Read data from the serial port
  pub fn read_port(&mut self, buff: &mut [u8]) -> Result<usize> {
    self
      .port
      .read(buff)
      .map_err(|err| ErrorKind::Io(err).into())
  }
}

/// Manages ports and their locks
pub struct PortManager {
  /// Maintains list of ports
  open_ports: HashMap<String, OpenPort>,
}

impl PortManager {
  /// Create a new PortManager instance
  pub fn new() -> PortManager {
    PortManager { open_ports: HashMap::new() }
  }

  /// Has the port been opened
  pub fn is_port_open(&self, port_name: &String) -> bool {
    self.open_ports.contains_key(port_name)
  }

  /// List all serial ports
  pub fn list_ports(&self) -> Result<Vec<sp::SerialPortInfo>> {
    sp::available_ports().map_err(|e| ErrorKind::Serialport(e).into())
  }

  /// Open a port
  pub fn open_port(&mut self, port_name: &String) -> Result<()> {

    if self.is_port_open(port_name) {
      Ok(())
    } else {

      let sp_settings = sp::SerialPortSettings {
        baud_rate: sp::BaudRate::Baud115200,
        data_bits: sp::DataBits::Eight,
        flow_control: sp::FlowControl::None,
        parity: sp::Parity::None,
        stop_bits: sp::StopBits::One,
        timeout: Duration::from_millis(1),
      };

      match sp::open_with_settings(&port_name, &sp_settings) {
        Ok(serial_port) => {
          let open_port = OpenPort { port: serial_port };
          self.open_ports.insert(port_name.to_string(), open_port);
          Ok(())
        }
        Err(e) => Err(ErrorKind::Serialport(e).into()),
      }
    }
  }

  pub fn close_port(&mut self, port_name: &String) {
    // This drops the underlying serial port and box
    self.open_ports.remove(port_name);
  }

  /// Write data to the port
  /// To write data to a port the port must have been previously locked by sub_id
  pub fn write_port(&mut self, port_name: &String, data: &[u8]) -> Result<()> {
    match self.open_ports.get_mut(port_name) {
      None => Err(ErrorKind::OpenPortNotFound(port_name.to_string()).into()),
      Some(p) => p.write_port(data),
    }
  }

  /// Read data from a port into the buffer buff
  /// If successful, returns Ok(usize) which is the number of
  /// bytes read
  pub fn read_port(&mut self, port_name: &String, buff: &mut [u8]) -> Result<usize> {
    match self.open_ports.get_mut(port_name) {
      None => Err(ErrorKind::OpenPortNotFound(port_name.to_string()).into()),
      Some(p) => p.read_port(buff),
    }
  }

  /// Read all currently open ports, return a hashmap of
  /// ports to Result<Vec<u8>>
  pub fn read_all_ports(&mut self) -> HashMap<String, Result<Vec<u8>>> {
    let mut buffer = vec![0; 4096];
    let mut map = HashMap::new();
    for (port_name, open_port) in self.open_ports.iter_mut() {
      match open_port.read_port(buffer.as_mut_slice()) {
        Ok(bytes_read) => {
          if bytes_read == 0 {
            // EOF
            info!("Received EOF reading from port {}", port_name);
            map.insert(
              port_name.to_string(),
              Err(ErrorKind::PortEOFError(port_name.clone()).into()),
            );
          } else {
            let bytes = buffer[0..bytes_read].to_vec();
            map.insert(port_name.to_string(), Ok(bytes));
          }
        }
        Err(e) => {
          // debug!("Error {} reading from port {}", e, port_name);
          match e.description() {
            "Operation timed out" => {}
            _ => {
              map.insert(port_name.to_string(), Err(e.into()));
            }
          }

        }
      }
    }
    map
  }

  /// Get a vec of open ports
  pub fn open_ports(&self) -> HashSet<String> {
    HashSet::<String>::from_iter(self.open_ports.keys().map(|k| k.clone()))
  }
}
<|endoftext|>


<commit_before>extern crate rusoto_mock;

use ::*;

use rusoto_core::Region;
use self::rusoto_mock::*;

#[test]
fn test_upload_multipart_part_response() {
    let mock = MockRequestDispatcher::with_status(204).with_header("x-amz-sha256-tree-hash", "42");
    let client = GlacierClient::new_with(mock, MockCredentialsProvider, Region::UsEast1);

    let upload_part_copy_req = UploadMultipartPartInput {
        account_id: "foo".to_owned(),
        upload_id: "bar".to_owned(),
        vault_name: "baz".to_owned(),
        ..Default::default()
    };
    let result = client
        .upload_multipart_part(upload_part_copy_req)
        .sync()
        .expect("Should parse empty body");
    assert_eq!(result.checksum.unwrap(), "42", "Should handle checksum in response");
}
<commit_msg>Test another Glacier response path.<commit_after>extern crate rusoto_mock;

use ::*;

use rusoto_core::Region;
use self::rusoto_mock::*;

#[test]
fn test_initiate_multipart_part_response() {
    let mock = MockRequestDispatcher::with_status(201)
        .with_header("Location", "/111122223333/vaults/examplevault/multipart-uploads/OW2fM5iVylEpFEMM9_HpKowRapC3vn5sSL39_396UW9zLFUWVrnRHaPjUJddQ5OxSHVXjYtrN47NBZ-khxOjyEXAMPLE")
        .with_header("x-amz-multipart-upload-id", "OW2fM5iVylEpFEMM9_HpKowRapC3vn5sSL39_396UW9zLFUWVrnRHaPjUJddQ5OxSHVXjYtrN47NBZ-khxOjyEXAMPLE");
    let client = GlacierClient::new_with(mock, MockCredentialsProvider, Region::UsEast1);

    let initiate_multipart_upload_req = InitiateMultipartUploadInput {
        account_id: "111122223333".to_owned(),
        vault_name: "examplevault".to_owned(),
        ..Default::default()
    };
    let result = client
        .initiate_multipart_upload(initiate_multipart_upload_req)
        .sync()
        .expect("Should parse empty body");
    assert_eq!(result.location.unwrap(), "/111122223333/vaults/examplevault/multipart-uploads/OW2fM5iVylEpFEMM9_HpKowRapC3vn5sSL39_396UW9zLFUWVrnRHaPjUJddQ5OxSHVXjYtrN47NBZ-khxOjyEXAMPLE", "Should see location in response");
    assert_eq!(result.upload_id.unwrap(), "OW2fM5iVylEpFEMM9_HpKowRapC3vn5sSL39_396UW9zLFUWVrnRHaPjUJddQ5OxSHVXjYtrN47NBZ-khxOjyEXAMPLE", "Should see upload id in response");
}

#[test]
fn test_upload_multipart_part_response() {
    let mock = MockRequestDispatcher::with_status(204).with_header("x-amz-sha256-tree-hash", "42");
    let client = GlacierClient::new_with(mock, MockCredentialsProvider, Region::UsEast1);

    let upload_part_copy_req = UploadMultipartPartInput {
        account_id: "foo".to_owned(),
        upload_id: "bar".to_owned(),
        vault_name: "baz".to_owned(),
        ..Default::default()
    };
    let result = client
        .upload_multipart_part(upload_part_copy_req)
        .sync()
        .expect("Should parse empty body");
    assert_eq!(result.checksum.unwrap(), "42", "Should handle checksum in response");
}<|endoftext|>