<commit_before>//! # mm_api_notify
#[cfg(test)]
extern crate mockito;

extern crate app_dirs;
#[macro_use]
extern crate bson;
extern crate chrono;
extern crate clap;
extern crate fern;
#[macro_use]
extern crate log;
extern crate mm_client;
extern crate mongodb;
extern crate rayon;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;

mod client;
mod config;
mod error;
mod hooks;
mod objects;
mod runtime;
mod storage;
mod types;

use app_dirs::{AppDataType, AppInfo, get_app_dir};
use clap::{Arg, App};
use chrono::{Duration, NaiveDateTime, UTC};
use serde_json::error::Result as JsonResult;
use serde_json::Value as Json;

use std::str::FromStr;
use std::{thread, time};

use client::{APIClient, ClientResult, MMClient};
use config::{DBConfig, APIConfig, parse_config};
use error::{IngestError, IngestResult};
use hooks::Payload;
use objects::{Collection, Importable};
use runtime::Runtime;
use storage::{MongoStore, Storage};
use types::{RunResult, StorageEngine, ThreadedAPI};

///
/// Starts processing
///
fn main() {

    let matches = App::new("Media Manager Notifier")
        .version(env!("CARGO_PKG_VERSION"))
        .arg(Arg::with_name("config")
            .short("c")
            .long("config")
            .takes_value(true)
            .help("Path to configuration file"))
        .arg(Arg::with_name("build")
            .short("b")
            .long("build")
            .takes_value(false)
            .help("Performs a full build run prior to entering the update loop"))
        .arg(Arg::with_name("skip-update")
            .short("k")
            .long("skip-update")
            .takes_value(false)
            .help("Prevents update loop from running"))
        .arg(Arg::with_name("start-time")
            .long("start-time")
            .short("t")
            .takes_value(true)
            .help("Defines the timestamp to start building or updating from"))
        .arg(Arg::with_name("log-level")
            .long("log-level")
            .short("l")
            .takes_value(true)
            .default_value("WARN")
            .help("Defines the log level to run at. Defaults to WARN"))
        .arg(Arg::with_name("query")
            .long("query")
            .short("q")
            .takes_value(true)
            .number_of_values(2)
            .value_names(&["type", "id"])
            .conflicts_with_all(&["build", "skip-update", "start-time"])
            .help("Queries the cache with a type and id pair and displays the payload that the \
                   runner will emit"))
        .get_matches();

    let config_path = if !matches.is_present("config") {
            let info = AppInfo {
                name: env!("CARGO_PKG_NAME"),
                author: env!("CARGO_PKG_AUTHORS"),
            };

            let path = get_app_dir(AppDataType::UserConfig, &info, "/")
                .and_then(|mut path| {
                    path.push("config.toml");
                    Ok(path)
                })
                .expect("Failed to run. Unable to determine path default config location.");

            path.to_str().map(|str| str.to_string())
        } else {
            matches.value_of("config").map(|str| str.to_string())
        }
        .expect("Failed to run. Unable to parse path to default config location.");

    let conf_res = parse_config(config_path.as_str())
        .ok_or(IngestError::InvalidConfig)
        .and_then(|config| {

            // Initialize logging
            if let &Some(ref log_location) = &config.log.location {

                let config_log_level_filter = match config.log.level {
                    Some(ref level) => log::LogLevelFilter::from_str(level.as_str()).ok(),
                    None => None,
                };

                let log_level = matches.value_of("log-level")
                    .and_then(|level| log::LogLevelFilter::from_str(level).ok())
                    .or(config_log_level_filter)
                    .unwrap_or(log::LogLevelFilter::Warn);

                fern::Dispatch::new()
                    .format(|out, message, record| {
                        out.finish(format_args!("[{}][{}] {}",
                                                UTC::now().format("%Y-%m-%d][%H:%M:%S"),
                                                record.level(),
                                                message))
                    })
                    .level(log_level)
                    .chain(std::io::stdout())
                    .chain(fern::log_file(log_location.as_str()).expect("Failed to open log file"))
                    .apply()
                    .expect("Failed to initialize logger");
            }

            // Initialize the thread pools
            rayon::initialize(rayon::Configuration::new().num_threads(config.thread_pool_size))
                .or_else(|err| {
                    panic!("Failed to initalize the configured thread pool size. Unable to \
                              start. {}",
                           err);
                })
                .and_then(|_| {
                    let store = get_store(&config.db);
                    let api = get_api_client(&config.mm);

                    let runtime = Runtime {
                        api: api,
                        config: config,
                        store: store,
                    };

                    if let Some(query) = matches.values_of("query") {
                        let query_args = query.collect::<Vec<&str>>();
                        match runtime.store.get(query_args[1], query_args[0]) {
                            Some(Ok(obj)) => {
                                match Payload::from_object(&obj, &runtime.store) {
                                    Some(payload) => {
                                        println!("{}",
                                                 serde_json::to_string_pretty(&payload).unwrap())
                                    }
                                    None => error!("Failed to generate payload from object."),
                                }
                            }
                            _ => println!("Could not find the requested object in the cache."),
                        };
                    } else {
                        let time_arg = matches.value_of("start-time").map_or(0, |arg| {
                            arg.parse::<i64>().expect("Could not parse start time")
                        });

                        let build_res = if matches.is_present("build") {
                            run_build(&runtime, time_arg).ok()
                        } else {
                            None
                        };

                        if !matches.is_present("skip-update") {

                            let now = UTC::now().timestamp();

                            let update_start_time = if time_arg <
                                                       (now -
                                                        runtime.config.mm.changelog_max_timespan) {
                                compute_update_start_time(runtime.store.updated_at(),
                                                          runtime.config.mm.changelog_max_timespan)
                            } else {
                                time_arg + build_res.map_or(0, |(dur, _)| dur.num_seconds())
                            };

                            run_update_loop(&runtime,
                                            update_start_time,
                                            runtime.config.min_runtime_delta)
                        };
                    }

                    Ok(())
                })
        });

    conf_res.expect("Failed to parse config.")
}

fn get_store(config: &DBConfig) -> MongoStore {
    MongoStore::new(Some(config)).expect("Failed to connect to storage")
}

fn get_api_client(config: &APIConfig) -> MMClient {
    MMClient::new(Some(config)).expect("Failed to initalize network client")
}

fn run_build<T: StorageEngine, S: ThreadedAPI>(runtime: &Runtime<T, S>,
                                               run_start_time: i64)
                                               -> IngestResult<RunResult> {

    info!("Starting build run from {} : {}",
          run_start_time,
          NaiveDateTime::from_timestamp(run_start_time, 0));

    let result = import_response(runtime.api.all_shows(), runtime, run_start_time);
    print_runtime("Create", &result);

    result
}

fn compute_update_start_time(last_updated_at: Option<i64>, max_timespan: i64) -> i64 {
    let newest_db_timestamp = last_updated_at.unwrap_or(0);
    let now = UTC::now().timestamp();

    if newest_db_timestamp < (now - max_timespan) {
        warn!("Newest database record exceeds the maximum threshold for updates. Performing \
                  update run with the maximum threshold. Consider performing a build (-b) run to \
                  fully update the database.");
        now - max_timespan
    } else {
        newest_db_timestamp
    }
}

fn run_update_loop<T: StorageEngine, S: ThreadedAPI>(runtime: &Runtime<T, S>,
                                                     run_start_time: i64,
                                                     delta: i64) {
    let mut import_start_time = run_start_time;
    let mut import_completion_time = UTC::now().timestamp();
    let mut next_run_time = run_start_time;
    let label = "Update";

    info!("Starting update loop from {} : {}",
          run_start_time,
          NaiveDateTime::from_timestamp(run_start_time, 0));

    loop {
        if UTC::now().timestamp() > next_run_time {

            next_run_time = UTC::now().timestamp() + delta;

            let run_time = run_update(runtime, import_start_time);

            print_runtime(label, &run_time);

            import_start_time = import_completion_time;
            import_completion_time = UTC::now().timestamp();

            let diff = next_run_time - import_completion_time;

            if diff > 0 {
                thread::sleep(time::Duration::from_secs(diff as u64));
            }
        }
    }
}

fn run_update<T: StorageEngine, S: ThreadedAPI>(runtime: &Runtime<T, S>,
                                                run_start_time: i64)
                                                -> IngestResult<RunResult> {

    let date_string = NaiveDateTime::from_timestamp(run_start_time, 0)
        .format("%Y-%m-%dT%H:%M:%S%.3fZ")
        .to_string();

    import_response(runtime.api.changes(date_string.as_str()),
                    runtime,
                    run_start_time)
}

fn import_response<T: StorageEngine, S: ThreadedAPI>(response: ClientResult<String>,
                                                     runtime: &Runtime<T, S>,
                                                     run_start_time: i64)
                                                     -> IngestResult<RunResult> {
    let start_time = UTC::now();

    let collection = match response {
        Ok(response_string) => {
            let full_json: JsonResult<Json> = serde_json::from_str(response_string.as_str());
            match full_json {
                Ok(json) => Collection::from_json(&json),
                Err(err) => Err(IngestError::Parse(err)),
            }
        }
        Err(err) => Err(IngestError::Client(err)),
    };

    collection.and_then(|coll| {
            let res = coll.import(runtime, true, run_start_time);
            Ok((UTC::now() - start_time, res))
        })
        .or(Ok((Duration::seconds(0), (0, 1))))
}

fn print_runtime(label: &str, run_time: &IngestResult<RunResult>) {
    match *run_time {
        Ok(ref results) => print_sucess(label, results),
        Err(ref err) => print_failure(label, err),
    }
}

fn print_sucess(label: &str, &(dur, (pass, fail)): &RunResult) {
    info!("{} run took {} seconds with {} successes and {} failures.",
          label,
          dur.num_seconds(),
          pass,
          fail)
}

fn print_failure(label: &str, error: &IngestError) {
    error!("{} run failed to run to completion. {}", label, error)
}
<commit_msg>Fix default log level<commit_after>//! # mm_api_notify
#[cfg(test)]
extern crate mockito;

extern crate app_dirs;
#[macro_use]
extern crate bson;
extern crate chrono;
extern crate clap;
extern crate fern;
#[macro_use]
extern crate log;
extern crate mm_client;
extern crate mongodb;
extern crate rayon;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;

mod client;
mod config;
mod error;
mod hooks;
mod objects;
mod runtime;
mod storage;
mod types;

use app_dirs::{AppDataType, AppInfo, get_app_dir};
use clap::{Arg, App};
use chrono::{Duration, NaiveDateTime, UTC};
use serde_json::error::Result as JsonResult;
use serde_json::Value as Json;

use std::str::FromStr;
use std::{thread, time};

use client::{APIClient, ClientResult, MMClient};
use config::{DBConfig, APIConfig, parse_config};
use error::{IngestError, IngestResult};
use hooks::Payload;
use objects::{Collection, Importable};
use runtime::Runtime;
use storage::{MongoStore, Storage};
use types::{RunResult, StorageEngine, ThreadedAPI};

///
/// Starts processing
///
fn main() {

    let matches = App::new("Media Manager Notifier")
        .version(env!("CARGO_PKG_VERSION"))
        .arg(Arg::with_name("config")
            .short("c")
            .long("config")
            .takes_value(true)
            .help("Path to configuration file"))
        .arg(Arg::with_name("build")
            .short("b")
            .long("build")
            .takes_value(false)
            .help("Performs a full build run prior to entering the update loop"))
        .arg(Arg::with_name("skip-update")
            .short("k")
            .long("skip-update")
            .takes_value(false)
            .help("Prevents update loop from running"))
        .arg(Arg::with_name("start-time")
            .long("start-time")
            .short("t")
            .takes_value(true)
            .help("Defines the timestamp to start building or updating from"))
        .arg(Arg::with_name("log-level")
            .long("log-level")
            .short("l")
            .takes_value(true)
            .help("Defines the log level to run at. Defaults to WARN"))
        .arg(Arg::with_name("query")
            .long("query")
            .short("q")
            .takes_value(true)
            .number_of_values(2)
            .value_names(&["type", "id"])
            .conflicts_with_all(&["build", "skip-update", "start-time"])
            .help("Queries the cache with a type and id pair and displays the payload that the \
                   runner will emit"))
        .get_matches();

    let config_path = if !matches.is_present("config") {
            let info = AppInfo {
                name: env!("CARGO_PKG_NAME"),
                author: env!("CARGO_PKG_AUTHORS"),
            };

            let path = get_app_dir(AppDataType::UserConfig, &info, "/")
                .and_then(|mut path| {
                    path.push("config.toml");
                    Ok(path)
                })
                .expect("Failed to run. Unable to determine path default config location.");

            path.to_str().map(|str| str.to_string())
        } else {
            matches.value_of("config").map(|str| str.to_string())
        }
        .expect("Failed to run. Unable to parse path to default config location.");

    let conf_res = parse_config(config_path.as_str())
        .ok_or(IngestError::InvalidConfig)
        .and_then(|config| {

            // Initialize logging
            if let &Some(ref log_location) = &config.log.location {

                let config_log_level_filter = match config.log.level {
                    Some(ref level) => log::LogLevelFilter::from_str(level.as_str()).ok(),
                    None => None,
                };

                let log_level = matches.value_of("log-level")
                    .and_then(|level| log::LogLevelFilter::from_str(level).ok())
                    .or(config_log_level_filter)
                    .unwrap_or(log::LogLevelFilter::Warn);

                fern::Dispatch::new()
                    .format(|out, message, record| {
                        out.finish(format_args!("[{}][{}] {}",
                                                UTC::now().format("%Y-%m-%d][%H:%M:%S"),
                                                record.level(),
                                                message))
                    })
                    .level(log_level)
                    .chain(std::io::stdout())
                    .chain(fern::log_file(log_location.as_str()).expect("Failed to open log file"))
                    .apply()
                    .expect("Failed to initialize logger");
            }

            // Initialize the thread pools
            rayon::initialize(rayon::Configuration::new().num_threads(config.thread_pool_size))
                .or_else(|err| {
                    panic!("Failed to initalize the configured thread pool size. Unable to \
                              start. {}",
                           err);
                })
                .and_then(|_| {
                    let store = get_store(&config.db);
                    let api = get_api_client(&config.mm);

                    let runtime = Runtime {
                        api: api,
                        config: config,
                        store: store,
                    };

                    if let Some(query) = matches.values_of("query") {
                        let query_args = query.collect::<Vec<&str>>();
                        match runtime.store.get(query_args[1], query_args[0]) {
                            Some(Ok(obj)) => {
                                match Payload::from_object(&obj, &runtime.store) {
                                    Some(payload) => {
                                        println!("{}",
                                                 serde_json::to_string_pretty(&payload).unwrap())
                                    }
                                    None => error!("Failed to generate payload from object."),
                                }
                            }
                            _ => println!("Could not find the requested object in the cache."),
                        };
                    } else {
                        let time_arg = matches.value_of("start-time").map_or(0, |arg| {
                            arg.parse::<i64>().expect("Could not parse start time")
                        });

                        let build_res = if matches.is_present("build") {
                            run_build(&runtime, time_arg).ok()
                        } else {
                            None
                        };

                        if !matches.is_present("skip-update") {

                            let now = UTC::now().timestamp();

                            let update_start_time = if time_arg <
                                                       (now -
                                                        runtime.config.mm.changelog_max_timespan) {
                                compute_update_start_time(runtime.store.updated_at(),
                                                          runtime.config.mm.changelog_max_timespan)
                            } else {
                                time_arg + build_res.map_or(0, |(dur, _)| dur.num_seconds())
                            };

                            run_update_loop(&runtime,
                                            update_start_time,
                                            runtime.config.min_runtime_delta)
                        };
                    }

                    Ok(())
                })
        });

    conf_res.expect("Failed to parse config.")
}

fn get_store(config: &DBConfig) -> MongoStore {
    MongoStore::new(Some(config)).expect("Failed to connect to storage")
}

fn get_api_client(config: &APIConfig) -> MMClient {
    MMClient::new(Some(config)).expect("Failed to initalize network client")
}

fn run_build<T: StorageEngine, S: ThreadedAPI>(runtime: &Runtime<T, S>,
                                               run_start_time: i64)
                                               -> IngestResult<RunResult> {

    info!("Starting build run from {} : {}",
          run_start_time,
          NaiveDateTime::from_timestamp(run_start_time, 0));

    let result = import_response(runtime.api.all_shows(), runtime, run_start_time);
    print_runtime("Create", &result);

    result
}

fn compute_update_start_time(last_updated_at: Option<i64>, max_timespan: i64) -> i64 {
    let newest_db_timestamp = last_updated_at.unwrap_or(0);
    let now = UTC::now().timestamp();

    if newest_db_timestamp < (now - max_timespan) {
        warn!("Newest database record exceeds the maximum threshold for updates. Performing \
                  update run with the maximum threshold. Consider performing a build (-b) run to \
                  fully update the database.");
        now - max_timespan
    } else {
        newest_db_timestamp
    }
}

fn run_update_loop<T: StorageEngine, S: ThreadedAPI>(runtime: &Runtime<T, S>,
                                                     run_start_time: i64,
                                                     delta: i64) {
    let mut import_start_time = run_start_time;
    let mut import_completion_time = UTC::now().timestamp();
    let mut next_run_time = run_start_time;
    let label = "Update";

    info!("Starting update loop from {} : {}",
          run_start_time,
          NaiveDateTime::from_timestamp(run_start_time, 0));

    loop {
        if UTC::now().timestamp() > next_run_time {

            next_run_time = UTC::now().timestamp() + delta;

            let run_time = run_update(runtime, import_start_time);

            print_runtime(label, &run_time);

            import_start_time = import_completion_time;
            import_completion_time = UTC::now().timestamp();

            let diff = next_run_time - import_completion_time;

            if diff > 0 {
                thread::sleep(time::Duration::from_secs(diff as u64));
            }
        }
    }
}

fn run_update<T: StorageEngine, S: ThreadedAPI>(runtime: &Runtime<T, S>,
                                                run_start_time: i64)
                                                -> IngestResult<RunResult> {

    let date_string = NaiveDateTime::from_timestamp(run_start_time, 0)
        .format("%Y-%m-%dT%H:%M:%S%.3fZ")
        .to_string();

    import_response(runtime.api.changes(date_string.as_str()),
                    runtime,
                    run_start_time)
}

fn import_response<T: StorageEngine, S: ThreadedAPI>(response: ClientResult<String>,
                                                     runtime: &Runtime<T, S>,
                                                     run_start_time: i64)
                                                     -> IngestResult<RunResult> {
    let start_time = UTC::now();

    let collection = match response {
        Ok(response_string) => {
            let full_json: JsonResult<Json> = serde_json::from_str(response_string.as_str());
            match full_json {
                Ok(json) => Collection::from_json(&json),
                Err(err) => Err(IngestError::Parse(err)),
            }
        }
        Err(err) => Err(IngestError::Client(err)),
    };

    collection.and_then(|coll| {
            let res = coll.import(runtime, true, run_start_time);
            Ok((UTC::now() - start_time, res))
        })
        .or(Ok((Duration::seconds(0), (0, 1))))
}

fn print_runtime(label: &str, run_time: &IngestResult<RunResult>) {
    match *run_time {
        Ok(ref results) => print_sucess(label, results),
        Err(ref err) => print_failure(label, err),
    }
}

fn print_sucess(label: &str, &(dur, (pass, fail)): &RunResult) {
    info!("{} run took {} seconds with {} successes and {} failures.",
          label,
          dur.num_seconds(),
          pass,
          fail)
}

fn print_failure(label: &str, error: &IngestError) {
    error!("{} run failed to run to completion. {}", label, error)
}
<|endoftext|>


<commit_before>extern crate ansi_term;
#[macro_use]
extern crate clap;
extern crate hyper;
extern crate libzou;
extern crate num_cpus;

use clap::{App, Arg};
use libzou::cargo_helper::get_remote_server_informations;
use libzou::download::download_chunks;
use libzou::filesize::StringFileType;
use libzou::protocol::{get_protocol, Protocol};
use libzou::util::prompt_user;
use libzou::write::OutputFileWriter;
#[macro_use]
mod logs;
use std::fs::{File, remove_file};
use std::path::Path;
use std::process::exit;

fn main() {

    // Parse arguments

    let argparse = App::new("Zou")
        .about("Zou, a simple and fast download accelerator, written in Rust.")
        .version(crate_version!())
        .arg(Arg::with_name("file")
                 .long("file")
                 .short("f")
                 .takes_value(true)
                 .help("The local file to save the remote content file"))
        .arg(Arg::with_name("threads")
                 .long("threads")
                 .short("t")
                 .takes_value(true)
                 .help("Threads which can use to download"))
        .arg(Arg::with_name("debug")
                 .long("debug")
                 .short("d")
                 .help("Active the debug mode"))
        .arg(Arg::with_name("force")
                 .long("force")
                 .help("Assume Yes to all queries and do not prompt"))
        .arg(Arg::with_name("mirrors")
                 .long("mirrors")
                 .short("m")
                 .multiple(true)
                 .takes_value(true)
                 .help("Download using a list of mirrors - the list of mirrors is used WITH the original URL"))
        .arg(Arg::with_name("ssl_support")
                .long("ssl_support")
                .short("s")
                .help("Switch to an SSL client"))
        .arg(Arg::with_name("url")
            .index(1)
            //.multiple(true)
            .required(true))
        .get_matches();

    // Get informations from arguments

    // Get the URL as a Path structure
    let url = Path::new(argparse.value_of("url").unwrap());
    let url_str = url.to_str().unwrap();

    // Get the path filename
    let filename = url.file_name().unwrap().to_str().unwrap();

    // Check if multi-threaded download is possible
    let mut threads: usize = value_t!(argparse, "threads", usize)
        .and_then(|v| if v != 0 {
            Ok(v)
        } else {
            Err(clap::Error::with_description(
                "Cannot download a file using 0 thread",
                clap::ErrorKind::InvalidValue,
            ))
        })
        .unwrap_or(num_cpus::get_physical());

    if argparse.is_present("debug") {
        info!(&format!("version: {}", crate_version!()));
        info!(&format!("file: {}", filename));
        info!(&format!("threads: {}", threads));
    }

    let local_path = Path::new(&filename);

    if local_path.exists() {
        if local_path.is_dir() {
            epanic!(
                "The local path to store the remote content is already exists, \
                        and is a directory!"
            );
        }
        if !argparse.is_present("force") {
            let user_input = prompt_user(
                "The path to store the file already exists! \
                                          Do you want to override it? [y/N]",
            );
            if !(user_input == "y" || user_input == "Y") {
                exit(0);
            }
        } else {
            warning!(
                "The path to store the file already exists! \
                                 It is going to be overriden."
            );
        }
    }

    // Get automaticaly the protocol from the given URL
    let ssl_support = match get_protocol(url.to_str().unwrap()) {
        Some(protocol) => match protocol {
            // If the protocol is HTTP, return the user decision for the HTTPS client
            Protocol::HTTP => argparse.is_present("ssl_support"),
            // Force to use HTTPS client
            Protocol::HTTPS => true,
        },
        None => epanic!("Unknown protocol!"),
    };

    // Get remote server informations in order to perform the best download strategy as possible
    let remote_server_informations = match get_remote_server_informations(url_str, ssl_support) {
        Ok(informations) => informations,
        Err(err) => panic!(err),
    };

    info!(
        &format!("Remote content length: {}", StringFileType::from(remote_server_informations.file.content_length))
    );

    let local_file = File::create(local_path).expect("[ERROR] Cannot create a file !");

    local_file.set_len(remote_server_informations.file.content_length).expect(
        "Cannot extend local file !",
    );
    let out_file = OutputFileWriter::new(local_file);

    // If the server does not accept PartialContent status, download the remote file
    // using only one thread
    if !remote_server_informations.accept_partialcontent {
        warning!(
            "The remote server does not accept PartialContent status! \
                             Downloading the remote file using one thread."
        );
        threads = 1;
    }

    if download_chunks(remote_server_informations, out_file, threads as u64, filename, ssl_support) {
        ok!(&format!(
            "Your download is available in {}",
            local_path.to_str().unwrap()
        ));
    } else {
        // If the file is not ok, delete it from the file system
        error!("Download failed! An error occured - erasing file... ");
        if remove_file(local_path).is_err() {
            error!("Cannot delete downloaded file!");
        }
    }

}
<commit_msg>Change the type<commit_after>extern crate ansi_term;
#[macro_use]
extern crate clap;
extern crate hyper;
extern crate libzou;
extern crate num_cpus;

use clap::{App, Arg};
use libzou::cargo_helper::get_remote_server_informations;
use libzou::download::download_chunks;
use libzou::filesize::StringFileSize;
use libzou::protocol::{get_protocol, Protocol};
use libzou::util::prompt_user;
use libzou::write::OutputFileWriter;
#[macro_use]
mod logs;
use std::fs::{File, remove_file};
use std::path::Path;
use std::process::exit;

fn main() {

    // Parse arguments

    let argparse = App::new("Zou")
        .about("Zou, a simple and fast download accelerator, written in Rust.")
        .version(crate_version!())
        .arg(Arg::with_name("file")
                 .long("file")
                 .short("f")
                 .takes_value(true)
                 .help("The local file to save the remote content file"))
        .arg(Arg::with_name("threads")
                 .long("threads")
                 .short("t")
                 .takes_value(true)
                 .help("Threads which can use to download"))
        .arg(Arg::with_name("debug")
                 .long("debug")
                 .short("d")
                 .help("Active the debug mode"))
        .arg(Arg::with_name("force")
                 .long("force")
                 .help("Assume Yes to all queries and do not prompt"))
        .arg(Arg::with_name("mirrors")
                 .long("mirrors")
                 .short("m")
                 .multiple(true)
                 .takes_value(true)
                 .help("Download using a list of mirrors - the list of mirrors is used WITH the original URL"))
        .arg(Arg::with_name("ssl_support")
                .long("ssl_support")
                .short("s")
                .help("Switch to an SSL client"))
        .arg(Arg::with_name("url")
            .index(1)
            //.multiple(true)
            .required(true))
        .get_matches();

    // Get informations from arguments

    // Get the URL as a Path structure
    let url = Path::new(argparse.value_of("url").unwrap());
    let url_str = url.to_str().unwrap();

    // Get the path filename
    let filename = url.file_name().unwrap().to_str().unwrap();

    // Check if multi-threaded download is possible
    let mut threads: usize = value_t!(argparse, "threads", usize)
        .and_then(|v| if v != 0 {
            Ok(v)
        } else {
            Err(clap::Error::with_description(
                "Cannot download a file using 0 thread",
                clap::ErrorKind::InvalidValue,
            ))
        })
        .unwrap_or(num_cpus::get_physical());

    if argparse.is_present("debug") {
        info!(&format!("version: {}", crate_version!()));
        info!(&format!("file: {}", filename));
        info!(&format!("threads: {}", threads));
    }

    let local_path = Path::new(&filename);

    if local_path.exists() {
        if local_path.is_dir() {
            epanic!(
                "The local path to store the remote content is already exists, \
                        and is a directory!"
            );
        }
        if !argparse.is_present("force") {
            let user_input = prompt_user(
                "The path to store the file already exists! \
                                          Do you want to override it? [y/N]",
            );
            if !(user_input == "y" || user_input == "Y") {
                exit(0);
            }
        } else {
            warning!(
                "The path to store the file already exists! \
                                 It is going to be overriden."
            );
        }
    }

    // Get automaticaly the protocol from the given URL
    let ssl_support = match get_protocol(url.to_str().unwrap()) {
        Some(protocol) => match protocol {
            // If the protocol is HTTP, return the user decision for the HTTPS client
            Protocol::HTTP => argparse.is_present("ssl_support"),
            // Force to use HTTPS client
            Protocol::HTTPS => true,
        },
        None => epanic!("Unknown protocol!"),
    };

    // Get remote server informations in order to perform the best download strategy as possible
    let remote_server_informations = match get_remote_server_informations(url_str, ssl_support) {
        Ok(informations) => informations,
        Err(err) => panic!(err),
    };

    info!(
        &format!("Remote content length: {}", StringFileSize::from(remote_server_informations.file.content_length))
    );

    let local_file = File::create(local_path).expect("[ERROR] Cannot create a file !");

    local_file.set_len(remote_server_informations.file.content_length).expect(
        "Cannot extend local file !",
    );
    let out_file = OutputFileWriter::new(local_file);

    // If the server does not accept PartialContent status, download the remote file
    // using only one thread
    if !remote_server_informations.accept_partialcontent {
        warning!(
            "The remote server does not accept PartialContent status! \
                             Downloading the remote file using one thread."
        );
        threads = 1;
    }

    if download_chunks(remote_server_informations, out_file, threads as u64, filename, ssl_support) {
        ok!(&format!(
            "Your download is available in {}",
            local_path.to_str().unwrap()
        ));
    } else {
        // If the file is not ok, delete it from the file system
        error!("Download failed! An error occured - erasing file... ");
        if remove_file(local_path).is_err() {
            error!("Cannot delete downloaded file!");
        }
    }

}
<|endoftext|>


<commit_before>extern crate rand;

use std::io::Read;
use std::fs::File;
use rand::Rng;

const DICT_FILE: &'static str = "/usr/share/dict/words";

fn main() {
    let mut dict = File::open(DICT_FILE).unwrap();
    // Not ideal, but whatever.
    let mut buf = String::new();
    dict.read_to_string(&mut buf);

    let mut lines: Vec<_> = buf
        .lines()
        .filter(|x| x.len() > 3 && x.len() < 7)
        .collect();
    rand::thread_rng().shuffle(&mut lines);
    for i in (0..4) {
        print!("{} ", lines[i]);
    }
}
<commit_msg>Print a newline after the words<commit_after>extern crate rand;

use std::io::Read;
use std::fs::File;
use rand::Rng;

const DICT_FILE: &'static str = "/usr/share/dict/words";

fn main() {
    let mut dict = File::open(DICT_FILE).unwrap();
    // Not ideal, but whatever.
    let mut buf = String::new();
    dict.read_to_string(&mut buf);

    let mut lines: Vec<_> = buf
        .lines()
        .filter(|x| x.len() > 3 && x.len() < 7)
        .collect();
    rand::thread_rng().shuffle(&mut lines);
    for i in (0..3) {
        print!("{} ", lines[i]);
    }
    println!("{}", lines[4]);
}
<|endoftext|>


<commit_before>extern crate git2;
extern crate clap;

use git2::*;
use std::env;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::process::exit;

const CENTRAL_NAME:    &'static str = "bsw/central";
const AUTOMATION_USER: &'static str = "automation";

// FIXME: hardcoded path
const TMP_REPO_DIR:    &'static str = "/home/christian/gerrit_testsite/tmp_automation_repo";

fn module_review_upload(project: &str, newrev: &str) -> Result<(),git2::Error> {

  let tmp_repo = try!(Repository::init_bare(TMP_REPO_DIR));
  let _ = in_tmp_repo("fetch --all");

  transfer_to_tmp(newrev);
  let parent_commit_obj = try!(tmp_repo.revparse_single(CENTRAL_NAME));
  let mut parent_commit_oid: git2::Oid = try!(parent_commit_obj
                                              .as_commit()
                                              .map(|x| x.id())
                                              .ok_or(git2::Error::from_str("could not get commit from obj")));

  let module_name: &str = try!(Path::new(project)
                               .components()
                               .last()
                               .map(|x| x.as_os_str().to_str().expect("not a valid unicode string"))
                               .ok_or(git2::Error::from_str("needs to be valid name")));
  let module_path = format!("remotes/modules/{}/master", module_name);
  let object = try!(tmp_repo.revparse_single(&module_path).map(|x| x.id()));
  let oldrev = format!("{}", object);

  {
    let old = try!(tmp_repo.revparse_single(&oldrev).map(|x| x.id()));
    let new = try!(tmp_repo.revparse_single(&newrev).map(|x| x.id()));

    if !try!(tmp_repo.graph_descendant_of(new,old)) {
      println!(".");
      println!("===========================================================");
      println!("======== Commit not based on master, rebase first! ========");
      println!("===========================================================");
      return Ok(());
    }
  }

  let walk = {
    let mut walk = try!(tmp_repo.revwalk());
    walk.set_sorting( Sort::from_bits(5).unwrap());
    let _ = walk.push_range(&format!("{}..{}", oldrev, newrev));
    walk
  };

  println!("===== project path: {}", project);
  println!("===== Apply commits from {} to {}", oldrev, newrev);

  for rev in walk {
    let newrev = format!("{}", try!(rev));
    if oldrev == newrev { continue; }
    println!("===== Apply commit {}", newrev);

    let module_commit_obj = try!(tmp_repo.revparse_single(&newrev));
    let module_commit = try!(module_commit_obj.as_commit()
                             .ok_or(git2::Error::from_str("object is not actually a commit")));
    let module_tree = try!(module_commit.tree());

    let parent_commit = try!(tmp_repo.find_commit(parent_commit_oid));

    let new_tree = {
      let master_tree: Tree = try!(parent_commit.tree());
      let new_tree_oid = module_to_subfolder(
        Path::new(module_name),
        &module_tree,
        &master_tree);
      try!(tmp_repo.find_tree(new_tree_oid))
    };

    parent_commit_oid = make_commit(&tmp_repo, &new_tree, module_commit, &vec!(&parent_commit)).unwrap();

  }

  println!(""); println!("");
  println!("===================== Doing actual upload in central git ========================");
  let x = push_from_tmp(
    &tmp_repo,
    &tmp_repo.find_commit(parent_commit_oid).unwrap(),
    CENTRAL_NAME,
    "refs/for/master"
    ).unwrap();
  println!("{}", x);
  println!("==== The review upload may have worked, even if it says error below. Look UP! ====");
  Ok(())
}

fn central_submit(newrev: &str) {
  println!("central_submit");

  let module_names = get_module_names(newrev);
  let tmp_repo = setup_tmp_repo(&module_names);
  transfer_to_tmp(newrev);

  let central_commit_obj = tmp_repo.revparse_single(newrev).unwrap();
  let central_commit = central_commit_obj.as_commit().unwrap();
  let central_tree = central_commit.tree().unwrap();
  let _ = tmp_repo.branch(CENTRAL_NAME,central_commit,true);

  for module_name in module_names {
    let module_master_commit_obj =
      tmp_repo.revparse_single(&format!("remotes/modules/{}/master",module_name)).unwrap();
    let module_master_commit =
      module_master_commit_obj.as_commit().unwrap();
    let _ = tmp_repo.branch(&format!("modules/{}",module_name),module_master_commit,true);

    let parents = vec!(module_master_commit);
    let old_tree_oid = module_master_commit.tree().unwrap().id();

    let module_path = { let mut p = PathBuf::new(); p.push("modules"); p.push(&module_name); p };

    let new_tree_oid = central_tree.get_path(&module_path).unwrap().id();

    if new_tree_oid != old_tree_oid {

      let new_tree = tmp_repo.find_tree(new_tree_oid).unwrap();

      let module_commit = make_commit(&tmp_repo, &new_tree, central_commit, &parents);
      let x = push_from_tmp(
        &tmp_repo,
        &tmp_repo.find_commit(module_commit.unwrap()).unwrap(),
        &format!("bsw/modules/{}",module_name),
        "master"
        ).unwrap();
      println!("{}", x);
    }
  }
}

fn transfer_to_tmp(rev: &str) {
  Command::new("git")
    .arg("branch").arg("-f").arg("tmp").arg(rev)
    .output().expect("failed to call git");

  Command::new("git")
    .arg("push").arg("--force").arg(TMP_REPO_DIR).arg("tmp")
    .output().expect("failed to call git");

  Command::new("git")
    .arg("branch").arg("-D").arg("tmp")
    .output().expect("failed to call git");
}

fn in_tmp_repo(cmd: &str) -> Result<String, std::io::Error> {
  let args: Vec<&str> = cmd.split(" ").collect();
  Command::new("git")
    .env("GIT_DIR",TMP_REPO_DIR)
    .args(&args).output().map(|output|
                              format!("{}", String::from_utf8_lossy(&output.stderr)))
}

fn setup_tmp_repo(modules: &Vec<String>) -> Repository {
  let repo = Repository::init_bare(TMP_REPO_DIR).unwrap();

  if !repo.find_remote("central_repo").is_ok() {
    let _ = repo.remote("central_repo",
                        &format!("ssh://{}@gerrit-test-git/{}.git",AUTOMATION_USER,CENTRAL_NAME)
                       );
  }

  for module in modules.iter() {
    let output = Command::new("ssh")
      .arg("-p").arg("29418")
      .arg("gerrit-test-git")
      .arg("gerrit")
      .arg("create-project")
      .arg(format!("bsw/modules/{}",module))
      .arg("--empty-commit")
      .output()
      .expect("failed to create project");

    println!("create-project: {}", String::from_utf8_lossy(&output.stderr));

    let remote_url = format!("ssh://{}@gerrit-test-git:29418/bsw/modules/{}.git",
                             AUTOMATION_USER,
                             module
                            );

    let remote_name = format!("modules/{}",module);
    if !repo.find_remote(&remote_name).is_ok() {
      let _ = repo.remote(&remote_name, &remote_url);
    }
  }

  let _ = in_tmp_repo("fetch --all");

  return repo;
}

fn module_to_subfolder(path: &Path, module_tree: &Tree, master_tree: &Tree) -> Oid {
  let mpath = Path::new("modules");
  let modules_oid = master_tree.get_path(mpath).unwrap().id();
  let tmp_repo = Repository::init_bare(TMP_REPO_DIR).unwrap();

  let modules_tree = tmp_repo.find_tree(modules_oid).unwrap();
  let mut mbuilder = tmp_repo.treebuilder(Some(&modules_tree)).unwrap();
  mbuilder.insert(path, module_tree.id(), 0o0040000).expect("mbuilder insert failed"); // GIT_FILEMODE_TREE
  let mtree = mbuilder.write().unwrap();

  let mut builder = tmp_repo.treebuilder(Some(master_tree)).unwrap();
  builder.insert(mpath, mtree, 0o0040000).expect("builder insert failed"); // GIT_FILEMODE_TREE
  let r = builder.write().unwrap();
  println!("module_to_subfolder {}", r);
  return r;
}

fn get_module_names(rev: &str) -> Vec<String> {
  let central_repo = Repository::open(".").unwrap();

  let object = central_repo.revparse_single(rev).unwrap();
  let commit = object.as_commit().unwrap();
  let tree = commit.tree().unwrap();

  let modules_o = tree.get_path(&Path::new("modules")).unwrap()
    .to_object(&central_repo).unwrap();
  let modules = modules_o.as_tree().unwrap();

  let mut names = Vec::<String>::new();
  for module in modules.iter() {
    names.push(module.name().unwrap().to_string());
  }
  return names;
}

fn push_from_tmp(tmp_repo: &Repository,
                 commit: &Commit,
                 repo: &str ,to: &str)
  -> Result<String, std::io::Error> {
    let _ = tmp_repo.set_head_detached(commit.id());
    in_tmp_repo(
      &format!("push ssh://{}@gerrit-test-git:29418/{}.git HEAD:{}",
               AUTOMATION_USER,
               repo,
               to
              )
      )
  }

fn make_commit(repo: &Repository, tree: &Tree, base: &Commit, parents: &[&Commit]) -> Option<Oid> {
  if parents.len() != 0 {
    let _ = repo.set_head_detached(parents[0].id());
  }
  repo.commit(
    Some("HEAD"),
    &base.author(),
    &base.committer(),
    &base.message().unwrap_or("no message"),
    tree,
    parents
    ).ok()
}

fn main() { exit(main_ret()); } fn main_ret() -> i32 {

  let args = clap::App::new("centralgithook")
    .arg(clap::Arg::with_name("oldrev").long("oldrev").takes_value(true))
    .arg(clap::Arg::with_name("newrev").long("newrev").takes_value(true))
    .arg(clap::Arg::with_name("project").long("project").takes_value(true))
    .arg(clap::Arg::with_name("refname").long("refname").takes_value(true))
    .arg(clap::Arg::with_name("uploader").long("uploader").takes_value(true))
    .arg(clap::Arg::with_name("commit").long("commit").takes_value(true))
    .arg(clap::Arg::with_name("change").long("change").takes_value(true))
    .arg(clap::Arg::with_name("change-url").long("change-url").takes_value(true))
    .arg(clap::Arg::with_name("change-owner").long("change-owner").takes_value(true))
    .arg(clap::Arg::with_name("branch").long("branch").takes_value(true))
    .arg(clap::Arg::with_name("submitter").long("submitter").takes_value(true))
    .arg(clap::Arg::with_name("topic").long("topic").takes_value(true))
    .get_matches();

  let newrev = args.value_of("newrev").unwrap_or("");
  let project = args.value_of("project").unwrap_or("");
  let refname = args.value_of("refname").unwrap_or("");
  let commit = args.value_of("commit").unwrap_or("");

  if let Some(hook) = env::args().nth(0) {
    let is_review = refname == "refs/for/master";
    let is_module = project != CENTRAL_NAME;
    let is_update = hook.ends_with("ref-update");
    let is_submit = hook.ends_with("change-merged");

    // // TODO
    // let uploader = args.value_of("uploader").unwrap_or("");
    // if !is_review && !uploader.contains("Automation") {
    //   println!("only push to refs/for/master");
    //   return 1;
    // }

    if is_submit { central_submit(commit); }
    else if !is_module && is_update && !is_review { central_submit(newrev); }
    else if is_module && is_update && is_review { let _ = module_review_upload(project,newrev); return 1; }
  }

  return 0;
}

<commit_msg>improve error handling<commit_after>extern crate git2;
extern crate clap;

use git2::*;
use std::env;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::process::exit;

const CENTRAL_NAME:    &'static str = "bsw/central";
const AUTOMATION_USER: &'static str = "automation";

// FIXME: hardcoded path
const TMP_REPO_DIR:    &'static str = "/home/christian/gerrit_testsite/tmp_automation_repo";

fn module_review_upload(project: &str, newrev: &str) -> Result<(),git2::Error> {

  let tmp_repo = try!(Repository::init_bare(TMP_REPO_DIR));
  let _ = in_tmp_repo("fetch --all");

  transfer_to_tmp(newrev);
  let parent_commit_obj = try!(tmp_repo.revparse_single(CENTRAL_NAME));
  let mut parent_commit_oid: git2::Oid = try!(parent_commit_obj
                                              .as_commit()
                                              .map(|x| x.id())
                                              .ok_or(git2::Error::from_str("could not get commit from obj")));

  let module_name: &str = try!(Path::new(project)
                               .components()
                               .last()
                               .map(|x| x.as_os_str().to_str().expect("not a valid unicode string"))
                               .ok_or(git2::Error::from_str("needs to be valid name")));
  let module_path = format!("remotes/modules/{}/master", module_name);
  let object = try!(tmp_repo.revparse_single(&module_path).map(|x| x.id()));
  let oldrev = format!("{}", object);

  {
    let old = try!(tmp_repo.revparse_single(&oldrev).map(|x| x.id()));
    let new = try!(tmp_repo.revparse_single(&newrev).map(|x| x.id()));

    if !try!(tmp_repo.graph_descendant_of(new,old)) {
      println!(".");
      println!("===========================================================");
      println!("======== Commit not based on master, rebase first! ========");
      println!("===========================================================");
      return Ok(());
    }
  }

  let walk = {
    let mut walk = try!(tmp_repo.revwalk());
    walk.set_sorting(git2::SORT_REVERSE | git2::SORT_TIME);
    try!(walk.push_range(&format!("{}..{}", oldrev, newrev)));
    walk
  };

  println!("===== project path: {}", project);
  println!("===== Apply commits from {} to {}", oldrev, newrev);

  for rev in walk {
    let newrev = format!("{}", try!(rev));
    if oldrev == newrev { continue; }
    println!("===== Apply commit {}", newrev);

    let module_commit_obj = try!(tmp_repo.revparse_single(&newrev));
    let module_commit = try!(module_commit_obj.as_commit()
                             .ok_or(git2::Error::from_str("object is not actually a commit")));
    let module_tree = try!(module_commit.tree());

    let parent_commit = try!(tmp_repo.find_commit(parent_commit_oid));

    let new_tree = {
      let master_tree: Tree = try!(parent_commit.tree());
      let new_tree_oid = try!(module_to_subfolder(
          Path::new(module_name),
          &module_tree,
          &master_tree));
      try!(tmp_repo.find_tree(new_tree_oid))
    };

    parent_commit_oid = try!(make_commit(&tmp_repo, &new_tree, module_commit, &vec!(&parent_commit)));

  }

  println!(""); println!("");
  println!("===================== Doing actual upload in central git ========================");
  let parent_commit = try!(tmp_repo.find_commit(parent_commit_oid));
  let x = try!(push_from_tmp(
      &tmp_repo,
      &parent_commit,
      CENTRAL_NAME,
      "refs/for/master"
      ));
  println!("{}", x);
  println!("==== The review upload may have worked, even if it says error below. Look UP! ====");
  Ok(())
}

fn central_submit(newrev: &str) {
  println!("central_submit");

  let module_names = get_module_names(newrev).unwrap();
  let tmp_repo = setup_tmp_repo(&module_names);
  transfer_to_tmp(newrev);

  let central_commit_obj = tmp_repo.revparse_single(newrev).unwrap();
  let central_commit = central_commit_obj.as_commit().unwrap();
  let central_tree = central_commit.tree().unwrap();
  let _ = tmp_repo.branch(CENTRAL_NAME,central_commit,true);

  for module_name in module_names {
    let module_master_commit_obj =
      tmp_repo.revparse_single(&format!("remotes/modules/{}/master",module_name)).unwrap();
    let module_master_commit =
      module_master_commit_obj.as_commit().unwrap();
    let _ = tmp_repo.branch(&format!("modules/{}",module_name),module_master_commit,true);

    let parents = vec!(module_master_commit);
    let old_tree_oid = module_master_commit.tree().unwrap().id();

    let module_path = { let mut p = PathBuf::new(); p.push("modules"); p.push(&module_name); p };

    let new_tree_oid = central_tree.get_path(&module_path).unwrap().id();

    if new_tree_oid != old_tree_oid {

      let new_tree = tmp_repo.find_tree(new_tree_oid).unwrap();

      let module_commit = make_commit(&tmp_repo, &new_tree, central_commit, &parents);
      let x = push_from_tmp(
        &tmp_repo,
        &tmp_repo.find_commit(module_commit.unwrap()).unwrap(),
        &format!("bsw/modules/{}",module_name),
        "master"
        ).unwrap();
      println!("{}", x);
    }
  }
}

fn transfer_to_tmp(rev: &str) {
  Command::new("git")
    .arg("branch").arg("-f").arg("tmp").arg(rev)
    .output().expect("failed to call git");

  Command::new("git")
    .arg("push").arg("--force").arg(TMP_REPO_DIR).arg("tmp")
    .output().expect("failed to call git");

  Command::new("git")
    .arg("branch").arg("-D").arg("tmp")
    .output().expect("failed to call git");
}

fn in_tmp_repo(cmd: &str) -> Result<String, git2::Error> {
  let args: Vec<&str> = cmd.split(" ").collect();
  match Command::new("git")
    .env("GIT_DIR",TMP_REPO_DIR)
    .args(&args).output().map(|output|
                              format!("{}", String::from_utf8_lossy(&output.stderr))) {
      Ok(value) => Ok(value),
      Err(_) => Err(git2::Error::from_str("could not fire git command")),
    }
}

fn setup_tmp_repo(modules: &Vec<String>) -> Repository {
  let repo = Repository::init_bare(TMP_REPO_DIR).unwrap();

  if !repo.find_remote("central_repo").is_ok() {
    let _ = repo.remote("central_repo",
                        &format!("ssh://{}@gerrit-test-git/{}.git",AUTOMATION_USER,CENTRAL_NAME)
                       );
  }

  for module in modules.iter() {
    let output = Command::new("ssh")
      .arg("-p").arg("29418")
      .arg("gerrit-test-git")
      .arg("gerrit")
      .arg("create-project")
      .arg(format!("bsw/modules/{}",module))
      .arg("--empty-commit")
      .output()
      .expect("failed to create project");

    println!("create-project: {}", String::from_utf8_lossy(&output.stderr));

    let remote_url = format!("ssh://{}@gerrit-test-git:29418/bsw/modules/{}.git",
                             AUTOMATION_USER,
                             module
                            );

    let remote_name = format!("modules/{}",module);
    if !repo.find_remote(&remote_name).is_ok() {
      let _ = repo.remote(&remote_name, &remote_url);
    }
  }

  let _ = in_tmp_repo("fetch --all");

  return repo;
}

fn module_to_subfolder(path: &Path, module_tree: &Tree, master_tree: &Tree) -> Result<Oid, git2::Error> {
  let mpath = Path::new("modules");
  let modules_oid = try!(master_tree.get_path(mpath).map(|x| x.id()));
  let tmp_repo = try!(Repository::init_bare(TMP_REPO_DIR));

  let modules_tree = try!(tmp_repo.find_tree(modules_oid));
  let mut mbuilder = try!(tmp_repo.treebuilder(Some(&modules_tree)));
  mbuilder.insert(path, module_tree.id(), 0o0040000).expect("mbuilder insert failed"); // GIT_FILEMODE_TREE
  let mtree = try!(mbuilder.write());

  let mut builder = try!(tmp_repo.treebuilder(Some(master_tree)));
  builder.insert(mpath, mtree, 0o0040000).expect("builder insert failed"); // GIT_FILEMODE_TREE
  let r = try!(builder.write());
  println!("module_to_subfolder {}", r);
  Ok(r)
}

fn get_module_names(rev: &str) -> Result<Vec<String>, git2::Error> {
  let central_repo = try!(Repository::open("."));

  let object = try!(central_repo.revparse_single(rev));
  let commit = try!(object
                    .as_commit()
                    .ok_or(git2::Error::from_str("could not get commit from obj")));
  let tree: git2::Tree = try!(commit.tree());

  let modules_o = try!(tree.get_path(&Path::new("modules")).unwrap()
                   .to_object(&central_repo));
  let modules = try!(modules_o.as_tree()
                    .ok_or(git2::Error::from_str("could not get tree from path")));

  let mut names = Vec::<String>::new();
  for module in modules.iter() {
    names.push(module.name().unwrap().to_string());
  }
  Ok(names)
}

fn push_from_tmp(tmp_repo: &Repository,
                 commit: &Commit,
                 repo: &str ,to: &str)
  -> Result<String, git2::Error> {
    let _ = tmp_repo.set_head_detached(commit.id());
    in_tmp_repo(
      &format!("push ssh://{}@gerrit-test-git:29418/{}.git HEAD:{}",
               AUTOMATION_USER,
               repo,
               to
              )
      )
  }

fn make_commit(repo: &Repository, tree: &Tree, base: &Commit, parents: &[&Commit]) -> Result<Oid, git2::Error> {
  if parents.len() != 0 {
    let _ = repo.set_head_detached(parents[0].id());
  }
  repo.commit(
    Some("HEAD"),
    &base.author(),
    &base.committer(),
    &base.message().unwrap_or("no message"),
    tree,
    parents
    )
}

fn main() { exit(main_ret()); } fn main_ret() -> i32 {

  let args = clap::App::new("centralgithook")
    .arg(clap::Arg::with_name("oldrev").long("oldrev").takes_value(true))
    .arg(clap::Arg::with_name("newrev").long("newrev").takes_value(true))
    .arg(clap::Arg::with_name("project").long("project").takes_value(true))
    .arg(clap::Arg::with_name("refname").long("refname").takes_value(true))
    .arg(clap::Arg::with_name("uploader").long("uploader").takes_value(true))
    .arg(clap::Arg::with_name("commit").long("commit").takes_value(true))
    .arg(clap::Arg::with_name("change").long("change").takes_value(true))
    .arg(clap::Arg::with_name("change-url").long("change-url").takes_value(true))
    .arg(clap::Arg::with_name("change-owner").long("change-owner").takes_value(true))
    .arg(clap::Arg::with_name("branch").long("branch").takes_value(true))
    .arg(clap::Arg::with_name("submitter").long("submitter").takes_value(true))
    .arg(clap::Arg::with_name("topic").long("topic").takes_value(true))
    .get_matches();

  let newrev = args.value_of("newrev").unwrap_or("");
  let project = args.value_of("project").unwrap_or("");
  let refname = args.value_of("refname").unwrap_or("");
  let commit = args.value_of("commit").unwrap_or("");

  if let Some(hook) = env::args().nth(0) {
    let is_review = refname == "refs/for/master";
    let is_module = project != CENTRAL_NAME;
    let is_update = hook.ends_with("ref-update");
    let is_submit = hook.ends_with("change-merged");

    // // TODO
    // let uploader = args.value_of("uploader").unwrap_or("");
    // if !is_review && !uploader.contains("Automation") {
    //   println!("only push to refs/for/master");
    //   return 1;
    // }

    if is_submit { central_submit(commit); }
    else if !is_module && is_update && !is_review { central_submit(newrev); }
    else if is_module && is_update && is_review { let _ = module_review_upload(project,newrev); return 1; }
  }

  return 0;
}

<|endoftext|>


<commit_before>use clap::{FromArgMatches, IntoApp};

use casile::cli::{Cli, Subcommand};
use casile::config::CONF;
use casile::{make, setup, status};
use casile::{Result, VERSION};

use std::env;

fn main() -> Result<()> {
    CONF.defaults()?;
    CONF.merge_env()?;
    CONF.merge_files()?;
    // Workaround for Github Actions usage to make the prebuilt Docker image
    // invocation interchangeable with the default run-time built invocation we
    // need to set some default arguments. These are not used by the regular CLI.
    // See the action.yml file for matching arguments for run-time invocations.
    let invocation: Vec<String> = env::args().collect();
    let ret = if status::is_gha()? && invocation.len() == 1 {
        CONF.set_str("language", "en-US")?;
        casile::show_welcome();
        let target = vec![String::from("_gha"), String::from("pdfs")];
        make::run(target)
    } else {
        let app = Cli::into_app().version(VERSION);
        let matches = app.get_matches();
        let args = Cli::from_arg_matches(&matches);
        CONF.merge_args(&args)?;
        casile::show_welcome();
        match args.subcommand {
            Subcommand::Make { target } => make::run(target),
            Subcommand::Setup {} => setup::run(),
            Subcommand::Status {} => status::run(),
        }
    };
    casile::show_outro();
    ret
}
<commit_msg>fix(actions): Use same default targets in GH Actions as CLI<commit_after>use clap::{FromArgMatches, IntoApp};

use casile::cli::{Cli, Subcommand};
use casile::config::CONF;
use casile::{make, setup, status};
use casile::{Result, VERSION};

use std::env;

fn main() -> Result<()> {
    CONF.defaults()?;
    CONF.merge_env()?;
    CONF.merge_files()?;
    // Workaround for Github Actions usage to make the prebuilt Docker image
    // invocation interchangeable with the default run-time built invocation we
    // need to set some default arguments. These are not used by the regular CLI.
    // See the action.yml file for matching arguments for run-time invocations.
    let invocation: Vec<String> = env::args().collect();
    let ret = if status::is_gha()? && invocation.len() == 1 {
        CONF.set_str("language", "en-US")?;
        casile::show_welcome();
        let target = vec![String::from("_gha"), String::from("default")];
        make::run(target)
    } else {
        let app = Cli::into_app().version(VERSION);
        let matches = app.get_matches();
        let args = Cli::from_arg_matches(&matches);
        CONF.merge_args(&args)?;
        casile::show_welcome();
        match args.subcommand {
            Subcommand::Make { target } => make::run(target),
            Subcommand::Setup {} => setup::run(),
            Subcommand::Status {} => status::run(),
        }
    };
    casile::show_outro();
    ret
}
<|endoftext|>


<commit_before>extern crate piston_window;
extern crate rand;
extern crate find_folder;
extern crate sdl2_window;

use piston_window::*;
// use rand::*;
use sdl2_window::Sdl2Window;

pub static GAME_NAME: &'static str = "Box Alive";
pub static WINDOW_HEIGHT: u32 = 480;
pub static WINDOW_WIDTH: u32 = 640;
pub static BLOCK_SIZE: u32 = 10; // NOTE: WINDOW_HEIGHT and WINDOW_WIDTH should be divisible by this

pub static GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
pub static RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
pub static BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
pub static WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];

#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
struct GameWindowSettings {
    window_height: u32,
    window_width: u32,
    block_size: u32,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
enum Direction {
    Up,
    Down,
    Left,
    Right,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
struct Player {
    x: u32,
    y: u32,
    direction: Direction,
}

impl Player {
    pub fn change_direction(player: Player, direction: Direction) -> Player {
        use Direction::*;
        if player.direction == direction {
            player
        } else {
            match (player.direction, direction) {
                (Right, Left) => player,
                (Left, Right) => player,
                (Up, Down) => player,
                (Down, Up) => player,
                _ => {
                    Player {
                        x: player.x,
                        y: player.y,
                        direction,
                    }
                }
            }
        }
    }

    pub fn validate_position(player: Player, gw: GameWindowSettings) -> bool {
        if player.x > 0 && player.y > 0 && player.x <= gw.window_width - gw.block_size &&
            player.y <= gw.window_height - gw.block_size
        {
            true
        } else {
            false
        }
    }

    pub fn advance(player: Player, gw: GameWindowSettings) -> Option<Player> {
        let new_player = Player::update_position(player, gw);
        if Player::validate_position(new_player, gw) {
            Some(new_player)
        } else {
            None
        }
    }

    pub fn update_position(player: Player, gw: GameWindowSettings) -> Player {
        match player.direction {
            Direction::Up => {
                if player.y > 0 {
                    Player {
                        x: player.x,
                        y: player.y - gw.block_size,
                        direction: player.direction,
                    }
                } else {
                    player
                }
            }
            Direction::Down => {
                Player {
                    x: player.x,
                    y: player.y + gw.block_size,
                    direction: player.direction,
                }
            }
            Direction::Right => {
                Player {
                    x: player.x + gw.block_size,
                    y: player.y,
                    direction: player.direction,
                }
            }
            Direction::Left => {
                if player.x > 0 {
                    Player {
                        x: player.x - gw.block_size,
                        y: player.y,
                        direction: player.direction,
                    }
                } else {
                    player
                }
            }
        }
    }
}

fn main() {
    let game_window_settings: GameWindowSettings = GameWindowSettings {
        window_height: WINDOW_HEIGHT,
        window_width: WINDOW_WIDTH,
        block_size: BLOCK_SIZE,
    };

    let opengl = OpenGL::V3_2;
    let mut window: PistonWindow<Sdl2Window> =
        WindowSettings::new(
            GAME_NAME,
            (game_window_settings.window_width, game_window_settings.window_height),
        )
                .opengl(opengl)
                .exit_on_esc(true)
                .build()
                .unwrap_or_else(|e| panic!("Failed to build Window: {}", e));
    let assets = find_folder::Search::ParentsThenKids(3, 3)
        .for_folder("assets")
        .unwrap();
    println!("{:?}", assets);
    let ref font = assets.join("FiraSans-Regular.ttf");
    println!("{:?}", font);
    let factory = window.factory.clone();
    let mut glyphs = Glyphs::new(font, factory).unwrap();
    window.set_lazy(false);

    let square = rectangle::square(0.0, 0.0, BLOCK_SIZE as f64);
    let mut player = Player {
        x: WINDOW_WIDTH / BLOCK_SIZE / 2 * BLOCK_SIZE,
        y: WINDOW_HEIGHT / BLOCK_SIZE / 2 * BLOCK_SIZE,
        direction: Direction::Right,
    };

    while let Some(e) = window.next() {
        match e {
            Input::Release(Button::Keyboard(key)) => {
                match key {
                    Key::Up => player = Player::change_direction(player, Direction::Up),
                    Key::Right => player = Player::change_direction(player, Direction::Right),
                    Key::Left => player = Player::change_direction(player, Direction::Left),
                    Key::Down => player = Player::change_direction(player, Direction::Down),
                    _ => {}
                }
            }
            Input::Render(_) => {
                window.draw_2d(
                    &e, |c, g| {
                        let transform = c.transform.trans(10.0, 100.0);

                        clear(WHITE, g);

                        let new_player_option = Player::advance(player, game_window_settings);

                        match new_player_option {
                            Some(new_player) => {
                                player = new_player;
                                rectangle(
                                    BLACK,
                                    square,
                                    c.transform.trans(player.x as f64, player.y as f64),
                                    g,
                                );
                            }
                            None => {
                                text::Text::new_color(BLACK, 30).draw(
                                    &format!(
                                        "You Went Out of Bounds!",
                                    ),
                                    &mut glyphs,
                                    &c.draw_state,
                                    c.transform
                                        .trans(
                                            game_window_settings.window_width as f64 /
                                                4 as f64,
                                            game_window_settings.window_height as f64 /
                                                2 as f64,
                                        ),
                                    g,
                                );
                            }
                        }

                    }
                );
            }
            _ => {}
        }

    }
}
<commit_msg>Color and Basic Implementation<commit_after>extern crate piston_window;
extern crate rand;
extern crate find_folder;
extern crate sdl2_window;

use piston_window::*;
use rand::*;
use sdl2_window::Sdl2Window;

pub static GAME_NAME: &'static str = "Box Alive";
pub static WINDOW_HEIGHT: u32 = 480;
pub static WINDOW_WIDTH: u32 = 640;
pub static BLOCK_SIZE: u32 = 10; // NOTE: WINDOW_HEIGHT and WINDOW_WIDTH should be divisible by this

pub static GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
pub static RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
pub static BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
pub static WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];

#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
struct GameWindowSettings {
    window_height: u32,
    window_width: u32,
    block_size: u32,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
enum Direction {
    Up,
    Down,
    Left,
    Right,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
struct Food {
    x: u32,
    y: u32,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
struct Player {
    x: u32,
    y: u32,
    direction: Direction,
}

impl Player {
    pub fn change_direction(player: Player, direction: Direction) -> Player {
        use Direction::*;
        if player.direction == direction {
            player
        } else {
            match (player.direction, direction) {
                (Right, Left) => player,
                (Left, Right) => player,
                (Up, Down) => player,
                (Down, Up) => player,
                _ => {
                    Player {
                        x: player.x,
                        y: player.y,
                        direction,
                    }
                }
            }
        }
    }

    pub fn validate_position(player: Player, gw: GameWindowSettings) -> bool {
        if player.x > 0 && player.y > 0 && player.x <= gw.window_width - gw.block_size &&
            player.y <= gw.window_height - gw.block_size
        {
            true
        } else {
            false
        }
    }

    pub fn advance(player: Player, gw: GameWindowSettings) -> Option<Player> {
        let new_player = Player::update_position(player, gw);
        if Player::validate_position(new_player, gw) {
            Some(new_player)
        } else {
            None
        }
    }

    pub fn update_position(player: Player, gw: GameWindowSettings) -> Player {
        match player.direction {
            Direction::Up => {
                if player.y > 0 {
                    Player {
                        x: player.x,
                        y: player.y - gw.block_size,
                        direction: player.direction,
                    }
                } else {
                    player
                }
            }
            Direction::Down => {
                Player {
                    x: player.x,
                    y: player.y + gw.block_size,
                    direction: player.direction,
                }
            }
            Direction::Right => {
                Player {
                    x: player.x + gw.block_size,
                    y: player.y,
                    direction: player.direction,
                }
            }
            Direction::Left => {
                if player.x > 0 {
                    Player {
                        x: player.x - gw.block_size,
                        y: player.y,
                        direction: player.direction,
                    }
                } else {
                    player
                }
            }
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
struct Game {
    active: bool,
    game_window_settings: GameWindowSettings,
    player: Player,
    tail: Vec<(u32, u32)>,
    food: Food,
}

impl Game {
    pub fn new(gws: GameWindowSettings) -> Game {
        let mut rng = rand::thread_rng();
        Game {
            active: true,
            game_window_settings: gws,
            player: Player {
                x: gws.window_width / gws.block_size / 2 * gws.block_size,
                y: gws.window_height / gws.block_size / 2 * gws.block_size,
                direction: Direction::Right,
            },
            tail: Vec::new(),
            food: Food {
                x: rng.gen_range(0, gws.window_width),
                y: rng.gen_range(0, gws.window_height),
            },
        }
    }
}

fn main() {
    let game_window_settings: GameWindowSettings = GameWindowSettings {
        window_height: WINDOW_HEIGHT,
        window_width: WINDOW_WIDTH,
        block_size: BLOCK_SIZE,
    };

    let opengl = OpenGL::V3_2;
    let mut window: PistonWindow<Sdl2Window> =
        WindowSettings::new(
            GAME_NAME,
            (game_window_settings.window_width, game_window_settings.window_height),
        )
                .opengl(opengl)
                .exit_on_esc(true)
                .build()
                .unwrap_or_else(|e| panic!("Failed to build Window: {}", e));
    let assets = find_folder::Search::ParentsThenKids(3, 3)
        .for_folder("assets")
        .unwrap();
    println!("{:?}", assets);
    let ref font = assets.join("FiraSans-Regular.ttf");
    println!("{:?}", font);
    let factory = window.factory.clone();
    let mut glyphs = Glyphs::new(font, factory).unwrap();
    window.set_lazy(false);

    let square = rectangle::square(0.0, 0.0, BLOCK_SIZE as f64);
    let mut player = Player {
        x: WINDOW_WIDTH / BLOCK_SIZE / 2 * BLOCK_SIZE,
        y: WINDOW_HEIGHT / BLOCK_SIZE / 2 * BLOCK_SIZE,
        direction: Direction::Right,
    };

    while let Some(e) = window.next() {
        match e {
            Input::Release(Button::Keyboard(key)) => {
                match key {
                    Key::Up => player = Player::change_direction(player, Direction::Up),
                    Key::Right => player = Player::change_direction(player, Direction::Right),
                    Key::Left => player = Player::change_direction(player, Direction::Left),
                    Key::Down => player = Player::change_direction(player, Direction::Down),
                    _ => {}
                }
            }
            Input::Render(_) => {
                window.draw_2d(
                    &e, |c, g| {
                        let transform = c.transform.trans(10.0, 100.0);

                        clear(BLACK, g);

                        let new_player_option = Player::advance(player, game_window_settings);

                        match new_player_option {
                            Some(new_player) => {
                                player = new_player;
                                rectangle(
                                    WHITE,
                                    square,
                                    c.transform.trans(player.x as f64, player.y as f64),
                                    g,
                                );
                            }
                            None => {
                                text::Text::new_color(WHITE, 30).draw(
                                    &format!(
                                        "You Went Out of Bounds!",
                                    ),
                                    &mut glyphs,
                                    &c.draw_state,
                                    c.transform
                                        .trans(
                                            game_window_settings.window_width as f64 /
                                                4 as f64,
                                            game_window_settings.window_height as f64 /
                                                2 as f64,
                                        ),
                                    g,
                                );
                            }
                        }

                    }
                );
            }
            _ => {}
        }

    }
}
<|endoftext|>


<commit_before>extern crate env_logger;
extern crate getopts;
extern crate hyper;
extern crate libotaplus;

use getopts::Options;
use hyper::Url;
use std::env;
use std::process::exit;

use libotaplus::{config, read_interpret};
use libotaplus::config::Config;
use libotaplus::read_interpret::ReplEnv;
use libotaplus::ota_plus::{Client as OtaClient};
use libotaplus::auth_plus::{Client as AuthClient};
use libotaplus::package_manager::{PackageManager, Dpkg};
use libotaplus::error::Error;

fn main() {

    env_logger::init().unwrap();

    let config_file = env::var("OTA_PLUS_CLIENT_CFG")
        .unwrap_or("/opt/ats/ota/etc/ota.toml".to_string());

    let config = config::load_config(&config_file)
        .unwrap_or_else(|err| {
            println!("{} (continuing with the default config)", err);
            return Config::default();
        });

    do_stuff(handle_flags(config));

}

fn do_stuff(config: Config) {

    fn post_installed_packages<M>(client: OtaClient, manager: M) -> Result<(), Error>
        where M: PackageManager {
            manager.installed_packages().and_then(|pkgs| client.post_packages(pkgs))
        }

    fn build_ota_client(config: Config) -> Result<OtaClient, Error> {
        AuthClient::new(config.auth.clone()).authenticate().map(|token| {
            OtaClient::new(token, config.ota.clone())
        })
    }

    let pkg_manager = Dpkg::new();
    let pkg_manager_clone = pkg_manager.clone();

    let _ = build_ota_client(config.clone()).and_then(|client| {
        post_installed_packages(client, pkg_manager)
    }).map(|_| {
        print!("Installed packages were posted successfully.");
    }).map_err(|e| {
        print!("{}", e);
    });

    if config.test.looping {
        read_interpret::read_interpret_loop(ReplEnv::new(pkg_manager_clone));
    }
}

fn handle_flags(config: Config) -> Config {

    fn print_usage(program: &str, opts: Options) {
        let brief = format!("Usage: {} [options]", program);
        print!("{}", opts.usage(&brief));
    }

    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("h", "help",
                 "print this help menu");
    opts.optopt("", "auth-server",
                "change the auth server url", "URL");
    opts.optopt("", "auth-client-id",
                "change auth client id", "ID");
    opts.optopt("", "auth-secret",
                "change auth secret", "SECRET");
    opts.optopt("", "ota-server",
                "change ota server url", "URL");
    opts.optopt("", "ota-vin",
                "change ota vin", "VIN");
    opts.optflag("", "test-looping",
                 "enable read-interpret test loop");

    let matches = opts.parse(&args[1..])
        .unwrap_or_else(|err| panic!(err.to_string()));

    if matches.opt_present("h") {
        print_usage(&program, opts);
        exit(1);
    }

    let mut config = config;

    if let Some(s) = matches.opt_str("auth-server") {
        match Url::parse(&s) {
            Ok(url)  => config.auth.server = url,
            Err(err) => panic!("invalid auth-server url: {}", err)
        }
    }

    if let Some(client_id) = matches.opt_str("auth-client-id") {
        config.auth.client_id = client_id;
    }

    if let Some(secret) = matches.opt_str("auth-secret") {
        config.auth.secret = secret;
    }

    if let Some(s) = matches.opt_str("ota-server") {
        match Url::parse(&s) {
            Ok(url)  => config.ota.server = url,
            Err(err) => panic!("invalid ota-server url: {}", err)
        }
    }

    if let Some(vin) = matches.opt_str("ota-vin") {
        config.ota.vin = vin;
    }

    if matches.opt_present("test-looping") {
        config.test.looping = true;
    }

    return config
}

#[cfg(test)]
mod tests {

    use std::ffi::OsStr;
    use std::process::Command;

    fn client<S: AsRef<OsStr>>(args: &[S]) -> String {
        let output = Command::new("target/debug/ota_plus_client")
            .args(args)
            .output()
            .unwrap_or_else(|e| { panic!("failed to execute child: {}", e) });

        return String::from_utf8(output.stdout).unwrap()
    }

    #[test]
    fn help() {

        assert_eq!(client(&["-h"]),
r#"Usage: target/debug/ota_plus_client [options]

Options:
    -h, --help          print this help menu
        --auth-server URL
                        change the auth server url
        --auth-client-id ID
                        change auth client id
        --auth-secret SECRET
                        change auth secret
        --ota-server URL
                        change ota server url
        --ota-vin VIN   change ota vin
        --test-looping  enable read-interpret test loop
"#);

    }

}
<commit_msg>Add a flag to change config file.<commit_after>extern crate env_logger;
extern crate getopts;
extern crate hyper;
extern crate libotaplus;

use getopts::Options;
use hyper::Url;
use std::env;
use std::process::exit;

use libotaplus::{config, read_interpret};
use libotaplus::config::Config;
use libotaplus::read_interpret::ReplEnv;
use libotaplus::ota_plus::{Client as OtaClient};
use libotaplus::auth_plus::{Client as AuthClient};
use libotaplus::package_manager::{PackageManager, Dpkg};
use libotaplus::error::Error;

fn main() {

    env_logger::init().unwrap();

    let config = build_config();

    fn post_installed_packages<M>(client: OtaClient, manager: M) -> Result<(), Error>
        where M: PackageManager {
            manager.installed_packages().and_then(|pkgs| client.post_packages(pkgs))
        }

    fn build_ota_client(config: Config) -> Result<OtaClient, Error> {
        AuthClient::new(config.auth.clone()).authenticate().map(|token| {
            OtaClient::new(token, config.ota.clone())
        })
    }

    let pkg_manager = Dpkg::new();
    let pkg_manager_clone = pkg_manager.clone();

    let _ = build_ota_client(config.clone()).and_then(|client| {
        post_installed_packages(client, pkg_manager)
    }).map(|_| {
        print!("Installed packages were posted successfully.");
    }).map_err(|e| {
        print!("{}", e);
    });

    if config.test.looping {
        read_interpret::read_interpret_loop(ReplEnv::new(pkg_manager_clone));
    }
}

fn build_config() -> Config {

    fn print_usage(program: &str, opts: Options) {
        let brief = format!("Usage: {} [options]", program);
        print!("{}", opts.usage(&brief));
    }

    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("h", "help",
                 "print this help menu");
    opts.optopt("", "config",
                "change config path", "PATH");
    opts.optopt("", "auth-server",
                "change the auth server url", "URL");
    opts.optopt("", "auth-client-id",
                "change auth client id", "ID");
    opts.optopt("", "auth-secret",
                "change auth secret", "SECRET");
    opts.optopt("", "ota-server",
                "change ota server url", "URL");
    opts.optopt("", "ota-vin",
                "change ota vin", "VIN");
    opts.optflag("", "test-looping",
                 "enable read-interpret test loop");

    let matches = opts.parse(&args[1..])
        .unwrap_or_else(|err| panic!(err.to_string()));

    if matches.opt_present("h") {
        print_usage(&program, opts);
        exit(1);
    }

    let mut config_file = env::var("OTA_PLUS_CLIENT_CFG")
        .unwrap_or("/opt/ats/ota/etc/ota.toml".to_string());

    if let Some(path) = matches.opt_str("config") {
        config_file = path;
    }

    let mut config = config::load_config(&config_file)
        .unwrap_or_else(|err| {
            println!("{} (continuing with the default config)", err);
            return Config::default();
        });

    if let Some(s) = matches.opt_str("auth-server") {
        match Url::parse(&s) {
            Ok(url)  => config.auth.server = url,
            Err(err) => panic!("invalid auth-server url: {}", err)
        }
    }

    if let Some(client_id) = matches.opt_str("auth-client-id") {
        config.auth.client_id = client_id;
    }

    if let Some(secret) = matches.opt_str("auth-secret") {
        config.auth.secret = secret;
    }

    if let Some(s) = matches.opt_str("ota-server") {
        match Url::parse(&s) {
            Ok(url)  => config.ota.server = url,
            Err(err) => panic!("invalid ota-server url: {}", err)
        }
    }

    if let Some(vin) = matches.opt_str("ota-vin") {
        config.ota.vin = vin;
    }

    if matches.opt_present("test-looping") {
        config.test.looping = true;
    }

    return config
}

#[cfg(test)]
mod tests {

    use std::ffi::OsStr;
    use std::process::Command;

    fn client<S: AsRef<OsStr>>(args: &[S]) -> String {
        let output = Command::new("target/debug/ota_plus_client")
            .args(args)
            .output()
            .unwrap_or_else(|e| { panic!("failed to execute child: {}", e) });
        return String::from_utf8(output.stdout).unwrap()
    }

    #[test]
    fn help() {

        assert_eq!(client(&["-h"]),
r#"Usage: target/debug/ota_plus_client [options]

Options:
    -h, --help          print this help menu
        --config PATH   change config path
        --auth-server URL
                        change the auth server url
        --auth-client-id ID
                        change auth client id
        --auth-secret SECRET
                        change auth secret
        --ota-server URL
                        change ota server url
        --ota-vin VIN   change ota vin
        --test-looping  enable read-interpret test loop
"#);

    }

    // TODO: exit if load config fails.
    #[test]
    fn bad_config_path() {
        assert_eq!(client(&["--config", "apa"]), r#"Application Error: failed to load config: No such file or directory (os error 2) (continuing with the default config)
Application Error: Cannot send token request: connection refused"#);
    }

}
<|endoftext|>


<commit_before>// TODO
// impl ToGeojson for ....
// generic number instead of f64 for position?
// rename Position to Pos or Positions

extern crate serialize;

use std::collections::TreeMap;
use serialize::json::ToJson;
use serialize::json;

/// Position
///
/// [GeoJSON Format Specification § 2.1.1](http://geojson.org/geojson-spec.html#positions)
pub struct Position(pub Vec<f64>);

impl ToJson for Position {
    fn to_json(&self) -> json::Json {
        let &Position(ref nums) = self;
        nums.to_json()
    }
}

impl Clone for Position {
    fn clone(&self) -> Position {
        let &Position(ref nums) = self;
        Position(nums.clone())
    }
}

/// Point
///
/// [GeoJSON Format Specification § 2.1.2](http://geojson.org/geojson-spec.html#point)
pub struct Point {
    pub coordinates: Position,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Point".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiPoint
///
/// [GeoJSON Format Specification § 2.1.3](http://geojson.org/geojson-spec.html#multipoint)
pub struct MultiPoint {
    pub points: Vec<Point>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Position> =
            self.points.iter().map(|p| p.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPoint".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// LineString
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
pub struct LineString {
    pub coordinates: Vec<Position>,
}

impl ToJson for LineString {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "LineString".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiLineString
///
/// [GeoJSON Format Specification § 2.1.5](http://geojson.org/geojson-spec.html#multilinestring)
pub struct MultiLineString {
    pub line_strings: Vec<LineString>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Position>> =
            self.line_strings.iter().map(|l| l.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiLineString".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Polygon
///
/// [GeoJSON Format Specification § 2.1.6](http://geojson.org/geojson-spec.html#polygon)
pub struct Polygon {
    pub exterior: Vec<Position>,
    pub holes: Vec<Vec<Position>>,
}

impl Polygon {
    fn coordinates(&self) -> Vec<Vec<Position>> {
        let mut coordinates = self.holes.clone();
        coordinates.insert(0, self.exterior.clone());
        coordinates
    }
}

impl ToJson for Polygon {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Polygon".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates().to_json());
        d.to_json()
    }
}

/// MultiPolygon
///
/// [GeoJSON Format Specification § 2.1.7](http://geojson.org/geojson-spec.html#multipolygon)
pub struct MultiPolygon {
    pub polygons: Vec<Polygon>,
}

impl ToJson for MultiPolygon {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Vec<Position>>> =
            self.polygons.iter().map(|p| p.coordinates()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPolygon".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Geometry
pub enum Geometry {
    Point(Point),
    MultiPoint(MultiPoint),
    LineString(LineString),
    MultiLineString(MultiLineString),
    Polygon(Polygon),
    MultiPolygon(MultiPolygon),
}

impl ToJson for Geometry {
    fn to_json(&self) -> json::Json {
        match *self {
            // TODO: is there a better way of doing this?
            Point(ref geom) => geom.to_json(),
            MultiPoint(ref geom) => geom.to_json(),
            LineString(ref geom) => geom.to_json(),
            MultiLineString(ref geom) => geom.to_json(),
            Polygon(ref geom) => geom.to_json(),
            MultiPolygon(ref geom) => geom.to_json(),
            // TODO: GeometryCollection(ref geom) => geom.to_json(),
        }
    }
}

/// GeometryCollection
///
/// [GeoJSON Format Specification § 2.1.8](http://geojson.org/geojson-spec.html#geometry-collection)
pub struct GeometryCollection {
    geometries: Vec<Geometry>,
}

impl ToJson for GeometryCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "GeometryCollection".to_string().to_json());
        d.insert("geometries".to_string(), self.geometries.to_json());
        d.to_json()
    }
}

fn main() {
    let point = Point {
        coordinates: Position(vec![1., 2., 3.]),
    };

    let j: json::Json = point.to_json();
    let s: String = j.to_pretty_str();

    println!("{}", s);
}
<commit_msg>Implement Feature<commit_after>// TODO
// impl ToGeojson for ....
// generic number instead of f64 for position?
// rename Position to Pos or Positions

extern crate serialize;

use std::collections::TreeMap;
use serialize::json::ToJson;
use serialize::json;

/// Position
///
/// [GeoJSON Format Specification § 2.1.1](http://geojson.org/geojson-spec.html#positions)
pub struct Position(pub Vec<f64>);

impl ToJson for Position {
    fn to_json(&self) -> json::Json {
        let &Position(ref nums) = self;
        nums.to_json()
    }
}

impl Clone for Position {
    fn clone(&self) -> Position {
        let &Position(ref nums) = self;
        Position(nums.clone())
    }
}

/// Point
///
/// [GeoJSON Format Specification § 2.1.2](http://geojson.org/geojson-spec.html#point)
pub struct Point {
    pub coordinates: Position,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Point".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiPoint
///
/// [GeoJSON Format Specification § 2.1.3](http://geojson.org/geojson-spec.html#multipoint)
pub struct MultiPoint {
    pub points: Vec<Point>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Position> =
            self.points.iter().map(|p| p.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPoint".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// LineString
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
pub struct LineString {
    pub coordinates: Vec<Position>,
}

impl ToJson for LineString {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "LineString".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiLineString
///
/// [GeoJSON Format Specification § 2.1.5](http://geojson.org/geojson-spec.html#multilinestring)
pub struct MultiLineString {
    pub line_strings: Vec<LineString>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Position>> =
            self.line_strings.iter().map(|l| l.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiLineString".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Polygon
///
/// [GeoJSON Format Specification § 2.1.6](http://geojson.org/geojson-spec.html#polygon)
pub struct Polygon {
    pub exterior: Vec<Position>,
    pub holes: Vec<Vec<Position>>,
}

impl Polygon {
    fn coordinates(&self) -> Vec<Vec<Position>> {
        let mut coordinates = self.holes.clone();
        coordinates.insert(0, self.exterior.clone());
        coordinates
    }
}

impl ToJson for Polygon {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Polygon".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates().to_json());
        d.to_json()
    }
}

/// MultiPolygon
///
/// [GeoJSON Format Specification § 2.1.7](http://geojson.org/geojson-spec.html#multipolygon)
pub struct MultiPolygon {
    pub polygons: Vec<Polygon>,
}

impl ToJson for MultiPolygon {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Vec<Position>>> =
            self.polygons.iter().map(|p| p.coordinates()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPolygon".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Geometry
pub enum Geometry {
    Point(Point),
    MultiPoint(MultiPoint),
    LineString(LineString),
    MultiLineString(MultiLineString),
    Polygon(Polygon),
    MultiPolygon(MultiPolygon),
}

impl ToJson for Geometry {
    fn to_json(&self) -> json::Json {
        match *self {
            // TODO: is there a better way of doing this?
            Point(ref geom) => geom.to_json(),
            MultiPoint(ref geom) => geom.to_json(),
            LineString(ref geom) => geom.to_json(),
            MultiLineString(ref geom) => geom.to_json(),
            Polygon(ref geom) => geom.to_json(),
            MultiPolygon(ref geom) => geom.to_json(),
            // TODO: GeometryCollection(ref geom) => geom.to_json(),
        }
    }
}

/// GeometryCollection
///
/// [GeoJSON Format Specification § 2.1.8](http://geojson.org/geojson-spec.html#geometry-collection)
pub struct GeometryCollection {
    geometries: Vec<Geometry>,
}

impl ToJson for GeometryCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "GeometryCollection".to_string().to_json());
        d.insert("geometries".to_string(), self.geometries.to_json());
        d.to_json()
    }
}

/// Feature
///
/// [GeoJSON Format Specification § 2.2](http://geojson.org/geojson-spec.html#feature-objects)
pub struct Feature {
    geometry: Geometry,
    properties: json::Json,
}

impl ToJson for Feature {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Feature".to_string().to_json());
        d.insert("geometry".to_string(), self.geometry.to_json());
        d.insert("properties".to_string(), self.properties.to_json());
        d.to_json()
    }
}

fn main() {
    let point = Point {
        coordinates: Position(vec![1., 2., 3.]),
    };

    let j: json::Json = point.to_json();
    let s: String = j.to_pretty_str();

    println!("{}", s);
}
<|endoftext|>