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

#![forbid(unsafe_code)]

use libra_config::config::NodeConfig;
use libra_genesis_tool::config_builder::FullnodeType;
use libra_swarm::{client, faucet, swarm::LibraSwarm};
use libra_temppath::TempPath;
use libra_types::chain_id::ChainId;
use std::path::Path;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(about = "Libra swarm to start local nodes")]
struct Args {
    /// Number of nodes to start (1 by default)
    #[structopt(short = "n", long, default_value = "1")]
    pub num_nodes: usize,
    /// Enable logging, by default spawned nodes will not perform logging
    #[structopt(short = "l", long)]
    pub enable_logging: bool,
    /// Start client
    #[structopt(short = "s", long)]
    pub start_client: bool,
    /// Directory used by launch_swarm to output LibraNodes' config files, logs, libradb, etc,
    /// such that user can still inspect them after exit.
    /// If unspecified, a temporary dir will be used and auto deleted.
    #[structopt(short = "c", long)]
    pub config_dir: Option<String>,
    /// If greater than 0, starts a full node swarm connected to the first node in the validator
    /// swarm.
    #[structopt(short = "f", long, default_value = "0")]
    pub num_full_nodes: usize,
    /// Start with faucet service for minting coins, this flag disables cli's dev commands.
    /// Used for manual testing faucet service integration.
    #[structopt(short = "m", long)]
    pub start_faucet: bool,
    /// Path to the libra-node binary
    #[structopt(long, default_value = "libra-node")]
    pub libra_node: String,

    /// Path to the cli binary
    #[structopt(long, default_value = "cli")]
    pub cli_path: String,
    /// Path to the faucet binary
    #[structopt(long, default_value = "libra-faucet")]
    pub faucet_path: String,
}

fn main() {
    let args = Args::from_args();
    let num_nodes = args.num_nodes;
    let num_full_nodes = args.num_full_nodes;

    libra_logger::Logger::new().init();

    let mut validator_swarm = LibraSwarm::configure_validator_swarm(
        args.libra_node.as_ref(),
        num_nodes,
        args.config_dir.clone(),
        None,
    )
    .expect("Failed to configure validator swarm");

    let mut full_node_swarm = if num_full_nodes > 0 {
        Some(
            LibraSwarm::configure_fn_swarm(
                args.libra_node.as_ref(),
                None, /* config dir */
                None,
                &validator_swarm.config,
                FullnodeType::ValidatorFullnode,
            )
            .expect("Failed to configure full node swarm"),
        )
    } else {
        None
    };
    validator_swarm
        .launch_attempt(!args.enable_logging)
        .expect("Failed to launch validator swarm");
    if let Some(ref mut swarm) = full_node_swarm {
        swarm
            .launch_attempt(!args.enable_logging)
            .expect("Failed to launch full node swarm");
    }

    let libra_root_key_path = &validator_swarm.config.libra_root_key_path;
    let validator_config = NodeConfig::load(&validator_swarm.config.config_files[0]).unwrap();
    let waypoint = validator_config.base.waypoint.waypoint();

    println!("To run the Libra CLI client in a separate process and connect to the validator nodes you just spawned, use this command:");

    println!(
        "\tcargo run --bin cli -- -u {} -m {:?} --waypoint {} --chain-id {:?}",
        format!("http://localhost:{}", validator_config.rpc.address.port()),
        libra_root_key_path,
        waypoint,
        ChainId::test().id()
    );

    let ports = validator_swarm.config.config_files.iter().map(|config| {
        let validator_config = NodeConfig::load(config).unwrap();
        let port = validator_config.rpc.address.port();
        let debug_interface_port = validator_config
            .debug_interface
            .admission_control_node_debug_port;
        (port, debug_interface_port)
    });

    let node_address_list = ports
        .clone()
        .map(|port| format!("localhost:{}", port.0))
        .collect::<Vec<String>>()
        .join(",");

    println!("To run transaction generator run:");
    println!(
        "\tcargo run -p cluster-test -- --mint-file {:?} --swarm --peers {:?} --emit-tx --workers-per-ac 1",
        libra_root_key_path, node_address_list,
    );

    let node_address_list = ports
        .map(|port| format!("localhost:{}:{}", port.0, port.1))
        .collect::<Vec<String>>()
        .join(",");

    println!("To run health check:");
    println!(
        "\tcargo run -p cluster-test -- --mint-file {:?} --swarm --peers {:?} --health-check --duration 30",
        libra_root_key_path, node_address_list,
    );

    if let Some(ref swarm) = full_node_swarm {
        let full_node_config = NodeConfig::load(&swarm.config.config_files[0]).unwrap();
        println!("To connect to the full nodes you just spawned, use this command:");
        println!(
            "\tcargo run --bin cli -- -u {} -m {:?} --waypoint {} --chain-id {}",
            format!("http://localhost:{}", full_node_config.rpc.address.port()),
            libra_root_key_path,
            waypoint,
            ChainId::test().id(),
        );
    }

    let faucet = if args.start_faucet {
        let faucet_port = libra_config::utils::get_available_port();
        let server_port = validator_swarm.get_client_port(0);
        println!("Starting faucet service at port: {}", faucet_port);
        let process = faucet::Process::start(
            args.faucet_path.as_ref(),
            faucet_port,
            server_port,
            Path::new(&libra_root_key_path),
        );
        println!("Waiting for faucet connectivity");
        process
            .wait_for_connectivity()
            .expect("Failed to start Faucet");
        Some(process)
    } else {
        None
    };

    if args.start_client {
        let tmp_mnemonic_file = TempPath::new();
        tmp_mnemonic_file.create_as_file().unwrap();

        let port = validator_swarm.get_client_port(0);
        let client = if let Some(ref f) = faucet {
            client::InteractiveClient::new_with_inherit_io_faucet(
                args.cli_path.as_ref(),
                port,
                f.mint_url(),
                waypoint,
            )
        } else {
            client::InteractiveClient::new_with_inherit_io(
                args.cli_path.as_ref(),
                port,
                Path::new(&libra_root_key_path),
                &tmp_mnemonic_file.path(),
                waypoint,
            )
        };
        println!("Loading client...");
        let _output = client.output().expect("Failed to wait on child");
        println!("Exit client.");
    } else {
        // Explicitly capture CTRL-C to drop LibraSwarm.
        let (tx, rx) = std::sync::mpsc::channel();
        ctrlc::set_handler(move || {
            tx.send(())
                .expect("failed to send unit when handling CTRL-C");
        })
        .expect("failed to set CTRL-C handler");
        println!("CTRL-C to exit.");
        rx.recv()
            .expect("failed to receive unit when handling CTRL-C");
    }

    if let Some(dir) = &args.config_dir {
        println!("Please manually cleanup {:?} after inspection", dir);
    }

    println!("Exit libra-swarm.");
}
<commit_msg>swarm: update docs so they don't mention cargo<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use libra_config::config::NodeConfig;
use libra_genesis_tool::config_builder::FullnodeType;
use libra_swarm::{client, faucet, swarm::LibraSwarm};
use libra_temppath::TempPath;
use libra_types::chain_id::ChainId;
use std::path::Path;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(about = "Libra swarm to start local nodes")]
struct Args {
    /// Number of nodes to start (1 by default)
    #[structopt(short = "n", long, default_value = "1")]
    pub num_nodes: usize,
    /// Enable logging, by default spawned nodes will not perform logging
    #[structopt(short = "l", long)]
    pub enable_logging: bool,
    /// Start client
    #[structopt(short = "s", long)]
    pub start_client: bool,
    /// Directory used by launch_swarm to output LibraNodes' config files, logs, libradb, etc,
    /// such that user can still inspect them after exit.
    /// If unspecified, a temporary dir will be used and auto deleted.
    #[structopt(short = "c", long)]
    pub config_dir: Option<String>,
    /// If greater than 0, starts a full node swarm connected to the first node in the validator
    /// swarm.
    #[structopt(short = "f", long, default_value = "0")]
    pub num_full_nodes: usize,
    /// Start with faucet service for minting coins, this flag disables cli's dev commands.
    /// Used for manual testing faucet service integration.
    #[structopt(short = "m", long)]
    pub start_faucet: bool,
    /// Path to the libra-node binary
    #[structopt(long, default_value = "libra-node")]
    pub libra_node: String,

    /// Path to the cli binary
    #[structopt(long, default_value = "cli")]
    pub cli_path: String,
    /// Path to the faucet binary
    #[structopt(long, default_value = "libra-faucet")]
    pub faucet_path: String,
}

fn main() {
    let args = Args::from_args();
    let num_nodes = args.num_nodes;
    let num_full_nodes = args.num_full_nodes;

    libra_logger::Logger::new().init();

    let mut validator_swarm = LibraSwarm::configure_validator_swarm(
        args.libra_node.as_ref(),
        num_nodes,
        args.config_dir.clone(),
        None,
    )
    .expect("Failed to configure validator swarm");

    let mut full_node_swarm = if num_full_nodes > 0 {
        Some(
            LibraSwarm::configure_fn_swarm(
                args.libra_node.as_ref(),
                None, /* config dir */
                None,
                &validator_swarm.config,
                FullnodeType::ValidatorFullnode,
            )
            .expect("Failed to configure full node swarm"),
        )
    } else {
        None
    };
    validator_swarm
        .launch_attempt(!args.enable_logging)
        .expect("Failed to launch validator swarm");
    if let Some(ref mut swarm) = full_node_swarm {
        swarm
            .launch_attempt(!args.enable_logging)
            .expect("Failed to launch full node swarm");
    }

    let libra_root_key_path = &validator_swarm.config.libra_root_key_path;
    let validator_config = NodeConfig::load(&validator_swarm.config.config_files[0]).unwrap();
    let waypoint = validator_config.base.waypoint.waypoint();

    println!("To run the Libra CLI client in a separate process and connect to the validator nodes you just spawned, use this command:");

    println!(
        "\tcli -u {} -m {:?} --waypoint {} --chain-id {:?}",
        format!("http://localhost:{}", validator_config.rpc.address.port()),
        libra_root_key_path,
        waypoint,
        ChainId::test().id()
    );

    let ports = validator_swarm.config.config_files.iter().map(|config| {
        let validator_config = NodeConfig::load(config).unwrap();
        let port = validator_config.rpc.address.port();
        let debug_interface_port = validator_config
            .debug_interface
            .admission_control_node_debug_port;
        (port, debug_interface_port)
    });

    let node_address_list = ports
        .clone()
        .map(|port| format!("localhost:{}", port.0))
        .collect::<Vec<String>>()
        .join(",");

    println!("To run transaction generator run:");
    println!(
        "\tcluster-test --mint-file {:?} --swarm --peers {:?} --emit-tx --workers-per-ac 1",
        libra_root_key_path, node_address_list,
    );

    let node_address_list = ports
        .map(|port| format!("localhost:{}:{}", port.0, port.1))
        .collect::<Vec<String>>()
        .join(",");

    println!("To run health check:");
    println!(
        "\tcluster-test --mint-file {:?} --swarm --peers {:?} --health-check --duration 30",
        libra_root_key_path, node_address_list,
    );

    if let Some(ref swarm) = full_node_swarm {
        let full_node_config = NodeConfig::load(&swarm.config.config_files[0]).unwrap();
        println!("To connect to the full nodes you just spawned, use this command:");
        println!(
            "\tcli -u {} -m {:?} --waypoint {} --chain-id {}",
            format!("http://localhost:{}", full_node_config.rpc.address.port()),
            libra_root_key_path,
            waypoint,
            ChainId::test().id(),
        );
    }

    let faucet = if args.start_faucet {
        let faucet_port = libra_config::utils::get_available_port();
        let server_port = validator_swarm.get_client_port(0);
        println!("Starting faucet service at port: {}", faucet_port);
        let process = faucet::Process::start(
            args.faucet_path.as_ref(),
            faucet_port,
            server_port,
            Path::new(&libra_root_key_path),
        );
        println!("Waiting for faucet connectivity");
        process
            .wait_for_connectivity()
            .expect("Failed to start Faucet");
        Some(process)
    } else {
        None
    };

    if args.start_client {
        let tmp_mnemonic_file = TempPath::new();
        tmp_mnemonic_file.create_as_file().unwrap();

        let port = validator_swarm.get_client_port(0);
        let client = if let Some(ref f) = faucet {
            client::InteractiveClient::new_with_inherit_io_faucet(
                args.cli_path.as_ref(),
                port,
                f.mint_url(),
                waypoint,
            )
        } else {
            client::InteractiveClient::new_with_inherit_io(
                args.cli_path.as_ref(),
                port,
                Path::new(&libra_root_key_path),
                &tmp_mnemonic_file.path(),
                waypoint,
            )
        };
        println!("Loading client...");
        let _output = client.output().expect("Failed to wait on child");
        println!("Exit client.");
    } else {
        // Explicitly capture CTRL-C to drop LibraSwarm.
        let (tx, rx) = std::sync::mpsc::channel();
        ctrlc::set_handler(move || {
            tx.send(())
                .expect("failed to send unit when handling CTRL-C");
        })
        .expect("failed to set CTRL-C handler");
        println!("CTRL-C to exit.");
        rx.recv()
            .expect("failed to receive unit when handling CTRL-C");
    }

    if let Some(dir) = &args.config_dir {
        println!("Please manually cleanup {:?} after inspection", dir);
    }

    println!("Exit libra-swarm.");
}
<|endoftext|>


<commit_before>//!   Library used in solving Project Euler problems needing `BigInt` or `BigUint`. (https://projecteuler.net)
//!
//!
//! # Example
//!
//! ```
//! use euler_library::big as eu_big;
//!
//! let big_number_string = eu_big::factorial(31).to_string();
//! assert_eq!(big_number_string.to_string(), "8222838654177922817725562880000000");
//! ```

extern crate num;
use self::num::{BigInt, BigUint, One, Zero, pow};
use self::num::bigint::ToBigUint;

/// Returns n factorial as a `BigUint`.
///
/// ```
/// use euler_library::big as eu_big;
///
/// let big_number_string = eu_big::factorial(31).to_string();
/// assert_eq!(big_number_string.to_string(), "8222838654177922817725562880000000");
/// ```
pub fn factorial(n: usize) -> BigUint {
    let mut fact: BigUint = One::one();
    if n > 1 {
        for i in 2..n + 1 {
            fact = fact * i.to_biguint().unwrap()
        }
    }
    fact
}

/// Returns `BigUnit` square root of usize n to digits precision.
///
/// Function does not tell you where decimal is.
/// For example square root of 2 is 1.1414213..., function return 11414213...
///
/// ```
/// use euler_library::big as eu_big;
///
/// let sqrt_2_string = eu_big::precision_sqrt(2, 40).to_string();
/// assert_eq!(sqrt_2_string.to_string(), "1414213562373095048801688724209698078569");
/// ```
pub fn precision_sqrt(n: usize, digits: usize) -> BigUint {
    let ten = &10.to_biguint().unwrap();
    let hundred = &(ten * ten);
    let limit = pow(ten.clone(), digits + 1);
    let mut a = (5 * n).to_biguint().unwrap();
    let mut b = 5.to_biguint().unwrap();
    while b < limit {
        if a >= b {
            a = a.clone() - b.clone();
            b = b.clone() + ten;
        } else {
            a = a.clone() * hundred;
            b = (b.clone() / ten) * hundred + 5.to_biguint().unwrap();
        }
    }
    b / hundred
}

/// Return (numerator, denominator) after evaluating `continued_fraction`.
///
/// Form of continued fraction: (a0, [t1, t2, t3, ....]).
/// see `euler_library::common::continued_fraction` to generate a periodic continued fraction.
/// `http://roycrippen.github.io/euler_library/euler_library/common/fn.continued_fraction.html`
///
/// ```
/// use euler_library::big as eu_big;
///
/// // periodic continued fraction for 23 = (4, [1,3,1,8])
/// let (a0, mut ts) = (4, vec![1, 3, 1, 8]);
/// ts = ts.clone().into_iter().cycle().take(64).collect::<Vec<usize>>();
///
/// let (numerator, denominator) = eu_big::continued_fraction(a0, ts.clone());
/// assert_eq!(numerator.to_string(), "3468077590434524694871282564");
/// assert_eq!(denominator.to_string(), "723144166673926627543073281");
/// ```
pub fn continued_fraction(a0: usize, mut xs: Vec<usize>) -> (BigUint, BigUint) {
    fn go(n: &BigUint, d: &BigUint, mut xs: Vec<BigUint>) -> (BigUint, BigUint) {
        if xs.is_empty() {
            return (n.clone(), d.clone());
        }
        let a = xs.pop().unwrap();
        go(&(a * n + d), n, xs)
    }

    xs.insert(0, a0);
    let a = xs.pop().unwrap().to_biguint().unwrap();
    let xs = xs.into_iter().map(|x| x.to_biguint().unwrap()).collect::<Vec<BigUint>>();
    go(&a, &1.to_biguint().unwrap(), xs)
}

/// Returns a `BigInt` vec[p(0), p(1)...p(n)] generating partition function
///
/// http://oeis.org/A000041/list
///
/// ```
/// use euler_library::big as eu_big;
///
/// let ps = eu_big::integer_partitions(1_000).iter().map(|x| x.to_string()).collect::<Vec<_>>();
/// assert_eq!(&ps[23..26], ["1255", "1575", "1958"]);
/// assert_eq!(&ps[1000..], ["24061467864032622473692149727991"]);
/// ```
pub fn integer_partitions(n: usize) -> Vec<BigInt> {
    let k = (1..n)
                .flat_map(|i| vec![i * (3 * i - 1) / 2, i * (3 * i - 1) / 2 + i])
                .collect::<Vec<_>>();

    let one: BigInt = One::one();
    let mut p: Vec<BigInt> = vec![one.clone()];
    let sign: Vec<BigInt> = vec![one.clone(), one.clone(), -one.clone(), -one.clone()];

    for i in 1..n + 1 {
        let mut t: BigInt = Zero::zero();
        let mut j = 0;
        while k[j] <= i {
            t = t + (p[i - k[j]].clone()) * sign[j % 4].clone();
            j += 1;
        }
        p.push(t)
    }
    p
}
<commit_msg>initial<commit_after>//!   Library used in solving Project Euler problems needing `BigInt` or `BigUint`.
//!
//!
//! # Example
//!
//! ```
//! use euler_library::big as eu_big;
//!
//! let big_number_string = eu_big::factorial(31).to_string();
//! assert_eq!(big_number_string.to_string(), "8222838654177922817725562880000000");
//! ```

extern crate num;
use self::num::{BigInt, BigUint, One, Zero, pow};
use self::num::bigint::ToBigUint;

/// Returns n factorial as a `BigUint`.
///
/// ```
/// use euler_library::big as eu_big;
///
/// let big_number_string = eu_big::factorial(31).to_string();
/// assert_eq!(big_number_string.to_string(), "8222838654177922817725562880000000");
/// ```
pub fn factorial(n: usize) -> BigUint {
    let mut fact: BigUint = One::one();
    if n > 1 {
        for i in 2..n + 1 {
            fact = fact * i.to_biguint().unwrap()
        }
    }
    fact
}

/// Returns `BigUnit` square root of usize n to digits precision.
///
/// Function does not tell you where decimal is.
/// For example square root of 2 is 1.1414213..., function return 11414213...
///
/// ```
/// use euler_library::big as eu_big;
///
/// let sqrt_2_string = eu_big::precision_sqrt(2, 40).to_string();
/// assert_eq!(sqrt_2_string.to_string(), "1414213562373095048801688724209698078569");
/// ```
pub fn precision_sqrt(n: usize, digits: usize) -> BigUint {
    let ten = &10.to_biguint().unwrap();
    let hundred = &(ten * ten);
    let limit = pow(ten.clone(), digits + 1);
    let mut a = (5 * n).to_biguint().unwrap();
    let mut b = 5.to_biguint().unwrap();
    while b < limit {
        if a >= b {
            a = a.clone() - b.clone();
            b = b.clone() + ten;
        } else {
            a = a.clone() * hundred;
            b = (b.clone() / ten) * hundred + 5.to_biguint().unwrap();
        }
    }
    b / hundred
}

/// Return (numerator, denominator) after evaluating `continued_fraction`.
///
/// Form of continued fraction: (a0, [t1, t2, t3, ....]).
/// see `euler_library::common::continued_fraction` to generate a periodic continued fraction.
/// `http://roycrippen.github.io/euler_library/euler_library/common/fn.continued_fraction.html`
///
/// ```
/// use euler_library::big as eu_big;
///
/// // periodic continued fraction for 23 = (4, [1,3,1,8])
/// let (a0, mut ts) = (4, vec![1, 3, 1, 8]);
/// ts = ts.clone().into_iter().cycle().take(64).collect::<Vec<usize>>();
///
/// let (numerator, denominator) = eu_big::continued_fraction(a0, ts.clone());
/// assert_eq!(numerator.to_string(), "3468077590434524694871282564");
/// assert_eq!(denominator.to_string(), "723144166673926627543073281");
/// ```
pub fn continued_fraction(a0: usize, mut xs: Vec<usize>) -> (BigUint, BigUint) {
    fn go(n: &BigUint, d: &BigUint, mut xs: Vec<BigUint>) -> (BigUint, BigUint) {
        if xs.is_empty() {
            return (n.clone(), d.clone());
        }
        let a = xs.pop().unwrap();
        go(&(a * n + d), n, xs)
    }

    xs.insert(0, a0);
    let a = xs.pop().unwrap().to_biguint().unwrap();
    let xs = xs.into_iter().map(|x| x.to_biguint().unwrap()).collect::<Vec<BigUint>>();
    go(&a, &1.to_biguint().unwrap(), xs)
}

/// Returns a `BigInt` vec[p(0), p(1)...p(n)] generating partition function
///
/// http://oeis.org/A000041/list
///
/// ```
/// use euler_library::big as eu_big;
///
/// let ps = eu_big::integer_partitions(1_000).iter().map(|x| x.to_string()).collect::<Vec<_>>();
/// assert_eq!(&ps[23..26], ["1255", "1575", "1958"]);
/// assert_eq!(&ps[1000..], ["24061467864032622473692149727991"]);
/// ```
pub fn integer_partitions(n: usize) -> Vec<BigInt> {
    let k = (1..n)
                .flat_map(|i| vec![i * (3 * i - 1) / 2, i * (3 * i - 1) / 2 + i])
                .collect::<Vec<_>>();

    let one: BigInt = One::one();
    let mut p: Vec<BigInt> = vec![one.clone()];
    let sign: Vec<BigInt> = vec![one.clone(), one.clone(), -one.clone(), -one.clone()];

    for i in 1..n + 1 {
        let mut t: BigInt = Zero::zero();
        let mut j = 0;
        while k[j] <= i {
            t = t + (p[i - k[j]].clone()) * sign[j % 4].clone();
            j += 1;
        }
        p.push(t)
    }
    p
}
<|endoftext|>


<commit_before>#![crate_id = "rustful_macros#0.1-pre"]

#![comment = "Macros for rustful"]
#![license = "MIT"]
#![crate_type = "dylib"]

#![doc(html_root_url = "http://ogeon.github.io/rustful/doc/")]

#![feature(macro_rules, macro_registrar, managed_boxes, quote, phase)]

//!This crate provides some helpful macros for rustful, including `router!` and `routes!`.
//!
//!#`router!`
//!The `router!` macro generates a `Router` containing the provided handlers and routing tree.
//!This can be useful to lower the risk of typing errors, among other things.
//!
//!##Example 1
//!
//!```rust
//!#![feature(phase)]
//!#[phase(syntax)]
//!extern crate rustful_macros;
//!
//!extern crate rustful;
//!
//!...
//!
//!
//!let router = router!{
//!	"/about" => Get: about_us,
//!	"/user/:user" => Get: show_user,
//!	"/product/:name" => Get: show_product,
//!	"/*" => Get: show_error,
//!	"/" => Get: show_welcome
//!};
//!```
//!
//!##Example 2
//!
//!```rust
//!#![feature(phase)]
//!#[phase(syntax)]
//!extern crate rustful_macros;
//!
//!extern crate rustful;
//!
//!...
//!
//!
//!let router = router!{
//!	"/" => Get: show_home,
//!	"home" => Get: show_home,
//!	"user/:username" => {Get: show_user, Post: save_user},
//!	"product" => {
//!		Get: show_all_products,
//!
//!		"json" => Get: send_all_product_data
//!		":id" => {
//!			Get: show_product,
//!			Post | Delete: edit_product,
//!
//!			"json" => Get: send_product_data
//!		}
//!	}
//!};
//!```
//!
//!#`routes!`
//!
//!The `routes!` macro generates a vector of routes, which can be used to create a `Router`.
//!It has the same syntax as `routes!`.
//!
//!```rust
//!#![feature(phase)]
//!#[phase(syntax)]
//!extern crate rustful_macros;
//!
//!extern crate rustful;
//!
//!...
//!
//!
//!let routes = routes!{
//!	"/" => Get: show_home,
//!	"home" => Get: show_home,
//!	"user/:username" => {Get: show_user, Post: save_user},
//!	"product" => {
//!		Get: show_all_products,
//!
//!		"json" => Get: send_all_product_data
//!		":id" => {
//!			Get: show_product,
//!			Post | Delete: edit_product,
//!
//!			"json" => Get: send_product_data
//!		}
//!	}
//!};
//!
//!let router = Router::from_routes(routes);
//!```

extern crate syntax;

use std::path::BytesContainer;

use syntax::{ast, codemap};
use syntax::ext::base::{
	SyntaxExtension, ExtCtxt, MacResult, MacExpr,
	NormalTT, BasicMacroExpander
};
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ExtParseUtils;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::parser;
use syntax::parse::parser::Parser;
//use syntax::print::pprust;

#[macro_registrar]
#[doc(hidden)]
pub fn macro_registrar(register: |ast::Name, SyntaxExtension|) {
	let expander = box BasicMacroExpander{expander: expand_router, span: None};
	register(token::intern("router"), NormalTT(expander, None));

	let expander = box BasicMacroExpander{expander: expand_routes, span: None};
	register(token::intern("routes"), NormalTT(expander, None));
}

fn expand_router(cx: &mut ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) -> Box<MacResult> {
	let router_ident = cx.ident_of("router");
	let insert_method = cx.ident_of("insert_item");

	let mut calls: Vec<@ast::Stmt> = vec!(
		cx.stmt_let(sp, true, router_ident, quote_expr!(&cx, ::rustful::Router::new()))
	);

	for (path, method, handler) in parse_routes(cx, tts).move_iter() {
		let path_expr = cx.parse_expr(format!("\"{}\"", path));
		let method_expr = cx.expr_path(method);
		let handler_expr = cx.expr_path(handler);
		calls.push(cx.stmt_expr(
			cx.expr_method_call(sp, cx.expr_ident(sp, router_ident), insert_method, vec!(method_expr, path_expr, handler_expr))
		));
	}

	let block = cx.expr_block(cx.block(sp, calls, Some(cx.expr_ident(sp, router_ident))));

	MacExpr::new(block)
}

fn expand_routes(cx: &mut ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) -> Box<MacResult> {
	let routes = parse_routes(cx, tts).move_iter().map(|(path, method, handler)| {
		let path_expr = cx.parse_expr(format!("\"{}\"", path));
		let method_expr = cx.expr_path(method);
		let handler_expr = cx.expr_path(handler);
		mk_tup(sp, vec!(method_expr, path_expr, handler_expr))
	}).collect();

	MacExpr::new(cx.expr_vec(sp, routes))
}

fn parse_routes(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Vec<(String, ast::Path, ast::Path)> {

	let mut parser = parse::new_parser_from_tts(
		cx.parse_sess(), cx.cfg(), Vec::from_slice(tts)
	);

	parse_subroutes("", cx, &mut parser)
}

fn parse_subroutes(base: &str, cx: &mut ExtCtxt, parser: &mut Parser) -> Vec<(String, ast::Path, ast::Path)> {
	let mut routes = Vec::new();

	while !parser.eat(&token::EOF) {
		match parser.parse_optional_str() {
			Some((ref s, _)) => {
				if !parser.eat(&token::FAT_ARROW) {
					parser.expect(&token::FAT_ARROW);
					break;
				}

				let mut new_base = base.to_string();
				match s.container_as_str() {
					Some(s) => {
						new_base.push_str(s.trim_chars('/'));
						new_base.push_str("/");
					},
					None => cx.span_err(parser.span, "invalid path")
				}

				if parser.eat(&token::EOF) {
					cx.span_err(parser.span, "unexpected end of routing tree");
				}

				if parser.eat(&token::LBRACE) {
					let subroutes = parse_subroutes(new_base.as_slice(), cx, parser);
					routes.push_all(subroutes.as_slice());

					if parser.eat(&token::RBRACE) {
						if !parser.eat(&token::COMMA) {
							break;
						}
					} else {
						parser.expect_one_of([token::COMMA, token::RBRACE], []);
					}
				} else {
					for (method, handler) in parse_handler(parser).move_iter() {
						routes.push((new_base.clone(), method, handler))
					}

					if !parser.eat(&token::COMMA) {
						break;
					}
				}
			},
			None => {
				for (method, handler) in parse_handler(parser).move_iter() {
					routes.push((base.to_string(), method, handler))
				}

				if !parser.eat(&token::COMMA) {
					break;
				}
			}
		}
	}

	routes
}

fn parse_handler(parser: &mut Parser) -> Vec<(ast::Path, ast::Path)> {
	let mut methods = Vec::new();

	loop {
		methods.push(parser.parse_path(parser::NoTypesAllowed).path);

		if parser.eat(&token::COLON) {
			break;
		}

		if !parser.eat(&token::BINOP(token::OR)) {
			parser.expect_one_of([token::COLON, token::BINOP(token::OR)], []);
		}
	}

	let handler = parser.parse_path(parser::NoTypesAllowed).path;

	methods.move_iter().map(|m| (m, handler.clone())).collect()
}

fn mk_tup(sp: codemap::Span, content: Vec<@ast::Expr>) -> @ast::Expr {
	dummy_expr(sp, ast::ExprTup(content))
}

fn dummy_expr(sp: codemap::Span, e: ast::Expr_) -> @ast::Expr {
	@ast::Expr {
		id: ast::DUMMY_NODE_ID,
		node: e,
		span: sp,
	}
}

/**
A macro for assigning content types.

It takes a main type, a sub type and a parameter list. Instead of this:

```
response.headers.content_type = Some(MediaType {
	type_: String::from_str("text"),
	subtype: String::from_str("html"),
	parameters: vec!((String::from_str("charset"), String::from_str("UTF-8")))
});
```

it can be written like this:

```
response.headers.content_type = content_type!("text", "html", "charset": "UTF-8");
```

The `"charset": "UTF-8"` part defines the parameter list for the content type.
It may contain more than one parameter, or be omitted:

```
response.headers.content_type = content_type!("application", "octet-stream", "type": "image/gif", "padding": "4");
```

```
response.headers.content_type = content_type!("image", "png");
```
**/
#[macro_export]
macro_rules! content_type(
	($main_type:expr, $sub_type:expr) => ({
		Some(::http::headers::content_type::MediaType {
			type_: String::from_str($main_type),
			subtype: String::from_str($sub_type),
			parameters: Vec::new()
		})
	});

	($main_type:expr, $sub_type:expr, $($param:expr: $value:expr),+) => ({
		Some(::http::headers::content_type::MediaType {
			type_: String::from_str($main_type),
			subtype: String::from_str($sub_type),
			parameters: vec!( $( (String::from_str($param), String::from_str($value)) ),+ )
		})
	});
)<commit_msg>router! and routes! macros takes expressions<commit_after>#![crate_id = "rustful_macros#0.1-pre"]

#![comment = "Macros for rustful"]
#![license = "MIT"]
#![crate_type = "dylib"]

#![doc(html_root_url = "http://ogeon.github.io/rustful/doc/")]

#![feature(macro_rules, macro_registrar, managed_boxes, quote, phase)]

//!This crate provides some helpful macros for rustful, including `router!` and `routes!`.
//!
//!#`router!`
//!The `router!` macro generates a `Router` containing the provided handlers and routing tree.
//!This can be useful to lower the risk of typing errors, among other things.
//!
//!##Example 1
//!
//!```rust
//!#![feature(phase)]
//!#[phase(syntax)]
//!extern crate rustful_macros;
//!
//!extern crate rustful;
//!
//!...
//!
//!
//!let router = router!{
//!	"/about" => Get: about_us,
//!	"/user/:user" => Get: show_user,
//!	"/product/:name" => Get: show_product,
//!	"/*" => Get: show_error,
//!	"/" => Get: show_welcome
//!};
//!```
//!
//!##Example 2
//!
//!```rust
//!#![feature(phase)]
//!#[phase(syntax)]
//!extern crate rustful_macros;
//!
//!extern crate rustful;
//!
//!...
//!
//!
//!let router = router!{
//!	"/" => Get: show_home,
//!	"home" => Get: show_home,
//!	"user/:username" => {Get: show_user, Post: save_user},
//!	"product" => {
//!		Get: show_all_products,
//!
//!		"json" => Get: send_all_product_data
//!		":id" => {
//!			Get: show_product,
//!			Post | Delete: edit_product,
//!
//!			"json" => Get: send_product_data
//!		}
//!	}
//!};
//!```
//!
//!#`routes!`
//!
//!The `routes!` macro generates a vector of routes, which can be used to create a `Router`.
//!It has the same syntax as `routes!`.
//!
//!```rust
//!#![feature(phase)]
//!#[phase(syntax)]
//!extern crate rustful_macros;
//!
//!extern crate rustful;
//!
//!...
//!
//!
//!let routes = routes!{
//!	"/" => Get: show_home,
//!	"home" => Get: show_home,
//!	"user/:username" => {Get: show_user, Post: save_user},
//!	"product" => {
//!		Get: show_all_products,
//!
//!		"json" => Get: send_all_product_data
//!		":id" => {
//!			Get: show_product,
//!			Post | Delete: edit_product,
//!
//!			"json" => Get: send_product_data
//!		}
//!	}
//!};
//!
//!let router = Router::from_routes(routes);
//!```

extern crate syntax;

use std::path::BytesContainer;

use syntax::{ast, codemap};
use syntax::ext::base::{
	SyntaxExtension, ExtCtxt, MacResult, MacExpr,
	NormalTT, BasicMacroExpander
};
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ExtParseUtils;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::parser;
use syntax::parse::parser::Parser;
//use syntax::print::pprust;

#[macro_registrar]
#[doc(hidden)]
pub fn macro_registrar(register: |ast::Name, SyntaxExtension|) {
	let expander = box BasicMacroExpander{expander: expand_router, span: None};
	register(token::intern("router"), NormalTT(expander, None));

	let expander = box BasicMacroExpander{expander: expand_routes, span: None};
	register(token::intern("routes"), NormalTT(expander, None));
}

fn expand_router(cx: &mut ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) -> Box<MacResult> {
	let router_ident = cx.ident_of("router");
	let insert_method = cx.ident_of("insert_item");

	let mut calls: Vec<@ast::Stmt> = vec!(
		cx.stmt_let(sp, true, router_ident, quote_expr!(&cx, ::rustful::Router::new()))
	);

	for (path, method, handler) in parse_routes(cx, tts).move_iter() {
		let path_expr = cx.parse_expr(format!("\"{}\"", path));
		let method_expr = cx.expr_path(method);
		calls.push(cx.stmt_expr(
			cx.expr_method_call(sp, cx.expr_ident(sp, router_ident), insert_method, vec!(method_expr, path_expr, handler))
		));
	}

	let block = cx.expr_block(cx.block(sp, calls, Some(cx.expr_ident(sp, router_ident))));

	MacExpr::new(block)
}

fn expand_routes(cx: &mut ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) -> Box<MacResult> {
	let routes = parse_routes(cx, tts).move_iter().map(|(path, method, handler)| {
		let path_expr = cx.parse_expr(format!("\"{}\"", path));
		let method_expr = cx.expr_path(method);
		mk_tup(sp, vec!(method_expr, path_expr, handler))
	}).collect();

	MacExpr::new(cx.expr_vec(sp, routes))
}

fn parse_routes(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Vec<(String, ast::Path, @ast::Expr)> {

	let mut parser = parse::new_parser_from_tts(
		cx.parse_sess(), cx.cfg(), Vec::from_slice(tts)
	);

	parse_subroutes("", cx, &mut parser)
}

fn parse_subroutes(base: &str, cx: &mut ExtCtxt, parser: &mut Parser) -> Vec<(String, ast::Path, @ast::Expr)> {
	let mut routes = Vec::new();

	while !parser.eat(&token::EOF) {
		match parser.parse_optional_str() {
			Some((ref s, _)) => {
				if !parser.eat(&token::FAT_ARROW) {
					parser.expect(&token::FAT_ARROW);
					break;
				}

				let mut new_base = base.to_string();
				match s.container_as_str() {
					Some(s) => {
						new_base.push_str(s.trim_chars('/'));
						new_base.push_str("/");
					},
					None => cx.span_err(parser.span, "invalid path")
				}

				if parser.eat(&token::EOF) {
					cx.span_err(parser.span, "unexpected end of routing tree");
				}

				if parser.eat(&token::LBRACE) {
					let subroutes = parse_subroutes(new_base.as_slice(), cx, parser);
					routes.push_all(subroutes.as_slice());

					if parser.eat(&token::RBRACE) {
						if !parser.eat(&token::COMMA) {
							break;
						}
					} else {
						parser.expect_one_of([token::COMMA, token::RBRACE], []);
					}
				} else {
					for (method, handler) in parse_handler(parser).move_iter() {
						routes.push((new_base.clone(), method, handler))
					}

					if !parser.eat(&token::COMMA) {
						break;
					}
				}
			},
			None => {
				for (method, handler) in parse_handler(parser).move_iter() {
					routes.push((base.to_string(), method, handler))
				}

				if !parser.eat(&token::COMMA) {
					break;
				}
			}
		}
	}

	routes
}

fn parse_handler(parser: &mut Parser) -> Vec<(ast::Path, @ast::Expr)> {
	let mut methods = Vec::new();

	loop {
		methods.push(parser.parse_path(parser::NoTypesAllowed).path);

		if parser.eat(&token::COLON) {
			break;
		}

		if !parser.eat(&token::BINOP(token::OR)) {
			parser.expect_one_of([token::COLON, token::BINOP(token::OR)], []);
		}
	}

	let handler = parser.parse_expr();

	methods.move_iter().map(|m| (m, handler.clone())).collect()
}

fn mk_tup(sp: codemap::Span, content: Vec<@ast::Expr>) -> @ast::Expr {
	dummy_expr(sp, ast::ExprTup(content))
}

fn dummy_expr(sp: codemap::Span, e: ast::Expr_) -> @ast::Expr {
	@ast::Expr {
		id: ast::DUMMY_NODE_ID,
		node: e,
		span: sp,
	}
}

/**
A macro for assigning content types.

It takes a main type, a sub type and a parameter list. Instead of this:

```
response.headers.content_type = Some(MediaType {
	type_: String::from_str("text"),
	subtype: String::from_str("html"),
	parameters: vec!((String::from_str("charset"), String::from_str("UTF-8")))
});
```

it can be written like this:

```
response.headers.content_type = content_type!("text", "html", "charset": "UTF-8");
```

The `"charset": "UTF-8"` part defines the parameter list for the content type.
It may contain more than one parameter, or be omitted:

```
response.headers.content_type = content_type!("application", "octet-stream", "type": "image/gif", "padding": "4");
```

```
response.headers.content_type = content_type!("image", "png");
```
**/
#[macro_export]
macro_rules! content_type(
	($main_type:expr, $sub_type:expr) => ({
		Some(::http::headers::content_type::MediaType {
			type_: String::from_str($main_type),
			subtype: String::from_str($sub_type),
			parameters: Vec::new()
		})
	});

	($main_type:expr, $sub_type:expr, $($param:expr: $value:expr),+) => ({
		Some(::http::headers::content_type::MediaType {
			type_: String::from_str($main_type),
			subtype: String::from_str($sub_type),
			parameters: vec!( $( (String::from_str($param), String::from_str($value)) ),+ )
		})
	});
)<|endoftext|>


<commit_before>extern crate url;
extern crate hyper;
extern crate xml;

use self::url::{Url, ParseError};
use self::hyper::server::response::Response;
use self::hyper::status::StatusCode;
use self::hyper::header::Location;
use self::hyper::Client;
use self::hyper::error::Error as HyperError;
use self::xml::reader::{EventReader, XmlEvent};
use self::xml::reader::Error as XmlError;

/// The username returned by `verify_ticket` on success
pub type Name = String;
/// The error returned by `verify_ticket` on failure
pub type TicketError = String;

/// The details of a CAS server.  All URLs are the full urls
pub struct CasClient {
    /// Login url (such as https://login.case.edu/cas/login)
    login_url: Url,
    /// Logout url (such as https://login.case.edu/cas/logout)
    logout_url: Url,
    /// Verify url, accessed by the server
    /// (such as https://login.case.edu/cas/serviceValidate)
    verify_url: Url,
    /// The URL of your service, which is used in the login sequence and
    /// so the login server knows where to redirect you back to
    service_url: Url,
}

/// The response from the server from `verify_ticket`
pub enum ServiceResponse {
    /// Returned on successful login
    Success(Name),
    /// Returned on unsuccessful login
    Failure(TicketError),
}

enum XmlMatchStatus {
    None,
    ExpectSuccess,
}

/// Errors that can happen when verifying.  Xml is unlikely.
pub enum VerifyError {
    Hyper(HyperError),
    Xml(XmlError),
}

impl From<HyperError> for VerifyError {
    fn from(err: HyperError) -> VerifyError {
        VerifyError::Hyper(err)
    }
}
impl From<XmlError> for VerifyError {
    fn from(err: XmlError) -> VerifyError {
        VerifyError::Xml(err)
    }
}

impl CasClient {
    /// Construct a new CasClient. The for each url except service_url, the
    /// \<thing\>_path is concatinated onto base_url to form the Url
    pub fn new(
        base_url: &str, login_path: &str, logout_path: &str, verify_path: &str,
        service_url: &str) -> Result<CasClient, ParseError> {
        Ok(CasClient {
            login_url: try!(
                Url::parse(&format!("{}{}", base_url, login_path))),
            logout_url: try!(
                Url::parse(&format!("{}{}", base_url, logout_path))),
            verify_url: try!(
                Url::parse(&format!("{}{}", base_url, verify_path))),
            service_url: try!(Url::parse(service_url)),
        })
    }

    /// Get the URL to redirect to for login.  Use this if you are not using
    /// Hyper as your web server
    pub fn get_login_url(&self) -> String {
        let mut url = self.login_url.clone();
        let param = vec![("service", self.service_url.serialize())];
        url.set_query_from_pairs(param);
        url.serialize()
    }

    /// Consumes a hyper::server::response::Response to return a 302 redirect
    /// to the CAS login url.  Use this if you're using Hyper as you web
    /// server
    pub fn login_redirect(&self, mut res: Response) {
        {
            let mut s = res.status_mut();
            *s = StatusCode::Found;
        }
        {
            let mut h = res.headers_mut();
            h.set::<Location>(Location(self.get_login_url()));
        }
        res.send(b"").unwrap();
    }

    /// Get the URL to redirect to for logout.  Use this if you are not using
    /// Hyper as your web server
    pub fn get_logout_url(&self) -> String {
        self.logout_url.serialize()
    }

    /// Consumes a hyper::server::response::Response to return a 302 redirect
    /// to the CAS logout url.  use this if you're using Hyper as your web
    /// server
    pub fn logout_redirect(&self, mut res: Response) {
        {
            let mut s = res.status_mut();
            *s = StatusCode::Found;
        }
        {
            let mut h = res.headers_mut();
            h.set::<Location>(Location(self.get_logout_url()));
        }
        res.send(b"").unwrap();
    }

    /// When login completes, the CAS server will redirec to your service_url
    /// with the added parameter ticket=\<ticket\>.  You pass \<ticket\> here,
    /// and it checks with the CAS server whether or not the login was
    /// successful.  On success, this will return
    /// `Ok(ServiceResponse::Success(username))`, where username is the username
    /// from the CAS server.  On failure it returns
    /// `Ok(ServiceResponse::Failure(reason))`, where reason is the reason for
    /// the failure.  In the event of an http error or an xml error, this
    /// returns Err(VerifyError)
    pub fn verify_ticket(&self, ticket: &str)
        -> Result<ServiceResponse, VerifyError> {
        let mut url: Url = self.verify_url.clone();
        let param = vec![
            ("service", self.service_url.serialize()),
            ("ticket", ticket.to_string()),
        ];
        url.set_query_from_pairs(param);

        let res = try!(Client::new().get(&url.serialize()).send());

        let parser = EventReader::new(res);
        let mut status = XmlMatchStatus::None;
        for e in parser {
            match try!(e) {
                XmlEvent::StartElement { name, attributes, .. } => {
                    if name.local_name == "authenticationSuccess".to_string() {
                        status = XmlMatchStatus::ExpectSuccess;
                    } else if name.local_name == "authenticationFailure"
                        .to_string() {
                            let reason = attributes[0].value.clone();
                            return Ok(ServiceResponse::Failure(reason));
                    }
                }
                XmlEvent::Characters(s) => {
                    match status {
                        XmlMatchStatus::None => {}
                        XmlMatchStatus::ExpectSuccess => {
                            return Ok(ServiceResponse::Success(s));
                        }
                    }
                }
                _ => {}
            }
        }

        Ok(ServiceResponse::Success("mtb89".to_string()))
    }
}
<commit_msg>Add debug derive for debugging purposes<commit_after>extern crate url;
extern crate hyper;
extern crate xml;

use self::url::{Url, ParseError};
use self::hyper::server::response::Response;
use self::hyper::status::StatusCode;
use self::hyper::header::Location;
use self::hyper::Client;
use self::hyper::error::Error as HyperError;
use self::xml::reader::{EventReader, XmlEvent};
use self::xml::reader::Error as XmlError;

/// The username returned by `verify_ticket` on success
pub type Name = String;
/// The error returned by `verify_ticket` on failure
pub type TicketError = String;

/// The details of a CAS server.  All URLs are the full urls
#[derive(Debug)]
pub struct CasClient {
    /// Login url (such as https://login.case.edu/cas/login)
    login_url: Url,
    /// Logout url (such as https://login.case.edu/cas/logout)
    logout_url: Url,
    /// Verify url, accessed by the server
    /// (such as https://login.case.edu/cas/serviceValidate)
    verify_url: Url,
    /// The URL of your service, which is used in the login sequence and
    /// so the login server knows where to redirect you back to
    service_url: Url,
}

/// The response from the server from `verify_ticket`
#[derive(Debug)]
pub enum ServiceResponse {
    /// Returned on successful login
    Success(Name),
    /// Returned on unsuccessful login
    Failure(TicketError),
}

#[derive(Debug)]
enum XmlMatchStatus {
    None,
    ExpectSuccess,
}

/// Errors that can happen when verifying.  Xml is unlikely.
#[derive(Debug)]
pub enum VerifyError {
    Hyper(HyperError),
    Xml(XmlError),
}

impl From<HyperError> for VerifyError {
    fn from(err: HyperError) -> VerifyError {
        VerifyError::Hyper(err)
    }
}
impl From<XmlError> for VerifyError {
    fn from(err: XmlError) -> VerifyError {
        VerifyError::Xml(err)
    }
}

impl CasClient {
    /// Construct a new CasClient. The for each url except service_url, the
    /// \<thing\>_path is concatinated onto base_url to form the Url
    pub fn new(
        base_url: &str, login_path: &str, logout_path: &str, verify_path: &str,
        service_url: &str) -> Result<CasClient, ParseError> {
        Ok(CasClient {
            login_url: try!(
                Url::parse(&format!("{}{}", base_url, login_path))),
            logout_url: try!(
                Url::parse(&format!("{}{}", base_url, logout_path))),
            verify_url: try!(
                Url::parse(&format!("{}{}", base_url, verify_path))),
            service_url: try!(Url::parse(service_url)),
        })
    }

    /// Get the URL to redirect to for login.  Use this if you are not using
    /// Hyper as your web server
    pub fn get_login_url(&self) -> String {
        let mut url = self.login_url.clone();
        let param = vec![("service", self.service_url.serialize())];
        url.set_query_from_pairs(param);
        url.serialize()
    }

    /// Consumes a hyper::server::response::Response to return a 302 redirect
    /// to the CAS login url.  Use this if you're using Hyper as you web
    /// server
    pub fn login_redirect(&self, mut res: Response) {
        {
            let mut s = res.status_mut();
            *s = StatusCode::Found;
        }
        {
            let mut h = res.headers_mut();
            h.set::<Location>(Location(self.get_login_url()));
        }
        res.send(b"").unwrap();
    }

    /// Get the URL to redirect to for logout.  Use this if you are not using
    /// Hyper as your web server
    pub fn get_logout_url(&self) -> String {
        self.logout_url.serialize()
    }

    /// Consumes a hyper::server::response::Response to return a 302 redirect
    /// to the CAS logout url.  use this if you're using Hyper as your web
    /// server
    pub fn logout_redirect(&self, mut res: Response) {
        {
            let mut s = res.status_mut();
            *s = StatusCode::Found;
        }
        {
            let mut h = res.headers_mut();
            h.set::<Location>(Location(self.get_logout_url()));
        }
        res.send(b"").unwrap();
    }

    /// When login completes, the CAS server will redirec to your service_url
    /// with the added parameter ticket=\<ticket\>.  You pass \<ticket\> here,
    /// and it checks with the CAS server whether or not the login was
    /// successful.  On success, this will return
    /// `Ok(ServiceResponse::Success(username))`, where username is the username
    /// from the CAS server.  On failure it returns
    /// `Ok(ServiceResponse::Failure(reason))`, where reason is the reason for
    /// the failure.  In the event of an http error or an xml error, this
    /// returns Err(VerifyError)
    pub fn verify_ticket(&self, ticket: &str)
        -> Result<ServiceResponse, VerifyError> {
        let mut url: Url = self.verify_url.clone();
        let param = vec![
            ("service", self.service_url.serialize()),
            ("ticket", ticket.to_string()),
        ];
        url.set_query_from_pairs(param);

        let res = try!(Client::new().get(&url.serialize()).send());

        let parser = EventReader::new(res);
        let mut status = XmlMatchStatus::None;
        for e in parser {
            match try!(e) {
                XmlEvent::StartElement { name, attributes, .. } => {
                    if name.local_name == "authenticationSuccess".to_string() {
                        status = XmlMatchStatus::ExpectSuccess;
                    } else if name.local_name == "authenticationFailure"
                        .to_string() {
                            let reason = attributes[0].value.clone();
                            return Ok(ServiceResponse::Failure(reason));
                    }
                }
                XmlEvent::Characters(s) => {
                    match status {
                        XmlMatchStatus::None => {}
                        XmlMatchStatus::ExpectSuccess => {
                            return Ok(ServiceResponse::Success(s));
                        }
                    }
                }
                _ => {}
            }
        }

        Ok(ServiceResponse::Success("mtb89".to_string()))
    }
}
<|endoftext|>


<commit_before>//! defines CLI for ff
use std;
use std::env;
use std::path::{Path, PathBuf};
use clap::{SubCommand, Arg};

use config::*;
use core::*;

/// Returns path to config file
pub fn get_config_file_path() -> PathBuf {
	let mut conf_file = env::home_dir().expect("Can't find home dir");
	conf_file.push(".ff");
	conf_file.push("config.ini");
	conf_file
}

fn home_dir_contained<T: AsRef<Path>>(dir: T) -> Result<bool, String> {
	let home_dir = std::env::home_dir()
		.ok_or("Can't find home dir")?;
	Ok(dir.as_ref().starts_with(&home_dir))
}

fn action_init(sync_dir: &str, config: Config) {
	let _sync_dir = match sync_dir.len() {
		0 => match std::env::current_dir() {
			Err(e) => {
				println!("Can't get home dir ({})", e);
				return
			},
			Ok(v) => v,
		},
		_ => Path::new(sync_dir).to_path_buf(),
	};
	let _sync_dir = match std::fs::canonicalize(&_sync_dir) {
		Err(e) => {
			println!("Can't canonicalize: {:?} ({})", &_sync_dir, e);
			return;
		},
		Ok(v) => v,
	};
	let is_home_dir = match home_dir_contained(&_sync_dir) {
		Err(e) => {
			println!("Can't validate if {:?} is descendat of home dir ({})", &_sync_dir, e);
			return
		},
		Ok(v) => v,
	};
	if !is_home_dir {
		println!("Sync dir should be descendant of home dir");
		return;
	}

	// TODO1: tmp conversion until code after action_ is moved to PathBuf
	let _sync_dir = match _sync_dir.as_path().to_str() {
		None => {
			println!("Can't convert {:?} to str", _sync_dir);
			return
		},
		Some(v) => v,
	};
	if let Err(e) = init(_sync_dir, config) {
		println!("{}", e);
	}
}

fn action_add(file_paths: &Vec<&str>, space_dir: &str, config: Config) -> Result<(), String> {
	let home_dir = env::home_dir()
		.ok_or("Can't get home dir")?;
	let home_dir = home_dir.to_str()
		.ok_or("Can't convert home dir to str")?;
	let sync_dir = with_space_dir(space_dir, config)?;
	let sync_dir = sync_dir.to_str()
		.ok_or("Can't convert home dir to str")?;
	add_files(file_paths, &home_dir, &sync_dir);
	Ok(())
}

fn with_space_dir(space_dir: &str, config: Config) -> Result<PathBuf, String> {
	let sync_dir = config.get("sync-dir")
		.map_err(|e| format!("Can't read sync-dir from {} ({})", config.get_path(), e))?
		.ok_or(
			format!("Can't find 'sync-dir' value in config file: {}
					Did you run: 'ff init' on your sync-dir?", config.get_path())
		)?;
	let mut sync_dir = PathBuf::from(sync_dir);
	if space_dir != "" {
		sync_dir = sync_dir.join(space_dir);
	}
	Ok(sync_dir)
}

fn action_remove(file_paths: &Vec<&str>) {
	remove_files(file_paths);
}

fn action_apply(space_dir: &str, config: Config) -> Result<(), String> {
	let sync_dir = with_space_dir(&space_dir, config)?;
	let sync_dir = sync_dir.to_str()
		.ok_or("Can't convert sync-dir with space to str")?;
	let home_dir = std::env::home_dir()
		.ok_or("Can't get home dir")?;
	let home_dir = home_dir.to_str()
		.ok_or(format!("Can't convert home dir to str"))?;
	apply(&sync_dir, &sync_dir, &home_dir)
}

/// Defines and initialize command line dispatcher which run suitable actions
pub fn run_cli() {
	let conf_path = get_config_file_path();
	let conf_path = match conf_path.to_str() {
		None => {
			println!("Can't convert config path");
			return;
		}
		Some(v) => v,
	};
	let config = match Config::new(conf_path) {
		Err(e) => {
			println!("Can't initialize config file {}: ({})", conf_path, e);
			return;
		},
		Ok(v) => v
	};

	let mut app = app_from_crate!()
		.version(crate_version!())
		.about("\n\
			`ff` helps you manage dot files by:\n\n\
			- symlinking files from your homedir to synchronized dir\n\
			- symlinking files from synchronized dir to homedir\n\
		")
		.subcommand(
			SubCommand::with_name("init")
				.about("Sets dir as sync-dir")
				.arg(Arg::with_name("dir-path")
						.required(false)
						.help("Sets dir as sync-dir (which means dot-files will be stored there and you sync that dir)")
				),
		)
		.subcommand(
			SubCommand::with_name("add")
				.about("Adds files to synchronized dir")
				.args(&[
					  Arg::with_name("file-path")
						  .multiple(true).required(true),
					  Arg::with_name("space-dir")
						  .short("d")
						  .takes_value(true)
						  .help("Specifies dir in which file is added (default: 'homedir')")
						  .required(false),
				])
		)
		.subcommand(
			SubCommand::with_name("remove")
				.about("Removes files from synchronized dir")
				.arg(Arg::with_name("file-path")
						.multiple(true).required(true)
				)
		)
		.subcommand(
			SubCommand::with_name("apply")
				.about("Replaces home dir's files with aliases from synchronized dir")
				.arg(
					Arg::with_name("space-dir")
				)
		);

	let matches = app.clone().get_matches();

	// apply matching
	match matches.subcommand_name() {
		Some("init") => {
			if let Some(ref matches) = matches.subcommand_matches("init") {
				action_init(matches.value_of("dir-path").unwrap_or(""), config);
			}
		},
		Some("add") => {
			if let Some(ref matches) = matches.subcommand_matches("add") {
				let file_paths: Vec<_> = matches.values_of("file-path").expect("Can't get file paths").collect();
				let space_dir = matches.value_of("space-dir").unwrap_or("");
				match action_add(&file_paths, &space_dir, config) {
					Err(e) => println!("{}", e),
					Ok(_) => (),
				}
			}
		},
		Some("remove") => {
			if let Some(ref matches) = matches.subcommand_matches("remove") {
				let file_paths: Vec<_> = matches.values_of("file-path").expect("Can't read file paths to remove").collect();
				action_remove(&file_paths);
			}
		},
		Some("apply") => {
			if let Some(ref matches) = matches.subcommand_matches("apply") {
				let space_dir = matches.value_of("space-dir").unwrap_or("");
				match action_apply(space_dir, config) {
					Err(e) => println!("{}", e),
					Ok(_) => (),
				}
			}
		},
		_ => {
			app.print_help().expect("Can't print help");
			()
		},
	}
}
<commit_msg>Better formatting for "Did you run.."<commit_after>//! defines CLI for ff
use std;
use std::env;
use std::path::{Path, PathBuf};
use clap::{SubCommand, Arg};

use config::*;
use core::*;

/// Returns path to config file
pub fn get_config_file_path() -> PathBuf {
	let mut conf_file = env::home_dir().expect("Can't find home dir");
	conf_file.push(".ff");
	conf_file.push("config.ini");
	conf_file
}

fn home_dir_contained<T: AsRef<Path>>(dir: T) -> Result<bool, String> {
	let home_dir = std::env::home_dir()
		.ok_or("Can't find home dir")?;
	Ok(dir.as_ref().starts_with(&home_dir))
}

fn action_init(sync_dir: &str, config: Config) {
	let _sync_dir = match sync_dir.len() {
		0 => match std::env::current_dir() {
			Err(e) => {
				println!("Can't get home dir ({})", e);
				return
			},
			Ok(v) => v,
		},
		_ => Path::new(sync_dir).to_path_buf(),
	};
	let _sync_dir = match std::fs::canonicalize(&_sync_dir) {
		Err(e) => {
			println!("Can't canonicalize: {:?} ({})", &_sync_dir, e);
			return;
		},
		Ok(v) => v,
	};
	let is_home_dir = match home_dir_contained(&_sync_dir) {
		Err(e) => {
			println!("Can't validate if {:?} is descendat of home dir ({})", &_sync_dir, e);
			return
		},
		Ok(v) => v,
	};
	if !is_home_dir {
		println!("Sync dir should be descendant of home dir");
		return;
	}

	// TODO1: tmp conversion until code after action_ is moved to PathBuf
	let _sync_dir = match _sync_dir.as_path().to_str() {
		None => {
			println!("Can't convert {:?} to str", _sync_dir);
			return
		},
		Some(v) => v,
	};
	if let Err(e) = init(_sync_dir, config) {
		println!("{}", e);
	}
}

fn action_add(file_paths: &Vec<&str>, space_dir: &str, config: Config) -> Result<(), String> {
	let home_dir = env::home_dir()
		.ok_or("Can't get home dir")?;
	let home_dir = home_dir.to_str()
		.ok_or("Can't convert home dir to str")?;
	let sync_dir = with_space_dir(space_dir, config)?;
	let sync_dir = sync_dir.to_str()
		.ok_or("Can't convert home dir to str")?;
	add_files(file_paths, &home_dir, &sync_dir);
	Ok(())
}

fn with_space_dir(space_dir: &str, config: Config) -> Result<PathBuf, String> {
	let sync_dir = config.get("sync-dir")
		.map_err(|e| format!("Can't read sync-dir from {} ({})", config.get_path(), e))?
		.ok_or(
			format!("Can't find 'sync-dir' value in config file: {}\n\
					Did you run: 'ff init' on your sync-dir?", config.get_path())
		)?;
	let mut sync_dir = PathBuf::from(sync_dir);
	if space_dir != "" {
		sync_dir = sync_dir.join(space_dir);
	}
	Ok(sync_dir)
}

fn action_remove(file_paths: &Vec<&str>) {
	remove_files(file_paths);
}

fn action_apply(space_dir: &str, config: Config) -> Result<(), String> {
	let sync_dir = with_space_dir(&space_dir, config)?;
	let sync_dir = sync_dir.to_str()
		.ok_or("Can't convert sync-dir with space to str")?;
	let home_dir = std::env::home_dir()
		.ok_or("Can't get home dir")?;
	let home_dir = home_dir.to_str()
		.ok_or(format!("Can't convert home dir to str"))?;
	apply(&sync_dir, &sync_dir, &home_dir)
}

/// Defines and initialize command line dispatcher which run suitable actions
pub fn run_cli() {
	let conf_path = get_config_file_path();
	let conf_path = match conf_path.to_str() {
		None => {
			println!("Can't convert config path");
			return;
		}
		Some(v) => v,
	};
	let config = match Config::new(conf_path) {
		Err(e) => {
			println!("Can't initialize config file {}: ({})", conf_path, e);
			return;
		},
		Ok(v) => v
	};

	let mut app = app_from_crate!()
		.version(crate_version!())
		.about("\n\
			`ff` helps you manage dot files by:\n\n\
			- symlinking files from your homedir to synchronized dir\n\
			- symlinking files from synchronized dir to homedir\n\
		")
		.subcommand(
			SubCommand::with_name("init")
				.about("Sets dir as sync-dir")
				.arg(Arg::with_name("dir-path")
						.required(false)
						.help("Sets dir as sync-dir (which means dot-files will be stored there and you sync that dir)")
				),
		)
		.subcommand(
			SubCommand::with_name("add")
				.about("Adds files to synchronized dir")
				.args(&[
					  Arg::with_name("file-path")
						  .multiple(true).required(true),
					  Arg::with_name("space-dir")
						  .short("d")
						  .takes_value(true)
						  .help("Specifies dir in which file is added (default: 'homedir')")
						  .required(false),
				])
		)
		.subcommand(
			SubCommand::with_name("remove")
				.about("Removes files from synchronized dir")
				.arg(Arg::with_name("file-path")
						.multiple(true).required(true)
				)
		)
		.subcommand(
			SubCommand::with_name("apply")
				.about("Replaces home dir's files with aliases from synchronized dir")
				.arg(
					Arg::with_name("space-dir")
				)
		);

	let matches = app.clone().get_matches();

	// apply matching
	match matches.subcommand_name() {
		Some("init") => {
			if let Some(ref matches) = matches.subcommand_matches("init") {
				action_init(matches.value_of("dir-path").unwrap_or(""), config);
			}
		},
		Some("add") => {
			if let Some(ref matches) = matches.subcommand_matches("add") {
				let file_paths: Vec<_> = matches.values_of("file-path").expect("Can't get file paths").collect();
				let space_dir = matches.value_of("space-dir").unwrap_or("");
				match action_add(&file_paths, &space_dir, config) {
					Err(e) => println!("{}", e),
					Ok(_) => (),
				}
			}
		},
		Some("remove") => {
			if let Some(ref matches) = matches.subcommand_matches("remove") {
				let file_paths: Vec<_> = matches.values_of("file-path").expect("Can't read file paths to remove").collect();
				action_remove(&file_paths);
			}
		},
		Some("apply") => {
			if let Some(ref matches) = matches.subcommand_matches("apply") {
				let space_dir = matches.value_of("space-dir").unwrap_or("");
				match action_apply(space_dir, config) {
					Err(e) => println!("{}", e),
					Ok(_) => (),
				}
			}
		},
		_ => {
			app.print_help().expect("Can't print help");
			()
		},
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
extern crate log;
use clap::{Arg, App};
use index::{Line, Column};
use config::{Dimensions, Shell};
use std::path::{Path, PathBuf};
use std::borrow::Cow;

const DEFAULT_TITLE: &'static str = "Alacritty";

/// Options specified on the command line
pub struct Options {
    pub print_events: bool,
    pub ref_test: bool,
    pub dimensions: Option<Dimensions>,
    pub title: String,
    pub log_level: log::LogLevelFilter,
    pub command: Option<Shell<'static>>,
    pub working_dir: Option<PathBuf>,
    pub config: Option<PathBuf>,
}

impl Default for Options {
    fn default() -> Options {
        Options {
            print_events: false,
            ref_test: false,
            dimensions: None,
            title: DEFAULT_TITLE.to_owned(),
            log_level: log::LogLevelFilter::Warn,
            command: None,
            working_dir: None,
            config: None,
        }
    }
}

impl Options {
    /// Build `Options` from command line arguments
    pub fn load() -> Options {
        let mut options = Options::default();

        let matches = App::new(crate_name!())
            .version(crate_version!())
            .author(crate_authors!("\n"))
            .about(crate_description!())
            .arg(Arg::with_name("ref-test")
                .long("ref-test")
                .help("Generates ref test"))
            .arg(Arg::with_name("print-events")
                .long("print-events"))
            .arg(Arg::with_name("dimensions")
                .long("dimensions")
                .short("d")
                .value_names(&["columns", "lines"])
                .help("Defines the window dimensions [default: 80x24]"))
            .arg(Arg::with_name("title")
                .long("title")
                .short("t")
                .default_value(DEFAULT_TITLE)
                .help("Defines the window title"))
            .arg(Arg::with_name("q")
                .short("q")
                .multiple(true)
                .conflicts_with("v")
                .help("Reduces the level of verbosity (the min level is -qq)"))
            .arg(Arg::with_name("v")
                .short("v")
                .multiple(true)
                .conflicts_with("q")
                .help("Increases the level of verbosity (the max level is -vvv)"))
            .arg(Arg::with_name("working-directory")
                 .long("working-directory")
                 .takes_value(true)
                 .help("Start the shell in the specified working directory"))
            .arg(Arg::with_name("config-file")
                 .long("config-file")
                 .takes_value(true)
                 .help("Specify alternative configuration file [default: $XDG_CONFIG_HOME/alacritty/alacritty.yml]"))
            .arg(Arg::with_name("command")
                .short("e")
                .multiple(true)
                .takes_value(true)
                .min_values(1)
                .allow_hyphen_values(true)
                .help("Command and args to execute (must be last argument)"))
            .get_matches();

        if matches.is_present("ref-test") {
            options.ref_test = true;
        }

        if matches.is_present("print-events") {
            options.print_events = true;
        }

        if let Some(mut dimensions) = matches.values_of("dimensions") {
            let width = dimensions.next().map(|w| w.parse().map(|w| Column(w)));
            let height = dimensions.next().map(|h| h.parse().map(|h| Line(h)));
            if let (Some(Ok(width)), Some(Ok(height))) = (width, height) {
                options.dimensions = Some(Dimensions::new(width, height));
            }
        }

        if let Some(title) = matches.value_of("title") {
            options.title = title.to_owned();
        }

        match matches.occurrences_of("q") {
            0 => {},
            1 => options.log_level = log::LogLevelFilter::Error,
            2 | _ => options.log_level = log::LogLevelFilter::Off
        }

        match matches.occurrences_of("v") {
            0 => {},
            1 => options.log_level = log::LogLevelFilter::Info,
            2 => options.log_level = log::LogLevelFilter::Debug,
            3 | _ => options.log_level = log::LogLevelFilter::Trace
        }

        if let Some(dir) = matches.value_of("working-directory") {
            options.working_dir = Some(PathBuf::from(dir.to_string()));
        }

        if let Some(path) = matches.value_of("config-file") {
            options.config = Some(PathBuf::from(path.to_string()));
        }

        if let Some(mut args) = matches.values_of("command") {
            // The following unwrap is guaranteed to succeed.
            // If 'command' exists it must also have a first item since
            // Arg::min_values(1) is set.
            let command = String::from(args.next().unwrap());
            let args = args.map(String::from).collect();
            options.command = Some(Shell::new_with_args(command, args));
        }

        options
    }

    pub fn dimensions(&self) -> Option<Dimensions> {
        self.dimensions
    }

    pub fn command(&self) -> Option<&Shell> {
        self.command.as_ref()
    }

    pub fn config_path(&self) -> Option<Cow<Path>> {
        self.config.as_ref().map(|p| Cow::Borrowed(p.as_path()))
    }
}
<commit_msg>Add a long option for the command flag (-e) (#655)<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
extern crate log;
use clap::{Arg, App};
use index::{Line, Column};
use config::{Dimensions, Shell};
use std::path::{Path, PathBuf};
use std::borrow::Cow;

const DEFAULT_TITLE: &'static str = "Alacritty";

/// Options specified on the command line
pub struct Options {
    pub print_events: bool,
    pub ref_test: bool,
    pub dimensions: Option<Dimensions>,
    pub title: String,
    pub log_level: log::LogLevelFilter,
    pub command: Option<Shell<'static>>,
    pub working_dir: Option<PathBuf>,
    pub config: Option<PathBuf>,
}

impl Default for Options {
    fn default() -> Options {
        Options {
            print_events: false,
            ref_test: false,
            dimensions: None,
            title: DEFAULT_TITLE.to_owned(),
            log_level: log::LogLevelFilter::Warn,
            command: None,
            working_dir: None,
            config: None,
        }
    }
}

impl Options {
    /// Build `Options` from command line arguments
    pub fn load() -> Options {
        let mut options = Options::default();

        let matches = App::new(crate_name!())
            .version(crate_version!())
            .author(crate_authors!("\n"))
            .about(crate_description!())
            .arg(Arg::with_name("ref-test")
                .long("ref-test")
                .help("Generates ref test"))
            .arg(Arg::with_name("print-events")
                .long("print-events"))
            .arg(Arg::with_name("dimensions")
                .long("dimensions")
                .short("d")
                .value_names(&["columns", "lines"])
                .help("Defines the window dimensions [default: 80x24]"))
            .arg(Arg::with_name("title")
                .long("title")
                .short("t")
                .default_value(DEFAULT_TITLE)
                .help("Defines the window title"))
            .arg(Arg::with_name("q")
                .short("q")
                .multiple(true)
                .conflicts_with("v")
                .help("Reduces the level of verbosity (the min level is -qq)"))
            .arg(Arg::with_name("v")
                .short("v")
                .multiple(true)
                .conflicts_with("q")
                .help("Increases the level of verbosity (the max level is -vvv)"))
            .arg(Arg::with_name("working-directory")
                 .long("working-directory")
                 .takes_value(true)
                 .help("Start the shell in the specified working directory"))
            .arg(Arg::with_name("config-file")
                 .long("config-file")
                 .takes_value(true)
                 .help("Specify alternative configuration file [default: $XDG_CONFIG_HOME/alacritty/alacritty.yml]"))
            .arg(Arg::with_name("command")
                .long("command")
                .short("e")
                .multiple(true)
                .takes_value(true)
                .min_values(1)
                .allow_hyphen_values(true)
                .help("Command and args to execute (must be last argument)"))
            .get_matches();

        if matches.is_present("ref-test") {
            options.ref_test = true;
        }

        if matches.is_present("print-events") {
            options.print_events = true;
        }

        if let Some(mut dimensions) = matches.values_of("dimensions") {
            let width = dimensions.next().map(|w| w.parse().map(|w| Column(w)));
            let height = dimensions.next().map(|h| h.parse().map(|h| Line(h)));
            if let (Some(Ok(width)), Some(Ok(height))) = (width, height) {
                options.dimensions = Some(Dimensions::new(width, height));
            }
        }

        if let Some(title) = matches.value_of("title") {
            options.title = title.to_owned();
        }

        match matches.occurrences_of("q") {
            0 => {},
            1 => options.log_level = log::LogLevelFilter::Error,
            2 | _ => options.log_level = log::LogLevelFilter::Off
        }

        match matches.occurrences_of("v") {
            0 => {},
            1 => options.log_level = log::LogLevelFilter::Info,
            2 => options.log_level = log::LogLevelFilter::Debug,
            3 | _ => options.log_level = log::LogLevelFilter::Trace
        }

        if let Some(dir) = matches.value_of("working-directory") {
            options.working_dir = Some(PathBuf::from(dir.to_string()));
        }

        if let Some(path) = matches.value_of("config-file") {
            options.config = Some(PathBuf::from(path.to_string()));
        }

        if let Some(mut args) = matches.values_of("command") {
            // The following unwrap is guaranteed to succeed.
            // If 'command' exists it must also have a first item since
            // Arg::min_values(1) is set.
            let command = String::from(args.next().unwrap());
            let args = args.map(String::from).collect();
            options.command = Some(Shell::new_with_args(command, args));
        }

        options
    }

    pub fn dimensions(&self) -> Option<Dimensions> {
        self.dimensions
    }

    pub fn command(&self) -> Option<&Shell> {
        self.command.as_ref()
    }

    pub fn config_path(&self) -> Option<Cow<Path>> {
        self.config.as_ref().map(|p| Cow::Borrowed(p.as_path()))
    }
}
<|endoftext|>


<commit_before>use clap::{AppSettings, Clap};
use std::path;

/// The command line interface to the CaSILE toolkit, a book publishing
/// workflow employing SILE and other wizardry
#[derive(Clap, Debug)]
#[clap(bin_name = "casile")]
#[clap(setting = AppSettings::InferSubcommands)]
pub struct Cli {
    /// Activate debug mode
    #[clap(short, long)]
    pub debug: bool,

    /// Set language
    #[clap(short, long, required = false, env = "LANG")]
    pub language: String,

    /// Outputs verbose feedback where possible
    #[clap(short, long)]
    pub verbose: bool,

    #[clap(subcommand)]
    pub subcommand: Subcommand,
}

#[derive(Clap, Debug)]
pub enum Subcommand {
    /// Executes a make target
    Make {
        /// Target as defined in CaSILE makefile
        target: Vec<String>,
    },

    /// Configure a book repository
    Setup {
        /// Path to project repository
        #[clap(default_value = "./")]
        path: path::PathBuf,
    },

    /// Pass any command through to the system shell
    Shell { command: Vec<String> },
}
<commit_msg>chore(cli): Allow shell subcommand to invoke interactive shell<commit_after>use clap::{AppSettings, Clap};
use std::path;

/// The command line interface to the CaSILE toolkit, a book publishing
/// workflow employing SILE and other wizardry
#[derive(Clap, Debug)]
#[clap(bin_name = "casile")]
#[clap(setting = AppSettings::InferSubcommands)]
pub struct Cli {
    /// Activate debug mode
    #[clap(short, long)]
    pub debug: bool,

    /// Set language
    #[clap(short, long, required = false, env = "LANG")]
    pub language: String,

    /// Outputs verbose feedback where possible
    #[clap(short, long)]
    pub verbose: bool,

    #[clap(subcommand)]
    pub subcommand: Subcommand,
}

#[derive(Clap, Debug)]
pub enum Subcommand {
    /// Executes a make target
    Make {
        /// Target as defined in CaSILE makefile
        target: Vec<String>,
    },

    /// Configure a book repository
    Setup {
        /// Path to project repository
        #[clap(default_value = "./")]
        path: path::PathBuf,
    },

    /// Pass any command through to the system shell
    Shell {
        #[clap(default_value = "bash")]
        command: Vec<String>,
    },
}
<|endoftext|>


<commit_before>use matrixerror::MatrixError;

use std::fmt;

///Holds the matrix data in a Vec with the following structure:

///(0,0);(0,1) .. (0,n);(1,0);(1,1) .. (1,n) .. (m,0);(m,1) .. (m,n)

///The size of the matrix is m*n

///m = row number

///n = column number

///

///Be aware that the values of an index are NOT (x;y), but (row;col)

#[derive(Clone, PartialEq)]
pub struct Matrix<T>
{
	columns: usize,
	rows: usize,
	fields: Vec<T>,
	default: T
}

impl<T> Matrix<T> where T: Clone
{
	///Constructs a new matrix with a given width + height

	///and fills it with copies of a default value

	///

	///Returns None if either the width or the height of the matrix is zero
	pub fn new(rows: usize, cols: usize, default: T) -> Option<Matrix<T>>
	{
		if rows == 0 || cols == 0
		{
			return None;
		}
		let vecsize = rows*cols;
		let mut fields = Vec::with_capacity(vecsize);
		for _ in 0..vecsize
		{
			fields.push(default.clone());
		}
		Some(Matrix
		{
			columns: cols,
			rows: rows,
			fields: fields,
			default: default
		})
	}

	///Constructs a new matrix with a given width + height

	///and fills it with data from a vector (data structure is described in Matrix struct doc)

	///

	///Returns None if:

	///-vector size doesn't match rows * cols
	///-rows or cols is zero
	pub fn from_vec(vector: Vec<T>, rows: usize, cols: usize) -> Option<Matrix<T>>
	{
		let size = rows*cols;
		if vector.len() != size
		{
			return None;
		}
		if rows == 0 || cols == 0
		{
			return None;
		}
		let default = vector.get(0).unwrap().clone();
		Some(
		Matrix
		{
			columns: cols,
			rows: rows,
			fields: vector,
			default: default
		})
	}

	///Returns a reference to the value at the given position -> M(row, col)

	///

	///Errors:

	///-IndexOOB
	pub fn get_ref(&self, row: usize, col: usize) -> (&T, MatrixError)
	{
		if !self.is_valid_index(row, col)
		{
			return (&self.default, MatrixError::IndexOOB);
		}
		let index = self.index_of(row, col);
		let result = self.fields.get(index).unwrap(); //should not happen
		(result, MatrixError::None)
	}

	///Returns a copy of the value at the given position -> M(row, col)

	///

	///Errors:

	///-IndexOOB
	pub fn get(&self, row: usize, col: usize) -> (T, MatrixError)
	{
		let (result, error) = self.get_ref(row, col);
		(result.clone(), error)
	}

	///Sets the field at the given position (M(row, col))

	///

	///Errors:

	///-IndexOOB
	pub fn set(&mut self, row: usize, col: usize, value: T) -> MatrixError
	{
		let (mutref, error) = self.get_mut(row, col);
		if error != MatrixError::None
		{
			return error;
		}
		match mutref
		{
			Some(mut v) => {
				*v = value;
			},
			//would only get called in case of OOB error, but OOB is handled in if error != MatrixError::None
			None => {}
		};
		MatrixError::None
	}

	pub fn swap(&mut self, row_1: usize, col_1: usize, row_2: usize, col_2: usize) -> MatrixError
	{
		let (temp_1, temp1_error) = self.get(row_1, col_1);
		let (temp_2, temp2_error) = self.get(row_2, col_2);
		if temp1_error != MatrixError::None
		{
			return temp1_error
		}
		if temp2_error != MatrixError::None
		{
			return temp2_error
		}
		self.set(row_1, col_1, temp_2);
		self.set(row_2, col_2, temp_1);
		MatrixError::None
	}

	///Returns the width/columns of the matrix
	pub fn get_col_count(&self) -> usize
	{
		self.columns
	}

	///Returns the height/rows of the matrix
	pub fn get_row_count(&self) -> usize
	{
		self.rows
	}

	///Returns a tuple representing the size of the matrix:

	///(height/rows, width/columns)
	pub fn get_size(&self) -> (usize, usize)
	{
		(self.rows, self.columns)
	}

	///Checks if the given index is inside the matrix bounds
	pub fn is_valid_index(&self, row: usize, col: usize) -> bool
	{
		row < self.rows && col < self.columns //not necessary to check >= 0 -> usize, not isize
	}

	//like get(..), but not used because of set(..)
	fn get_mut(&mut self, row: usize, col: usize) -> (Option<&mut T>, MatrixError)
	{
		if !self.is_valid_index(row, col)
		{
			return (None, MatrixError::IndexOOB);
		}
		let index = self.index_of(row, col);
		let result = self.fields.get_mut(index).unwrap();
		(Some(result), MatrixError::None)
	}

	//projects the 2D indices to 1D index
	fn index_of(&self, row: usize, col: usize) -> usize
	{
		row * self.columns + col
	}
}

impl<T> fmt::Display for Matrix<T> where T: Clone + fmt::Display
{
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
	{
		let mut output = String::new();
		output.push('[');
		for row in 0..self.get_row_count()
		{
			output.push('[');
			for col in 0..self.get_col_count()
			{
				let val = self.get(row, col);
				if col != self.get_col_count() - 1
				{
					output.push_str(&format!("{}, ", val.0));
				}
				else
				{
				    output.push_str(&format!("{}", val.0));
				}
			}
			output.push(']');
			if row != self.get_row_count() - 1
			{
				output.push('\n');
			}
		}
		output.push(']');
		write!(f, "{}", output)
	}
}

impl<T> fmt::Debug for Matrix<T> where T: Clone + fmt::Debug
{
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
	{
		let mut output = String::new();
		output.push_str(&format!("{} x {}\n", self.get_row_count(), self.get_col_count()));
		output.push('[');
		for row in 0..self.get_row_count()
		{
			output.push('[');
			for col in 0..self.get_col_count()
			{
				let val = self.get(row, col);
				if col != self.get_col_count() - 1
				{
					output.push_str(&format!("{:?}, ", val.0));
				}
				else
				{
				    output.push_str(&format!("{:?}", val.0));
				}
			}
			output.push(']');
			if row != self.get_row_count() - 1
			{
				output.push('\n');
			}
		}
		output.push(']');
		write!(f, "{}", output)
	}
}<commit_msg>first slicing<commit_after>use matrixerror::MatrixError;
use matrixtraits::MatrixSlice;

use std::fmt;

///Holds the matrix data in a Vec with the following structure:

///(0,0);(0,1) .. (0,n);(1,0);(1,1) .. (1,n) .. (m,0);(m,1) .. (m,n)

///The size of the matrix is m*n

///m = row number

///n = column number

///

///Be aware that the values of an index are NOT (x;y), but (row;col)

#[derive(Clone, PartialEq)]
pub struct Matrix<T>
{
	columns: usize,
	rows: usize,
	fields: Vec<T>,
	default: T
}

impl<T> Matrix<T> where T: Clone
{
	///Constructs a new matrix with a given width + height

	///and fills it with copies of a default value

	///

	///Returns None if either the width or the height of the matrix is zero
	pub fn new(rows: usize, cols: usize, default: T) -> Option<Matrix<T>>
	{
		if rows == 0 || cols == 0
		{
			return None;
		}
		let vecsize = rows*cols;
		let mut fields = Vec::with_capacity(vecsize);
		for _ in 0..vecsize
		{
			fields.push(default.clone());
		}
		Some(Matrix
		{
			columns: cols,
			rows: rows,
			fields: fields,
			default: default
		})
	}

	///Constructs a new matrix with a given width + height

	///and fills it with data from a vector (data structure is described in Matrix struct doc)

	///

	///Returns None if:

	///-vector size doesn't match rows * cols
	///-rows or cols is zero
	pub fn from_vec(vector: Vec<T>, rows: usize, cols: usize) -> Option<Matrix<T>>
	{
		let size = rows*cols;
		if vector.len() != size
		{
			return None;
		}
		if rows == 0 || cols == 0
		{
			return None;
		}
		let default = vector.get(0).unwrap().clone();
		Some(
		Matrix
		{
			columns: cols,
			rows: rows,
			fields: vector,
			default: default
		})
	}

	///Returns a reference to the value at the given position -> M(row, col)

	///

	///Errors:

	///-IndexOOB
	pub fn get_ref(&self, row: usize, col: usize) -> (&T, MatrixError)
	{
		if !self.is_valid_index(row, col)
		{
			return (&self.default, MatrixError::IndexOOB);
		}
		let index = self.index_of(row, col);
		let result = self.fields.get(index).unwrap(); //should not happen
		(result, MatrixError::None)
	}

	///Returns a copy of the value at the given position -> M(row, col)

	///

	///Errors:

	///-IndexOOB
	pub fn get(&self, row: usize, col: usize) -> (T, MatrixError)
	{
		let (result, error) = self.get_ref(row, col);
		(result.clone(), error)
	}

	///Sets the field at the given position (M(row, col))

	///

	///Errors:

	///-IndexOOB
	pub fn set(&mut self, row: usize, col: usize, value: T) -> MatrixError
	{
		let (mutref, error) = self.get_mut(row, col);
		if error != MatrixError::None
		{
			return error;
		}
		match mutref
		{
			Some(mut v) => {
				*v = value;
			},
			//would only get called in case of OOB error, but OOB is handled in if error != MatrixError::None
			None => {}
		};
		MatrixError::None
	}

	pub fn swap(&mut self, row_1: usize, col_1: usize, row_2: usize, col_2: usize) -> MatrixError
	{
		let (temp_1, temp1_error) = self.get(row_1, col_1);
		let (temp_2, temp2_error) = self.get(row_2, col_2);
		if temp1_error != MatrixError::None
		{
			return temp1_error
		}
		if temp2_error != MatrixError::None
		{
			return temp2_error
		}
		self.set(row_1, col_1, temp_2);
		self.set(row_2, col_2, temp_1);
		MatrixError::None
	}

	///Returns the width/columns of the matrix
	pub fn get_col_count(&self) -> usize
	{
		self.columns
	}

	///Returns the height/rows of the matrix
	pub fn get_row_count(&self) -> usize
	{
		self.rows
	}

	///Returns a tuple representing the size of the matrix:

	///(height/rows, width/columns)
	pub fn get_size(&self) -> (usize, usize)
	{
		(self.rows, self.columns)
	}

	///Checks if the given index is inside the matrix bounds
	pub fn is_valid_index(&self, row: usize, col: usize) -> bool
	{
		row < self.rows && col < self.columns //not necessary to check >= 0 -> usize, not isize
	}

	//like get(..), but not used because of set(..)
	fn get_mut(&mut self, row: usize, col: usize) -> (Option<&mut T>, MatrixError)
	{
		if !self.is_valid_index(row, col)
		{
			return (None, MatrixError::IndexOOB);
		}
		let index = self.index_of(row, col);
		let result = self.fields.get_mut(index).unwrap();
		(Some(result), MatrixError::None)
	}

	//projects the 2D indices to 1D index
	fn index_of(&self, row: usize, col: usize) -> usize
	{
		row * self.columns + col
	}
}

impl<T> MatrixSlice<T> for Matrix<T> where T: Clone
{
	fn get_row(&self, row: usize) -> Vec<T>
	{
		let mut result = Vec::new();
		for col in 0..self.get_col_count()
		{
			result.push(self.get(row, col).0);
		}
		result
	}

	fn get_col(&self, col: usize) -> Vec<T>
	{
		let mut result = Vec::new();
		for row in 0..self.get_row_count()
		{
			result.push(self.get(row, col).0);
		}
		result
	}

	fn crop(self, row_1: usize, col_1: usize, row_2: usize, col_2: usize) -> Matrix<T>
	{
		let valid_1 = self.is_valid_index(row_1, col_1);
		let valid_2 = self.is_valid_index(row_2, col_2);

	}

	fn copy_crop(&self, row_1: usize, col_1: usize, row_2: usize, col_2: usize) -> Matrix<T>
	{

	}

	fn replace_area(&self, row_1: usize, col_1: usize, row_2: usize, col_2: usize, replacement: Matrix<T>)
	{

	}
}

impl<T> fmt::Display for Matrix<T> where T: Clone + fmt::Display
{
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
	{
		let mut output = String::new();
		output.push('[');
		for row in 0..self.get_row_count()
		{
			output.push('[');
			for col in 0..self.get_col_count()
			{
				let val = self.get(row, col);
				if col != self.get_col_count() - 1
				{
					output.push_str(&format!("{}, ", val.0));
				}
				else
				{
				    output.push_str(&format!("{}", val.0));
				}
			}
			output.push(']');
			if row != self.get_row_count() - 1
			{
				output.push('\n');
			}
		}
		output.push(']');
		write!(f, "{}", output)
	}
}

impl<T> fmt::Debug for Matrix<T> where T: Clone + fmt::Debug
{
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
	{
		let mut output = String::new();
		output.push_str(&format!("{} x {}\n", self.get_row_count(), self.get_col_count()));
		output.push('[');
		for row in 0..self.get_row_count()
		{
			output.push('[');
			for col in 0..self.get_col_count()
			{
				let val = self.get(row, col);
				if col != self.get_col_count() - 1
				{
					output.push_str(&format!("{:?}, ", val.0));
				}
				else
				{
				    output.push_str(&format!("{:?}", val.0));
				}
			}
			output.push(']');
			if row != self.get_row_count() - 1
			{
				output.push('\n');
			}
		}
		output.push(']');
		write!(f, "{}", output)
	}
}<|endoftext|>


<commit_before>use helpers;
use std::collections::HashMap;
use std::ops::Deref;
use std::fmt;

static MEMORY_FILE: &'static str = "/proc/meminfo";

pub struct MemoryInfo {
    mem_total: String,
    mem_free: String,
    mem_available: String,
    buffers: String,
    cached: String
}

impl fmt::Display for MemoryInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "mem_total: {}, mem_free: {}, mem_available: {}, buffers: {}, cached: {}",
               self.mem_total, self.mem_free, self.mem_available, self.buffers, self.cached)
    }
}

pub fn read_usage() -> Result<MemoryInfo, String> {
    let content = helpers::read_file_to_string(MEMORY_FILE);
    match content {
        Err(err) => Err(err),
        Ok(s) => {
            let lines: Vec<&str> = s.split('\n').collect();
            let mut stats: HashMap<&str, &str> = HashMap::new();
            for line in lines {
                let parts: Vec<&str> = line.split(':').map(|s| s.trim()).collect();
                let parts = parts.deref();
                if parts.len() >= 2 {
                    stats.insert(parts[0], parts[1]);
                }
            }

            let info = MemoryInfo {
                mem_total: (*stats.get(&"MemTotal").unwrap()).to_string(),
                mem_free: (*stats.get(&"MemFree").unwrap()).to_string(),
                mem_available: (*stats.get(&"MemAvailable").unwrap()).to_string(),
                buffers: (*stats.get(&"Buffers").unwrap()).to_string(),
                cached: (*stats.get(&"Cached").unwrap()).to_string()
            };

            Ok(info)
        }
    }
}
<commit_msg>Better unwrapping for memory stats<commit_after>use helpers;
use std::collections::HashMap;
use std::ops::Deref;
use std::fmt;

static MEMORY_FILE: &'static str = "/proc/meminfo";

pub struct MemoryInfo {
    mem_total: String,
    mem_free: String,
    mem_available: String,
    buffers: String,
    cached: String
}

impl fmt::Display for MemoryInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "mem_total: {}, mem_free: {}, mem_available: {}, buffers: {}, cached: {}",
               self.mem_total, self.mem_free, self.mem_available, self.buffers, self.cached)
    }
}

pub fn read_usage() -> Result<MemoryInfo, String> {
    let content = helpers::read_file_to_string(MEMORY_FILE);
    match content {
        Err(err) => Err(err),
        Ok(s) => {
            let lines: Vec<&str> = s.split('\n').collect();
            let mut stats: HashMap<&str, &str> = HashMap::new();
            for line in lines {
                let parts: Vec<&str> = line.split(':').map(|s| s.trim()).collect();
                let parts = parts.deref();
                if parts.len() >= 2 {
                    stats.insert(parts[0], parts[1]);
                }
            }

            let info = MemoryInfo {
                mem_total: (stats.get(&"MemTotal").map(|s| *s).unwrap_or("0 kB")).to_string(),
                mem_free: (stats.get(&"MemFree").map(|s| *s).unwrap_or("0 kB")).to_string(),
                mem_available: (stats.get(&"MemAvailable").map(|s| *s).unwrap_or("0 kB")).to_string(),
                buffers: (stats.get(&"Buffers").map(|s| *s).unwrap_or("0 kB")).to_string(),
                cached: (stats.get(&"Cached").map(|s| *s).unwrap_or("0 kB")).to_string()
            };

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


<commit_before>use helpers;
use std::collections::HashMap;
use std::ops::Deref;
use std::fmt;

static MEMORY_FILE: &'static str = "/proc/meminfo";

pub struct MemoryInfo {
    mem_total: String,
    mem_free: String,
    mem_available: String,
    buffers: String,
    cached: String
}

impl fmt::Display for MemoryInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "mem_total: {}, mem_free: {}, mem_available: {}, buffers: {}, cached: {}",
               self.mem_total, self.mem_free, self.mem_available, self.buffers, self.cached)
    }
}

pub fn read_usage() -> Result<MemoryInfo, String> {
    let content = helpers::read_file_to_string(MEMORY_FILE);
    match content {
        Err(err) => Err(err),
        Ok(s) => {
            let lines: Vec<&str> = s.split('\n').collect();
            let mut stats: HashMap<&str, &str> = HashMap::new();
            for line in lines {
                let parts: Vec<&str> = line.split(':').map(|s| s.trim()).collect();
                let parts = parts.deref();
                if parts.len() >= 2 {
                    stats.insert(parts[0], parts[1]);
                }
            }

            let info = MemoryInfo {
                mem_total: (stats.get(&"MemTotal").map(|s| *s).unwrap_or("0 kB")).to_string(),
                mem_free: (stats.get(&"MemFree").map(|s| *s).unwrap_or("0 kB")).to_string(),
                mem_available: (stats.get(&"MemAvailable").map(|s| *s).unwrap_or("0 kB")).to_string(),
                buffers: (stats.get(&"Buffers").map(|s| *s).unwrap_or("0 kB")).to_string(),
                cached: (stats.get(&"Cached").map(|s| *s).unwrap_or("0 kB")).to_string()
            };

            Ok(info)
        }
    }
}
<commit_msg>Refactor<commit_after>use helpers;
use std::collections::HashMap;
use std::ops::Deref;
use std::fmt;

static MEMORY_FILE: &'static str = "/proc/meminfo";

pub struct MemoryInfo {
    mem_total: String,
    mem_free: String,
    mem_available: String,
    buffers: String,
    cached: String
}

impl fmt::Display for MemoryInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "mem_total: {}, mem_free: {}, mem_available: {}, buffers: {}, cached: {}",
               self.mem_total, self.mem_free, self.mem_available, self.buffers, self.cached)
    }
}

trait GetStr {
    fn get_str(&self, &str) -> Option<&str>;
}

impl<'a> GetStr for HashMap<&'a str, &'a str> {
    fn get_str(&self, key: &str) -> Option<&str> {
        self.get(&key).map(|s| *s)
    }
}

pub fn read_usage() -> Result<MemoryInfo, String> {
    let content = helpers::read_file_to_string(MEMORY_FILE);
    match content {
        Err(err) => Err(err),
        Ok(s) => {
            let lines: Vec<&str> = s.split('\n').collect();
            let mut stats: HashMap<&str, &str> = HashMap::new();
            for line in lines {
                let parts: Vec<&str> = line.split(':').map(|s| s.trim()).collect();
                let parts = parts.deref();
                if parts.len() >= 2 {
                    stats.insert(parts[0], parts[1]);
                }
            }

            let info = MemoryInfo {
                mem_total: (stats.get_str("MemTotal").unwrap_or("0 kB")).to_string(),
                mem_free: (stats.get_str("MemFree").unwrap_or("0 kB")).to_string(),
                mem_available: (stats.get_str("MemAvailable").unwrap_or("0 kB")).to_string(),
                buffers: (stats.get_str("Buffers").unwrap_or("0 kB")).to_string(),
                cached: (stats.get_str("Cached").unwrap_or("0 kB")).to_string()
            };

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