<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::{
    env,
    error::Error,
    fmt::{self, Display},
    fs::OpenOptions,
    path::PathBuf,
};

use clap::{App, Arg};
use data_encoding::BASE32_NOPAD;
use serde_json::{json, Value};

use devicemapper::{Bytes, Sectors};

use libstratis::{
    engine::{blkdev_size, crypt_metadata_size, BDA},
    stratis::StratisResult,
};

#[derive(Debug)]
struct ExecutableError(String);

impl Display for ExecutableError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Error for ExecutableError {}

/// Compare two strings and output on stdout 0 if they match and 1 if they do not.
fn string_compare(arg1: &str, arg2: &str) {
    if arg1 == arg2 {
        println!("0");
    } else {
        println!("1");
    }
}

fn base32_decode(var_name: &str, base32_str: &str) -> Result<(), Box<dyn Error>> {
    let base32_decoded = String::from_utf8(BASE32_NOPAD.decode(base32_str.as_bytes())?)?;
    println!("{}={}", var_name, base32_decoded);
    Ok(())
}

// Predict the free space that would be available in a pool given the
// following information:
// 1. Whether or not the pool is to be encrypted.
// 2. All the devices to be included in the pool.
fn predict_usage(encrypted: bool, devices: Vec<PathBuf>) -> Result<(), Box<dyn Error>> {
    let crypt_metadata_size = if encrypted {
        Bytes(u128::from(crypt_metadata_size()))
    } else {
        Bytes(0)
    };

    let crypt_metadata_size_sectors = crypt_metadata_size.sectors();

    // verify that crypt metadata size is divisible by sectors size
    assert_eq!(crypt_metadata_size_sectors.bytes(), crypt_metadata_size);

    let stratis_metadata_size_sectors = BDA::default().extended_size().sectors();

    let sizes = devices
        .iter()
        .map(|device| {
            OpenOptions::new()
                .read(true)
                .open(&device)
                .map_err(|e| e.into())
                .and_then(|f| blkdev_size(&f))
                // always truncated to sectors by stratisd
                .map(|s| s.sectors())
        })
        .collect::<StratisResult<Vec<_>>>()?;

    let total_size: Sectors = sizes.iter().cloned().sum();

    let stratis_device_sizes = sizes
        .iter()
        .map(|&s| s - crypt_metadata_size_sectors)
        .collect::<Vec<_>>();

    let stratis_avail_sizes = stratis_device_sizes
        .iter()
        .map(|&s| s - stratis_metadata_size_sectors)
        .collect::<Vec<_>>();

    let avail_size: Sectors = stratis_avail_sizes.iter().cloned().sum();

    let used_size = total_size - avail_size;

    let total_size_str = Value::String((*(total_size.bytes())).to_string());
    let used_size_str = Value::String((*(used_size.bytes())).to_string());
    let avail_size_str = Value::String((*(avail_size.bytes())).to_string());

    let json = json!(
        {"total": total_size_str, "used": used_size_str, "free": avail_size_str}
    );

    println!("{}", json);

    Ok(())
}

/// Parse the arguments based on which hard link was accessed.
fn parse_args() -> Result<(), Box<dyn Error>> {
    let args = env::args().collect::<Vec<_>>();
    let argv1 = args[0].as_str();

    if argv1.ends_with("stratis-str-cmp") {
        if args.len() != 3 {
            return Err(Box::new(ExecutableError(format!(
                "{} requires two positional arguments",
                argv1
            ))));
        }

        string_compare(&args[1], &args[2]);
    } else if argv1.ends_with("stratis-base32-decode") {
        if args.len() != 3 {
            return Err(Box::new(ExecutableError(format!(
                "{} requires two positional arguments",
                argv1
            ))));
        }

        base32_decode(&args[1], &args[2])?;
    } else if argv1.ends_with("stratis-predict-usage") {
        let parser = App::new("stratis-predict-usage")
            .arg(
                Arg::with_name("encrypted")
                    .long("encrypted")
                    .help("Whether the pool will be encrypted"),
            )
            .arg(
                Arg::with_name("blockdevs")
                    .multiple(true)
                    .help("Devices to include in the pool"),
            );
        let matches = parser.get_matches_from(&args);
        predict_usage(
            matches.is_present("encrypted"),
            matches
                .values_of("blockdevs")
                .map(|bs| bs.map(PathBuf::from).collect::<Vec<_>>())
                .unwrap_or_default(),
        )?;
    } else {
        return Err(Box::new(ExecutableError(format!(
            "{} is not a recognized executable name",
            argv1
        ))));
    }

    Ok(())
}

/// This is the main method that dispatches the desired method based on the first
/// argument (the executable name). This will vary based on the hard link that was
/// invoked.
fn main() -> Result<(), Box<dyn Error>> {
    parse_args()
}
<commit_msg>Use a clap parser for stratis-str-cmp and stratis-base32-decode<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::{
    env,
    error::Error,
    fmt::{self, Display},
    fs::OpenOptions,
    path::PathBuf,
};

use clap::{App, Arg};
use data_encoding::BASE32_NOPAD;
use serde_json::{json, Value};

use devicemapper::{Bytes, Sectors};

use libstratis::{
    engine::{blkdev_size, crypt_metadata_size, BDA},
    stratis::StratisResult,
};

#[derive(Debug)]
struct ExecutableError(String);

impl Display for ExecutableError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Error for ExecutableError {}

/// Compare two strings and output on stdout 0 if they match and 1 if they do not.
fn string_compare(arg1: &str, arg2: &str) {
    if arg1 == arg2 {
        println!("0");
    } else {
        println!("1");
    }
}

fn base32_decode(var_name: &str, base32_str: &str) -> Result<(), Box<dyn Error>> {
    let base32_decoded = String::from_utf8(BASE32_NOPAD.decode(base32_str.as_bytes())?)?;
    println!("{}={}", var_name, base32_decoded);
    Ok(())
}

// Predict the free space that would be available in a pool given the
// following information:
// 1. Whether or not the pool is to be encrypted.
// 2. All the devices to be included in the pool.
fn predict_usage(encrypted: bool, devices: Vec<PathBuf>) -> Result<(), Box<dyn Error>> {
    let crypt_metadata_size = if encrypted {
        Bytes(u128::from(crypt_metadata_size()))
    } else {
        Bytes(0)
    };

    let crypt_metadata_size_sectors = crypt_metadata_size.sectors();

    // verify that crypt metadata size is divisible by sectors size
    assert_eq!(crypt_metadata_size_sectors.bytes(), crypt_metadata_size);

    let stratis_metadata_size_sectors = BDA::default().extended_size().sectors();

    let sizes = devices
        .iter()
        .map(|device| {
            OpenOptions::new()
                .read(true)
                .open(&device)
                .map_err(|e| e.into())
                .and_then(|f| blkdev_size(&f))
                // always truncated to sectors by stratisd
                .map(|s| s.sectors())
        })
        .collect::<StratisResult<Vec<_>>>()?;

    let total_size: Sectors = sizes.iter().cloned().sum();

    let stratis_device_sizes = sizes
        .iter()
        .map(|&s| s - crypt_metadata_size_sectors)
        .collect::<Vec<_>>();

    let stratis_avail_sizes = stratis_device_sizes
        .iter()
        .map(|&s| s - stratis_metadata_size_sectors)
        .collect::<Vec<_>>();

    let avail_size: Sectors = stratis_avail_sizes.iter().cloned().sum();

    let used_size = total_size - avail_size;

    let total_size_str = Value::String((*(total_size.bytes())).to_string());
    let used_size_str = Value::String((*(used_size.bytes())).to_string());
    let avail_size_str = Value::String((*(avail_size.bytes())).to_string());

    let json = json!(
        {"total": total_size_str, "used": used_size_str, "free": avail_size_str}
    );

    println!("{}", json);

    Ok(())
}

/// Parse the arguments based on which hard link was accessed.
fn parse_args() -> Result<(), Box<dyn Error>> {
    let args = env::args().collect::<Vec<_>>();
    let argv1 = args[0].as_str();

    if argv1.ends_with("stratis-str-cmp") {
        let parser = App::new("stratis-str-cmp")
            .arg(
                Arg::with_name("left")
                    .help("First string to compare")
                    .required(true),
            )
            .arg(
                Arg::with_name("right")
                    .help("Second string to compare")
                    .required(true),
            );
        let matches = parser.get_matches_from(&args);
        string_compare(
            &matches.value_of("left").expect("required argument"),
            &matches.value_of("right").expect("required argument"),
        );
    } else if argv1.ends_with("stratis-base32-decode") {
        let parser = App::new("stratis-base32-decode")
            .arg(
                Arg::with_name("key")
                    .help("Key for output string")
                    .required(true),
            )
            .arg(
                Arg::with_name("value")
                    .help("value to be decoded from base32 encoded sequence")
                    .required(true),
            );
        let matches = parser.get_matches_from(&args);
        base32_decode(
            &matches.value_of("key").expect("required argument"),
            &matches.value_of("value").expect("required argument"),
        )?;
    } else if argv1.ends_with("stratis-predict-usage") {
        let parser = App::new("stratis-predict-usage")
            .arg(
                Arg::with_name("encrypted")
                    .long("encrypted")
                    .help("Whether the pool will be encrypted"),
            )
            .arg(
                Arg::with_name("blockdevs")
                    .multiple(true)
                    .help("Devices to include in the pool"),
            );
        let matches = parser.get_matches_from(&args);
        predict_usage(
            matches.is_present("encrypted"),
            matches
                .values_of("blockdevs")
                .map(|bs| bs.map(PathBuf::from).collect::<Vec<_>>())
                .unwrap_or_default(),
        )?;
    } else {
        return Err(Box::new(ExecutableError(format!(
            "{} is not a recognized executable name",
            argv1
        ))));
    }

    Ok(())
}

/// This is the main method that dispatches the desired method based on the first
/// argument (the executable name). This will vary based on the hard link that was
/// invoked.
fn main() -> Result<(), Box<dyn Error>> {
    parse_args()
}
<|endoftext|>


<commit_before>// Copyright 2016 The xi-editor Authors.
//
// 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.

#[macro_use]
extern crate log;
extern crate chrono;
extern crate fern;

extern crate dirs;

extern crate xi_core_lib;
extern crate xi_rpc;

use std::collections::HashMap;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

use xi_core_lib::XiCore;
use xi_rpc::RpcLoop;

const XI_LOG_DIR: &str = "xi-core";
const XI_LOG_FILE: &str = "xi-core.log";

fn get_logging_directory_path<P: AsRef<Path>>(directory: P) -> Result<PathBuf, io::Error> {
    match dirs::data_local_dir() {
        Some(mut log_dir) => {
            log_dir.push(directory);
            Ok(log_dir)
        }
        None => Err(io::Error::new(
            io::ErrorKind::NotFound,
            "No standard logging directory known for this platform",
        )),
    }
}

/// This function tries to create the parent directories for a file
///
/// It wraps around the `parent()` function of `Path` which returns an `Option<&Path>` and
/// `fs::create_dir_all` which returns an `io::Result<()`.
///
/// This allows you to use `?`/`try!()` to create the dir and you recive the additional custom error for when `parent()`
/// returns nothing.
///
/// # Errors
/// This can return an `io::Error` if `fs::create_dir_all` fails or if `parent()` returns `None`.
/// See `Path`'s `parent()` function for more details.
/// # Examples
/// ```
/// use std::path::Path;
/// use std::ffi::OsStr;
///
/// let path_with_file = Path::new("/some/directory/then/file");
/// assert_eq!(Some(OsStr::new("file")), path_with_file.file_name());
/// assert_eq!(create_log_directory(path_with_file).is_ok(), true);
///
/// let path_with_other_file = Path::new("/other_file");
/// assert_eq!(Some(OsStr::new("other_file")), path_with_other_file.file_name());
/// assert_eq!(create_log_directory(path_with_file).is_ok(), true);
///
/// // Path that is just the root or prefix:
/// let path_without_file = Path::new("/");
/// assert_eq!(None, path_without_file.file_name());
/// assert_eq!(create_log_directory(path_without_file).is_ok(), false);
/// ```
fn create_log_directory(path_with_file: &Path) -> Result<(), io::Error> {
    let log_dir = path_with_file.parent().ok_or(io::Error::new(
        io::ErrorKind::InvalidInput,
        format!(
            "Unable to get the parent of the following Path: {}, Your path should contain a file name",
            path_with_file.display(),
        ),
    ))?;
    fs::create_dir_all(log_dir)?;
    Ok(())
}

fn setup_logging(logging_path: Option<&Path>) -> Result<(), fern::InitError> {
    let level_filter = match std::env::var("XI_LOG") {
        Ok(level) => match level.to_lowercase().as_ref() {
            "trace" => log::LevelFilter::Trace,
            "debug" => log::LevelFilter::Debug,
            _ => log::LevelFilter::Info,
        },
        // Default to info
        Err(_) => log::LevelFilter::Info,
    };

    let mut fern_dispatch = fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!(
                "{}[{}][{}] {}",
                chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
                record.target(),
                record.level(),
                message,
            ))
        }).level(level_filter)
        .chain(io::stderr());

    if let Some(logging_file_path) = logging_path {
        create_log_directory(logging_file_path)?;

        fern_dispatch = fern_dispatch.chain(fern::log_file(logging_file_path)?);
    };

    // Start fern
    fern_dispatch.apply()?;
    info!("Logging with fern is set up");

    // Log details of the logging_file_path result using fern/log
    // Either logging the path fern is outputting to or the error from obtaining the path
    match logging_path {
        Some(logging_file_path) => info!("Writing logs to: {}", logging_file_path.display()),
        None => warn!("No path was supplied for the log file. Not saving logs to disk, falling back to just stderr"),
    }
    Ok(())
}

fn generate_logging_path(logfile_config: LogfileConfig) -> Result<PathBuf, io::Error> {
    // Use the file name set in logfile_config or fallback to the default
    let logfile_file_name = match logfile_config.file {
        Some(file_name) => file_name,
        None => PathBuf::from(XI_LOG_FILE),
    };
    if logfile_file_name.eq(Path::new("")) {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "A blank file name was supplied",
        ));
    };
    // Use the directory name set in logfile_config or fallback to the default
    let logfile_directory_name = match logfile_config.directory {
        Some(dir) => dir,
        None => PathBuf::from(XI_LOG_DIR),
    };

    let mut logging_directory_path = get_logging_directory_path(logfile_directory_name)?;

    // Add the file name & return the full path
    logging_directory_path.push(logfile_file_name);
    Ok(logging_directory_path)
}

fn get_flags() -> HashMap<String, Option<String>> {
    let mut flags: HashMap<String, Option<String>> = HashMap::new();

    let flag_prefix = "-";
    let mut args_iterator = std::env::args().peekable();
    while let Some(arg) = args_iterator.next() {
        if arg.starts_with(flag_prefix) {
            let key = arg.trim_left_matches(flag_prefix).to_string();

            // Check the next argument doesn't start with the flag prefix
            // map_or accounts for peek returning an Option
            let next_arg_not_a_flag: bool = args_iterator
                .peek()
                .map_or(false, |val| !val.starts_with(flag_prefix));
            if next_arg_not_a_flag {
                flags.insert(key, args_iterator.next());
            }
        }
    }
    flags
}

struct EnvFlagConfig {
    env_name: &'static str,
    flag_name: &'static str,
}

/// Extracts a value from the flags and the env.
///
/// In this order: `String` from the flags, then `String` from the env, then `None`
fn extract_env_or_flag(
    flags: &HashMap<String, Option<String>>,
    conf: EnvFlagConfig,
) -> Option<String> {
    flags
        .get(conf.flag_name)
        .cloned()
        .unwrap_or(std::env::var(conf.env_name).ok())
}

struct LogfileConfig {
    directory: Option<PathBuf>,
    file: Option<PathBuf>,
}

fn generate_logfile_config(flags: &HashMap<String, Option<String>>) -> LogfileConfig {
    // If the key is set, get the Option within
    let log_dir_env_flag = EnvFlagConfig {
        env_name: "XI_LOG_DIR",
        flag_name: "log-dir",
    };
    let log_file_env_flag = EnvFlagConfig {
        env_name: "XI_LOG_FILE",
        flag_name: "log-file",
    };
    let log_dir_flag_option = extract_env_or_flag(&flags, log_dir_env_flag).map(PathBuf::from);

    let log_file_flag_option = extract_env_or_flag(&flags, log_file_env_flag).map(PathBuf::from);

    LogfileConfig {
        directory: log_dir_flag_option,
        file: log_file_flag_option,
    }
}

fn main() {
    let mut state = XiCore::new();
    let stdin = io::stdin();
    let stdout = io::stdout();
    let mut rpc_looper = RpcLoop::new(stdout);

    let flags = get_flags();

    let logfile_config = generate_logfile_config(&flags);

    let logging_path_result = generate_logging_path(logfile_config);

    let logging_path = logging_path_result
        .as_ref()
        .map(|p: &PathBuf| -> &Path { p.as_path() })
        .ok();

    if let Err(e) = setup_logging(logging_path) {
        eprintln!(
            "[ERROR] setup_logging returned error, logging not enabled: {:?}",
            e
        );
    }
    if let Err(e) = logging_path_result.as_ref() {
        warn!(
            "Unable to generate the logging path to pass to set up: {}",
            e
        )
    }

    match rpc_looper.mainloop(|| stdin.lock(), &mut state) {
        Ok(_) => (),
        Err(err) => error!("xi-core exited with error:\n{:?}", err),
    }
}
<commit_msg>Fixed a minor issue with the Docs<commit_after>// Copyright 2016 The xi-editor Authors.
//
// 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.

#[macro_use]
extern crate log;
extern crate chrono;
extern crate fern;

extern crate dirs;

extern crate xi_core_lib;
extern crate xi_rpc;

use std::collections::HashMap;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

use xi_core_lib::XiCore;
use xi_rpc::RpcLoop;

const XI_LOG_DIR: &str = "xi-core";
const XI_LOG_FILE: &str = "xi-core.log";

fn get_logging_directory_path<P: AsRef<Path>>(directory: P) -> Result<PathBuf, io::Error> {
    match dirs::data_local_dir() {
        Some(mut log_dir) => {
            log_dir.push(directory);
            Ok(log_dir)
        }
        None => Err(io::Error::new(
            io::ErrorKind::NotFound,
            "No standard logging directory known for this platform",
        )),
    }
}

/// This function tries to create the parent directories for a file
///
/// It wraps around the `parent()` function of `Path` which returns an `Option<&Path>` and
/// `fs::create_dir_all` which returns an `io::Result<()>`.
///
/// This allows you to use `?`/`try!()` to create the dir and you recive the additional custom error for when `parent()`
/// returns nothing.
///
/// # Errors
/// This can return an `io::Error` if `fs::create_dir_all` fails or if `parent()` returns `None`.
/// See `Path`'s `parent()` function for more details.
/// # Examples
/// ```
/// use std::path::Path;
/// use std::ffi::OsStr;
///
/// let path_with_file = Path::new("/some/directory/then/file");
/// assert_eq!(Some(OsStr::new("file")), path_with_file.file_name());
/// assert_eq!(create_log_directory(path_with_file).is_ok(), true);
///
/// let path_with_other_file = Path::new("/other_file");
/// assert_eq!(Some(OsStr::new("other_file")), path_with_other_file.file_name());
/// assert_eq!(create_log_directory(path_with_file).is_ok(), true);
///
/// // Path that is just the root or prefix:
/// let path_without_file = Path::new("/");
/// assert_eq!(None, path_without_file.file_name());
/// assert_eq!(create_log_directory(path_without_file).is_ok(), false);
/// ```
fn create_log_directory(path_with_file: &Path) -> io::Result<()> {
    let log_dir = path_with_file.parent().ok_or(io::Error::new(
        io::ErrorKind::InvalidInput,
        format!(
            "Unable to get the parent of the following Path: {}, Your path should contain a file name",
            path_with_file.display(),
        ),
    ))?;
    fs::create_dir_all(log_dir)?;
    Ok(())
}

fn setup_logging(logging_path: Option<&Path>) -> Result<(), fern::InitError> {
    let level_filter = match std::env::var("XI_LOG") {
        Ok(level) => match level.to_lowercase().as_ref() {
            "trace" => log::LevelFilter::Trace,
            "debug" => log::LevelFilter::Debug,
            _ => log::LevelFilter::Info,
        },
        // Default to info
        Err(_) => log::LevelFilter::Info,
    };

    let mut fern_dispatch = fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!(
                "{}[{}][{}] {}",
                chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
                record.target(),
                record.level(),
                message,
            ))
        }).level(level_filter)
        .chain(io::stderr());

    if let Some(logging_file_path) = logging_path {
        create_log_directory(logging_file_path)?;

        fern_dispatch = fern_dispatch.chain(fern::log_file(logging_file_path)?);
    };

    // Start fern
    fern_dispatch.apply()?;
    info!("Logging with fern is set up");

    // Log details of the logging_file_path result using fern/log
    // Either logging the path fern is outputting to or the error from obtaining the path
    match logging_path {
        Some(logging_file_path) => info!("Writing logs to: {}", logging_file_path.display()),
        None => warn!("No path was supplied for the log file. Not saving logs to disk, falling back to just stderr"),
    }
    Ok(())
}

fn generate_logging_path(logfile_config: LogfileConfig) -> Result<PathBuf, io::Error> {
    // Use the file name set in logfile_config or fallback to the default
    let logfile_file_name = match logfile_config.file {
        Some(file_name) => file_name,
        None => PathBuf::from(XI_LOG_FILE),
    };
    if logfile_file_name.eq(Path::new("")) {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "A blank file name was supplied",
        ));
    };
    // Use the directory name set in logfile_config or fallback to the default
    let logfile_directory_name = match logfile_config.directory {
        Some(dir) => dir,
        None => PathBuf::from(XI_LOG_DIR),
    };

    let mut logging_directory_path = get_logging_directory_path(logfile_directory_name)?;

    // Add the file name & return the full path
    logging_directory_path.push(logfile_file_name);
    Ok(logging_directory_path)
}

fn get_flags() -> HashMap<String, Option<String>> {
    let mut flags: HashMap<String, Option<String>> = HashMap::new();

    let flag_prefix = "-";
    let mut args_iterator = std::env::args().peekable();
    while let Some(arg) = args_iterator.next() {
        if arg.starts_with(flag_prefix) {
            let key = arg.trim_left_matches(flag_prefix).to_string();

            // Check the next argument doesn't start with the flag prefix
            // map_or accounts for peek returning an Option
            let next_arg_not_a_flag: bool = args_iterator
                .peek()
                .map_or(false, |val| !val.starts_with(flag_prefix));
            if next_arg_not_a_flag {
                flags.insert(key, args_iterator.next());
            }
        }
    }
    flags
}

struct EnvFlagConfig {
    env_name: &'static str,
    flag_name: &'static str,
}

/// Extracts a value from the flags and the env.
///
/// In this order: `String` from the flags, then `String` from the env, then `None`
fn extract_env_or_flag(
    flags: &HashMap<String, Option<String>>,
    conf: EnvFlagConfig,
) -> Option<String> {
    flags
        .get(conf.flag_name)
        .cloned()
        .unwrap_or(std::env::var(conf.env_name).ok())
}

struct LogfileConfig {
    directory: Option<PathBuf>,
    file: Option<PathBuf>,
}

fn generate_logfile_config(flags: &HashMap<String, Option<String>>) -> LogfileConfig {
    // If the key is set, get the Option within
    let log_dir_env_flag = EnvFlagConfig {
        env_name: "XI_LOG_DIR",
        flag_name: "log-dir",
    };
    let log_file_env_flag = EnvFlagConfig {
        env_name: "XI_LOG_FILE",
        flag_name: "log-file",
    };
    let log_dir_flag_option = extract_env_or_flag(&flags, log_dir_env_flag).map(PathBuf::from);

    let log_file_flag_option = extract_env_or_flag(&flags, log_file_env_flag).map(PathBuf::from);

    LogfileConfig {
        directory: log_dir_flag_option,
        file: log_file_flag_option,
    }
}

fn main() {
    let mut state = XiCore::new();
    let stdin = io::stdin();
    let stdout = io::stdout();
    let mut rpc_looper = RpcLoop::new(stdout);

    let flags = get_flags();

    let logfile_config = generate_logfile_config(&flags);

    let logging_path_result = generate_logging_path(logfile_config);

    let logging_path = logging_path_result
        .as_ref()
        .map(|p: &PathBuf| -> &Path { p.as_path() })
        .ok();

    if let Err(e) = setup_logging(logging_path) {
        eprintln!(
            "[ERROR] setup_logging returned error, logging not enabled: {:?}",
            e
        );
    }
    if let Err(e) = logging_path_result.as_ref() {
        warn!(
            "Unable to generate the logging path to pass to set up: {}",
            e
        )
    }

    match rpc_looper.mainloop(|| stdin.lock(), &mut state) {
        Ok(_) => (),
        Err(err) => error!("xi-core exited with error:\n{:?}", err),
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate kiss3d;
extern crate nalgebra as na;

use clap::Parser;
use kiss3d::light::Light;
use kiss3d::window::Window;
use na::vector;
use na::{Translation, UnitQuaternion, Vector3};

/// Program to display a 3x3 cube solution.
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
   /// Solve the planes problem.
   #[arg(short, long)]
   planes: bool,
}

fn main() {
    env_logger::init();
    let args = Args::parse();

    let mut window = Window::new("Kiss3d: cube");
    window.set_light(Light::StickToCamera);

    let mut cubes = Vec::new();
    let rot1 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), -0.5);
    for i in 0..27 {
        let c = window.add_cube(0.08, 0.08, 0.08);
        cubes.push(c);

        cubes[i].append_rotation(&rot1);

        let r = (i % 3) as f32 * 0.1;
        let c = (i / 9) as f32 * 0.1;
        let d = (i % 9) as f32 * 0.05;
        cubes[i].append_translation(&Translation { vector: vector!(r, c, d) });
    }

    if args.planes {
        for i in 0..9 {
                cubes[i].set_color(1., 0., 0.);
            }
            for i in 9..27 {
                cubes[i].set_color(0., 1., 0.);
            }
            for i in 18..27 {
                cubes[i].set_color(0., 0., 1.);
            }
    }

    let rot = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 0.014);
    while window.render() {
        for i in 0..27 {
            cubes[i].append_rotation(&rot);
        }
    }
}<commit_msg>Fix identation.<commit_after>extern crate clap;
extern crate kiss3d;
extern crate nalgebra as na;

use clap::Parser;
use kiss3d::light::Light;
use kiss3d::window::Window;
use na::vector;
use na::{Translation, UnitQuaternion, Vector3};

/// Program to display a 3x3 cube solution.
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
   /// Solve the planes problem.
   #[arg(short, long)]
   planes: bool,
}

fn main() {
    env_logger::init();
    let args = Args::parse();

    let mut window = Window::new("Kiss3d: cube");
    window.set_light(Light::StickToCamera);

    let mut cubes = Vec::new();
    let rot1 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), -0.5);
    for i in 0..27 {
        let c = window.add_cube(0.08, 0.08, 0.08);
        cubes.push(c);

        cubes[i].append_rotation(&rot1);

        let r = (i % 3) as f32 * 0.1;
        let c = (i / 9) as f32 * 0.1;
        let d = (i % 9) as f32 * 0.05;
        cubes[i].append_translation(&Translation { vector: vector!(r, c, d) });
    }

    if args.planes {
        for i in 0..9 {
            cubes[i].set_color(1., 0., 0.);
        }
        for i in 9..27 {
            cubes[i].set_color(0., 1., 0.);
        }
        for i in 18..27 {
            cubes[i].set_color(0., 0., 1.);
        }
    }

    let rot = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 0.014);
    while window.render() {
        for i in 0..27 {
            cubes[i].append_rotation(&rot);
        }
    }
}<|endoftext|>


<commit_before>use super::Position;
use super::Range;
use std::str::from_utf8;

pub struct GapBuffer {
    data: Vec<u8>,
    gap_start: usize,
    gap_length: usize,
}

pub fn new(mut data: String) -> GapBuffer {
    let mut bytes = data.into_bytes();
    let capacity = bytes.capacity();
    let gap_start = bytes.len();
    let gap_length = capacity - gap_start;
    unsafe {
        bytes.set_len(capacity);
    }
    GapBuffer{ data: bytes, gap_start: gap_start, gap_length: gap_length }
}

impl GapBuffer {
    // TODO: Return an optional error.
    pub fn insert(&mut self, data: &str, position: &Position) {
        // Ensure we have the capacity to insert this data.
        if data.len() > self.gap_length {
            // TODO: Move gap to the end before resizing buffer.
            self.data.reserve(data.len());
            let capacity = self.data.capacity();
            self.gap_length = capacity - self.gap_start;
            unsafe {
                self.data.set_len(capacity);
            }
        }

        let offset = match self.find_offset(position) {
            Some(o) => o,
            None => return,
        };

        self.move_gap(offset);
        self.write_to_gap(data);
    }

    pub fn to_string(&self) -> String {
        from_utf8(&self.data[..self.gap_start]).unwrap().to_string() + from_utf8(&self.data[self.gap_start+self.gap_length..]).unwrap()
    }

    // Maps a position to its offset equivalent in the data.
    fn find_offset(&self, position: &Position) -> Option<usize> {
        let first_half = from_utf8(&self.data[0..self.gap_start]).unwrap();
        let mut line = 0;
        let mut line_offset = 0;

        for char_index in first_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        // We haven't reached the position yet, so we'll move on to the other half.
        let second_half = from_utf8(&self.data[self.gap_start+self.gap_length..self.data.len()-1]).unwrap();
        for char_index in second_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(self.gap_start + self.gap_length + offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        None
    }

    fn move_gap(&mut self, offset: usize) {
        if offset < self.gap_start {
            for index in (offset..self.gap_start) {
                self.data[index + self.gap_length] = self.data[index];
                self.data[index] = 0;
            }
        } else if offset > self.gap_start {
            for index in (self.gap_start+self.gap_length..offset) {
                self.data[index-self.gap_length] = self.data[index];
                self.data[index] = 0;
            }
        }

        self.gap_start = offset;
        for byte in self.data.iter() {
            println!("{}", byte);
        }
    }

    fn write_to_gap(&mut self, data: &str) {
        for byte in data.bytes() {
            self.data[self.gap_start] = byte;
            self.gap_start+=1;
            self.gap_length-=1;
        }
    }
}

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

    #[test]
    fn insert_works() {
        let mut gb = new("This is a test.\nPlease be gentle.".to_string());
        gb.insert(" very", &Position { line: 1, offset: 9 });
        assert_eq!(gb.to_string(), "This is a test.\nPlease be very gentle.");
    }
}
<commit_msg>Remove buffer data debug printing.<commit_after>use super::Position;
use super::Range;
use std::str::from_utf8;

pub struct GapBuffer {
    data: Vec<u8>,
    gap_start: usize,
    gap_length: usize,
}

pub fn new(mut data: String) -> GapBuffer {
    let mut bytes = data.into_bytes();
    let capacity = bytes.capacity();
    let gap_start = bytes.len();
    let gap_length = capacity - gap_start;
    unsafe {
        bytes.set_len(capacity);
    }
    GapBuffer{ data: bytes, gap_start: gap_start, gap_length: gap_length }
}

impl GapBuffer {
    // TODO: Return an optional error.
    pub fn insert(&mut self, data: &str, position: &Position) {
        // Ensure we have the capacity to insert this data.
        if data.len() > self.gap_length {
            // TODO: Move gap to the end before resizing buffer.
            self.data.reserve(data.len());
            let capacity = self.data.capacity();
            self.gap_length = capacity - self.gap_start;
            unsafe {
                self.data.set_len(capacity);
            }
        }

        let offset = match self.find_offset(position) {
            Some(o) => o,
            None => return,
        };

        self.move_gap(offset);
        self.write_to_gap(data);
    }

    pub fn to_string(&self) -> String {
        from_utf8(&self.data[..self.gap_start]).unwrap().to_string() + from_utf8(&self.data[self.gap_start+self.gap_length..]).unwrap()
    }

    // Maps a position to its offset equivalent in the data.
    fn find_offset(&self, position: &Position) -> Option<usize> {
        let first_half = from_utf8(&self.data[0..self.gap_start]).unwrap();
        let mut line = 0;
        let mut line_offset = 0;

        for char_index in first_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        // We haven't reached the position yet, so we'll move on to the other half.
        let second_half = from_utf8(&self.data[self.gap_start+self.gap_length..self.data.len()-1]).unwrap();
        for char_index in second_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(self.gap_start + self.gap_length + offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        None
    }

    fn move_gap(&mut self, offset: usize) {
        if offset < self.gap_start {
            for index in (offset..self.gap_start) {
                self.data[index + self.gap_length] = self.data[index];
                self.data[index] = 0;
            }
        } else if offset > self.gap_start {
            for index in (self.gap_start+self.gap_length..offset) {
                self.data[index-self.gap_length] = self.data[index];
                self.data[index] = 0;
            }
        }

        self.gap_start = offset;
    }

    fn write_to_gap(&mut self, data: &str) {
        for byte in data.bytes() {
            self.data[self.gap_start] = byte;
            self.gap_start+=1;
            self.gap_length-=1;
        }
    }
}

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

    #[test]
    fn insert_works() {
        let mut gb = new("This is a test.\nPlease be gentle.".to_string());
        gb.insert(" very", &Position { line: 1, offset: 9 });
        assert_eq!(gb.to_string(), "This is a test.\nPlease be very gentle.");
    }
}
<|endoftext|>


<commit_before>use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use result::Result;
use super::{Binomial, Distribution, Univariate, Discrete};

/// Implements the [Bernoulli](https://en.wikipedia.org/wiki/Bernoulli_distribution)
/// distribution which is a special case of the [Binomial](https://en.wikipedia.org/wiki/Binomial_distribution)
/// distribution where `n = 1`
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Bernoulli, Univariate, Discrete};
///
/// let n = Bernoulli::new(0.5).unwrap();
/// assert_eq!(n.mean(), 0.5);
/// assert_eq!(n.pmf(0), 0.5);
/// assert_eq!(n.pmf(1), 0.5);
/// assert_eq!(n.pmf(2), 0.0);
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Bernoulli {
    b: Binomial,
}

impl Bernoulli {
    /// Constructs a new Bernoulli distribution with
    /// the given `p` probability of success.
    ///
    /// # Errors
    ///
    /// Returns an error if `p` is `NaN, less than `0`
    /// or greater than `1`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Bernoulli;
    ///
    /// let mut result = Bernoulli::new(0.5);
    /// assert!(result.is_ok());
    ///
    /// result = Bernoulli::new(-0.5);
    /// assert!(result.is_err());
    /// ```
    pub fn new(p: f64) -> Result<Bernoulli> {
        Binomial::new(p, 1).map(|b| Bernoulli { b: b })
    }

    /// Returns the probability of success `p` of the
    /// Bernoulli distribution.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Bernoulli;
    ///
    /// let n = Bernoulli::new(0.5).unwrap();
    /// assert_eq!(n.p(), 0.5);
    /// ```
    pub fn p(&self) -> f64 {
        self.b.p()
    }

    /// Returns the number of trials `n` of the
    /// Bernoulli distribution. Will always be `1.0`.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Bernoulli;
    ///
    /// let n = Bernoulli::new(0.5).unwrap();
    /// assert_eq!(n.n(), 1.0);
    /// ```
    pub fn n(&self) -> f64 {
        1.0
    }
}

impl Sample<f64> for Bernoulli {
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Bernoulli {
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution for Bernoulli {
    /// Draws and returns a random sample from the
    /// Bernoulli distribution where the returned
    /// values are `1` with probability `p` and `0`
    /// with probability `1-p`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    ///
    /// use rand::StdRng;
    /// use statrs::distribution::{Bernoulli, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Bernoulli::new(0.5).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        self.b.sample(r)
    }
}

impl Univariate for Bernoulli {
    /// Returns the mean of the Bernoulli
    /// distribution
    fn mean(&self) -> f64 {
        self.b.mean()
    }

    /// Returns the variance of the Bernoulli
    /// distribution
    fn variance(&self) -> f64 {
        self.b.variance()
    }

    /// Returns the standard deviation of the
    /// Bernoulli distribution
    fn std_dev(&self) -> f64 {
        self.b.std_dev()
    }

    /// Returns the entropy of the Bernoulli
    /// distribution
    fn entropy(&self) -> f64 {
        self.b.entropy()
    }

    /// Returns the skewness of the Bernoulli
    /// distribution
    fn skewness(&self) -> f64 {
        self.b.skewness()
    }

    /// Returns the median of the Bernoulli
    /// distribution
    fn median(&self) -> f64 {
        self.b.median()
    }

    /// Calculates and returns the cumulative distribution
    /// function for the Bernoulli distribution at `x`.
    ///
    /// # Remarks
    ///
    /// Returns `0.0` if `x < 0.0` and `1.0` if `x >= 1.0`
    fn cdf(&self, x: f64) -> f64 {
        self.b.cdf(x)
    }
}

impl Discrete for Bernoulli {
    fn mode(&self) -> i64 {
        self.b.mode()
    }

    fn min(&self) -> i64 {
        0
    }

    fn max(&self) -> i64 {
        1
    }

    fn pmf(&self, x: i64) -> f64 {
        self.b.pmf(x)
    }

    fn ln_pmf(&self, x: i64) -> f64 {
        self.b.ln_pmf(x)
    }
}
<commit_msg>update docs for bernoulli sample methods<commit_after>use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use result::Result;
use super::{Binomial, Distribution, Univariate, Discrete};

/// Implements the [Bernoulli](https://en.wikipedia.org/wiki/Bernoulli_distribution)
/// distribution which is a special case of the [Binomial](https://en.wikipedia.org/wiki/Binomial_distribution)
/// distribution where `n = 1`
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Bernoulli, Univariate, Discrete};
///
/// let n = Bernoulli::new(0.5).unwrap();
/// assert_eq!(n.mean(), 0.5);
/// assert_eq!(n.pmf(0), 0.5);
/// assert_eq!(n.pmf(1), 0.5);
/// assert_eq!(n.pmf(2), 0.0);
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Bernoulli {
    b: Binomial,
}

impl Bernoulli {
    /// Constructs a new Bernoulli distribution with
    /// the given `p` probability of success.
    ///
    /// # Errors
    ///
    /// Returns an error if `p` is `NaN, less than `0`
    /// or greater than `1`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Bernoulli;
    ///
    /// let mut result = Bernoulli::new(0.5);
    /// assert!(result.is_ok());
    ///
    /// result = Bernoulli::new(-0.5);
    /// assert!(result.is_err());
    /// ```
    pub fn new(p: f64) -> Result<Bernoulli> {
        Binomial::new(p, 1).map(|b| Bernoulli { b: b })
    }

    /// Returns the probability of success `p` of the
    /// Bernoulli distribution.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Bernoulli;
    ///
    /// let n = Bernoulli::new(0.5).unwrap();
    /// assert_eq!(n.p(), 0.5);
    /// ```
    pub fn p(&self) -> f64 {
        self.b.p()
    }

    /// Returns the number of trials `n` of the
    /// Bernoulli distribution. Will always be `1.0`.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Bernoulli;
    ///
    /// let n = Bernoulli::new(0.5).unwrap();
    /// assert_eq!(n.n(), 1.0);
    /// ```
    pub fn n(&self) -> f64 {
        1.0
    }
}

impl Sample<f64> for Bernoulli {
    /// Generate a random sample from a Bernoulli
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1)
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Bernoulli {
    /// Generate a random independent sample from a Bernoulli
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1)
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution for Bernoulli {
    /// Generate a random sample from the
    /// Bernoulli distribution using `r` as the source
    /// of randomness where the generated
    /// values are `1` with probability `p` and `0`
    /// with probability `1-p`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{Bernoulli, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Bernoulli::new(0.5).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        self.b.sample(r)
    }
}

impl Univariate for Bernoulli {
    /// Returns the mean of the Bernoulli
    /// distribution
    fn mean(&self) -> f64 {
        self.b.mean()
    }

    /// Returns the variance of the Bernoulli
    /// distribution
    fn variance(&self) -> f64 {
        self.b.variance()
    }

    /// Returns the standard deviation of the
    /// Bernoulli distribution
    fn std_dev(&self) -> f64 {
        self.b.std_dev()
    }

    /// Returns the entropy of the Bernoulli
    /// distribution
    fn entropy(&self) -> f64 {
        self.b.entropy()
    }

    /// Returns the skewness of the Bernoulli
    /// distribution
    fn skewness(&self) -> f64 {
        self.b.skewness()
    }

    /// Returns the median of the Bernoulli
    /// distribution
    fn median(&self) -> f64 {
        self.b.median()
    }

    /// Calculates and returns the cumulative distribution
    /// function for the Bernoulli distribution at `x`.
    ///
    /// # Remarks
    ///
    /// Returns `0.0` if `x < 0.0` and `1.0` if `x >= 1.0`
    fn cdf(&self, x: f64) -> f64 {
        self.b.cdf(x)
    }
}

impl Discrete for Bernoulli {
    fn mode(&self) -> i64 {
        self.b.mode()
    }

    fn min(&self) -> i64 {
        0
    }

    fn max(&self) -> i64 {
        1
    }

    fn pmf(&self, x: i64) -> f64 {
        self.b.pmf(x)
    }

    fn ln_pmf(&self, x: i64) -> f64 {
        self.b.ln_pmf(x)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Integration tests for validator_network.

use crate::{
    error::NetworkError,
    peer_manager::{ConnectionRequestSender, PeerManagerRequestSender},
    protocols::{
        network::{Event, NetworkEvents, NetworkSender, NewNetworkSender},
        rpc::error::RpcError,
    },
    validator_network::network_builder::{
        AuthenticationMode, NetworkBuilder, NETWORK_CHANNEL_SIZE,
    },
    ProtocolId,
};
use channel::message_queues::QueueStyle;
use futures::{executor::block_on, StreamExt};
use libra_config::{chain_id::ChainId, config::RoleType, network_id::NetworkId};
use libra_crypto::{test_utils::TEST_SEED, x25519, Uniform};
use libra_network_address::NetworkAddress;
use libra_types::PeerId;
use rand::{rngs::StdRng, SeedableRng};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, time::Duration};
use tokio::runtime::Runtime;

const TEST_RPC_PROTOCOL: ProtocolId = ProtocolId::ConsensusRpc;
const TEST_DIRECT_SEND_PROTOCOL: ProtocolId = ProtocolId::ConsensusDirectSend;

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct DummyMsg(pub Vec<u8>);

fn add_to_network(network: &mut NetworkBuilder) -> (DummyNetworkSender, DummyNetworkEvents) {
    network.add_protocol_handler((
        vec![TEST_RPC_PROTOCOL],
        vec![TEST_DIRECT_SEND_PROTOCOL],
        QueueStyle::LIFO,
        NETWORK_CHANNEL_SIZE,
        None,
    ))
}

/// TODO(davidiw): In DummyNetwork, replace DummyMsg with a Serde compatible type once migration
/// is complete
pub type DummyNetworkEvents = NetworkEvents<DummyMsg>;

#[derive(Clone)]
pub struct DummyNetworkSender {
    inner: NetworkSender<DummyMsg>,
}

impl NewNetworkSender for DummyNetworkSender {
    fn new(
        peer_mgr_reqs_tx: PeerManagerRequestSender,
        connection_reqs_tx: ConnectionRequestSender,
    ) -> Self {
        Self {
            inner: NetworkSender::new(peer_mgr_reqs_tx, connection_reqs_tx),
        }
    }
}

impl DummyNetworkSender {
    pub fn send_to(&mut self, recipient: PeerId, message: DummyMsg) -> Result<(), NetworkError> {
        let protocol = TEST_DIRECT_SEND_PROTOCOL;
        self.inner.send_to(recipient, protocol, message)
    }

    pub async fn send_rpc(
        &mut self,
        recipient: PeerId,
        message: DummyMsg,
        timeout: Duration,
    ) -> Result<DummyMsg, RpcError> {
        let protocol = TEST_RPC_PROTOCOL;
        self.inner
            .send_rpc(recipient, protocol, message, timeout)
            .await
    }
}

pub struct DummyNetwork {
    pub runtime: Runtime,
    pub dialer_peer_id: PeerId,
    pub dialer_events: DummyNetworkEvents,
    pub dialer_sender: DummyNetworkSender,
    pub listener_peer_id: PeerId,
    pub listener_events: DummyNetworkEvents,
    pub listener_sender: DummyNetworkSender,
}

/// The following sets up a 2 peer network and verifies connectivity.
pub fn setup_network() -> DummyNetwork {
    let runtime = Runtime::new().unwrap();
    let network_id = NetworkId::Validator;
    let chain_id = ChainId::default();
    let dialer_peer_id = PeerId::random();
    let listener_peer_id = PeerId::random();

    // Setup keys for dialer.
    let mut rng = StdRng::from_seed(TEST_SEED);
    let dialer_identity_private_key = x25519::PrivateKey::generate(&mut rng);
    let dialer_identity_public_key = dialer_identity_private_key.public_key();

    // Setup keys for listener.
    let listener_identity_private_key = x25519::PrivateKey::generate(&mut rng);
    let listener_identity_public_key = listener_identity_private_key.public_key();

    // Setup listen addresses
    let dialer_addr: NetworkAddress = "/ip4/127.0.0.1/tcp/0".parse().unwrap();
    let listener_addr: NetworkAddress = "/ip4/127.0.0.1/tcp/0".parse().unwrap();

    // Setup trusted peers.
    let trusted_peers: HashMap<_, _> = vec![
        (dialer_peer_id, dialer_identity_public_key),
        (listener_peer_id, listener_identity_public_key),
    ]
    .into_iter()
    .collect();

    // Set up the listener network
    let mut network_builder = NetworkBuilder::new(
        runtime.handle().clone(),
        chain_id.clone(),
        network_id.clone(),
        RoleType::Validator,
        listener_peer_id,
        listener_addr,
    );
    network_builder
        .authentication_mode(AuthenticationMode::Mutual(listener_identity_private_key))
        .trusted_peers(trusted_peers.clone())
        .add_connectivity_manager();
    let (listener_sender, mut listener_events) = add_to_network(&mut network_builder);
    let listener_addr = network_builder.build();

    // Set up the dialer network
    let mut network_builder = NetworkBuilder::new(
        runtime.handle().clone(),
        chain_id,
        network_id,
        RoleType::Validator,
        dialer_peer_id,
        dialer_addr,
    );
    network_builder
        .authentication_mode(AuthenticationMode::Mutual(dialer_identity_private_key))
        .trusted_peers(trusted_peers)
        .seed_peers(
            [(listener_peer_id, vec![listener_addr])]
                .iter()
                .cloned()
                .collect(),
        )
        .add_connectivity_manager();
    let (dialer_sender, mut dialer_events) = add_to_network(&mut network_builder);
    let _dialer_addr = network_builder.build();

    // Wait for establishing connection
    let first_dialer_event = block_on(dialer_events.next()).unwrap().unwrap();
    assert_eq!(first_dialer_event, Event::NewPeer(listener_peer_id));
    let first_listener_event = block_on(listener_events.next()).unwrap().unwrap();
    assert_eq!(first_listener_event, Event::NewPeer(dialer_peer_id));

    DummyNetwork {
        runtime,
        dialer_peer_id,
        dialer_events,
        dialer_sender,
        listener_peer_id,
        listener_events,
        listener_sender,
    }
}
<commit_msg>[network] convert dummy::add_to_network(network_builder) to network_builder.add_protocol_handles(dummy::network_endpoint_config())<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Integration tests for validator_network.

use crate::{
    error::NetworkError,
    peer_manager::{ConnectionRequestSender, PeerManagerRequestSender},
    protocols::{
        network::{Event, NetworkEvents, NetworkSender, NewNetworkSender},
        rpc::error::RpcError,
    },
    validator_network::network_builder::{
        AuthenticationMode, NetworkBuilder, NETWORK_CHANNEL_SIZE,
    },
    ProtocolId,
};
use channel::message_queues::QueueStyle;
use futures::{executor::block_on, StreamExt};
use libra_config::{chain_id::ChainId, config::RoleType, network_id::NetworkId};
use libra_crypto::{test_utils::TEST_SEED, x25519, Uniform};
use libra_metrics::IntCounterVec;
use libra_network_address::NetworkAddress;
use libra_types::PeerId;
use rand::{rngs::StdRng, SeedableRng};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, time::Duration};
use tokio::runtime::Runtime;

const TEST_RPC_PROTOCOL: ProtocolId = ProtocolId::ConsensusRpc;
const TEST_DIRECT_SEND_PROTOCOL: ProtocolId = ProtocolId::ConsensusDirectSend;

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct DummyMsg(pub Vec<u8>);

pub fn network_endpoint_config() -> (
    Vec<ProtocolId>,
    Vec<ProtocolId>,
    QueueStyle,
    usize,
    Option<&'static IntCounterVec>,
) {
    (
        vec![TEST_RPC_PROTOCOL],
        vec![TEST_DIRECT_SEND_PROTOCOL],
        QueueStyle::LIFO,
        NETWORK_CHANNEL_SIZE,
        None,
    )
}

/// TODO(davidiw): In DummyNetwork, replace DummyMsg with a Serde compatible type once migration
/// is complete
pub type DummyNetworkEvents = NetworkEvents<DummyMsg>;

#[derive(Clone)]
pub struct DummyNetworkSender {
    inner: NetworkSender<DummyMsg>,
}

impl NewNetworkSender for DummyNetworkSender {
    fn new(
        peer_mgr_reqs_tx: PeerManagerRequestSender,
        connection_reqs_tx: ConnectionRequestSender,
    ) -> Self {
        Self {
            inner: NetworkSender::new(peer_mgr_reqs_tx, connection_reqs_tx),
        }
    }
}

impl DummyNetworkSender {
    pub fn send_to(&mut self, recipient: PeerId, message: DummyMsg) -> Result<(), NetworkError> {
        let protocol = TEST_DIRECT_SEND_PROTOCOL;
        self.inner.send_to(recipient, protocol, message)
    }

    pub async fn send_rpc(
        &mut self,
        recipient: PeerId,
        message: DummyMsg,
        timeout: Duration,
    ) -> Result<DummyMsg, RpcError> {
        let protocol = TEST_RPC_PROTOCOL;
        self.inner
            .send_rpc(recipient, protocol, message, timeout)
            .await
    }
}

pub struct DummyNetwork {
    pub runtime: Runtime,
    pub dialer_peer_id: PeerId,
    pub dialer_events: DummyNetworkEvents,
    pub dialer_sender: DummyNetworkSender,
    pub listener_peer_id: PeerId,
    pub listener_events: DummyNetworkEvents,
    pub listener_sender: DummyNetworkSender,
}

/// The following sets up a 2 peer network and verifies connectivity.
pub fn setup_network() -> DummyNetwork {
    let runtime = Runtime::new().unwrap();
    let network_id = NetworkId::Validator;
    let chain_id = ChainId::default();
    let dialer_peer_id = PeerId::random();
    let listener_peer_id = PeerId::random();

    // Setup keys for dialer.
    let mut rng = StdRng::from_seed(TEST_SEED);
    let dialer_identity_private_key = x25519::PrivateKey::generate(&mut rng);
    let dialer_identity_public_key = dialer_identity_private_key.public_key();

    // Setup keys for listener.
    let listener_identity_private_key = x25519::PrivateKey::generate(&mut rng);
    let listener_identity_public_key = listener_identity_private_key.public_key();

    // Setup listen addresses
    let dialer_addr: NetworkAddress = "/ip4/127.0.0.1/tcp/0".parse().unwrap();
    let listener_addr: NetworkAddress = "/ip4/127.0.0.1/tcp/0".parse().unwrap();

    // Setup trusted peers.
    let trusted_peers: HashMap<_, _> = vec![
        (dialer_peer_id, dialer_identity_public_key),
        (listener_peer_id, listener_identity_public_key),
    ]
    .into_iter()
    .collect();

    // Set up the listener network
    let mut network_builder = NetworkBuilder::new(
        runtime.handle().clone(),
        chain_id.clone(),
        network_id.clone(),
        RoleType::Validator,
        listener_peer_id,
        listener_addr,
    );
    network_builder
        .authentication_mode(AuthenticationMode::Mutual(listener_identity_private_key))
        .trusted_peers(trusted_peers.clone())
        .add_connectivity_manager();
    let (listener_sender, mut listener_events) = network_builder
        .add_protocol_handler::<DummyNetworkSender, DummyNetworkEvents>(network_endpoint_config());
    let listener_addr = network_builder.build();

    // Set up the dialer network
    let mut network_builder = NetworkBuilder::new(
        runtime.handle().clone(),
        chain_id,
        network_id,
        RoleType::Validator,
        dialer_peer_id,
        dialer_addr,
    );
    network_builder
        .authentication_mode(AuthenticationMode::Mutual(dialer_identity_private_key))
        .trusted_peers(trusted_peers)
        .seed_peers(
            [(listener_peer_id, vec![listener_addr])]
                .iter()
                .cloned()
                .collect(),
        )
        .add_connectivity_manager();
    let (dialer_sender, mut dialer_events) = network_builder
        .add_protocol_handler::<DummyNetworkSender, DummyNetworkEvents>(network_endpoint_config());
    let _dialer_addr = network_builder.build();

    // Wait for establishing connection
    let first_dialer_event = block_on(dialer_events.next()).unwrap().unwrap();
    assert_eq!(first_dialer_event, Event::NewPeer(listener_peer_id));
    let first_listener_event = block_on(listener_events.next()).unwrap().unwrap();
    assert_eq!(first_listener_event, Event::NewPeer(dialer_peer_id));

    DummyNetwork {
        runtime,
        dialer_peer_id,
        dialer_events,
        dialer_sender,
        listener_peer_id,
        listener_events,
        listener_sender,
    }
}
<|endoftext|>


<commit_before>use std::ops::Range;
use {pso, target, Backend, IndexCount, InstanceCount, VertexCount, VertexOffset};
use buffer::IndexBufferView;
use queue::{Supports, Graphics};
use super::{AttachmentClear, ClearValue, CommandBuffer, RawCommandBuffer};

/// Specifies how commands for the following renderpasses will be recorded.
pub enum SubpassContents {
    ///
    Inline,
    ///
    SecondaryBuffers,
}

///
pub struct RenderPassInlineEncoder<'a, B: Backend>(pub(crate) &'a mut B::CommandBuffer)
where B::CommandBuffer: 'a;

impl<'a, B: Backend> RenderPassInlineEncoder<'a, B> {
    ///
    pub fn new<C>(
        cmd_buffer: &'a mut CommandBuffer<B, C>,
        render_pass: &B::RenderPass,
        frame_buffer: &B::Framebuffer,
        render_area: target::Rect,
        clear_values: &[ClearValue],
    ) -> Self
    where
        C: Supports<Graphics>,
    {
        cmd_buffer.raw.begin_renderpass(
            render_pass,
            frame_buffer,
            render_area,
            clear_values,
            SubpassContents::Inline);
        RenderPassInlineEncoder(cmd_buffer.raw)
    }

    ///
    pub fn next_subpass_inline(self) -> Self {
        self.0.next_subpass(SubpassContents::Inline);
        self
    }

    ///
    pub fn clear_attachments(&mut self, clears: &[AttachmentClear], rects: &[target::Rect]) {
        self.0.clear_attachments(clears, rects)
    }

    ///
    pub fn draw(&mut self, vertices: Range<VertexCount>, instances: Range<InstanceCount>) {
        self.0.draw(vertices, instances)
    }
    ///
    pub fn draw_indexed(&mut self, indices: Range<IndexCount>, base_vertex: VertexOffset, instances: Range<InstanceCount>) {
        self.0.draw_indexed(indices, base_vertex, instances)
    }
    ///
    pub fn draw_indirect(&mut self, buffer: &B::Buffer, offset: u64, draw_count: u32, stride: u32) {
        self.0.draw_indirect(buffer, offset, draw_count, stride)
    }
    ///
    pub fn draw_indexed_indirect(&mut self, buffer: &B::Buffer, offset: u64, draw_count: u32, stride: u32) {
        self.0.draw_indexed_indirect(buffer, offset, draw_count, stride)
    }

    /// Bind index buffer view.
    pub fn bind_index_buffer(&mut self, ibv: IndexBufferView<B>) {
        self.0.bind_index_buffer(ibv)
    }

    /// Bind vertex buffers.
    pub fn bind_vertex_buffers(&mut self, vbs: pso::VertexBufferSet<B>) {
        self.0.bind_vertex_buffers(vbs);
    }

    /// Bind a graphics pipeline.
    ///
    /// There is only *one* pipeline slot for compute and graphics.
    /// Calling the corresponding `bind_pipeline` functions will override the slot.
    pub fn bind_graphics_pipeline(&mut self, pipeline: &B::GraphicsPipeline) {
        self.0.bind_graphics_pipeline(pipeline)
    }
}

impl<'a, B: Backend> Drop for RenderPassInlineEncoder<'a, B> {
    fn drop(&mut self) {
        self.0.end_renderpass();
    }
}
<commit_msg>initial work<commit_after>use std::ops::Range;
use {pso, target, Backend, IndexCount, InstanceCount, VertexCount, VertexOffset};
use buffer::IndexBufferView;
use queue::{Supports, Graphics};
use super::{AttachmentClear, ClearValue, CommandBuffer, RawCommandBuffer};

/// Specifies how commands for the following renderpasses will be recorded.
pub enum SubpassContents {
    ///
    Inline,
    ///
    SecondaryBuffers,
}

///
pub struct RenderPassInlineEncoder<'a, B: Backend>(pub(crate) &'a mut B::CommandBuffer)
where B::CommandBuffer: 'a;

impl<'a, B: Backend> RenderPassInlineEncoder<'a, B> {
    ///
    pub fn new<C>(
        cmd_buffer: &'a mut CommandBuffer<B, C>,
        render_pass: &B::RenderPass,
        frame_buffer: &B::Framebuffer,
        render_area: target::Rect,
        clear_values: &[ClearValue],
    ) -> Self
    where
        C: Supports<Graphics>,
    {
        cmd_buffer.raw.begin_renderpass(
            render_pass,
            frame_buffer,
            render_area,
            clear_values,
            SubpassContents::Inline);
        RenderPassInlineEncoder(cmd_buffer.raw)
    }

    ///
    pub fn next_subpass_inline(self) -> Self {
        self.0.next_subpass(SubpassContents::Inline);
        self
    }

    ///
    pub fn clear_attachments(&mut self, clears: &[AttachmentClear], rects: &[target::Rect]) {
        self.0.clear_attachments(clears, rects)
    }

    ///
    pub fn draw(&mut self, vertices: Range<VertexCount>, instances: Range<InstanceCount>) {
        self.0.draw(vertices, instances)
    }
    ///
    pub fn draw_indexed(&mut self, indices: Range<IndexCount>, base_vertex: VertexOffset, instances: Range<InstanceCount>) {
        self.0.draw_indexed(indices, base_vertex, instances)
    }
    ///
    pub fn draw_indirect(&mut self, buffer: &B::Buffer, offset: u64, draw_count: u32, stride: u32) {
        self.0.draw_indirect(buffer, offset, draw_count, stride)
    }
    ///
    pub fn draw_indexed_indirect(&mut self, buffer: &B::Buffer, offset: u64, draw_count: u32, stride: u32) {
        self.0.draw_indexed_indirect(buffer, offset, draw_count, stride)
    }

    /// Bind index buffer view.
    pub fn bind_index_buffer(&mut self, ibv: IndexBufferView<B>) {
        self.0.bind_index_buffer(ibv)
    }

    /// Bind vertex buffers.
    pub fn bind_vertex_buffers(&mut self, vbs: pso::VertexBufferSet<B>) {
        self.0.bind_vertex_buffers(vbs);
    }

    /// Bind a graphics pipeline.
    ///
    /// There is only *one* pipeline slot for compute and graphics.
    /// Calling the corresponding `bind_pipeline` functions will override the slot.
    pub fn bind_graphics_pipeline(&mut self, pipeline: &B::GraphicsPipeline) {
        self.0.bind_graphics_pipeline(pipeline)
    }

    ///
    pub fn bind_graphics_descriptor_sets(
        &mut self,
        layout: &B::PipelineLayout,
        first_set: usize,
        sets: &[&B::DescriptorSet],
    ) {
        self.0.bind_graphics_descriptor_sets(layout, first_set, sets)
    }

    // TODO: set_viewports
    // TODO: set_scissors
    // TODO: set_line_width
    // TODO: set_depth_bounds
    // TODO: set_depth_bias
    // TODO: set_blend_constants
    // TODO: set_stencil_compare_mask
    // TODO: set_stencil_reference
    // TODO: set_stencil_write_mask

    // TODO: push constants
    // TODO: pipeline barrier
    // TODO: begin/end query

}

impl<'a, B: Backend> Drop for RenderPassInlineEncoder<'a, B> {
    fn drop(&mut self) {
        self.0.end_renderpass();
    }
}
<|endoftext|>


<commit_before>use std::io::{Write};

use parser::html;
use parser::html::Statement::{Element, Text};
use parser::{Ast, Block};
use util::join;

use super::ast::{Code, Statement, Param, Expression};

use super::Generator;

impl<'a, W:Write+'a> Generator<'a, W> {
    fn attrs(&self, name: &String, cls: &Vec<String>) -> Expression {
        let mut attrs = vec!();
        if cls.len() > 0 {
            let namestr = &self.block_name.to_string();
            let nclasses = vec![namestr].into_iter()
                .chain(cls.iter());
            attrs.push((String::from("class"),
                        Expression::Str(join(nclasses, " "))));
        } else if self.bare_element_names.contains(name) {
            attrs.push((String::from("class"),
                Expression::Str(self.block_name.to_string())));
        }
        Expression::Object(attrs)
    }
    fn element(&self, st: &html::Statement) -> Expression {
        match st {
            &Element { ref name, ref classes, ref body } => {
                if classes.len() == 0 && body.len() == 0 {
                    Expression::Object(vec![
                        (String::from("tag"), Expression::Str(name.clone())),
                        ])
                } else {
                    Expression::Object(vec![
                        (String::from("tag"), Expression::Str(name.clone())),
                        (String::from("attrs"), self.attrs(name, classes)),
                        (String::from("children"), self.fragment(&body)),
                        ])
                }
            }
            &Text(ref value) => {
                Expression::Str(value.clone())
            }
        }
    }
    fn fragment(&self, statements: &Vec<html::Statement>) -> Expression {
        if statements.len() == 1 {
            return self.element(&statements[0]);
        } else {
            return Expression::Object(vec![(
                String::from("children"),
                Expression::List(
                    statements.iter()
                    .map(|s| self.element(s))
                    .collect())
                )]);
        }
    }
    pub fn code(&self, ast: &Ast) -> Code {
        let mut stmt = vec!();
        for blk in ast.blocks.iter() {
            if let &Block::Html {ref name, ref params, ref statements, ..} = blk {
                stmt.push(Statement::Function(name.clone(),
                    params.iter().map(|p| Param {
                        name: p.name.clone(),
                        default_value: p.default_value.as_ref().map(
                            |v| Expression::Str(v.clone())),
                    }).collect(),
                    vec![
                        Statement::Return(self.fragment(statements)),
                    ]
                ));
            }
        }
        return Code {
            statements: stmt,
        }
    }

}
<commit_msg>Add attributes to codegen<commit_after>use std::io::{Write};

use parser::html;
use parser::html::Expression as Expr;
use parser::html::Statement::{Element, Text};
use parser::{Ast, Block};
use util::join;

use super::ast::{Code, Statement, Param, Expression};

use super::Generator;

impl<'a, W:Write+'a> Generator<'a, W> {
    fn attrs(&self, name: &String, cls: &Vec<String>,
        attrs: &Vec<(String, Expr)>)
        -> Expression
    {
        let mut attrs = vec!();
        if cls.len() > 0 {
            let namestr = &self.block_name.to_string();
            let nclasses = vec![namestr].into_iter()
                .chain(cls.iter());
            attrs.push((String::from("class"),
                        Expression::Str(join(nclasses, " "))));
        } else if self.bare_element_names.contains(name) {
            attrs.push((String::from("class"),
                Expression::Str(self.block_name.to_string())));
        }
        for (name, value) in attrs {
            // TODO(tailhook) compile real attribute expression
            attrs.push((name.clone(), Expression::Str(String::from("value"))));
        }
        Expression::Object(attrs)
    }
    fn element(&self, st: &html::Statement) -> Expression {
        match st {
            &Element { ref name, ref classes, ref body, ref attributes } => {
                if classes.len() == 0 && body.len() == 0 {
                    Expression::Object(vec![
                        (String::from("tag"), Expression::Str(name.clone())),
                        ])
                } else {
                    Expression::Object(vec![
                        (String::from("tag"), Expression::Str(name.clone())),
                        (String::from("attrs"),
                            self.attrs(name, classes, attributes)),
                        (String::from("children"), self.fragment(&body)),
                        ])
                }
            }
            &Text(ref value) => {
                Expression::Str(value.clone())
            }
        }
    }
    fn fragment(&self, statements: &Vec<html::Statement>) -> Expression {
        if statements.len() == 1 {
            return self.element(&statements[0]);
        } else {
            return Expression::Object(vec![(
                String::from("children"),
                Expression::List(
                    statements.iter()
                    .map(|s| self.element(s))
                    .collect())
                )]);
        }
    }
    pub fn code(&self, ast: &Ast) -> Code {
        let mut stmt = vec!();
        for blk in ast.blocks.iter() {
            if let &Block::Html {ref name, ref params, ref statements, ..} = blk {
                stmt.push(Statement::Function(name.clone(),
                    params.iter().map(|p| Param {
                        name: p.name.clone(),
                        default_value: p.default_value.as_ref().map(
                            |v| Expression::Str(v.clone())),
                    }).collect(),
                    vec![
                        Statement::Return(self.fragment(statements)),
                    ]
                ));
            }
        }
        return Code {
            statements: stmt,
        }
    }

}
<|endoftext|>


<commit_before>#![feature(slice_bytes, path_relative_from)]

use std::fs::File;
use std::path::PathBuf;
use std::ops::DerefMut;

extern crate byteorder;
extern crate docopt;
extern crate env_logger;
#[macro_use] extern crate log;

use docopt::Docopt;

mod disk;
mod fs;

use fs::*;
use disk::*;

static VERSION: &'static str = "0.0.1";
static USAGE: &'static str = "
Usage: mkdisk [options] <dir>

Creates a bootable disk image.

Options:
    -h, --help     Print this help message
    -v, --version  Print the version of mkdisk
    -s, --size=SIZE         The fixed size of the disk image [default: 4MiB]
    -o, --out=FILE          The output disk image file
    -b, --bootloader=FILE   The bootloader to use for the first few sectors

File sizes measured using KB = 1000, KiB=1024 etc
";

fn main() {
    env_logger::init().unwrap();

    let args: docopt::ArgvMap = Docopt::new(USAGE)
                      .and_then(|d| d.help(true)
                                     .version(Some(VERSION.into()))
                                     .parse())
                      .unwrap_or_else(|e| e.exit());

    let mut config = Config::new(args);
    config.exec();
}

struct Config {
    dsize: usize,
    src: PathBuf,

    boot_path: PathBuf,
    boot: File,

    out_path: PathBuf,
    out: File,
}

impl Config {
    pub fn new(args: docopt::ArgvMap) -> Config {
        // default is 4MiB, as specified in USAGE
        let dsize = parse_size(args.get_str("-s"));

        let boot_path: PathBuf = match args.get_str("-b") {
            ""   => panic!("Bootloader unspecified: use `-b` or `--bootloader`"),
            path => {
                path.into()
            },
        };
        let boot = File::open(&boot_path)
                        .unwrap_or_else(|e| panic!("Unable to open bootloader `{}`: {}",
                                                   args.get_str("-b"), e));

        let src = args.get_str("<dir>").into();
        let out_path = PathBuf::from(match args.get_str("-o") {
            "" => {
                // if source dir is `bin/fs/`, then the output file becomes `bin/fs.disk`
                let mut path = PathBuf::from(&src);
                path.set_extension("disk");
                path
            },
            s  => PathBuf::from(s),
        });

        let out = File::create(&out_path)
                       .unwrap_or_else(|e| panic!("Unable to open output file `{:?}`: {}", out_path, e));

        Config {
            dsize: dsize,
            src: src,

            boot_path: boot_path,
            boot: boot,

            out_path: out_path,
            out: out,
        }
    }

    pub fn exec(&mut self) {
        use std::io::Read;
        use std::ops::Deref;

        let smeta = ::std::fs::metadata(&self.src)
                              .unwrap_or_else(|e| panic!("Unable to query source `{}`: {}", &self.src.display(), e));
        if !smeta.is_dir() {
            panic!("Source path is not a folder: `{}`", &self.src.display());
        }

        let sectors = self.dsize / 512;

        // ensure room for filesystem
        assert!(sectors >= 128, "Minimum disk size is 64KiB");

        let mut disk = RamDisk::new(sectors);

        let mut i = 0;
        loop {
            let mut sector: [u8; 512] = [0; 512];
            match self.boot.read(&mut sector) {
                // Ok(n) if n == 512 => { }, // read sector fine
                // Ok(n) if n < 512  => { break; } // finished reading bootloader
                Ok(0) => { break; }
                Ok(n) => { }
                Err(e) => { panic!("Unable to read bootloader `{}`: {}", self.out_path.display(), e); },
                // _ => unreachable!(),
            }
            disk.write_sector(i, &sector);
            i += 1;
        }

        let pinfo = PartitionInfo {
            format: Format::Fat32,
            size: sectors - 64,
            start: 64, // historically, partitions are aligned to cylinder boundaries, so start on sector 64
            bootable: true,
        };
        disk::set_pinfo(&mut disk, 0, &pinfo).unwrap();

        {
            let mut partition = disk::get_partition(&mut disk, 0).unwrap();
            fs::fat::format(&mut partition).unwrap();
        }

        fn recurse<T: FileSystem + ?Sized>(fs: &mut T, src: &PathBuf, dir: PathBuf) {
            for item in ::std::fs::read_dir(&dir).unwrap() {
                let item = item.unwrap(); // TODO unwrap
                let rpath = item.path();
                let rc = rpath.clone();
                let vpath = rc.relative_from(src).unwrap();

                debug!("Config::exec::recurse() vpath: {:?}", &vpath);
                let ft = item.file_type().unwrap();
                if ft.is_dir() {
                    fs.make_dir(vpath).unwrap();
                    recurse(fs, src, rpath);
                } else if ft.is_file() {
                    use std::io::Read;

                    let mut file = match File::open(&rpath) {
                        Ok(f) => f,
                        Err(e) => panic!("Cannot open file `{:?}`: {}", rpath, e),
                    };

                    let mut v = Vec::new();
                    file.read_to_end(&mut v).unwrap();

                    fs.write_file(vpath, &v);
                }
            }
        }

        let mut fs = disk::mount(&mut disk, 0).unwrap();
        recurse(fs.deref_mut(), &self.src, self.src.clone());

        for sector in &*disk {
            use std::io::Write;
            self.out.write(sector);
        }
    }
}

// TODO: error handling
fn parse_size(s: &str) -> usize {
    let mut num = s.chars().take_while(|c| c.is_numeric())
                           .collect::<String>()
                           .parse::<usize>()
                           .unwrap_or_else(|_| panic!("Unable to interpret size: `{}`", s));

    const UNITS: [(&'static str, usize); 4] = [
        // update test::parse_size() when expanding
        ("kb",     1_000), ("kib", 1 << 10),
        ("mb", 1_000_000), ("mib", 1 << 20),
    ];

    let mut success = false;
    let unit = s.chars().skip_while(|c| c.is_numeric())
                        .collect::<String>()
                        .to_lowercase();

    // TODO: refactor
    for &(suffix, factor) in &UNITS {
        if unit == suffix {
            success = true;
            num *= factor;
            break;
        }
    }
    if !success {
        panic!("Unknown unit suffix: `{}`", unit);
    }

    num
}

#[cfg(test)]
mod test {
    #[test]
    fn parse_size() {
        assert_eq!(super::parse_size("1mib"),2 << 20);
        assert_eq!(super::parse_size("4MiB"),4 * 2 << 20);
        assert_eq!(super::parse_size("35kb"), 35 * 1_000);
    }
}
<commit_msg>Start partition after bootmanager<commit_after>#![feature(slice_bytes, path_relative_from)]

use std::fs::File;
use std::path::PathBuf;
use std::ops::DerefMut;

extern crate byteorder;
extern crate docopt;
extern crate env_logger;
#[macro_use] extern crate log;

use docopt::Docopt;

mod disk;
mod fs;

use fs::*;
use disk::*;

static VERSION: &'static str = "0.0.1";
static USAGE: &'static str = "
Usage: mkdisk [options] <dir>

Creates a bootable disk image.

Options:
    -h, --help     Print this help message
    -v, --version  Print the version of mkdisk
    -s, --size=SIZE         The fixed size of the disk image [default: 4MiB]
    -o, --out=FILE          The output disk image file
    -b, --bootloader=FILE   The bootloader to use for the first few sectors

File sizes measured using KB = 1000, KiB=1024 etc
";

fn main() {
    env_logger::init().unwrap();

    let args: docopt::ArgvMap = Docopt::new(USAGE)
                      .and_then(|d| d.help(true)
                                     .version(Some(VERSION.into()))
                                     .parse())
                      .unwrap_or_else(|e| e.exit());

    let mut config = Config::new(args);
    config.exec();
}

struct Config {
    dsize: usize,
    src: PathBuf,

    boot_path: PathBuf,
    boot: File,

    out_path: PathBuf,
    out: File,
}

impl Config {
    pub fn new(args: docopt::ArgvMap) -> Config {
        // default is 4MiB, as specified in USAGE
        let dsize = parse_size(args.get_str("-s"));

        let boot_path: PathBuf = match args.get_str("-b") {
            ""   => panic!("Bootloader unspecified: use `-b` or `--bootloader`"),
            path => {
                path.into()
            },
        };
        let boot = File::open(&boot_path)
                        .unwrap_or_else(|e| panic!("Unable to open bootloader `{}`: {}",
                                                   args.get_str("-b"), e));

        let src = args.get_str("<dir>").into();
        let out_path = PathBuf::from(match args.get_str("-o") {
            "" => {
                // if source dir is `bin/fs/`, then the output file becomes `bin/fs.disk`
                let mut path = PathBuf::from(&src);
                path.set_extension("disk");
                path
            },
            s  => PathBuf::from(s),
        });

        let out = File::create(&out_path)
                       .unwrap_or_else(|e| panic!("Unable to open output file `{:?}`: {}", out_path, e));

        Config {
            dsize: dsize,
            src: src,

            boot_path: boot_path,
            boot: boot,

            out_path: out_path,
            out: out,
        }
    }

    pub fn exec(&mut self) {
        use std::io::Read;
        use std::ops::Deref;

        let smeta = ::std::fs::metadata(&self.src)
                              .unwrap_or_else(|e| panic!("Unable to query source `{}`: {}", &self.src.display(), e));
        if !smeta.is_dir() {
            panic!("Source path is not a folder: `{}`", &self.src.display());
        }

        let sectors = self.dsize / 512;

        // ensure room for filesystem
        assert!(sectors >= 128, "Minimum disk size is 64KiB");

        let mut disk = RamDisk::new(sectors);

        let mut bs_i = 0; // also use index to count size of bootmanager
        loop {
            let mut sector: [u8; 512] = [0; 512];
            match self.boot.read(&mut sector) {
                Ok(0) => { break; }
                Ok(n) => { }
                Err(e) => { panic!("Unable to read bootloader `{}`: {}", self.out_path.display(), e); },
            }
            disk.write_sector(bs_i, &sector);
            bs_i += 1;
        }

        let pinfo = PartitionInfo {
            format: Format::Fat32,
            size: sectors - bs_i,
            start: bs_i,
            bootable: true,
        };
        disk::set_pinfo(&mut disk, 0, &pinfo).unwrap();

        { // borrowck strikes again!
            let mut partition = disk::get_partition(&mut disk, 0).unwrap();
            fs::fat::format(&mut partition).unwrap();
        }

        fn recurse<T: FileSystem + ?Sized>(fs: &mut T, src: &PathBuf, dir: PathBuf) {
            for item in ::std::fs::read_dir(&dir).unwrap() {
                let item = item.unwrap(); // TODO unwrap
                let rpath = item.path();
                let rc = rpath.clone();
                let vpath = rc.relative_from(src).unwrap();

                debug!("Config::exec::recurse() vpath: {:?}", &vpath);
                let ft = item.file_type().unwrap();
                if ft.is_dir() {
                    fs.make_dir(vpath).unwrap();
                    recurse(fs, src, rpath);
                } else if ft.is_file() {
                    use std::io::Read;

                    let mut file = match File::open(&rpath) {
                        Ok(f) => f,
                        Err(e) => panic!("Cannot open file `{:?}`: {}", rpath, e),
                    };

                    let mut v = Vec::new();
                    file.read_to_end(&mut v).unwrap();

                    fs.write_file(vpath, &v);
                }
            }
        }

        let mut fs = disk::mount(&mut disk, 0).unwrap();
        recurse(fs.deref_mut(), &self.src, self.src.clone());

        for sector in &*disk {
            use std::io::Write;
            self.out.write(sector);
        }
    }
}

// TODO: error handling
fn parse_size(s: &str) -> usize {
    let mut num = s.chars().take_while(|c| c.is_numeric())
                           .collect::<String>()
                           .parse::<usize>()
                           .unwrap_or_else(|_| panic!("Unable to interpret size: `{}`", s));

    const UNITS: [(&'static str, usize); 4] = [
        // update test::parse_size() when expanding
        ("kb",     1_000), ("kib", 1 << 10),
        ("mb", 1_000_000), ("mib", 1 << 20),
    ];

    let mut success = false;
    let unit = s.chars().skip_while(|c| c.is_numeric())
                        .collect::<String>()
                        .to_lowercase();

    // TODO: refactor
    for &(suffix, factor) in &UNITS {
        if unit == suffix {
            success = true;
            num *= factor;
            break;
        }
    }
    if !success {
        panic!("Unknown unit suffix: `{}`", unit);
    }

    num
}

#[cfg(test)]
mod test {
    #[test]
    fn parse_size() {
        assert_eq!(super::parse_size("1mib"),2 << 20);
        assert_eq!(super::parse_size("4MiB"),4 * 2 << 20);
        assert_eq!(super::parse_size("35kb"), 35 * 1_000);
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.
//! Provides a summary representation of a filesystem.
//!
//! A [`Filesystem`] struct represents a device containing a
//! filesystem mounted at a particular directory. It also includes
//! information on amount of space available and amount of space used.
#[cfg(windows)]
use std::path::Path;

#[cfg(unix)]
use uucore::fsext::statfs;
use uucore::fsext::{FsUsage, MountInfo};

/// Summary representation of a filesystem.
///
/// A [`Filesystem`] struct represents a device containing a
/// filesystem mounted at a particular directory. The
/// [`Filesystem::mount_info`] field exposes that information. The
/// [`Filesystem::usage`] field provides information on the amount of
/// space available on the filesystem and the amount of space used.
#[derive(Debug, Clone)]
pub(crate) struct Filesystem {
    /// Information about the mounted device, mount directory, and related options.
    pub mount_info: MountInfo,

    /// Information about the amount of space used on the filesystem.
    pub usage: FsUsage,
}

impl Filesystem {
    // TODO: resolve uuid in `mount_info.dev_name` if exists
    pub(crate) fn new(mount_info: MountInfo) -> Option<Self> {
        let _stat_path = if !mount_info.mount_dir.is_empty() {
            mount_info.mount_dir.clone()
        } else {
            #[cfg(unix)]
            {
                mount_info.dev_name.clone()
            }
            #[cfg(windows)]
            {
                // On windows, we expect the volume id
                mount_info.dev_id.clone()
            }
        };
        #[cfg(unix)]
        let usage = FsUsage::new(statfs(_stat_path).ok()?);
        #[cfg(windows)]
        let usage = FsUsage::new(Path::new(&_stat_path));
        Some(Self { mount_info, usage })
    }
}
<commit_msg>df: add Filesystem::from_path() function<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.
//! Provides a summary representation of a filesystem.
//!
//! A [`Filesystem`] struct represents a device containing a
//! filesystem mounted at a particular directory. It also includes
//! information on amount of space available and amount of space used.
use std::path::Path;

#[cfg(unix)]
use uucore::fsext::statfs;
use uucore::fsext::{FsUsage, MountInfo};

/// Summary representation of a filesystem.
///
/// A [`Filesystem`] struct represents a device containing a
/// filesystem mounted at a particular directory. The
/// [`Filesystem::mount_info`] field exposes that information. The
/// [`Filesystem::usage`] field provides information on the amount of
/// space available on the filesystem and the amount of space used.
#[derive(Debug, Clone)]
pub(crate) struct Filesystem {
    /// Information about the mounted device, mount directory, and related options.
    pub mount_info: MountInfo,

    /// Information about the amount of space used on the filesystem.
    pub usage: FsUsage,
}

/// Find the mount info that best matches a given filesystem path.
///
/// This function returns the element of `mounts` on which `path` is
/// mounted. If there are no matches, this function returns
/// [`None`]. If there are two or more matches, then the single
/// [`MountInfo`] with the longest mount directory is returned.
///
/// If `canonicalize` is `true`, then the `path` is canonicalized
/// before checking whether it matches any mount directories.
///
/// # See also
///
/// * [`Path::canonicalize`]
/// * [`MountInfo::mount_dir`]
fn mount_info_from_path<P>(
    mounts: &[MountInfo],
    path: P,
    // This is really only used for testing purposes.
    canonicalize: bool,
) -> Option<&MountInfo>
where
    P: AsRef<Path>,
{
    // TODO Refactor this function with `Stater::find_mount_point()`
    // in the `stat` crate.
    let path = if canonicalize {
        path.as_ref().canonicalize().ok()?
    } else {
        path.as_ref().to_path_buf()
    };
    let matches = mounts.iter().filter(|mi| path.starts_with(&mi.mount_dir));
    matches.max_by_key(|mi| mi.mount_dir.len())
}

impl Filesystem {
    // TODO: resolve uuid in `mount_info.dev_name` if exists
    pub(crate) fn new(mount_info: MountInfo) -> Option<Self> {
        let _stat_path = if !mount_info.mount_dir.is_empty() {
            mount_info.mount_dir.clone()
        } else {
            #[cfg(unix)]
            {
                mount_info.dev_name.clone()
            }
            #[cfg(windows)]
            {
                // On windows, we expect the volume id
                mount_info.dev_id.clone()
            }
        };
        #[cfg(unix)]
        let usage = FsUsage::new(statfs(_stat_path).ok()?);
        #[cfg(windows)]
        let usage = FsUsage::new(Path::new(&_stat_path));
        Some(Self { mount_info, usage })
    }

    /// Find and create the filesystem that best matches a given path.
    ///
    /// This function returns a new `Filesystem` derived from the
    /// element of `mounts` on which `path` is mounted. If there are
    /// no matches, this function returns [`None`]. If there are two
    /// or more matches, then the single [`Filesystem`] with the
    /// longest mount directory is returned.
    ///
    /// The `path` is canonicalized before checking whether it matches
    /// any mount directories.
    ///
    /// # See also
    ///
    /// * [`Path::canonicalize`]
    /// * [`MountInfo::mount_dir`]
    ///
    pub(crate) fn from_path<P>(mounts: &[MountInfo], path: P) -> Option<Self>
    where
        P: AsRef<Path>,
    {
        let canonicalize = true;
        let mount_info = mount_info_from_path(mounts, path, canonicalize)?;
        // TODO Make it so that we do not need to clone the `mount_info`.
        let mount_info = (*mount_info).clone();
        Self::new(mount_info)
    }
}

#[cfg(test)]
mod tests {

    mod mount_info_from_path {

        use uucore::fsext::MountInfo;

        use crate::filesystem::mount_info_from_path;

        // Create a fake `MountInfo` with the given directory name.
        fn mount_info(mount_dir: &str) -> MountInfo {
            MountInfo {
                dev_id: Default::default(),
                dev_name: Default::default(),
                fs_type: Default::default(),
                mount_dir: String::from(mount_dir),
                mount_option: Default::default(),
                mount_root: Default::default(),
                remote: Default::default(),
                dummy: Default::default(),
            }
        }

        // Check whether two `MountInfo` instances are equal.
        fn mount_info_eq(m1: &MountInfo, m2: &MountInfo) -> bool {
            m1.dev_id == m2.dev_id
                && m1.dev_name == m2.dev_name
                && m1.fs_type == m2.fs_type
                && m1.mount_dir == m2.mount_dir
                && m1.mount_option == m2.mount_option
                && m1.mount_root == m2.mount_root
                && m1.remote == m2.remote
                && m1.dummy == m2.dummy
        }

        #[test]
        fn test_empty_mounts() {
            assert!(mount_info_from_path(&[], "/", false).is_none());
        }

        #[test]
        fn test_exact_match() {
            let mounts = [mount_info("/foo")];
            let actual = mount_info_from_path(&mounts, "/foo", false).unwrap();
            assert!(mount_info_eq(actual, &mounts[0]));
        }

        #[test]
        fn test_prefix_match() {
            let mounts = [mount_info("/foo")];
            let actual = mount_info_from_path(&mounts, "/foo/bar", false).unwrap();
            assert!(mount_info_eq(actual, &mounts[0]));
        }

        #[test]
        fn test_multiple_matches() {
            let mounts = [mount_info("/foo"), mount_info("/foo/bar")];
            let actual = mount_info_from_path(&mounts, "/foo/bar", false).unwrap();
            assert!(mount_info_eq(actual, &mounts[1]));
        }

        #[test]
        fn test_no_match() {
            let mounts = [mount_info("/foo")];
            assert!(mount_info_from_path(&mounts, "/bar", false).is_none());
        }

        #[test]
        fn test_partial_match() {
            let mounts = [mount_info("/foo/bar")];
            assert!(mount_info_from_path(&mounts, "/foo/baz", false).is_none());
        }
    }
}
<|endoftext|>