<commit_before>#![feature(box_syntax)]
#![feature(trace_macros)]
#![feature(inclusive_range_syntax)]
#![feature(log_syntax)]
#![allow(non_snake_case)]

#[cfg(test)] extern crate rand;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate router;
#[macro_use] extern crate log;
extern crate env_logger;
extern crate postgres;
extern crate r2d2;
extern crate r2d2_postgres;
extern crate hyper;
extern crate params;
extern crate iron;
extern crate cookie;
extern crate oven;
extern crate rustc_serialize;
extern crate dotenv;
extern crate chrono;

use iron::prelude::*;

#[macro_use]
mod proto;
mod db;
mod api;

fn main() {
    init_logging();

    let router = router! (
        signin:                   post   "/api/signin/"                  => api::authorization::signin,
        signup:                   post   "/api/signup/"                  => api::authorization::signup,

        city_get_cities:          get    "/api/city/"                    => api::city::get_cities,
        city_put_city:            put    "/api/city/"                    => api::city::put_city,

        account_get_all_bookings: get    "/api/account/bookings/"        => api::account::get_bookings,
        account_get_n_bookings:   get    "/api/account/bookings/:cnt"    => api::account::get_bookings,
        account_get_info:         get    "/api/account/"                 => api::account::get_account_info,
        account_update_info:      post   "/api/account/"                 => api::account::update_account_info,

        booking_get_booking:      get    "/api/booking/:id"              => api::booking::get_booking_by_id,
        booking_put_booking:      put    "/api/booking/"                 => api::booking::put_booking,

        hotel_get_all_hotels:     get    "/api/hotels/"                  => api::hotel::get_hotels,
        hotel_get_n_hotels:       get    "/api/hotels/:cnt"              => api::hotel::get_hotels,
        hotel_get_hotel_by_id:    get    "/api/hotel/:id"                => api::hotel::get_hotel,
        hotel_put_hotel:          put    "/api/hotel/"                   => api::hotel::put_hotel,
        hotel_update_hotel:       post   "/api/hotel/:id"                => api::hotel::update_hotel,
        hotel_get_all_rooms:      get    "/api/hotel/:id/rooms/"         => api::hotel::get_rooms,
        hotel_get_n_rooms:        get    "/api/hotel/:id/rooms/:cnt"     => api::hotel::get_rooms,
        hotel_get_room:           get    "/api/hotel/:id/room/:number"   => api::hotel::get_room,
        hotel_put_room:           put    "/api/hotel/:id/room/"          => api::hotel::put_room,
        hotel_update_room:        post   "/api/hotel/:id/room/:number"   => api::hotel::update_room,
        hotel_get_all_reviews:    get    "/api/hotel/:id/reviews/"       => api::hotel::get_reviews,
        hotel_get_n_reviews:      get    "/api/hotel/:id/reviews/:cnt"   => api::hotel::get_reviews,
        hotel_get_all_employees:  get    "/api/hotel/:id/employees/"     => api::hotel::get_employees,
        hotel_get_n_employees:    get    "/api/hotel/:id/employees/:cnt" => api::hotel::get_employees,
        hotel_del_employee:       delete "/api/hotel/:id/employee/:eid"  => api::hotel::fire_employee,

        manager_get_all_rulesets: get    "/api/manager/rulesets/"        => api::manager::get_rulesets,
        manager_get_ruleset:      get    "/api/manager/rulesets/:id"     => api::manager::get_ruleset,
        manager_put_ruleset:      put    "/api/manager/ruleset/"         => api::manager::put_ruleset,
        manager_update_ruleset:   post   "/api/manager/ruleset/:id"      => api::manager::update_ruleset,
        manager_delete_ruleset:   delete "/api/manager/ruleset/:id"      => api::manager::delete_ruleset,

        search:                   post   "/api/search/"                  => api::search::search

    );

    let mut chain = Chain::new(router);

    // TODO __CHANGE__ key and load it from non-gited file.
    chain.link(oven::new(Vec::from(&b"f8f9eaf1ecdedff5e5b749c58115441e"[..])));

    // Get db connection from pool (will block until pool is ready)
    db::get_db_connection();

    Iron::new(chain).http("localhost:8080").unwrap();
}

use std::env;
use log::LogLevelFilter;
use env_logger::LogBuilder;

fn init_logging() {
    let mut builder = LogBuilder::new();
    builder.filter(None, LogLevelFilter::Info);

    if env::var("RUST_LOG").is_ok() {
        builder.parse(&env::var("RUST_LOG").unwrap());
    }

    builder.init().unwrap();
}
<commit_msg>Listening on 0.0.0.0<commit_after>#![feature(box_syntax)]
#![feature(trace_macros)]
#![feature(inclusive_range_syntax)]
#![feature(log_syntax)]
#![allow(non_snake_case)]

#[cfg(test)] extern crate rand;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate router;
#[macro_use] extern crate log;
extern crate env_logger;
extern crate postgres;
extern crate r2d2;
extern crate r2d2_postgres;
extern crate hyper;
extern crate params;
extern crate iron;
extern crate cookie;
extern crate oven;
extern crate rustc_serialize;
extern crate dotenv;
extern crate chrono;

use iron::prelude::*;

#[macro_use]
mod proto;
mod db;
mod api;

fn main() {
    init_logging();

    let router = router! (
        signin:                   post   "/api/signin/"                  => api::authorization::signin,
        signup:                   post   "/api/signup/"                  => api::authorization::signup,

        city_get_cities:          get    "/api/city/"                    => api::city::get_cities,
        city_put_city:            put    "/api/city/"                    => api::city::put_city,

        account_get_all_bookings: get    "/api/account/bookings/"        => api::account::get_bookings,
        account_get_n_bookings:   get    "/api/account/bookings/:cnt"    => api::account::get_bookings,
        account_get_info:         get    "/api/account/"                 => api::account::get_account_info,
        account_update_info:      post   "/api/account/"                 => api::account::update_account_info,

        booking_get_booking:      get    "/api/booking/:id"              => api::booking::get_booking_by_id,
        booking_put_booking:      put    "/api/booking/"                 => api::booking::put_booking,

        hotel_get_all_hotels:     get    "/api/hotels/"                  => api::hotel::get_hotels,
        hotel_get_n_hotels:       get    "/api/hotels/:cnt"              => api::hotel::get_hotels,
        hotel_get_hotel_by_id:    get    "/api/hotel/:id"                => api::hotel::get_hotel,
        hotel_put_hotel:          put    "/api/hotel/"                   => api::hotel::put_hotel,
        hotel_update_hotel:       post   "/api/hotel/:id"                => api::hotel::update_hotel,
        hotel_get_all_rooms:      get    "/api/hotel/:id/rooms/"         => api::hotel::get_rooms,
        hotel_get_n_rooms:        get    "/api/hotel/:id/rooms/:cnt"     => api::hotel::get_rooms,
        hotel_get_room:           get    "/api/hotel/:id/room/:number"   => api::hotel::get_room,
        hotel_put_room:           put    "/api/hotel/:id/room/"          => api::hotel::put_room,
        hotel_update_room:        post   "/api/hotel/:id/room/:number"   => api::hotel::update_room,
        hotel_get_all_reviews:    get    "/api/hotel/:id/reviews/"       => api::hotel::get_reviews,
        hotel_get_n_reviews:      get    "/api/hotel/:id/reviews/:cnt"   => api::hotel::get_reviews,
        hotel_get_all_employees:  get    "/api/hotel/:id/employees/"     => api::hotel::get_employees,
        hotel_get_n_employees:    get    "/api/hotel/:id/employees/:cnt" => api::hotel::get_employees,
        hotel_del_employee:       delete "/api/hotel/:id/employee/:eid"  => api::hotel::fire_employee,

        manager_get_all_rulesets: get    "/api/manager/rulesets/"        => api::manager::get_rulesets,
        manager_get_ruleset:      get    "/api/manager/rulesets/:id"     => api::manager::get_ruleset,
        manager_put_ruleset:      put    "/api/manager/ruleset/"         => api::manager::put_ruleset,
        manager_update_ruleset:   post   "/api/manager/ruleset/:id"      => api::manager::update_ruleset,
        manager_delete_ruleset:   delete "/api/manager/ruleset/:id"      => api::manager::delete_ruleset,

        search:                   post   "/api/search/"                  => api::search::search

    );

    let mut chain = Chain::new(router);

    // TODO __CHANGE__ key and load it from non-gited file.
    chain.link(oven::new(Vec::from(&b"f8f9eaf1ecdedff5e5b749c58115441e"[..])));

    // Get db connection from pool (will block until pool is ready)
    db::get_db_connection();

    Iron::new(chain).http("0.0.0.0:8080").unwrap();
}

use std::env;
use log::LogLevelFilter;
use env_logger::LogBuilder;

fn init_logging() {
    let mut builder = LogBuilder::new();
    builder.filter(None, LogLevelFilter::Info);

    if env::var("RUST_LOG").is_ok() {
        builder.parse(&env::var("RUST_LOG").unwrap());
    }

    builder.init().unwrap();
}
<|endoftext|>


<commit_before>//#![cfg_attr(feature = "serde_derive", feature(proc_macro))]

//#[cfg(feature = "serde_derive")]
//#[macro_use]
//extern crate serde_derive;

extern crate env_logger;
extern crate futures;
extern crate tokio_core;
//extern crate serde;
//extern crate serde_json;

// TCP or UDP?
// Can we get non-persistent TCP connections which don't have buffer stalls?
// Or should we work on UDP to make sure we have control over whether or not
// messages are sent / received?

// Note on the copy(reader, writer) function, it's very simple.
// The function takes data given to reader and copies it over to writer, writing back
// whatever was written. The 'copy' might as well be called 'echo'.

// Also, in this case, when an incoming socket happens, we cannot handle the split
// without a future, since the connection will persist far longer than the 'for_each'
// iteration will, therefore it must be run asynchronously, to avoid only being able
// to handle one client at a time.

use std::net::SocketAddr;
use std::io::{Write, Read};
use std::str::{from_utf8};

use futures::Future;
use futures::stream::Stream;

use tokio_core::io::{copy, Io};
use tokio_core::net::{TcpListener, TcpStream};
use tokio_core::reactor::Core;

//use serde_json::*;

//mod server;
//mod client;
mod data;
mod xmpp;

use data::Data;

struct Writer;

impl Write for Writer {
    fn write(&mut self, buf : &[u8]) -> Result<usize, std::io::Error> {
        print!("Recieved : {}", from_utf8(buf).unwrap().to_string());
        //let msg = from_utf8(buf).unwrap().to_string();
        //let val : Data = serde_json::from_slice(&buf);
        Ok(buf.len())
    }
    fn flush(&mut self) -> Result<(), std::io::Error> {
        Ok(())
    }
}

// We're gonna read some JSON
fn main() {
    let addr = "127.0.0.1:8080".to_string().parse::<SocketAddr>().unwrap();
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let socket = TcpListener::bind(&addr, &handle).unwrap();

    let core_loop = socket.incoming().for_each(|(stream, addr)| {
        let message =
            futures::lazy(move || {
                Ok(stream.split())
            }).and_then(|(r, _w)| {
                copy(r, Writer)
            }).map(move |amt| {
                println!("Said hello to client {} at {}!", amt, addr);
            }).map_err(|e| {
                panic!("Error: {}", e);
            });

        handle.spawn(message);

        Ok(())
    });

    core.run(core_loop).unwrap();
}

<commit_msg>Just some formattin ' stuff<commit_after>#![feature(proc_macro, plugin, custom_attribute, custom_derive, plugin, test)]
#![plugin(serde_macros)]

// Imports:

// -- Parsing:
extern crate serde;
extern crate serde_xml;
#[macro_use]
extern crate serde_derive;

// -- Logs:
extern crate env_logger;

// -- Network:
extern crate futures;
extern crate tokio_core;

// TODO: mod xmpp -> Implement XmlStream struct.
// TODO: mod server, client? -> Implement logging ('log') for the XML stream.

// TCP or UDP?
// Can we get non-persistent TCP connections which don't have buffer stalls?
// Or should we work on UDP to make sure we have control over whether or not
// messages are sent / received?

// Note on the copy(reader, writer) function, it's very simple.
// The function takes data given to reader and copies it over to writer, writing back
// whatever was written. The 'copy' might as well be called 'echo'.

// Also, in this case, when an incoming socket happens, we cannot handle the split
// without a future, since the connection will persist far longer than the 'for_each'
// iteration will, therefore it must be run asynchronously, to avoid only being able
// to handle one client at a time.

use std::net::SocketAddr;
use std::io::{Write, Read};
use std::str::{from_utf8};

use futures::Future;
use futures::stream::Stream;

use tokio_core::io::{copy, Io};
use tokio_core::net::{TcpListener, TcpStream};
use tokio_core::reactor::Core;

//use serde_json::*;

mod server;
//mod client;
mod data;
mod xmpp;

use server::Writer;

// We're gonna read some JSON
fn main() {
    let addr = "127.0.0.1:8080".to_string().parse::<SocketAddr>().unwrap();
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let socket = TcpListener::bind(&addr, &handle).unwrap();

    let core_loop = socket.incoming().for_each(|(stream, addr)| {
        let message =
            futures::lazy(move || {
                Ok(stream.split())
            }).and_then(move |(r, _w)| {
                copy(r, Writer{ addr: addr.clone() }) // 'Connect' the streams.
            }).map(move |amt| {
                println!("Said hello to client {} at {}!", amt, addr);
            }).map_err(|e| {
                panic!("Error: {}", e);
            });

        handle.spawn(message);

        Ok(())
    });

    core.run(core_loop).unwrap();
}

<|endoftext|>


<commit_before>use cargo_tarpaulin::config::{Config, ConfigWrapper, OutputFile, RunType};
use cargo_tarpaulin::cargo::{rustdoc_flags, rust_flags};
use cargo_tarpaulin::run;
use clap::{crate_version, App, Arg, ArgSettings, SubCommand};
use env_logger::Builder;
use log::{info, trace};
use std::collections::HashMap;
use std::io::Write;
use std::path::Path;

fn print_env(seen_rustflags: HashMap<String, Vec<String>>, prefix: &str, default_val: &str) {
    info!("Printing `{}`", prefix);
    if seen_rustflags.is_empty() {
        info!("No configs provided printing default RUSTFLAGS");
        println!("{}={}", prefix, default_val);
    } else if seen_rustflags.len() == 1 {
        let flags = seen_rustflags.keys().next().unwrap();
        println!(r#"{}="{}""#, prefix, flags);
    } else {
        for (k, v) in seen_rustflags.iter() {
            info!("RUSTFLAGS for configs {:?}", v);
            println!(r#"{}="{}""#, prefix, k);
        }
    }
}

fn is_dir(d: String) -> Result<(), String> {
    if Path::new(&d).is_dir() {
        Ok(())
    } else {
        Err(String::from("root must be a directory"))
    }
}

fn set_up_logging(debug: bool, verbose: bool) {
    let mut builder = Builder::new();

    // NOTE: This overwrites RUST_LOG
    if debug {
        builder.filter_module("cargo_tarpaulin", log::LevelFilter::Trace);
    } else if verbose {
        builder.filter_module("cargo_tarpaulin", log::LevelFilter::Debug);
    } else {
        builder.filter_module("cargo_tarpaulin", log::LevelFilter::Info);
    }

    builder
        .format_timestamp(None)
        .format(|buf, record| {
            let level_style = buf.default_level_style(record.level());
            writeln!(
                buf,
                "[{} tarpaulin] {}",
                level_style.value(record.level()),
                record.args()
            )
        })
        .init();
}

const CI_SERVER_HELP: &str = "Name of service, supported services are:
travis-ci, travis-pro, circle-ci, semaphore, jenkins and codeship.
If you are interfacing with coveralls.io or another site you can \
also specify a name that they will recognise. Refer to their documentation for this.";

fn main() -> Result<(), String> {
    let args = App::new("cargo-tarpaulin")
        .author("Daniel McKenna, <danielmckenna93@gmail.com>")
        .about("Tool to analyse test coverage of cargo projects")
        .version(concat!("version: ", crate_version!()))
        .bin_name("cargo")
        .subcommand(SubCommand::with_name("tarpaulin")
            .about("Tool to analyse test coverage of cargo projects")
            .version(concat!("version: ", crate_version!()))
            .args_from_usage(
                 "--config [FILE] 'Path to a toml file specifying a list of options this will override any other options set'
                 --ignore-config 'Ignore any project config files'
                 --lib 'Test only this package's library unit tests'
                 --bin [NAME]... 'Test only the specified binary`
                 --bins 'Test all binaries'
                 --example [NAME]... 'Test only the specified example'
                 --examples 'Test all examples'
                 --test [NAME]... 'Test only the specified test target'
                 --tests 'Test all tests'
                 --bench [NAME]... 'Test only the specified bench target'
                 --benches 'Test all benches'
                 --doc 'Test only this library's documentation'
                 --all-targets 'Test all targets'
                 --no-fail-fast 'Run all tests regardless of failure'
                 --profile [NAME] 'Build artefacts with the specified profile'
                 --debug 'Show debug output - this is used for diagnosing issues with tarpaulin'
                 --dump-traces 'Log tracing events and save to a json file. Also, enabled when --debug is used'
                 --verbose -v 'Show extra output'
                 --ignore-tests 'Ignore lines of test functions when collecting coverage'
                 --ignore-panics 'Ignore panic macros in tests'
                 --count   'Counts the number of hits during coverage'
                 --ignored -i 'Run ignored tests as well'
                 --line -l    'Line coverage'
                 --force-clean 'Adds a clean stage to work around cargo bugs that may affect coverage results'
                 --fail-under [PERCENTAGE] 'Sets a percentage threshold for failure ranging from 0-100, if coverage is below exit with a non-zero code'
                 --branch -b  'Branch coverage: NOT IMPLEMENTED'
                 --forward -f 'Forwards unexpected signals to test. Tarpaulin will still take signals it is expecting.'
                 --coveralls [KEY]  'Coveralls key, either the repo token, or if you're using travis use $TRAVIS_JOB_ID and specify travis-{ci|pro} in --ciserver'
                 --report-uri [URI] 'URI to send report to, only used if the option --coveralls is used'
                 --no-default-features 'Do not include default features'
                 --features [FEATURES]... 'Features to be included in the target project'
                 --all-features 'Build all available features'
                 --all        'Alias for --workspace (deprecated)'
                 --workspace 'Test all packages in the workspace'
                 --packages -p [PACKAGE]... 'Package id specifications for which package should be build. See cargo help pkgid for more info'
                 --exclude -e [PACKAGE]... 'Package id specifications to exclude from coverage. See cargo help pkgid for more info'
                 --exclude-files [FILE]... 'Exclude given files from coverage results has * wildcard'
                 --timeout -t [SECONDS] 'Integer for the maximum time in seconds without response from test before timeout (default is 1 minute).'
                 --release   'Build in release mode.'
                 --no-run 'Compile tests but don't run coverage'
                 --locked 'Do not update Cargo.lock'
                 --frozen 'Do not update Cargo.lock or any caches'
                 --target [TRIPLE] 'Compilation target triple'
                 --target-dir [DIR] 'Directory for all generated artifacts'
                 --offline 'Run without accessing the network'
                 --print-rust-flags 'Print the RUSTFLAGS options that tarpaulin will compile your program with and exit'
                 --print-rustdoc-flags 'Print the RUSTDOCFLAGS options that tarpaulin will compile any doctests with and exit'
                 -Z [FEATURES]...   'List of unstable nightly only flags'")
            .args(&[
                Arg::from_usage("--out -o [FMT]   'Output format of coverage report'")
                    .possible_values(&OutputFile::variants())
                    .multiple(true),
                Arg::from_usage("--output-dir [PATH] 'Specify a custom directory to write report files'"),
                Arg::from_usage("--run-types [TYPE]... 'Type of the coverage run'")
                    .possible_values(&RunType::variants())
                    .multiple(true),
                Arg::from_usage("--root -r [DIR]  'Calculates relative paths to root directory. If --manifest-path isn't specified it will look for a Cargo.toml in root'")
                    .validator(is_dir),
                Arg::from_usage("--manifest-path [PATH] 'Path to Cargo.toml'"),
                Arg::from_usage("--ciserver [SERVICE] 'CI server being used, if unspecified tarpaulin may automatically infer for coveralls uploads'")
                    .help(CI_SERVER_HELP),
                Arg::with_name("args")
                    .set(ArgSettings::Last)
                    .multiple(true)
                    .help("Arguments to be passed to the test executables can be used to filter or skip certain tests")
            ]))
        .get_matches();

    let args = args.subcommand_matches("tarpaulin").unwrap_or(&args);

    set_up_logging(args.is_present("debug"), args.is_present("verbose"));
    let config = ConfigWrapper::from(args);
    let mut run_coverage = true;
    if args.is_present("print-rust-flags") {
        run_coverage = false;
        let mut seen_rustflags = HashMap::new();
        for config in &config.0 {
            let rustflags = rust_flags(config);
            seen_rustflags
                .entry(rustflags)
                .or_insert(vec![])
                .push(config.name.clone());
        }
        let default = Config::default();
        print_env(seen_rustflags, "RUSTFLAGS", &rust_flags(&default));
    }
    if args.is_present("print-rustdoc-flags") {
        run_coverage = false;
        let mut seen_rustflags = HashMap::new();
        for config in &config.0 {
            let rustflags = rustdoc_flags(config);
            seen_rustflags
                .entry(rustflags)
                .or_insert(vec![])
                .push(config.name.clone());
        }
        let default = Config::default();
        print_env(seen_rustflags, "RUSTDOCFLAGS", &rustdoc_flags(&default));
    }
    if run_coverage {
        trace!("Debug mode activated");
        // Since this is the last function we run and don't do any error mitigations (other than
        // printing the error to the user it's fine to unwrap here
        run(&config.0).map_err(|e| e.to_string())
    } else {
        Ok(())
    }
}
<commit_msg>Fix formatting<commit_after>use cargo_tarpaulin::cargo::{rust_flags, rustdoc_flags};
use cargo_tarpaulin::config::{Config, ConfigWrapper, OutputFile, RunType};
use cargo_tarpaulin::run;
use clap::{crate_version, App, Arg, ArgSettings, SubCommand};
use env_logger::Builder;
use log::{info, trace};
use std::collections::HashMap;
use std::io::Write;
use std::path::Path;

fn print_env(seen_rustflags: HashMap<String, Vec<String>>, prefix: &str, default_val: &str) {
    info!("Printing `{}`", prefix);
    if seen_rustflags.is_empty() {
        info!("No configs provided printing default RUSTFLAGS");
        println!("{}={}", prefix, default_val);
    } else if seen_rustflags.len() == 1 {
        let flags = seen_rustflags.keys().next().unwrap();
        println!(r#"{}="{}""#, prefix, flags);
    } else {
        for (k, v) in seen_rustflags.iter() {
            info!("RUSTFLAGS for configs {:?}", v);
            println!(r#"{}="{}""#, prefix, k);
        }
    }
}

fn is_dir(d: String) -> Result<(), String> {
    if Path::new(&d).is_dir() {
        Ok(())
    } else {
        Err(String::from("root must be a directory"))
    }
}

fn set_up_logging(debug: bool, verbose: bool) {
    let mut builder = Builder::new();

    // NOTE: This overwrites RUST_LOG
    if debug {
        builder.filter_module("cargo_tarpaulin", log::LevelFilter::Trace);
    } else if verbose {
        builder.filter_module("cargo_tarpaulin", log::LevelFilter::Debug);
    } else {
        builder.filter_module("cargo_tarpaulin", log::LevelFilter::Info);
    }

    builder
        .format_timestamp(None)
        .format(|buf, record| {
            let level_style = buf.default_level_style(record.level());
            writeln!(
                buf,
                "[{} tarpaulin] {}",
                level_style.value(record.level()),
                record.args()
            )
        })
        .init();
}

const CI_SERVER_HELP: &str = "Name of service, supported services are:
travis-ci, travis-pro, circle-ci, semaphore, jenkins and codeship.
If you are interfacing with coveralls.io or another site you can \
also specify a name that they will recognise. Refer to their documentation for this.";

fn main() -> Result<(), String> {
    let args = App::new("cargo-tarpaulin")
        .author("Daniel McKenna, <danielmckenna93@gmail.com>")
        .about("Tool to analyse test coverage of cargo projects")
        .version(concat!("version: ", crate_version!()))
        .bin_name("cargo")
        .subcommand(SubCommand::with_name("tarpaulin")
            .about("Tool to analyse test coverage of cargo projects")
            .version(concat!("version: ", crate_version!()))
            .args_from_usage(
                 "--config [FILE] 'Path to a toml file specifying a list of options this will override any other options set'
                 --ignore-config 'Ignore any project config files'
                 --lib 'Test only this package's library unit tests'
                 --bin [NAME]... 'Test only the specified binary`
                 --bins 'Test all binaries'
                 --example [NAME]... 'Test only the specified example'
                 --examples 'Test all examples'
                 --test [NAME]... 'Test only the specified test target'
                 --tests 'Test all tests'
                 --bench [NAME]... 'Test only the specified bench target'
                 --benches 'Test all benches'
                 --doc 'Test only this library's documentation'
                 --all-targets 'Test all targets'
                 --no-fail-fast 'Run all tests regardless of failure'
                 --profile [NAME] 'Build artefacts with the specified profile'
                 --debug 'Show debug output - this is used for diagnosing issues with tarpaulin'
                 --dump-traces 'Log tracing events and save to a json file. Also, enabled when --debug is used'
                 --verbose -v 'Show extra output'
                 --ignore-tests 'Ignore lines of test functions when collecting coverage'
                 --ignore-panics 'Ignore panic macros in tests'
                 --count   'Counts the number of hits during coverage'
                 --ignored -i 'Run ignored tests as well'
                 --line -l    'Line coverage'
                 --force-clean 'Adds a clean stage to work around cargo bugs that may affect coverage results'
                 --fail-under [PERCENTAGE] 'Sets a percentage threshold for failure ranging from 0-100, if coverage is below exit with a non-zero code'
                 --branch -b  'Branch coverage: NOT IMPLEMENTED'
                 --forward -f 'Forwards unexpected signals to test. Tarpaulin will still take signals it is expecting.'
                 --coveralls [KEY]  'Coveralls key, either the repo token, or if you're using travis use $TRAVIS_JOB_ID and specify travis-{ci|pro} in --ciserver'
                 --report-uri [URI] 'URI to send report to, only used if the option --coveralls is used'
                 --no-default-features 'Do not include default features'
                 --features [FEATURES]... 'Features to be included in the target project'
                 --all-features 'Build all available features'
                 --all        'Alias for --workspace (deprecated)'
                 --workspace 'Test all packages in the workspace'
                 --packages -p [PACKAGE]... 'Package id specifications for which package should be build. See cargo help pkgid for more info'
                 --exclude -e [PACKAGE]... 'Package id specifications to exclude from coverage. See cargo help pkgid for more info'
                 --exclude-files [FILE]... 'Exclude given files from coverage results has * wildcard'
                 --timeout -t [SECONDS] 'Integer for the maximum time in seconds without response from test before timeout (default is 1 minute).'
                 --release   'Build in release mode.'
                 --no-run 'Compile tests but don't run coverage'
                 --locked 'Do not update Cargo.lock'
                 --frozen 'Do not update Cargo.lock or any caches'
                 --target [TRIPLE] 'Compilation target triple'
                 --target-dir [DIR] 'Directory for all generated artifacts'
                 --offline 'Run without accessing the network'
                 --print-rust-flags 'Print the RUSTFLAGS options that tarpaulin will compile your program with and exit'
                 --print-rustdoc-flags 'Print the RUSTDOCFLAGS options that tarpaulin will compile any doctests with and exit'
                 -Z [FEATURES]...   'List of unstable nightly only flags'")
            .args(&[
                Arg::from_usage("--out -o [FMT]   'Output format of coverage report'")
                    .possible_values(&OutputFile::variants())
                    .multiple(true),
                Arg::from_usage("--output-dir [PATH] 'Specify a custom directory to write report files'"),
                Arg::from_usage("--run-types [TYPE]... 'Type of the coverage run'")
                    .possible_values(&RunType::variants())
                    .multiple(true),
                Arg::from_usage("--root -r [DIR]  'Calculates relative paths to root directory. If --manifest-path isn't specified it will look for a Cargo.toml in root'")
                    .validator(is_dir),
                Arg::from_usage("--manifest-path [PATH] 'Path to Cargo.toml'"),
                Arg::from_usage("--ciserver [SERVICE] 'CI server being used, if unspecified tarpaulin may automatically infer for coveralls uploads'")
                    .help(CI_SERVER_HELP),
                Arg::with_name("args")
                    .set(ArgSettings::Last)
                    .multiple(true)
                    .help("Arguments to be passed to the test executables can be used to filter or skip certain tests")
            ]))
        .get_matches();

    let args = args.subcommand_matches("tarpaulin").unwrap_or(&args);

    set_up_logging(args.is_present("debug"), args.is_present("verbose"));
    let config = ConfigWrapper::from(args);
    let mut run_coverage = true;
    if args.is_present("print-rust-flags") {
        run_coverage = false;
        let mut seen_rustflags = HashMap::new();
        for config in &config.0 {
            let rustflags = rust_flags(config);
            seen_rustflags
                .entry(rustflags)
                .or_insert(vec![])
                .push(config.name.clone());
        }
        let default = Config::default();
        print_env(seen_rustflags, "RUSTFLAGS", &rust_flags(&default));
    }
    if args.is_present("print-rustdoc-flags") {
        run_coverage = false;
        let mut seen_rustflags = HashMap::new();
        for config in &config.0 {
            let rustflags = rustdoc_flags(config);
            seen_rustflags
                .entry(rustflags)
                .or_insert(vec![])
                .push(config.name.clone());
        }
        let default = Config::default();
        print_env(seen_rustflags, "RUSTDOCFLAGS", &rustdoc_flags(&default));
    }
    if run_coverage {
        trace!("Debug mode activated");
        // Since this is the last function we run and don't do any error mitigations (other than
        // printing the error to the user it's fine to unwrap here
        run(&config.0).map_err(|e| e.to_string())
    } else {
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! A cargo subcommand for displaying line counts of source code in projects,
//! including a niave `unsafe` counter for Rust source files. This subcommand
//! was originally based off and inspired by the project
//! [tokei](https://github.com/aaronepower/tokei) by
//! [Aaronepower](https://github.com/aaronepower)
//!
//! ## Demo
//!
//! To count the source code in the [Rust](https://github.com/rust-lang/rust)
//! repository (checkout `4c99649`), and print some naive statistics on how much
//! "unsafe" code exists.
//!
//! **NOTE:** The Rust repository is quite large, if you're on a slow internet
//! connection consider using a smaller repository, such as the `cargo-count`
//! repo.
//!
//! ```ignore
//! $ git clone https://github.com/rust-lang/rust
//! $ cd rust
//! $ cargo count --separator , --unsafe-statistics
//! Gathering information...
//!          Language    Files  Lines    Blanks  Comments  Code     Unsafe (%)
//!          --------    -----  -----    ------  --------  ----     ----------
//! Rust        6,018  528,510  66,984  133,698   327,792  3,163
//! (0.96%)
//! C           54     9,962    1,445   1,492     7,025    7,025
//! (100.00%)
//!          CSS         4      1,266    149     52        1,065
//!          JavaScript  4      1,118    131     166       821
//!          Python      31     4,797    843     585       3,369
//! C Header    13     1,865    284     585       996      996
//! (100.00%)
//! C++         4      1,611    185     81        1,345    1,345
//! (100.00%)
//!          --------    -----  -----    ------  --------  ----     ----------
//! Totals:              6,128  549,129  70,021  136,659   342,413  12,529
//! (3.66%)
//!
//! ```
//!
//! The `--separator ,` sets a `,` character as the thousands separator, and
//! `--unsafe-statistics` looks for, and counts lines of `unsafe`.
//!
//! ## Compiling
//!
//! Follow these instructions to compile `cargo-count`, then skip down to
//! Installation.
//!
//!  1. Ensure you have current version of `cargo` and
//!     [Rust](https://www.rust-lang.org) installed
//!  2. Clone the project
//!     `$ git clone https://github.com/kbknapp/cargo-count && cd cargo-count`
//!  3. Build the project `$ cargo build --release` (**NOTE:** There is a large
//!     performance differnce when compiling without optimizations, so I
//!     recommend alwasy using `--release` to enable to them)
//!  4. Once complete, the binary will be located at
//!     `target/release/cargo-count`
//!
//! ## Installation and Usage
//!
//! All you need to do is place `cargo-count` somewhere in your `$PATH`. Then
//! run `cargo count` anywhere in your project directory. For full details see
//! below.
//!
//! ### Linux / OS X
//!
//! You have two options, place `cargo-count` into a directory that is already
//! located in your `$PATH` variable (To see which directories those are, open
//! a terminal and type `echo "${PATH//:/\n}"`, the quotation marks are
//! important), or you can add a custom directory to your `$PATH`
//!
//! **Option 1**
//! If you have write permission to a directory listed in your `$PATH` or you
//! have root permission (or via `sudo`), simply copy the `cargo-count` to that
//! directory `# sudo cp cargo-count /usr/local/bin`
//!
//! **Option 2**
//! If you do not have root, `sudo`, or write permission to any directory
//! already in `$PATH` you can create a directory inside your home directory,
//! and add that. Many people use `$HOME/.bin` to keep it hidden (and not
//! clutter your home directory), or `$HOME/bin` if you want it to be always
//! visible. Here is an example to make the directory, add it to `$PATH`, and
//! copy `cargo-count` there.
//!
//! Simply change `bin` to whatever you'd like to name the directory, and
//! `.bashrc` to whatever your shell startup file is (usually `.bashrc`,
//! `.bash_profile`, or `.zshrc`)
//!
//! ```sh
//! $ mkdir ~/bin
//! $ echo "export PATH=$PATH:$HOME/bin" >> ~/.bashrc
//! $ cp cargo-count ~/bin
//! $ source ~/.bashrc
//! ```
//!
//! ### Windows
//!
//! On Windows 7/8 you can add directory to the `PATH` variable by opening a
//! command line as an administrator and running
//!
//! ```sh
//! C:\> setx path "%path%;C:\path\to\cargo-count\binary"
//! ```
//!
//! Otherwise, ensure you have the `cargo-count` binary in the directory which
//! you operating in the command line from, because Windows automatically adds
//! your current directory to PATH (i.e. if you open a command line to
//! `C:\my_project\` to use `cargo-count` ensure `cargo-count.exe` is inside
//! that directory as well).
//!
//!
//! ### Options
//!
//! There are a few options for using `cargo-count` which should be somewhat
//! self explanitory.
//!
//! ```ignore
//! USAGE:
//!     cargo count [FLAGS] [OPTIONS] [--] [ARGS]
//!
//! FLAGS:
//! -S, --follow-symlinks      Follows symlinks and counts source files it
//! finds
//! -a, --all                  Do not ignore .gitignored paths
//!                                (Defaults to false when omitted)
//!     -h, --help                 Prints help information
//! --unsafe-statistics    Displays lines and percentages of "unsafe"
//! code
//!     -V, --version              Prints version information
//!     -v, --verbose              Print verbose output
//!
//! OPTIONS:
//! -l, --language <exts>...    Only count these languges (by source code
//! extension)
//!                                 (i.e. '-l js py cpp')
//! -e, --exclude <paths>...    Files or directories to exclude
//! (automatically includes '.git')
//! --utf8-rule <rule>      Sets the UTF-8 parsing rule (Defaults to
//! 'strict')
//!                                  [values: ignore lossy strict]
//! -s, --separator <sep>       Set the thousands separator for pretty
//! printing
//!
//! ARGS:
//!     to_count...    The files or directories (including children) to count
//!                    (defaults to current working directory when omitted)
//!
//! When using '--exclude <path>' the path given can either be relative to the
//! current
//! directory, or absolute. When '<path>' is a file, it must be relative to the
//! current
//! directory or it will not be found. Example, if the current directory has a
//! child
//! directory named 'target' with a child fild 'test.rs' and you use `--exclude
//! target/test.rs'
//!
//! Globs are also supported. For example, to eclude 'test.rs' files from all
//! child directories
//! of the current directory you could do '--exclude */test.rs'.
//! ```
//!
//! ## License
//!
//! `cargo-count` is released under the terms of the MIT. See the LICENSE-MIT
//! file for the details.
#![cfg_attr(feature = "nightly", feature(plugin))]
#![cfg_attr(feature = "lints", plugin(clippy))]
#![cfg_attr(feature = "lints", allow(explicit_iter_loop))]
#![cfg_attr(feature = "lints", allow(should_implement_trait))]
#![cfg_attr(feature = "lints", allow(unstable_features))]
#![cfg_attr(feature = "lints", deny(warnings))]
#![cfg_attr(not(any(feature = "nightly", feature = "unstable")), deny(unstable_features))]
#![deny(missing_docs,
        missing_debug_implementations,
        missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unused_import_braces,
        unused_qualifications)]

#[macro_use]
extern crate clap;
#[cfg(feature = "color")]
extern crate ansi_term;
extern crate tabwriter;
extern crate glob;
extern crate regex;
extern crate gitignore;

use std::io::Write;
#[cfg(feature = "debug")]
use std::env;

use clap::{App, AppSettings, Arg, SubCommand};

use config::Config;
use count::Counts;
use error::{CliError, CliResult};
use fmt::Format;

#[macro_use]
mod macros;
mod comment;
mod config;
mod count;
mod error;
mod fmt;
mod fsutil;
mod language;

static UTF8_RULES: [&'static str; 3] = ["strict", "lossy", "ignore"];

fn main() {
    debugln!("executing; cmd=cargo-count; args={:?}",
             env::args().collect::<Vec<_>>());
    let m = App::new("cargo-count")
        .version(&*format!("v{}", crate_version!()))
    // We have to lie about our binary name since this will be a third party
    // subcommand for cargo but we want usage strings to generated properly
        .bin_name("cargo")
    // Global version uses the version we supplied (Cargo.toml) for all subcommands
    // as well
        .settings(&[AppSettings::GlobalVersion,
                    AppSettings::SubcommandRequired])
    // We use a subcommand because everything parsed after `cargo` is sent to the
    // third party
    // plugin which will then be interpreted as a subcommand/positional arg by clap
        .subcommand(SubCommand::with_name("count")
            .author("Kevin K. <kbknapp@gmail.com>")
            .about("Displays line counts of code for cargo projects")
            .args_from_usage("-e, --exclude [paths]...    'Files or directories to exclude (automatically includes \'.git\')'
                              -a, --all                   'Do not ignore .gitignore'd paths'
                              --unsafe-statistics         'Displays lines and percentages of \"unsafe\" code'
                              -l, --language [exts]...    'Only count these languges (i.e. \'-l js py cpp\')'
                              -v, --verbose               'Print verbose output'
                              -S, --follow-symlinks       'Follows symlinks and counts source files it finds (Defaults to false when omitted)'
                              [to_count]...               'The files or directories (including children) to count{n}\
                                                           (defaults to current working directory when omitted)'")
            .arg(Arg::from_usage("-s, --separator [sep]   'Set the thousands separator for pretty printing'")
                .validator(single_char))
            .arg(Arg::from_usage("--utf8-rule [rule]     'Sets the UTF-8 parsing rule (Defaults to \'strict\'){n}'")
                .possible_values(&UTF8_RULES))
            .after_help("When using '--exclude <path>' the path given can either be relative to the current \n\
                         directory, or absolute. When '<path>' is a file, it must be relative to the current \n\
                         directory or it will not be found. Example, if the current directory has a child \n\
                         directory named 'target' with a child fild 'test.rs' and you use `--exclude target/test.rs' \n\
                         \n\
                         Globs are also supported. For example, to eclude 'test.rs' files from all child directories \n\
                         of the current directory you could do '--exclude */test.rs'."))
        .get_matches();

    if let Some(m) = m.subcommand_matches("count") {
        let cfg = Config::from_matches(m).unwrap_or_else(|e| e.exit());
        println!("Gathering information...");
        if let Err(e) = execute(cfg) {
            e.exit();
        }
    }
}

fn execute(cfg: Config) -> CliResult<()> {
    debugln!("executing; cmd=execute;");
    verboseln!(cfg, "{}: {:?}", Format::Warning("Excluding"), cfg.exclude);
    verbose!(cfg,
             "{}",
             if cfg.exts.is_some() {
                 format!("{} including files with extension: {}\n",
                         Format::Warning("Only"),
                         cfg.exts
                            .as_ref()
                            .unwrap()
                            .join(", "))
             } else {
                 "".to_owned()
             });

    debugln!("Checking for files or dirs to count from cli");

    let mut counts = Counts::new(&cfg);
    counts.fill_from();
    cli_try!(counts.count());
    cli_try!(counts.write_results());
    Ok(())
}

fn single_char(s: String) -> Result<(), String> {
    if s.len() == 1 {
        Ok(())
    } else {
        Err(
          format!(
            "the --separator argument option only accepts a single character but found '{}'",
             Format::Warning(s)))
    }
}
<commit_msg>style(main): remove unused std::io::Write import<commit_after>//! A cargo subcommand for displaying line counts of source code in projects,
//! including a niave `unsafe` counter for Rust source files. This subcommand
//! was originally based off and inspired by the project
//! [tokei](https://github.com/aaronepower/tokei) by
//! [Aaronepower](https://github.com/aaronepower)
//!
//! ## Demo
//!
//! To count the source code in the [Rust](https://github.com/rust-lang/rust)
//! repository (checkout `4c99649`), and print some naive statistics on how much
//! "unsafe" code exists.
//!
//! **NOTE:** The Rust repository is quite large, if you're on a slow internet
//! connection consider using a smaller repository, such as the `cargo-count`
//! repo.
//!
//! ```ignore
//! $ git clone https://github.com/rust-lang/rust
//! $ cd rust
//! $ cargo count --separator , --unsafe-statistics
//! Gathering information...
//!          Language    Files  Lines    Blanks  Comments  Code     Unsafe (%)
//!          --------    -----  -----    ------  --------  ----     ----------
//! Rust        6,018  528,510  66,984  133,698   327,792  3,163
//! (0.96%)
//! C           54     9,962    1,445   1,492     7,025    7,025
//! (100.00%)
//!          CSS         4      1,266    149     52        1,065
//!          JavaScript  4      1,118    131     166       821
//!          Python      31     4,797    843     585       3,369
//! C Header    13     1,865    284     585       996      996
//! (100.00%)
//! C++         4      1,611    185     81        1,345    1,345
//! (100.00%)
//!          --------    -----  -----    ------  --------  ----     ----------
//! Totals:              6,128  549,129  70,021  136,659   342,413  12,529
//! (3.66%)
//!
//! ```
//!
//! The `--separator ,` sets a `,` character as the thousands separator, and
//! `--unsafe-statistics` looks for, and counts lines of `unsafe`.
//!
//! ## Compiling
//!
//! Follow these instructions to compile `cargo-count`, then skip down to
//! Installation.
//!
//!  1. Ensure you have current version of `cargo` and
//!     [Rust](https://www.rust-lang.org) installed
//!  2. Clone the project
//!     `$ git clone https://github.com/kbknapp/cargo-count && cd cargo-count`
//!  3. Build the project `$ cargo build --release` (**NOTE:** There is a large
//!     performance differnce when compiling without optimizations, so I
//!     recommend alwasy using `--release` to enable to them)
//!  4. Once complete, the binary will be located at
//!     `target/release/cargo-count`
//!
//! ## Installation and Usage
//!
//! All you need to do is place `cargo-count` somewhere in your `$PATH`. Then
//! run `cargo count` anywhere in your project directory. For full details see
//! below.
//!
//! ### Linux / OS X
//!
//! You have two options, place `cargo-count` into a directory that is already
//! located in your `$PATH` variable (To see which directories those are, open
//! a terminal and type `echo "${PATH//:/\n}"`, the quotation marks are
//! important), or you can add a custom directory to your `$PATH`
//!
//! **Option 1**
//! If you have write permission to a directory listed in your `$PATH` or you
//! have root permission (or via `sudo`), simply copy the `cargo-count` to that
//! directory `# sudo cp cargo-count /usr/local/bin`
//!
//! **Option 2**
//! If you do not have root, `sudo`, or write permission to any directory
//! already in `$PATH` you can create a directory inside your home directory,
//! and add that. Many people use `$HOME/.bin` to keep it hidden (and not
//! clutter your home directory), or `$HOME/bin` if you want it to be always
//! visible. Here is an example to make the directory, add it to `$PATH`, and
//! copy `cargo-count` there.
//!
//! Simply change `bin` to whatever you'd like to name the directory, and
//! `.bashrc` to whatever your shell startup file is (usually `.bashrc`,
//! `.bash_profile`, or `.zshrc`)
//!
//! ```sh
//! $ mkdir ~/bin
//! $ echo "export PATH=$PATH:$HOME/bin" >> ~/.bashrc
//! $ cp cargo-count ~/bin
//! $ source ~/.bashrc
//! ```
//!
//! ### Windows
//!
//! On Windows 7/8 you can add directory to the `PATH` variable by opening a
//! command line as an administrator and running
//!
//! ```sh
//! C:\> setx path "%path%;C:\path\to\cargo-count\binary"
//! ```
//!
//! Otherwise, ensure you have the `cargo-count` binary in the directory which
//! you operating in the command line from, because Windows automatically adds
//! your current directory to PATH (i.e. if you open a command line to
//! `C:\my_project\` to use `cargo-count` ensure `cargo-count.exe` is inside
//! that directory as well).
//!
//!
//! ### Options
//!
//! There are a few options for using `cargo-count` which should be somewhat
//! self explanitory.
//!
//! ```ignore
//! USAGE:
//!     cargo count [FLAGS] [OPTIONS] [--] [ARGS]
//!
//! FLAGS:
//! -S, --follow-symlinks      Follows symlinks and counts source files it
//! finds
//! -a, --all                  Do not ignore .gitignored paths
//!                                (Defaults to false when omitted)
//!     -h, --help                 Prints help information
//! --unsafe-statistics    Displays lines and percentages of "unsafe"
//! code
//!     -V, --version              Prints version information
//!     -v, --verbose              Print verbose output
//!
//! OPTIONS:
//! -l, --language <exts>...    Only count these languges (by source code
//! extension)
//!                                 (i.e. '-l js py cpp')
//! -e, --exclude <paths>...    Files or directories to exclude
//! (automatically includes '.git')
//! --utf8-rule <rule>      Sets the UTF-8 parsing rule (Defaults to
//! 'strict')
//!                                  [values: ignore lossy strict]
//! -s, --separator <sep>       Set the thousands separator for pretty
//! printing
//!
//! ARGS:
//!     to_count...    The files or directories (including children) to count
//!                    (defaults to current working directory when omitted)
//!
//! When using '--exclude <path>' the path given can either be relative to the
//! current
//! directory, or absolute. When '<path>' is a file, it must be relative to the
//! current
//! directory or it will not be found. Example, if the current directory has a
//! child
//! directory named 'target' with a child fild 'test.rs' and you use `--exclude
//! target/test.rs'
//!
//! Globs are also supported. For example, to eclude 'test.rs' files from all
//! child directories
//! of the current directory you could do '--exclude */test.rs'.
//! ```
//!
//! ## License
//!
//! `cargo-count` is released under the terms of the MIT. See the LICENSE-MIT
//! file for the details.
#![cfg_attr(feature = "nightly", feature(plugin))]
#![cfg_attr(feature = "lints", plugin(clippy))]
#![cfg_attr(feature = "lints", allow(explicit_iter_loop))]
#![cfg_attr(feature = "lints", allow(should_implement_trait))]
#![cfg_attr(feature = "lints", allow(unstable_features))]
#![cfg_attr(feature = "lints", deny(warnings))]
#![cfg_attr(not(any(feature = "nightly", feature = "unstable")), deny(unstable_features))]
#![deny(missing_docs,
        missing_debug_implementations,
        missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unused_import_braces,
        unused_qualifications)]

#[macro_use]
extern crate clap;
#[cfg(feature = "color")]
extern crate ansi_term;
extern crate tabwriter;
extern crate glob;
extern crate regex;
extern crate gitignore;

#[cfg(feature = "debug")]
use std::env;

use clap::{App, AppSettings, Arg, SubCommand};

use config::Config;
use count::Counts;
use error::{CliError, CliResult};
use fmt::Format;

#[macro_use]
mod macros;
mod comment;
mod config;
mod count;
mod error;
mod fmt;
mod fsutil;
mod language;

static UTF8_RULES: [&'static str; 3] = ["strict", "lossy", "ignore"];

fn main() {
    debugln!("executing; cmd=cargo-count; args={:?}",
             env::args().collect::<Vec<_>>());
    let m = App::new("cargo-count")
        .version(&*format!("v{}", crate_version!()))
    // We have to lie about our binary name since this will be a third party
    // subcommand for cargo but we want usage strings to generated properly
        .bin_name("cargo")
    // Global version uses the version we supplied (Cargo.toml) for all subcommands
    // as well
        .settings(&[AppSettings::GlobalVersion,
                    AppSettings::SubcommandRequired])
    // We use a subcommand because everything parsed after `cargo` is sent to the
    // third party
    // plugin which will then be interpreted as a subcommand/positional arg by clap
        .subcommand(SubCommand::with_name("count")
            .author("Kevin K. <kbknapp@gmail.com>")
            .about("Displays line counts of code for cargo projects")
            .args_from_usage("-e, --exclude [paths]...    'Files or directories to exclude (automatically includes \'.git\')'
                              -a, --all                   'Do not ignore .gitignore'd paths'
                              --unsafe-statistics         'Displays lines and percentages of \"unsafe\" code'
                              -l, --language [exts]...    'Only count these languges (i.e. \'-l js py cpp\')'
                              -v, --verbose               'Print verbose output'
                              -S, --follow-symlinks       'Follows symlinks and counts source files it finds (Defaults to false when omitted)'
                              [to_count]...               'The files or directories (including children) to count{n}\
                                                           (defaults to current working directory when omitted)'")
            .arg(Arg::from_usage("-s, --separator [sep]   'Set the thousands separator for pretty printing'")
                .validator(single_char))
            .arg(Arg::from_usage("--utf8-rule [rule]     'Sets the UTF-8 parsing rule (Defaults to \'strict\'){n}'")
                .possible_values(&UTF8_RULES))
            .after_help("When using '--exclude <path>' the path given can either be relative to the current \n\
                         directory, or absolute. When '<path>' is a file, it must be relative to the current \n\
                         directory or it will not be found. Example, if the current directory has a child \n\
                         directory named 'target' with a child fild 'test.rs' and you use `--exclude target/test.rs' \n\
                         \n\
                         Globs are also supported. For example, to eclude 'test.rs' files from all child directories \n\
                         of the current directory you could do '--exclude */test.rs'."))
        .get_matches();

    if let Some(m) = m.subcommand_matches("count") {
        let cfg = Config::from_matches(m).unwrap_or_else(|e| e.exit());
        println!("Gathering information...");
        if let Err(e) = execute(cfg) {
            e.exit();
        }
    }
}

fn execute(cfg: Config) -> CliResult<()> {
    debugln!("executing; cmd=execute;");
    verboseln!(cfg, "{}: {:?}", Format::Warning("Excluding"), cfg.exclude);
    verbose!(cfg,
             "{}",
             if cfg.exts.is_some() {
                 format!("{} including files with extension: {}\n",
                         Format::Warning("Only"),
                         cfg.exts
                            .as_ref()
                            .unwrap()
                            .join(", "))
             } else {
                 "".to_owned()
             });

    debugln!("Checking for files or dirs to count from cli");

    let mut counts = Counts::new(&cfg);
    counts.fill_from();
    cli_try!(counts.count());
    cli_try!(counts.write_results());
    Ok(())
}

fn single_char(s: String) -> Result<(), String> {
    if s.len() == 1 {
        Ok(())
    } else {
        Err(
          format!(
            "the --separator argument option only accepts a single character but found '{}'",
             Format::Warning(s)))
    }
}
<|endoftext|>


<commit_before>extern crate xml;
extern crate rustc;

use std::os;

use std::io::{File, BufferedReader};
use std::fmt;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::thread::Thread;
use std::io::timer::sleep;
use std::time::duration::Duration;

use rustc::middle::graph::{Graph, NodeIndex, Node, EdgeIndex, Edge};

use xml::reader::EventReader;
use xml::reader::events::XmlEvent;

struct TaskMessage {
index: NodeIndex,
task: BuildTask
}

impl fmt::Show for TaskMessage {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "index={}, title={}", self .index, self .task.title)
}
}

struct ResultMessage {
index: NodeIndex
}

impl fmt::Show for ResultMessage {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "index={}", self .index)
}
}

fn main() {
	println!("XGConsole:");
	for arg in parse_command_line(os::args()).iter() {
		println!("  {}", arg);
	}

	let (tx_result, rx_result): (Sender<ResultMessage>, Receiver<ResultMessage>) = channel();
	let (tx_task, rx_task): (Sender<TaskMessage>, Receiver<TaskMessage>) = channel();

	let mutex_rx_task = Arc::new(Mutex::new(rx_task));
	for cpu_id in range(0, std::os::num_cpus()) {
		let local_rx_task = mutex_rx_task.clone();
		let local_tx_result = tx_result .clone();
				Thread::spawn(move || {
				loop {
					match local_rx_task.lock().recv_opt() {
							Ok(message) => {
							println!("{}: {}", cpu_id, message);
								sleep(Duration::milliseconds(100));
								local_tx_result.send(ResultMessage{
							index: message.index,
							});
						}
							Err(_) => {break;}
						}
				}
			}).detach();
	}

	let mut path = Path::new(&os::args()[0]).dir_path();
	path.push("../tests/graph-parser.xml");
	println!("Example path: {}", path.display());
	match xg_parse(&path) {
			Ok(graph) => {
				execute_graph(&graph, tx_task, rx_result);
		}
			Err(msg) =>{panic! (msg);}
		}

	println!("done");
}

fn validate_graph(graph: Graph<BuildTask, ()>) -> Result<Graph<BuildTask, ()>, String> {
	let mut completed:Vec<bool> = vec![];
	let mut queue:Vec<NodeIndex> = vec![];
		graph. each_node(|index: NodeIndex, node:&Node<BuildTask>|->bool {
			completed.push(false);
			queue.push(index);
			true
	});
	let mut count:uint = 0;
	let mut i:uint = 0;
	while i < queue.len() {
		let index = queue[i];
		if (!completed[index.node_id()]) && (is_ready(&graph, &completed, &index)) {
			completed[index.node_id()] = true;
				graph.each_incoming_edge(index, |_:EdgeIndex, edge:&Edge<()>| -> bool {
					queue.push(edge.source());
					true
			});
			count += 1;
			if count ==completed.len() {
				return Ok(graph);
			}
		}
		i = i + 1;
	}
	return Err("Found cycles in build dependencies.".to_string());
}

fn execute_graph(graph: &Graph<BuildTask, ()>, tx_task: Sender<TaskMessage>, rx_result: Receiver<ResultMessage>) {
	let mut completed:Vec<bool> = vec![];
		graph. each_node(|index: NodeIndex, node:&Node<BuildTask>|->bool {
		let mut has_edges = false;
			graph.each_outgoing_edge(index, |_:EdgeIndex, _:&Edge<()>| -> bool {
			has_edges = true;
			false
		});
		if !has_edges {
				tx_task.send(TaskMessage{
			index: index,
			task: node.data.clone(),
			})  ;
		}
			completed.push(false);
		true
	});
	let mut count:uint = 0;
	for message in rx_result.iter() {
		assert!(!completed[message.index.node_id()]);
		completed[message.index.node_id()] = true;
			graph.each_incoming_edge(message.index, |_:EdgeIndex, edge:&Edge<()>| -> bool {
			let source = edge.source();
			if !completed[source.node_id()] {
				if is_ready(graph, &completed, &source) {
						tx_task.send(TaskMessage{
					index: source,
					task: graph.node(source).data.clone(),
					})  ;
				}
			}
			true
		});
		println!("R: {}", message);
		count += 1;
		if count ==completed.len() {
			break;
		}
	}
}

fn is_ready(graph: &Graph<BuildTask, ()>, completed: &Vec<bool>, source: &NodeIndex) -> bool {
	let mut ready = true;
		graph.each_outgoing_edge(*source, |_:EdgeIndex, deps:&Edge<()>| -> bool {
		if !completed[deps.target().node_id()]{
			ready = false;
			false
		} else {
			true
		}
	});
	ready
}

fn parse_command_line(args: Vec<String>) -> Vec<String> {
	let mut result: Vec<String> = Vec::new();
	for arg in args.slice(1, args.len()).iter() {
			result.push(arg.clone());
	}
	result
}

struct BuildTask {
title: String,
exec: String,
args: Vec<String>,
working_dir: String,
}

impl Clone for BuildTask {
fn clone(& self) -> BuildTask {
	BuildTask {
	title: self.title.clone(),
	exec: self.exec.clone(),
	args: self.args.clone(),
	working_dir: self .working_dir.clone(),
	}
}
}

struct XgTask {
id: Option<String>,
title: Option<String>,
tool: String,
working_dir: String,
depends_on: Vec<String>,
}

impl fmt::Show for XgTask {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "id={}, title={}, tool={}, working_dir={}, depends_on={}", self .id, self .title, self .tool, self .working_dir, self .depends_on)
}
}

struct XgTool {
id: String,
exec: String,
args: String,
output: Option<String>,
}

impl fmt::Show for XgTool {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "id={}, exec={}", self .id, self .exec)
}
}

fn xg_parse(path: &Path) -> Result<Graph<BuildTask, ()>, String> {
	let file = File::open(path).unwrap();
	let reader = BufferedReader::new(file);

	let mut parser = EventReader::new(reader);
	let mut tasks:Vec<XgTask> = vec![];
	let mut tools:HashMap<String, XgTool> = HashMap::new();
	for e in parser.events() {
		match e {
				XmlEvent::StartElement {name, attributes, ..} => {
				match name.local_name.as_slice() {
						"Task" =>
						{
							match xg_parse_task(&attributes) {
									Ok(task) =>
									{
											tasks.push(task);
									}
									Err(msg) =>
									{
										panic!(msg);
									}
								};
						}
						"Tool" =>
						{
							match xg_parse_tool(&attributes) {
									Ok(tool) =>
									{
											tools.insert(tool.id.to_string(), tool);
									}
									Err(msg) =>
									{
										panic!(msg);
									}
								};
						}
						_ => {}
					}
			}
				XmlEvent::EndElement{..} => {
			}
				_ => {
			}
			}
	}
	xg_parse_create_graph(&tasks, &tools)
}

fn xg_parse_create_graph(tasks:&Vec<XgTask>, tools:&HashMap<String, XgTool>) -> Result<Graph<BuildTask, ()>, String> {
	let mut graph: Graph<BuildTask, ()> = Graph::new();
	let mut nodes: Vec<NodeIndex> = vec![];
	let mut task_refs: HashMap<&str, NodeIndex> = HashMap::new();
	for task in tasks.iter() {
		match tools.get(task.tool.as_slice()){
				Some(tool) => {
				let node = graph.add_node(BuildTask {
				title: match task.title {
						Some(ref v) => {v.clone()}
						_ => {
						match tool.output {
								Some(ref v) => {v.clone()}
								_ => "".to_string()
							}
					}
					},
				exec: tool.exec.clone(),
				args: cmd_parse(tool.args.as_slice()),
				working_dir : task.working_dir.clone(),
				});
				match task.id {
						Some(ref v) => {
							task_refs.insert(v.as_slice(), node);
					}
						_ => {}
					}
				nodes.push(node);
			}
				_ => {
				return Err(format!("Can't find tool with id: {}", task.tool));
			}
			}
	}
	for idx in range(0, nodes.len()) {
		let ref task = tasks[idx];
		let ref node = nodes[idx];
		for id in task.depends_on.iter() {
			let dep_node = task_refs.get(id.as_slice());
			match dep_node {
					Some(v) => {
						graph.add_edge(*node, *v, ());
				}
					_ => {
					return Err(format!("Can't find task for dependency with id: {}", id));
				}
				}
		}
	}
	validate_graph(graph)
}

fn map_attributes (attributes: &Vec<xml::attribute::OwnedAttribute>) -> HashMap< String, String> {
	let mut attrs: HashMap<String, String> = HashMap::new();
	for attr in attributes.iter() {
			attrs.insert(attr.name.local_name.clone(), attr.value.clone());
	}
	attrs
}

fn xg_parse_task (attributes: & Vec<xml::attribute::OwnedAttribute>)->Result<XgTask, String> {
	let mut attrs = map_attributes(attributes);
	// Tool
	let tool: String;
	match attrs.remove("Tool") {
			Some(v) => {tool = v;}
			_ => {return Err("Invalid task data: attribute @Tool not found.".to_string());}
		}
	// WorkingDir
	let working_dir: String;
	match attrs.remove("WorkingDir") {
			Some(v) => {working_dir = v;}
			_ => {return Err("Invalid task data: attribute @WorkingDir not found.".to_string());}
		}
	// DependsOn
	let mut depends_on : Vec<String> = vec![];
	match attrs.remove("DependsOn") {
			Some(v) =>
			{
				for item in v.split_str(";").collect::<Vec<&str>>().iter() {
						depends_on.push(item.to_string())
				}
			}
			_ =>
			{
			}
		};

		Ok(XgTask {
	id: attrs.remove("Name"),
	title: attrs.remove("Caption"),
	tool: tool,
	working_dir: working_dir,
	depends_on: depends_on,
	})
}

fn xg_parse_tool (attributes: &Vec<xml::attribute::OwnedAttribute>)->Result<XgTool, String> {
	let mut attrs = map_attributes(attributes);
	// Name
	let id: String;
	match attrs.remove("Name") {
			Some(v) => {id = v;}
			_ => {return Err("Invalid task data: attribute @Name not found.".to_string());}
		}
	// Path
	let exec: String;
	match attrs.remove("Path") {
			Some(v) => {exec = v;}
			_ => {return Err("Invalid task data: attribute @Name not found.".to_string());}
		}

	Ok(XgTool {
	id: id,
	exec: exec,
	output: attrs.remove("OutputPrefix"),
	args: match attrs.remove("Params") {
			Some(v) => {v}
			_ => {"".to_string()}
		},
	})
}

fn cmd_parse(cmd: &str) -> Vec<String> {
	let mut args: Vec<String> = vec![];
	let mut arg: String = "".to_string();
	let mut escape = false;
	let mut quote = false;
	let mut data = false;
	for c in cmd.chars() {
		match escape {
				true => {
				if data {
						arg.push(c);
						escape = false;
						data = false;
				}
			}
				false => {
				match c {
						' ' | '\t' => {
						if quote {
								arg.push(c);
								data = true;
						} else if data {
								args.push(arg);
								arg = "".to_string();
								data = false;
						}
					}
						'\\' => {
						escape = true;
						data = true;
					}
						'"' => {
						quote = !quote;
						data = true;
					}
						_ => {
							arg.push(c);
							data = true;
					}
					}
			}
			}
	}
	if data {
			args.push(arg);
	}
	return args;
}

#[test]
fn test_cmd_parse_1() {
	assert_eq!(cmd_parse("\"abc\" d e"), ["abc", "d", "e"]);
}

#[test]
fn test_cmd_parse_2() {
	assert_eq!(cmd_parse(" \"abc\" d e "), ["abc", "d", "e"]);
}

#[test]
fn test_cmd_parse_3() {
	assert_eq!(cmd_parse("\"\" \"abc\" d e \"\""), ["", "abc", "d", "e", ""]);
}

#[test]
fn test_cmd_parse_4() {
	assert_eq!(cmd_parse("a\\\\\\\\b d\"e f\"g h"), ["a\\\\b", "de fg", "h"]);
}

#[test]
fn test_cmd_parse_5() {
	assert_eq!(cmd_parse("a\\\\\\\"b c d"), ["a\\\"b", "c", "d"]);
}

#[test]
fn test_cmd_parse_6() {
	assert_eq!(cmd_parse("a\\\\\\\\\"b c\" d e"), ["a\\\\b c", "d", "e"]);
}
<commit_msg>Compilation worked.<commit_after>extern crate xml;
extern crate rustc;

use std::os;

use std::io::{Command, File, BufferedReader};
use std::fmt;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::thread::Thread;

use rustc::middle::graph::{Graph, NodeIndex, Node, EdgeIndex, Edge};

use xml::reader::EventReader;
use xml::reader::events::XmlEvent;

struct TaskMessage {
index: NodeIndex,
task: BuildTask
}

impl fmt::Show for TaskMessage {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "index={}, title={}", self .index, self .task.title)
}
}

struct ResultMessage {
index: NodeIndex
}

impl fmt::Show for ResultMessage {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "index={}", self .index)
}
}

fn main() {
	println!("XGConsole:");
	for arg in parse_command_line(os::args()).iter() {
		println!("  {}", arg);
	}

	let (tx_result, rx_result): (Sender<ResultMessage>, Receiver<ResultMessage>) = channel();
	let (tx_task, rx_task): (Sender<TaskMessage>, Receiver<TaskMessage>) = channel();

	let mutex_rx_task = Arc::new(Mutex::new(rx_task));
	for cpu_id in range(0, std::os::num_cpus()) {
		let local_rx_task = mutex_rx_task.clone();
		let local_tx_result = tx_result .clone();
				Thread::spawn(move || {
				loop {
					match local_rx_task.lock().recv_opt() {
							Ok(message) => {
							println!("{}: {}", cpu_id, message);
							local_tx_result.send(execute_task(message));
						}
							Err(_) => {break;}
						}
				}
			}).detach();
	}

	let args = os::args();
	let mut path;
	if args.len() <= 1 {
				path = Path::new(&args[0]).dir_path();
				path.push("../tests/graph-parser.xml");
	} else {
			path =Path::new(&args[1]);
	}
	println!("Example path: {}", path.display());
	match xg_parse(&path) {
			Ok(graph) => {
				execute_graph(&graph, tx_task, rx_result);
		}
			Err(msg) =>{panic! (msg);}
		}

	println!("done");
}

fn validate_graph(graph: Graph<BuildTask, ()>) -> Result<Graph<BuildTask, ()>, String> {
	let mut completed:Vec<bool> = vec![];
	let mut queue:Vec<NodeIndex> = vec![];
		graph. each_node(|index: NodeIndex, _:&Node<BuildTask>|->bool {
			completed.push(false);
			queue.push(index);
			true
	});
	let mut count:uint = 0;
	let mut i:uint = 0;
	while i < queue.len() {
		let index = queue[i];
		if (!completed[index.node_id()]) && (is_ready(&graph, &completed, &index)) {
			completed[index.node_id()] = true;
				graph.each_incoming_edge(index, |_:EdgeIndex, edge:&Edge<()>| -> bool {
					queue.push(edge.source());
					true
			});
			count += 1;
			if count ==completed.len() {
				return Ok(graph);
			}
		}
		i = i + 1;
	}
	return Err("Found cycles in build dependencies.".to_string());
}

fn execute_task(message: TaskMessage) -> ResultMessage {
	println!("{} {} {}", message.task.working_dir, message.task.exec, message.task.args);
	let output = match Command::new(message.task.exec)
	.args(message.task.args.as_slice())
	.cwd(&Path::new(&message.task.working_dir))
	.output(){
			Ok(output) => output,
			Err(e) => panic!("failed to execute process: {}", e),
		};
	println!("status: {}", output.status);
	ResultMessage {
	index: message.index,
	}
}

fn execute_graph(graph: &Graph<BuildTask, ()>, tx_task: Sender<TaskMessage>, rx_result: Receiver<ResultMessage>) {
	let mut completed:Vec<bool> = vec![];
		graph. each_node(|index: NodeIndex, node:&Node<BuildTask>|->bool {
		let mut has_edges = false;
			graph.each_outgoing_edge(index, |_:EdgeIndex, _:&Edge<()>| -> bool {
			has_edges = true;
			false
		});
		if !has_edges {
				tx_task.send(TaskMessage{
			index: index,
			task: node.data.clone(),
			})  ;
		}
			completed.push(false);
		true
	});
	let mut count:uint = 0;
	for message in rx_result.iter() {
		assert!(!completed[message.index.node_id()]);
		completed[message.index.node_id()] = true;
			graph.each_incoming_edge(message.index, |_:EdgeIndex, edge:&Edge<()>| -> bool {
			let source = edge.source();
			if !completed[source.node_id()] {
				if is_ready(graph, &completed, &source) {
						tx_task.send(TaskMessage{
					index: source,
					task: graph.node(source).data.clone(),
					})  ;
				}
			}
			true
		});
		println!("R: {}", message);
		count += 1;
		if count ==completed.len() {
			break;
		}
	}
}

fn is_ready(graph: &Graph<BuildTask, ()>, completed: &Vec<bool>, source: &NodeIndex) -> bool {
	let mut ready = true;
		graph.each_outgoing_edge(*source, |_:EdgeIndex, deps:&Edge<()>| -> bool {
		if !completed[deps.target().node_id()]{
			ready = false;
			false
		} else {
			true
		}
	});
	ready
}

fn parse_command_line(args: Vec<String>) -> Vec<String> {
	let mut result: Vec<String> = Vec::new();
	for arg in args.slice(1, args.len()).iter() {
			result.push(arg.clone());
	}
	result
}

struct BuildTask {
title: String,
exec: String,
args: Vec<String>,
working_dir: String,
}

impl Clone for BuildTask {
fn clone(& self) -> BuildTask {
	BuildTask {
	title: self.title.clone(),
	exec: self.exec.clone(),
	args: self.args.clone(),
	working_dir: self .working_dir.clone(),
	}
}
}

struct XgTask {
id: Option<String>,
title: Option<String>,
tool: String,
working_dir: String,
depends_on: Vec<String>,
}

impl fmt::Show for XgTask {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "id={}, title={}, tool={}, working_dir={}, depends_on={}", self .id, self .title, self .tool, self .working_dir, self .depends_on)
}
}

struct XgTool {
id: String,
exec: String,
args: String,
output: Option<String>,
}

impl fmt::Show for XgTool {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "id={}, exec={}", self .id, self .exec)
}
}

fn xg_parse(path: &Path) -> Result<Graph<BuildTask, ()>, String> {
	let file = File::open(path).unwrap();
	let reader = BufferedReader::new(file);

	let mut parser = EventReader::new(reader);
	let mut tasks:Vec<XgTask> = vec![];
	let mut tools:HashMap<String, XgTool> = HashMap::new();
	for e in parser.events() {
		match e {
				XmlEvent::StartElement {name, attributes, ..} => {
				match name.local_name.as_slice() {
						"Task" =>
						{
							match xg_parse_task(&attributes) {
									Ok(task) =>
									{
											tasks.push(task);
									}
									Err(msg) =>
									{
										panic!(msg);
									}
								};
						}
						"Tool" =>
						{
							match xg_parse_tool(&attributes) {
									Ok(tool) =>
									{
											tools.insert(tool.id.to_string(), tool);
									}
									Err(msg) =>
									{
										panic!(msg);
									}
								};
						}
						_ => {}
					}
			}
				XmlEvent::EndElement{..} => {
			}
				_ => {
			}
			}
	}
	xg_parse_create_graph(&tasks, &tools)
}

fn xg_parse_create_graph(tasks:&Vec<XgTask>, tools:&HashMap<String, XgTool>) -> Result<Graph<BuildTask, ()>, String> {
	let mut graph: Graph<BuildTask, ()> = Graph::new();
	let mut nodes: Vec<NodeIndex> = vec![];
	let mut task_refs: HashMap<&str, NodeIndex> = HashMap::new();
	for task in tasks.iter() {
		match tools.get(task.tool.as_slice()){
				Some(tool) => {
				let node = graph.add_node(BuildTask {
				title: match task.title {
						Some(ref v) => {v.clone()}
						_ => {
						match tool.output {
								Some(ref v) => {v.clone()}
								_ => "".to_string()
							}
					}
					},
				exec: tool.exec.clone(),
				args: cmd_parse(tool.args.as_slice()),
				working_dir : task.working_dir.clone(),
				});
				match task.id {
						Some(ref v) => {
							task_refs.insert(v.as_slice(), node);
					}
						_ => {}
					}
				nodes.push(node);
			}
				_ => {
				return Err(format!("Can't find tool with id: {}", task.tool));
			}
			}
	}
	for idx in range(0, nodes.len()) {
		let ref task = tasks[idx];
		let ref node = nodes[idx];
		for id in task.depends_on.iter() {
			let dep_node = task_refs.get(id.as_slice());
			match dep_node {
					Some(v) => {
						graph.add_edge(*node, *v, ());
				}
					_ => {
					return Err(format!("Can't find task for dependency with id: {}", id));
				}
				}
		}
	}
	validate_graph(graph)
}

fn map_attributes (attributes: &Vec<xml::attribute::OwnedAttribute>) -> HashMap< String, String> {
	let mut attrs: HashMap<String, String> = HashMap::new();
	for attr in attributes.iter() {
			attrs.insert(attr.name.local_name.clone(), attr.value.clone());
	}
	attrs
}

fn xg_parse_task (attributes: & Vec<xml::attribute::OwnedAttribute>)->Result<XgTask, String> {
	let mut attrs = map_attributes(attributes);
	// Tool
	let tool: String;
	match attrs.remove("Tool") {
			Some(v) => {tool = v;}
			_ => {return Err("Invalid task data: attribute @Tool not found.".to_string());}
		}
	// WorkingDir
	let working_dir: String;
	match attrs.remove("WorkingDir") {
			Some(v) => {working_dir = v;}
			_ => {return Err("Invalid task data: attribute @WorkingDir not found.".to_string());}
		}
	// DependsOn
	let mut depends_on : Vec<String> = vec![];
	match attrs.remove("DependsOn") {
			Some(v) =>
			{
				for item in v.split_str(";").collect::<Vec<&str>>().iter() {
						depends_on.push(item.to_string())
				}
			}
			_ =>
			{
			}
		};

		Ok(XgTask {
	id: attrs.remove("Name"),
	title: attrs.remove("Caption"),
	tool: tool,
	working_dir: working_dir,
	depends_on: depends_on,
	})
}

fn xg_parse_tool (attributes: &Vec<xml::attribute::OwnedAttribute>)->Result<XgTool, String> {
	let mut attrs = map_attributes(attributes);
	// Name
	let id: String;
	match attrs.remove("Name") {
			Some(v) => {id = v;}
			_ => {return Err("Invalid task data: attribute @Name not found.".to_string());}
		}
	// Path
	let exec: String;
	match attrs.remove("Path") {
			Some(v) => {exec = v;}
			_ => {return Err("Invalid task data: attribute @Name not found.".to_string());}
		}

	Ok(XgTool {
	id: id,
	exec: exec,
	output: attrs.remove("OutputPrefix"),
	args: match attrs.remove("Params") {
			Some(v) => {v}
			_ => {"".to_string()}
		},
	})
}

fn cmd_parse(cmd: &str) -> Vec<String> {
	let mut args: Vec<String> = vec![];
	let mut arg: String = "".to_string();
	let mut escape = false;
	let mut quote = false;
	let mut data = false;
	for c in cmd.chars() {
		match c {
				' ' | '\t' => {
				if escape {
						arg.push('\\');
						escape = false;
				}
				if quote {
						arg.push(c);
						data = true;
				} else if data {
						args.push(arg);
						arg = "".to_string();
						data = false;
				}
			}
				'\\' => {
				if escape {
						arg.push(c);
				}
				data = true;
				escape = !escape;
			}
				'"' => {
				if escape {
						arg.push(c);
						escape = false;
				} else {
					quote = !quote;
				}
				data = true;
			}
				_ => {
				if escape {
						arg.push('\\');
						escape = false;
				}
				arg.push(c);
				data = true;
			}
			}
	}
	if data {
			args.push(arg);
	}
	return args;
}

#[test]
fn test_cmd_parse_1() {
	assert_eq!(cmd_parse("\"abc\" d e"), ["abc", "d", "e"]);
}

#[test]
fn test_cmd_parse_2() {
	assert_eq!(cmd_parse(" \"abc\" d e "), ["abc", "d", "e"]);
}

#[test]
fn test_cmd_parse_3() {
	assert_eq!(cmd_parse("\"\" \"abc\" d e \"\""), ["", "abc", "d", "e", ""]);
}

#[test]
fn test_cmd_parse_4() {
	assert_eq!(cmd_parse("a\\\\\\\\b d\"e f\"g h"), ["a\\\\b", "de fg", "h"]);
}

#[test]
fn test_cmd_parse_5() {
	assert_eq!(cmd_parse("a\\\\\\\"b c d"), ["a\\\"b", "c", "d"]);
}

#[test]
fn test_cmd_parse_6() {
	assert_eq!(cmd_parse("a\\\\\\\\\"b c\" d e"), ["a\\\\b c", "d", "e"]);
}

#[test]
fn test_cmd_parse_7() {
	assert_eq!(cmd_parse("C:\\Windows\\System32 d e"), ["C:\\Windows\\System32", "d", "e"]);
}
<|endoftext|>


<commit_before>#![feature(collections, io, slice_patterns)]
use std::fs;
use std::io;
use std::io::{Read, Write};
use std::path::Path;

#[derive(Debug)]
enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

#[derive(Debug)]
enum Op {
    Add(u8),
    Mov(isize),
    In,
    Out,
    Loop(OpStream)
}

use Op::*;

#[derive(Debug)]
struct OpStream {
    ops: Vec<Op>
}

impl OpStream {
    fn add(&mut self, op: Op) {
        self.ops.push(op);
    }

    fn optimize(&mut self) {
        let mut i = 0;
        while i < self.ops.len() {
            match &self.ops[i..] {
                [Add(a), Add(b), ..] => {
                    self.ops[i] = Add(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Mov(a), Mov(b), ..] => {
                    self.ops[i] = Mov(a + b);
                    self.ops.remove(i + 1);
                }
                [Add(0), ..] | [Mov(0), ..] => {
                    self.ops.remove(i);
                }
                [Loop(_), ..] => {
                    if let &mut Loop(ref mut stream) = &mut self.ops[i] {
                        stream.optimize();
                    }
                    i += 1
                }
                _ => i += 1
            }
        }
    }

    fn get(&self) -> &[Op] {
        &self.ops[..]
    }

    fn new() -> OpStream {
        OpStream { ops: Vec::new() }
    }
}

struct State {
    index: usize,
    memory: Vec<u8>
}

impl State {
    fn new() -> State {
        State { index: 0, memory: vec![] }
    }

    fn peek(&self) -> u8 {
        if self.index >= self.memory.len() {
            0
        } else {
            self.memory[self.index]
        }
    }

    fn poke(&mut self, value: u8) {
        if self.index >= self.memory.len() {
            self.memory.resize(self.index * 2 + 1, 0);
        }
        self.memory[self.index] = value;
    }

    fn step(&mut self, op: &Op) -> bool {
        match op {
            &Add(i) => {
                // XXX: Ugly expression due to lexical scoping of borrow,
                //      cf. https://github.com/rust-lang/rust/issues/6393
                let x = self.peek();
                self.poke(x.wrapping_add(i));
            }
            &Mov(n) => {
                self.index = (self.index as isize + n) as usize;
            }
            &In => {
                let mut c = vec![0u8];
                if io::stdin().read(&mut c).unwrap() == 0 {
                    return false;
                }
                self.poke(c[0]);
            }
            &Out => {
                io::stdout().write(&vec![self.peek()]).unwrap();
            }
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    if !self.run(ops.get()) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    fn run(&mut self, ops: &[Op]) -> bool {
        for op in ops {
            if !self.step(op) {
                return false;
            }
        }
        return true;
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in &filenames[1..] {
        match reader(&Path::new(filename)) {
            Ok(reader) => {
                let mut chars = reader.chars().peekable();

                let mut opstream = OpStream::new();
                loop {
                    match parse(&mut chars) {
                        Something(op) => opstream.add(op),
                        EOF => break,
                        _ => {}
                    }
                }

                opstream.optimize();

                State::new().run(opstream.get());
            }
            Err(e) => {
                writeln!(&mut io::stderr(), "Error while processing {}: {}", filename, e).unwrap();
            }
        }
    }
}

fn parse<T: io::Read>(mut chars: &mut std::iter::Peekable<io::Chars<T>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(0x01)),
            '-' => Something(Add(0xff)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut childstream = OpStream::new();
                while match chars.peek() {
                    Some(&Ok(c)) => c != ']',
                    _ => false
                } {
                    match parse(&mut chars) {
                        Something(op) => childstream.add(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(childstream))
            },
            _ => Nothing  // other characters
        },
        _ => EOF  // XXX: really?
    }
}

fn reader(path: &Path) -> Result<io::BufReader<fs::File>, io::Error> {
    Ok(io::BufReader::new(try!(fs::File::open(path))))
}

#[cfg(test)]
mod tests {
    use std::io;
    use std::io::Read;
    use super::{parse, ParserResult, State, OpStream};
    use super::Op::*;

    macro_rules! assert_let(
        ($test:pat, $value:expr, $then:block) => (
            if let $test = $value {
                $then
            } else {
                panic!("{:?} doesn't match {}", $value, stringify!($test))
            }
        );
        ($test:pat, $value:expr) => (
            assert_let!($test, $value, {})
        );
    );

    #[test]
    fn test_state_peek() {
        let mut state = State { index: 0, memory: vec![23, 0, 0, 0, 0, 42] };
        assert_eq!(23, state.peek());
        state.index = 5;
        assert_eq!(42, state.peek());
    }

    #[test]
    fn test_state_poke() {
        let mut state = State::new();
        state.poke(23);
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state.poke(42);
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn test_state_step_add() {
        let mut state = State::new();
        state.step(&Add(23));
        assert_eq!(23, state.peek());
        state.step(&Add(42));
        assert_eq!(65, state.peek());
        state.step(&Add(190));
        assert_eq!(255, state.peek());
    }

    #[test]
    fn test_state_step_mov() {
        let mut state = State::new();
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn test_state_step_loop() {
        let mut state = State::new();
        state.poke(23);
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state.peek());
    }

    #[test]
    fn test_opstream_new_empty() {
        let opstream = OpStream::new();
        assert_eq!(0, opstream.ops.len());
    }

    #[test]
    fn test_opstream_optimize() {
        let mut opstream = OpStream::new();
        opstream.add(Mov(1));
        opstream.add(Mov(1));
        opstream.add(Add(0x01));
        opstream.add(Add(0xff));
        opstream.add(Add(0xff));
        opstream.add(Mov(1));
        opstream.add(Mov(-1));
        let mut opstream2 = OpStream::new();
        opstream2.add(Mov(2));
        opstream2.add(Mov(3));
        opstream.add(Loop(opstream2));
        opstream.optimize();

        assert_let!([Mov(2), Add(0xff), Loop(ref s2)], &opstream.ops[..], {
            assert_let!([Mov(5)], &s2.ops[..]);
        });
    }

    #[test]
    fn test_parse() {
        let input = b"+-[+.,]+";
        let mut chars = io::BufReader::new(&input[..]).chars().peekable();
        assert_let!(ParserResult::Something(Add(0x01)), parse(&mut chars));
        assert_let!(ParserResult::Something(Add(0xff)), parse(&mut chars));
        assert_let!(ParserResult::Something(Loop(loop_op)), parse(&mut chars), {
            assert_let!([Add(1), Out, In], &loop_op.ops[..]);
        });
        assert_let!(ParserResult::Something(Add(1)), parse(&mut chars));
    }
}
<commit_msg>refactor: implement Index(Mut) for State<commit_after>#![feature(collections, io, slice_patterns)]
use std::fs;
use std::io;
use std::io::{Read, Write};
use std::path::Path;

#[derive(Debug)]
enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

#[derive(Debug)]
enum Op {
    Add(u8),
    Mov(isize),
    In,
    Out,
    Loop(OpStream)
}

use Op::*;

#[derive(Debug)]
struct OpStream {
    ops: Vec<Op>
}

impl OpStream {
    fn add(&mut self, op: Op) {
        self.ops.push(op);
    }

    fn optimize(&mut self) {
        let mut i = 0;
        while i < self.ops.len() {
            match &self.ops[i..] {
                [Add(a), Add(b), ..] => {
                    self.ops[i] = Add(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Mov(a), Mov(b), ..] => {
                    self.ops[i] = Mov(a + b);
                    self.ops.remove(i + 1);
                }
                [Add(0), ..] | [Mov(0), ..] => {
                    self.ops.remove(i);
                }
                [Loop(_), ..] => {
                    if let &mut Loop(ref mut stream) = &mut self.ops[i] {
                        stream.optimize();
                    }
                    i += 1
                }
                _ => i += 1
            }
        }
    }

    fn get(&self) -> &[Op] {
        &self.ops[..]
    }

    fn new() -> OpStream {
        OpStream { ops: Vec::new() }
    }
}

static ZERO: u8 = 0;

struct State {
    index: usize,
    memory: Vec<u8>
}

impl State {
    fn new() -> State {
        State { index: 0, memory: vec![] }
    }

    fn rel_index(&self, relative: isize) -> usize {
        (self.index as isize + relative) as usize
    }

    fn step(&mut self, op: &Op) -> bool {
        match op {
            &Add(i) => {
                self[0] = self[0].wrapping_add(i);
            }
            &Mov(n) => {
                self.index = self.rel_index(n);
            }
            &In => {
                let mut c = vec![0u8];
                if io::stdin().read(&mut c).unwrap() == 0 {
                    return false;
                }
                self[0] = c[0];
            }
            &Out => {
                io::stdout().write(&vec![self[0]]).unwrap();
            }
            &Loop(ref ops) => {
                while self[0] != 0 {
                    if !self.run(ops.get()) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    fn run(&mut self, ops: &[Op]) -> bool {
        for op in ops {
            if !self.step(op) {
                return false;
            }
        }
        return true;
    }
}

impl std::ops::Index<isize> for State {
    type Output = u8;
    fn index(&self, _index: isize) -> &u8 {
        let idx = self.rel_index(_index);
        if idx >= self.memory.len() {
            &ZERO
        } else {
            &self.memory[idx]
        }
    }
}

impl std::ops::IndexMut<isize> for State {
    fn index_mut(&mut self, _index: isize) -> &mut u8 {
        let idx = self.rel_index(_index);
        if idx >= self.memory.len() {
            self.memory.resize(idx * 2 + 1, 0);
        }
        &mut self.memory[idx]
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in &filenames[1..] {
        match reader(&Path::new(filename)) {
            Ok(reader) => {
                let mut chars = reader.chars().peekable();

                let mut opstream = OpStream::new();
                loop {
                    match parse(&mut chars) {
                        Something(op) => opstream.add(op),
                        EOF => break,
                        _ => {}
                    }
                }

                opstream.optimize();

                State::new().run(opstream.get());
            }
            Err(e) => {
                writeln!(&mut io::stderr(), "Error while processing {}: {}", filename, e).unwrap();
            }
        }
    }
}

fn parse<T: io::Read>(mut chars: &mut std::iter::Peekable<io::Chars<T>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(0x01)),
            '-' => Something(Add(0xff)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut childstream = OpStream::new();
                while match chars.peek() {
                    Some(&Ok(c)) => c != ']',
                    _ => false
                } {
                    match parse(&mut chars) {
                        Something(op) => childstream.add(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(childstream))
            },
            _ => Nothing  // other characters
        },
        _ => EOF  // XXX: really?
    }
}

fn reader(path: &Path) -> Result<io::BufReader<fs::File>, io::Error> {
    Ok(io::BufReader::new(try!(fs::File::open(path))))
}

#[cfg(test)]
mod tests {
    use std::io;
    use std::io::Read;
    use super::{parse, ParserResult, State, OpStream};
    use super::Op::*;

    macro_rules! assert_let(
        ($test:pat, $value:expr, $then:block) => (
            if let $test = $value {
                $then
            } else {
                panic!("{:?} doesn't match {}", $value, stringify!($test))
            }
        );
        ($test:pat, $value:expr) => (
            assert_let!($test, $value, {})
        );
    );

    #[test]
    fn test_state_index() {
        let mut state = State { index: 0, memory: vec![23, 0, 0, 0, 0, 42] };
        assert_eq!(23, state[0]);
        state.index = 5;
        assert_eq!(42, state[0]);
    }

    #[test]
    fn test_state_index_mut() {
        let mut state = State::new();
        state[0] = 23;
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state[0] = 42;
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn test_state_step_add() {
        let mut state = State::new();
        state.step(&Add(23));
        assert_eq!(23, state[0]);
        state.step(&Add(42));
        assert_eq!(65, state[0]);
        state.step(&Add(190));
        assert_eq!(255, state[0]);
    }

    #[test]
    fn test_state_step_mov() {
        let mut state = State::new();
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn test_state_step_loop() {
        let mut state = State::new();
        state[0] = 23;
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state[0]);
    }

    #[test]
    fn test_opstream_new_empty() {
        let opstream = OpStream::new();
        assert_eq!(0, opstream.ops.len());
    }

    #[test]
    fn test_opstream_optimize() {
        let mut opstream = OpStream::new();
        opstream.add(Mov(1));
        opstream.add(Mov(1));
        opstream.add(Add(0x01));
        opstream.add(Add(0xff));
        opstream.add(Add(0xff));
        opstream.add(Mov(1));
        opstream.add(Mov(-1));
        let mut opstream2 = OpStream::new();
        opstream2.add(Mov(2));
        opstream2.add(Mov(3));
        opstream.add(Loop(opstream2));
        opstream.optimize();

        assert_let!([Mov(2), Add(0xff), Loop(ref s2)], &opstream.ops[..], {
            assert_let!([Mov(5)], &s2.ops[..]);
        });
    }

    #[test]
    fn test_parse() {
        let input = b"+-[+.,]+";
        let mut chars = io::BufReader::new(&input[..]).chars().peekable();
        assert_let!(ParserResult::Something(Add(0x01)), parse(&mut chars));
        assert_let!(ParserResult::Something(Add(0xff)), parse(&mut chars));
        assert_let!(ParserResult::Something(Loop(loop_op)), parse(&mut chars), {
            assert_let!([Add(1), Out, In], &loop_op.ops[..]);
        });
        assert_let!(ParserResult::Something(Add(1)), parse(&mut chars));
    }
}
<|endoftext|>