<commit_before>extern crate zip;
extern crate yaml_rust;

use yaml_rust::{yaml,YamlLoader};
use zip::read::{ZipArchive, ZipFile};
use std::fs::{self, File};
use std::path::Path;
use std::io::{copy, Write, Read, BufReader, BufRead, Error, ErrorKind, Result};
use std::collections::{HashMap, HashSet};
use std::env;

fn main() {

    let args: Vec<String> = env::args().collect();

    match args.len() {
        2 => generate_entirely_from_yaml(&args[1]),
        3 => generate_from_yaml_with_output(&args[1], &args[2]),
        _ => {
            println!("PARAMP: Generate an Alfresco deployment with modules");
            println!("Usage: {} source.yaml <target_dir>", args[0])
        }
    }
}

fn generate_entirely_from_yaml(input_file: &str) {

    match read_file(resolve_file(input_file).unwrap()) {
        Ok(contents) => {
            let input = YamlLoader::load_from_str(&contents).unwrap();

            match &input[0]["output_dir"] {
                &yaml::Yaml::String(ref output_dir) => {

                    generate_from_yaml_with_output(input_file, output_dir);

                }
                _ => { println!("Could not find an output_dir property in input yaml file, specify an output directory with `output_dir` on the command line or within the yaml file");}
            }

        },
        _ => {}
    }

}

fn generate_from_yaml_with_output(input_file: &str, output_dir: &str) {

    match fs::remove_dir_all(output_dir) {
        Ok(_) => {
            println!("   Clearing dir: {}", output_dir);
        },
        _ => {}
    }

    match read_file(resolve_file(input_file).unwrap()) {
        Ok(contents) => {
            let input = YamlLoader::load_from_str(&contents).unwrap();

            match &input[0]["files"] {
                &yaml::Yaml::Array(ref v) => {
                    for amp in v {

                        let amp = amp.as_str().unwrap();

                        println!("Extracting file: {}", amp);

                        generate_output(amp, output_dir);
                    }
                },
                _ => {}
            }

        },
        _ => {}
    }

}

fn generate_output(input_file: &str, output_dir: &str) {

    let file = File::open(input_file).unwrap();

    let mut archive = ZipArchive::new(file).unwrap();

    let mut file_map = get_default_map();

    let exclusion_map = get_exclusion_map();

    match archive.by_name("file-mapping.properties") {
        Ok(amp_map) => {
            file_map = decorate_map(amp_map);
        },
        _ => {}
    }

    match archive.by_name("module.properties") {
        Ok(module_file) => {
            create_module_file(module_file, output_dir);
        },
        _ => {}
    }

    for i in 0..archive.len() {
        let mut file = archive.by_index(i).unwrap();

        if !exclusion_map.contains(file.name()) {

            let mut change_filename = String::from(format!("/{}",file.name()));

            for (from, to) in &file_map {
                if change_filename.starts_with(from) {
                    change_filename = format!("{}{}", to , &change_filename[from.len()..]);
                }
            }

            let new_file = create_file_and_dirs(&*format!("{}/{}", output_dir, change_filename));

            match new_file {
                Ok(mut file_handle) => {
                    copy(&mut file, &mut file_handle).unwrap();
                    //println!("{}", change_filename);
                },
                _ => {}
            }

        }

    }
}

fn create_module_file(file: ZipFile, output_dir: &str) {

    let reader = BufReader::new(file);

    let mut output_file: Option<String> = None;

    let mut output_content = String::new();

    for line in reader.lines() {
        match line {
            Ok(property) => {

                let components: Vec<&str> = property.split("=").collect();
                if components.len() == 2 {

                    output_content.push_str(&*format!("{}={}\n", components[0], components[1]));

                    if components[0] == "module.id" {
                        output_file = Some(format!("{}/WEB-INF/classes/alfresco/module/{}/module.properties", output_dir, components[1]));
                    }
                }
            },
            _ => {}
        }
    }

    match output_file {
        Some(file_name) => {
            let new_file = create_file_and_dirs(&*file_name);

            match new_file {
                Ok(mut file_handle) => {

                    output_content.push_str("module.installState=INSTALLED\n");

                    file_handle.write(&output_content.into_bytes()).unwrap();
                },
                _ => {}
            }
        },
        _ => {}
    }

}

fn create_file_and_dirs(file: &str) -> Result<File> {
    create_parent_dirs(file);
    return File::create(file);
}

fn create_parent_dirs(file: &str) {
    let path = Path::new(file);
    fs::create_dir_all(path.parent().unwrap()).unwrap();
}

fn decorate_map(amp_map: ZipFile) -> HashMap<String, String> {

    let mut return_map = get_default_map();

    let reader = BufReader::new(amp_map);

    for line in reader.lines() {
        match line {
            Ok(map) => {
                let components: Vec<&str> = map.split("=").collect();
                if components.len() == 2 {
                    return_map.insert(String::from(components[0]), String::from(components[1]));
                }
            },
            _=> {}
        }
    }

    return_map
}

fn get_exclusion_map() -> HashSet<String> {
    let mut return_set: HashSet<String> = HashSet::new();

    return_set.insert(String::from("file-mapping.properties"));
    return_set.insert(String::from("module.properties"));

    return_set
}

fn get_default_map() -> HashMap<String,String> {

    let mut return_map: HashMap<String,String> = HashMap::new();

    return_map.insert(String::from("/config"),String::from("/WEB-INF/classes"));
    return_map.insert(String::from("/lib"),String::from("/WEB-INF/lib"));
    return_map.insert(String::from("/licenses"),String::from("/WEB-INF/licenses"));
    return_map.insert(String::from("/web/jsp"),String::from("/jsp"));
    return_map.insert(String::from("/web/css"),String::from("/css"));
    return_map.insert(String::from("/web/images"),String::from("/images"));
    return_map.insert(String::from("/web/scripts"),String::from("/scripts"));
    return_map.insert(String::from("/web/php"),String::from("/"));

    return_map
}

fn read_file(mut file: File) -> Result<String> {
    let mut s = String::new();
    match file.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(_) => Err(Error::new(ErrorKind::InvalidInput,
                      "the file cannot be read"))
    }
}

fn resolve_file(search_path: &str) -> Result<File> {
    let path = Path::new(search_path);
    match path.exists(){
        true => File::open(&path),
        false =>
                Err(Error::new(ErrorKind::NotFound,
                              "the file cannot be found"))
    }
}
<commit_msg>Trim whitespace in properties file<commit_after>extern crate zip;
extern crate yaml_rust;

use yaml_rust::{yaml,YamlLoader};
use zip::read::{ZipArchive, ZipFile};
use std::fs::{self, File};
use std::path::Path;
use std::io::{copy, Write, Read, BufReader, BufRead, Error, ErrorKind, Result};
use std::collections::{HashMap, HashSet};
use std::env;

fn main() {

    let args: Vec<String> = env::args().collect();

    match args.len() {
        2 => generate_entirely_from_yaml(&args[1]),
        3 => generate_from_yaml_with_output(&args[1], &args[2]),
        _ => {
            println!("PARAMP: Generate an Alfresco deployment with modules");
            println!("Usage: {} source.yaml <target_dir>", args[0])
        }
    }
}

fn generate_entirely_from_yaml(input_file: &str) {

    match read_file(resolve_file(input_file).unwrap()) {
        Ok(contents) => {
            let input = YamlLoader::load_from_str(&contents).unwrap();

            match &input[0]["output_dir"] {
                &yaml::Yaml::String(ref output_dir) => {

                    generate_from_yaml_with_output(input_file, output_dir);

                }
                _ => { println!("Could not find an output_dir property in input yaml file, specify an output directory with `output_dir` on the command line or within the yaml file");}
            }

        },
        _ => {}
    }

}

fn generate_from_yaml_with_output(input_file: &str, output_dir: &str) {

    match fs::remove_dir_all(output_dir) {
        Ok(_) => {
            println!("   Clearing dir: {}", output_dir);
        },
        _ => {}
    }

    match read_file(resolve_file(input_file).unwrap()) {
        Ok(contents) => {
            let input = YamlLoader::load_from_str(&contents).unwrap();

            match &input[0]["files"] {
                &yaml::Yaml::Array(ref v) => {
                    for amp in v {

                        let amp = amp.as_str().unwrap();

                        println!("Extracting file: {}", amp);

                        generate_output(amp, output_dir);
                    }
                },
                _ => {}
            }

        },
        _ => {}
    }

}

fn generate_output(input_file: &str, output_dir: &str) {

    let file = File::open(input_file).unwrap();

    let mut archive = ZipArchive::new(file).unwrap();

    let mut file_map = get_default_map();

    let exclusion_map = get_exclusion_map();

    match archive.by_name("file-mapping.properties") {
        Ok(amp_map) => {
            file_map = decorate_map(amp_map);
        },
        _ => {}
    }

    match archive.by_name("module.properties") {
        Ok(module_file) => {
            create_module_file(module_file, output_dir);
        },
        _ => {}
    }

    for i in 0..archive.len() {
        let mut file = archive.by_index(i).unwrap();

        if !exclusion_map.contains(file.name()) {

            let mut change_filename = String::from(format!("/{}",file.name()));

            for (from, to) in &file_map {
                if change_filename.starts_with(from) {
                    change_filename = format!("{}{}", to , &change_filename[from.len()..]);
                }
            }

            let new_file = create_file_and_dirs(&*format!("{}/{}", output_dir, change_filename));

            match new_file {
                Ok(mut file_handle) => {
                    copy(&mut file, &mut file_handle).unwrap();
                    //println!("{}", change_filename);
                },
                _ => {}
            }

        }

    }
}

fn create_module_file(file: ZipFile, output_dir: &str) {

    let reader = BufReader::new(file);

    let mut output_file: Option<String> = None;

    let mut output_content = String::new();

    for line in reader.lines() {
        match line {
            Ok(property) => {

                let components: Vec<&str> = property.split("=").collect();
                if components.len() == 2 {

                    let name = components[0].trim();
                    let value = components[1].trim();

                    output_content.push_str(&*format!("{}={}\n", name, value));

                    if name == "module.id" {
                        output_file = Some(format!("{}/WEB-INF/classes/alfresco/module/{}/module.properties", output_dir, value));
                    }
                }
            },
            _ => {}
        }
    }

    match output_file {
        Some(file_name) => {
            let new_file = create_file_and_dirs(&*file_name);

            match new_file {
                Ok(mut file_handle) => {

                    output_content.push_str("module.installState=INSTALLED\n");

                    file_handle.write(&output_content.into_bytes()).unwrap();
                },
                _ => {}
            }
        },
        _ => {}
    }

}

fn create_file_and_dirs(file: &str) -> Result<File> {
    create_parent_dirs(file);
    return File::create(file);
}

fn create_parent_dirs(file: &str) {
    let path = Path::new(file);
    fs::create_dir_all(path.parent().unwrap()).unwrap();
}

fn decorate_map(amp_map: ZipFile) -> HashMap<String, String> {

    let mut return_map = get_default_map();

    let reader = BufReader::new(amp_map);

    for line in reader.lines() {
        match line {
            Ok(map) => {
                let components: Vec<&str> = map.split("=").collect();
                if components.len() == 2 {
                    return_map.insert(String::from(components[0]), String::from(components[1]));
                }
            },
            _=> {}
        }
    }

    return_map
}

fn get_exclusion_map() -> HashSet<String> {
    let mut return_set: HashSet<String> = HashSet::new();

    return_set.insert(String::from("file-mapping.properties"));
    return_set.insert(String::from("module.properties"));

    return_set
}

fn get_default_map() -> HashMap<String,String> {

    let mut return_map: HashMap<String,String> = HashMap::new();

    return_map.insert(String::from("/config"),String::from("/WEB-INF/classes"));
    return_map.insert(String::from("/lib"),String::from("/WEB-INF/lib"));
    return_map.insert(String::from("/licenses"),String::from("/WEB-INF/licenses"));
    return_map.insert(String::from("/web/jsp"),String::from("/jsp"));
    return_map.insert(String::from("/web/css"),String::from("/css"));
    return_map.insert(String::from("/web/images"),String::from("/images"));
    return_map.insert(String::from("/web/scripts"),String::from("/scripts"));
    return_map.insert(String::from("/web/php"),String::from("/"));

    return_map
}

fn read_file(mut file: File) -> Result<String> {
    let mut s = String::new();
    match file.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(_) => Err(Error::new(ErrorKind::InvalidInput,
                      "the file cannot be read"))
    }
}

fn resolve_file(search_path: &str) -> Result<File> {
    let path = Path::new(search_path);
    match path.exists(){
        true => File::open(&path),
        false =>
                Err(Error::new(ErrorKind::NotFound,
                              "the file cannot be found"))
    }
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate time;

use std::os::{homedir, args};
use std::io::{File, SeekStyle, FileMode, FileAccess, FilePermission, USER_RWX};
use std::io::fs::{unlink, PathExtensions, mkdir};
use getopts::{reqopt, getopts, usage};
use time::{now_utc, Tm};

fn main() {
    let now = now_utc();
    let args = args();
    let home = homedir().unwrap();
    let base_dir = home.join(Path::new(".punch"));
    if !base_dir.exists() {
        mkdir(&base_dir, USER_RWX);
    }
    let timesheet_path = base_dir.join("timesheet");
    let mut working_state_path = base_dir.join("state");

    let mut timesheet = File::open_mode(&timesheet_path,
                                        FileMode::Append,
                                        FileAccess::Write).unwrap();
    timesheet.seek(0, SeekStyle::SeekEnd);

    match args.get(1) {
        None => panic!("No command given"),
        Some(command) => {
            match &command[] {
                "in" =>
                    punch_in(&now, &mut timesheet, &mut working_state_path),
                "out" =>
                    punch_out(&now, &mut timesheet, &mut working_state_path),
                _ => panic!("unknown command")
            }
        }
    }
}

fn punch_in(now: &Tm, timesheet: &mut File, state: &Path) {
    if currently_working(state) {
        panic!("You're already working");
    }
    writeln!(timesheet, "in: {}", now.rfc822());
    set_current_working_state(true, state);
}

fn punch_out(now: &Tm, timesheet: &mut File, state: &Path) {
    if !currently_working(state) {
        panic!("Can't punch out if you're not working!");
    }
    writeln!(timesheet, "out: {}", now.rfc822());
    set_current_working_state(false, state);
}

fn currently_working(p: &Path) -> bool {
    p.exists()
}

fn set_current_working_state(currently_working: bool, p: &Path) {
    if currently_working {
        File::create(p);
    } else {
        unlink(p);
    }
}
<commit_msg>Add timeclock object to avoid some repetition, fix warnings<commit_after>#![allow(unstable)]

extern crate time;

use std::os::{homedir, args};
use std::io::{File, SeekStyle, FileMode, FileAccess, USER_RWX};
use std::io::fs::{unlink, PathExtensions, mkdir};
use time::{now_utc, Tm};

fn main() {
    let args = args();
    match args.get(1) {
        None => panic!("No command given"),
        Some(command) => {
            let mut time_clock = TimeClock::new();
            match &command[] {
                "in" => time_clock.punch_in(),
                "out" => time_clock.punch_out(),
                _ => panic!("unknown command")
            }
        }
    }
}

struct TimeClock {
    now: Tm,
    timesheet: File,
    state_path: Path // TODO: maybe we can make this a bool that we
                           // initalise with the TimeClock
                           // and write back when we destroy the timeclock
                            // object
}

impl TimeClock {
    fn new() -> TimeClock {
        let now = now_utc();
        let home = homedir().unwrap();
        let base_dir = home.join(Path::new(".punch"));
        let timesheet_path = base_dir.join("timesheet");
        let working_state_path = base_dir.join("state");
        if !base_dir.exists() {
            mkdir(&base_dir, USER_RWX).unwrap();
        }
        let timesheet = File::open_mode(&timesheet_path,
                                            FileMode::Append,
                                            FileAccess::Write).unwrap();
        TimeClock {
            timesheet: timesheet,
            state_path: working_state_path,
            now: now
        }
    }

    fn punch_in(&mut self) {
        if self.currently_working() {
            panic!("You're already working");
        }
        self.timesheet.seek(0, SeekStyle::SeekEnd).unwrap();
        writeln!(&mut self.timesheet, "in: {}", self.now.rfc822()).unwrap();
        self.set_current_working_state(true);
    }

    fn punch_out(&mut self) {
        if !self.currently_working() {
            panic!("Can't punch out if you're not working!");
        }
        self.timesheet.seek(0, SeekStyle::SeekEnd).unwrap();
        writeln!(&mut self.timesheet, "out: {}", self.now.rfc822()).unwrap();
        self.set_current_working_state(false);
    }

    fn set_current_working_state(&self, currently_working: bool) {
        if currently_working {
            File::create(&self.state_path).unwrap();
        } else {
            unlink(&self.state_path).unwrap();
        }
    }

    fn currently_working(&self) -> bool {
        self.state_path.exists()
    }
}
<|endoftext|>


<commit_before>extern crate sass_rs;

use sass_rs::{compile_string, Options, OutputStyle};
use std::io::{self, Read};

fn main() {
    let mut buffer = String::new();
    io::stdin().read_to_string(&mut buffer).unwrap();

    let mut opts = Options::default();

    // SCSS vs. SASS.
    if std::env::args().any(|i| i == "--sass") {
        opts.indented_syntax = true;
    }

    // Output style.
    if std::env::args().any(|i| i == "--expanded") {
        opts.output_style = OutputStyle::Expanded;
    }
    if std::env::args().any(|i| i == "--compact") {
        opts.output_style = OutputStyle::Compact;
    }
    if std::env::args().any(|i| i == "--compressed") {
        opts.output_style = OutputStyle::Compressed;
    }

    let sass = compile_string(buffer.as_str(), opts).unwrap();
    println!("{}", sass);
}
<commit_msg>Updated: better error handling.<commit_after>extern crate sass_rs;

use sass_rs::{compile_string, Options, OutputStyle};
use std::io::{self, Read};

fn main() {
    let mut buffer = String::new();
    io::stdin().read_to_string(&mut buffer).unwrap();

    let mut opts = Options::default();

    // SCSS vs. SASS.
    if std::env::args().any(|i| i == "--sass") {
        opts.indented_syntax = true;
    }

    // Output style.
    if std::env::args().any(|i| i == "--expanded") {
        opts.output_style = OutputStyle::Expanded;
    }
    if std::env::args().any(|i| i == "--compact") {
        opts.output_style = OutputStyle::Compact;
    }
    if std::env::args().any(|i| i == "--compressed") {
        opts.output_style = OutputStyle::Compressed;
    }

    match compile_string(buffer.as_str(), opts) {
        Ok(sass) => println!("{}", sass),
        Err(e) => {
            println!("\nSASS/SCSS couldn't be converted bacause of the following error. Please check the input.\n");
            eprintln!("{}", e);
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;
extern crate capnp;
extern crate capnp_rpc;
// extern crate killranswers_capnp;

use capnp::capability::{Server};
use capnp_rpc::ez_rpc::EzRpcServer;
use std::collections::HashMap;

pub mod killranswers_capnp {
  include!(concat!(env!("OUT_DIR"), "/killranswers_capnp.rs"));
}

lazy_static! {
    static ref QUERIES: HashMap<String, String> = {
        let mut m = HashMap::new();
        m.insert("create_user".to_string(), "insert into user (user_id), values (?)".to_string());
        m
    };
}

use killranswers_capnp::killr_answers;

struct KillrAnswersImpl;

impl killr_answers::Server for KillrAnswersImpl {
    // fn ask(&mut self, mut context: killr_answers::AskContext) {
    //     println!("Asking");
    // }
    fn register_user(&mut self, mut context: killr_answers::RegisterUserContext) {
        context.done();
    }

}

fn main() {
    println!("Starting up...");
    let rpc_server = EzRpcServer::new("127.0.0.1:6000").unwrap();
    let ka = Box::new(killr_answers::ServerDispatch { server : Box::new(KillrAnswersImpl)});
    //
    rpc_server.serve(ka);

    println!("Done");
}
<commit_msg>cassandra import<commit_after>#[macro_use]
extern crate lazy_static;
extern crate capnp;
extern crate capnp_rpc;
extern crate cassandra;

use std::collections::HashMap;
use capnp::capability::{Server};
use capnp_rpc::ez_rpc::EzRpcServer;
use cassandra::*;

pub mod killranswers_capnp {
  include!(concat!(env!("OUT_DIR"), "/killranswers_capnp.rs"));
}

lazy_static! {
    static ref QUERIES: HashMap<String, String> = {
        let mut m = HashMap::new();
        m.insert("create_user".to_string(), "insert into user (user_id), values (?)".to_string());
        m
    };
}

use killranswers_capnp::killr_answers;

struct KillrAnswersImpl;

impl killr_answers::Server for KillrAnswersImpl {
    // fn ask(&mut self, mut context: killr_answers::AskContext) {
    //     println!("Asking");
    // }
    fn register_user(&mut self, mut context: killr_answers::RegisterUserContext) {
        context.done();
    }

}

fn main() {
    println!("Starting up...");
    let rpc_server = EzRpcServer::new("127.0.0.1:6000").unwrap();
    let ka = Box::new(killr_answers::ServerDispatch { server : Box::new(KillrAnswersImpl)});
    //
    rpc_server.serve(ka);

    println!("Done");
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate serde_json;
extern crate wdsapi;
extern crate rayon;

use clap::{App, AppSettings, Arg, SubCommand};
use rayon::prelude::*;
use serde_json::de::from_reader;
use serde_json::ser::to_string_pretty;
use std::thread::{JoinHandle, spawn};
use wdsapi::{Collection, Configuration, Credentials, Environment,
             NewCollection, NewEnvironment, Status, create_collection,
             create_configuration, create_environment, credentials_from_file,
             delete_environment, get_collection_detail, get_collections,
             get_configurations, get_environments};

#[derive(Clone, Debug)]
struct EnvironmentInfo {
    environment: Environment,
    configurations: Vec<Configuration>,
    collections: Vec<Collection>,
}

#[derive(Clone, Debug)]
struct DiscoveryServiceInfo {
    creds: Credentials,
    environments: Vec<EnvironmentInfo>,
}

fn get_configurations_thread(creds: &Credentials,
                             env_id: &str)
                             -> JoinHandle<Vec<Configuration>> {
    let creds = creds.clone();
    let env_id = env_id.to_string();
    spawn(move || {
        get_configurations(&creds, &env_id)
            .expect("Failed to get configuration information, in thread")
            .configurations
    })
}

fn get_collections_thread(creds: &Credentials,
                          env_id: &str)
                          -> JoinHandle<Vec<Collection>> {
    let creds = creds.clone();
    let env_id = env_id.to_string();
    spawn(move || {
        get_collections(&creds, &env_id)
            .expect("Failed to get collection information, in thread")
            .collections
            .par_iter()
            .map({
                |col| {
                    get_collection_detail(&creds, &env_id, &col.collection_id)
                        .expect("Failed to get collection detail, in thread")
                }
            })
            .weight_max()
            .collect()
    })
}

fn environment_info(creds: &Credentials, env: &Environment) -> EnvironmentInfo {
    let env_id = env.environment_id.clone();
    // launch threads for these API calls
    let conf_thread = get_configurations_thread(creds, &env_id);
    let col_thread = get_collections_thread(creds, &env_id);
    // Gather the results from the threads
    let configurations = conf_thread.join()
                                    .expect("Failed to get configuration \
                                             information");
    let collections = col_thread.join()
                                .expect("Failed to get collection information");
    EnvironmentInfo {
        environment: env.clone(),
        configurations: configurations,
        collections: collections,
    }
}

fn discovery_service_info(matches: &clap::ArgMatches) -> DiscoveryServiceInfo {
    let creds_file = matches.value_of("credentials")
                            .expect("Internal error: Missing credentials?");
    let creds = credentials_from_file(creds_file).expect("Invalid credentials");
    let environments = get_environments(&creds)
        .expect("Failed to get environment information")
        .environments
        .par_iter()
        .map({
            |env| environment_info(&creds, env)
        })
        .weight_max()
        .collect();
    DiscoveryServiceInfo {
        creds: creds,
        environments: environments,
    }
}

fn writable_environment(info: &DiscoveryServiceInfo) -> EnvironmentInfo {
    let writables: Vec<EnvironmentInfo> =
        info.environments
            .clone()
            .into_iter()
            .filter({
                |env| !env.environment.read_only
            })
            .collect();

    assert!(writables.len() <= 1,
            format!("Multiple writable environments found {:?}", writables));

    writables.first()
             .expect("No writable environment found")
             .clone()
}

fn newest_configuration(env: &EnvironmentInfo) -> Configuration {
    env.configurations
       .clone()
       .into_iter()
       .max_by_key({
           |i| i.created
       })
       .expect("No configurations found")
}

fn newest_collection(env: &EnvironmentInfo) -> Collection {
    env.collections
       .clone()
       .into_iter()
       .max_by_key({
           |i| i.created
       })
       .expect("No collections found")
}

fn configuration(env: &EnvironmentInfo,
                 configuration_id: &str)
                 -> Configuration {
    env.configurations
       .clone()
       .into_iter()
       .filter({
           |c| c.configuration_id == Some(configuration_id.to_string())
       })
       .last()
       .expect("No configuration found")
       .clone()
}

fn print_env_children(env: &EnvironmentInfo) {
    let mut first = true;
    let configs: &Vec<Configuration> = &env.configurations;
    let collections: &Vec<Collection> = &env.collections;
    for conf in configs {
        if first {
            first = false;
            println!("   Configurations: {}", conf.name)
        } else {
            println!("                   {}", conf.name)
        }
    }
    first = true;
    for col in collections {
        let counts = col.document_counts.clone().unwrap();
        let formatted_counts = if counts.failed > 0 {
            format!("{} available, {} processing, {} failed",
                    counts.available,
                    counts.processing,
                    counts.failed)
        } else if counts.processing > 0 {
            format!("{} available, {} processing",
                    counts.available,
                    counts.processing)
        } else {
            format!("{} available", counts.available)
        };

        if first {
            first = false;
            println!("   Collections: {}, {}", col.name, formatted_counts)
        } else {
            println!("                {}, {}", col.name, formatted_counts)
        }
    }
}

fn show(matches: &clap::ArgMatches) {
    let info = discovery_service_info(matches);
    for env in info.environments {
        let status = match env.environment.status {
            Status::Pending => " - pending",
            _ => {
                if env.environment.read_only {
                    " - read only"
                } else {
                    ""
                }
            }
        };
        let capacity = env.environment.index_capacity.as_ref();
        match capacity {
            Some(index_capacity) => {
                println!("Environment: {}, {} disk, {} memory{}",
                         env.environment.name,
                         index_capacity.disk_usage.total,
                         index_capacity.memory_usage.total,
                         status)
            }
            None => {
                println!("Environment: {}{}", env.environment.name, status);
            }
        }
        print_env_children(&env)
    }
}

// I suppose there is a standard library way to do this...
fn optional_string(s: &Option<&str>) -> Option<String> {
    match *s {
        Some(s) => Some(s.to_string()),
        None => None,
    }
}

fn cenv(matches: &clap::ArgMatches) {
    let creds_file = matches.value_of("credentials").unwrap();
    let creds = credentials_from_file(creds_file).unwrap(); // FIXME

    let env_options = NewEnvironment {
        name: matches.value_of("name").unwrap().to_string(),
        description: optional_string(&matches.value_of("description")),
        size: matches.value_of("size").unwrap_or("0").parse::<u64>().unwrap(),
    };
    match create_environment(&creds, &env_options) {
        Ok(response) => {
            println!("{}",
                     to_string_pretty(&response)
                         .expect("Internal error: failed to format \
                                  create_environment response"))
        }
        Err(e) => println!("Failed to create environment {}", e),
    }
}

fn denv(matches: &clap::ArgMatches) {
    let info = discovery_service_info(matches);
    let env_id = writable_environment(&info).environment.environment_id;

    match delete_environment(&info.creds, &env_id) {
        Ok(response) => {
            println!("{}",
                     to_string_pretty(&response)
                         .expect("Internal error: failed to format \
                                  delete_environment response"))
        }
        Err(e) => println!("Failed to delete environment {}", e),
    }
}

fn ccol(matches: &clap::ArgMatches) {
    let info = discovery_service_info(matches);
    let env = writable_environment(&info);
    let env_id = env.environment.environment_id.clone();

    let col_options = NewCollection {
        name: matches.value_of("name").unwrap().to_string(),
        description: optional_string(&matches.value_of("description")),
        configuration_id: match matches.value_of("configuration_id") {
            Some(s) => Some(s.to_string()),
            None => newest_configuration(&env).configuration_id,
        },
    };

    match create_collection(&info.creds, &env_id, &col_options) {
        Ok(response) => {
            println!("{}",
                     to_string_pretty(&response)
                         .expect("Internal error: failed to format \
                                  create_collection response"))
        }
        Err(e) => println!("Failed to create collection {}", e),
    }
}

fn cconfig(matches: &clap::ArgMatches) {
    let info = discovery_service_info(matches);
    let env = writable_environment(&info);
    let env_id = env.environment.environment_id.clone();
    let config_filename =
        matches.value_of("configuration").unwrap().to_string();
    let config_file = std::fs::File::open(config_filename)
        .expect("Failed to read configuration JSON file");
    let config: Configuration = from_reader(config_file)
        .expect("Failed to parse configuration JSON");

    match create_configuration(&info.creds, &env_id, &config) {
        Ok(response) => {
            println!("{}",
                     to_string_pretty(&response)
                         .expect("Internal error: failed to format \
                                  create_collection response"))
        }
        Err(e) => println!("Failed to create collection {}", e),
    }
}

fn crawler(matches: &clap::ArgMatches) {
    let info = discovery_service_info(matches);
    let env = writable_environment(&info);

    let collection = newest_collection(&env);
    let config = configuration(&env, &collection.configuration_id);

    println!("# discovery_service.conf \
              generated by https://github.com/bruceadams/wdsapi
{{
    environment_id   = {:?} # {}
    collection_id    = {:?} # {}
    configuration_id = {:?} # {}

    base_url = {:?}
    credentials {{
            username = {:?}
            password = {:?}
    }}

    api_version = \"2016-11-07\"
    concurrent_upload_connection_limit = 2
    http_timeout = 125
    send_stats {{
            jvm = true
            os  = true
    }}
}}
",
             env.environment.environment_id,
             env.environment.name,
             collection.collection_id,
             collection.name,
             collection.configuration_id,
             config.name,
             info.creds.url,
             info.creds.username,
             info.creds.password);
}

fn main() {
    rayon::initialize(rayon::Configuration::new().set_num_threads(64))
        .expect("Failed to initialize thread pool");

    let matches = App::new("wdscli")
        .about("Basic administration for Watson Discovery Service.")
        .setting(AppSettings::SubcommandRequired)
        .subcommand(SubCommand::with_name("show")
            .about("Displays information about existing resources.")
            .arg(Arg::with_name("credentials")
                .required(true)
                .help("A JSON file containing service credentials.")))
            // .arg(Arg::with_name("guid")
            //     .short("g")
            //     .help("Displays the GUID for each resource.")))
        .subcommand(SubCommand::with_name("create-environment")
            .visible_alias("ce")
            .about("Create a writable environment")
            .arg(Arg::with_name("credentials")
                .required(true)
                .help("A JSON file containing service credentials."))
            .arg(Arg::with_name("name")
                .required(true)
                .help("The name of the environment."))
            .arg(Arg::with_name("size")
                .short("s")
                .takes_value(true)
                .help("The size environment to create."))
            .arg(Arg::with_name("description")
                .short("d")
                .takes_value(true)
                .help("Description text for the environment.")))
        .subcommand(SubCommand::with_name("delete-environment")
            .visible_alias("de")
            .about("Delete the writable environment")
            .arg(Arg::with_name("credentials")
                .required(true)
                .help("A JSON file containing service credentials.")))
        .subcommand(SubCommand::with_name("create-collection")
            .visible_alias("cl")
            .about("Create a new collection using the most recently created \
                    configuration")
            .arg(Arg::with_name("credentials")
                .required(true)
                .help("A JSON file containing service credentials."))
            .arg(Arg::with_name("name")
                .required(true)
                .help("The name of the collection."))
            .arg(Arg::with_name("description")
                .short("d")
                .short("desc")
                .takes_value(true)
                .help("Description text for the collection.")))
        .subcommand(SubCommand::with_name("crawler-configuration")
            .visible_alias("cc")
            .about("Print out crawler configuration.")
            .arg(Arg::with_name("credentials")
                .required(true)
                .help("A JSON file containing service credentials.")))
        .subcommand(SubCommand::with_name("create-configuration")
            .visible_alias("cn")
            .about("Create a new configuration, or replace existing \
                    configuration with the same name.")
            .arg(Arg::with_name("credentials")
                .required(true)
                .help("A JSON file containing service credentials."))
            .arg(Arg::with_name("configuration")
                .required(true)
                .help("File containing the configuration JSON.")))
        .subcommand(SubCommand::with_name("query")
            .visible_alias("q")
            .about("Issue a query.")
            .arg(Arg::with_name("credentials")
                .required(true)
                .help("A JSON file containing service credentials."))
            .arg(Arg::with_name("query").help("The query string."))
            .arg(Arg::with_name("count")
                .short("n")
                .takes_value(true)
                .help("The number of results to return. Defaults to 2."))
            .arg(Arg::with_name("collection")
                .short("c")
                .takes_value(true)
                .help("The name of the collection to query. \
                       Defaults to every collection.")))
        .get_matches();

    match matches.subcommand() {
        ("show", Some(m)) => show(m),
        ("create-environment", Some(m)) => cenv(m),
        ("delete-environment", Some(m)) => denv(m),
        ("create-collection", Some(m)) => ccol(m),
        ("create-configuration", Some(m)) => cconfig(m),
        ("crawler-configuration", Some(m)) => crawler(m),
        _ => println!("Not implemented yet; sorry!"),
    }
}
<commit_msg>Cleanup command to reflect reality<commit_after>extern crate clap;
extern crate serde_json;
extern crate wdsapi;
extern crate rayon;

use clap::{App, AppSettings, Arg, SubCommand};
use rayon::prelude::*;
use serde_json::de::from_reader;
use serde_json::ser::to_string_pretty;
use std::thread::{JoinHandle, spawn};
use wdsapi::{Collection, Configuration, Credentials, Environment,
             NewCollection, NewEnvironment, Status, create_collection,
             create_configuration, create_environment, credentials_from_file,
             delete_environment, get_collection_detail, get_collections,
             get_configurations, get_environments};

#[derive(Clone, Debug)]
struct EnvironmentInfo {
    environment: Environment,
    configurations: Vec<Configuration>,
    collections: Vec<Collection>,
}

#[derive(Clone, Debug)]
struct DiscoveryServiceInfo {
    creds: Credentials,
    environments: Vec<EnvironmentInfo>,
}

fn get_configurations_thread(creds: &Credentials,
                             env_id: &str)
                             -> JoinHandle<Vec<Configuration>> {
    let creds = creds.clone();
    let env_id = env_id.to_string();
    spawn(move || {
        get_configurations(&creds, &env_id)
            .expect("Failed to get configuration information, in thread")
            .configurations
    })
}

fn get_collections_thread(creds: &Credentials,
                          env_id: &str)
                          -> JoinHandle<Vec<Collection>> {
    let creds = creds.clone();
    let env_id = env_id.to_string();
    spawn(move || {
        get_collections(&creds, &env_id)
            .expect("Failed to get collection information, in thread")
            .collections
            .par_iter()
            .map({
                |col| {
                    get_collection_detail(&creds, &env_id, &col.collection_id)
                        .expect("Failed to get collection detail, in thread")
                }
            })
            .weight_max()
            .collect()
    })
}

fn environment_info(creds: &Credentials, env: &Environment) -> EnvironmentInfo {
    let env_id = env.environment_id.clone();
    // launch threads for these API calls
    let conf_thread = get_configurations_thread(creds, &env_id);
    let col_thread = get_collections_thread(creds, &env_id);
    // Gather the results from the threads
    let configurations = conf_thread.join()
                                    .expect("Failed to get configuration \
                                             information");
    let collections = col_thread.join()
                                .expect("Failed to get collection information");
    EnvironmentInfo {
        environment: env.clone(),
        configurations: configurations,
        collections: collections,
    }
}

fn discovery_service_info(matches: &clap::ArgMatches) -> DiscoveryServiceInfo {
    let creds_file = matches.value_of("credentials")
                            .expect("Internal error: Missing credentials?");
    let creds = credentials_from_file(creds_file).expect("Invalid credentials");
    let environments = get_environments(&creds)
        .expect("Failed to get environment information")
        .environments
        .par_iter()
        .map({
            |env| environment_info(&creds, env)
        })
        .weight_max()
        .collect();
    DiscoveryServiceInfo {
        creds: creds,
        environments: environments,
    }
}

fn writable_environment(info: &DiscoveryServiceInfo) -> EnvironmentInfo {
    let writables: Vec<EnvironmentInfo> =
        info.environments
            .clone()
            .into_iter()
            .filter({
                |env| !env.environment.read_only
            })
            .collect();

    assert!(writables.len() <= 1,
            format!("Multiple writable environments found {:?}", writables));

    writables.first()
             .expect("No writable environment found")
             .clone()
}

fn newest_configuration(env: &EnvironmentInfo) -> Configuration {
    env.configurations
       .clone()
       .into_iter()
       .max_by_key({
           |i| i.created
       })
       .expect("No configurations found")
}

fn newest_collection(env: &EnvironmentInfo) -> Collection {
    env.collections
       .clone()
       .into_iter()
       .max_by_key({
           |i| i.created
       })
       .expect("No collections found")
}

fn configuration(env: &EnvironmentInfo,
                 configuration_id: &str)
                 -> Configuration {
    env.configurations
       .clone()
       .into_iter()
       .filter({
           |c| c.configuration_id == Some(configuration_id.to_string())
       })
       .last()
       .expect("No configuration found")
       .clone()
}

fn print_env_children(env: &EnvironmentInfo) {
    let mut first = true;
    let configs: &Vec<Configuration> = &env.configurations;
    let collections: &Vec<Collection> = &env.collections;
    for conf in configs {
        if first {
            first = false;
            println!("   Configurations: {}", conf.name)
        } else {
            println!("                   {}", conf.name)
        }
    }
    first = true;
    for col in collections {
        let counts = col.document_counts.clone().unwrap();
        let formatted_counts = if counts.failed > 0 {
            format!("{} available, {} processing, {} failed",
                    counts.available,
                    counts.processing,
                    counts.failed)
        } else if counts.processing > 0 {
            format!("{} available, {} processing",
                    counts.available,
                    counts.processing)
        } else {
            format!("{} available", counts.available)
        };

        if first {
            first = false;
            println!("   Collections: {}, {}", col.name, formatted_counts)
        } else {
            println!("                {}, {}", col.name, formatted_counts)
        }
    }
}

fn show(matches: &clap::ArgMatches) {
    let info = discovery_service_info(matches);
    for env in info.environments {
        let status = match env.environment.status {
            Status::Pending => " - pending",
            _ => {
                if env.environment.read_only {
                    " - read only"
                } else {
                    ""
                }
            }
        };
        let capacity = env.environment.index_capacity.as_ref();
        match capacity {
            Some(index_capacity) => {
                println!("Environment: {}, {} disk, {} memory{}",
                         env.environment.name,
                         index_capacity.disk_usage.total,
                         index_capacity.memory_usage.total,
                         status)
            }
            None => {
                println!("Environment: {}{}", env.environment.name, status);
            }
        }
        print_env_children(&env)
    }
}

// I suppose there is a standard library way to do this...
fn optional_string(s: &Option<&str>) -> Option<String> {
    match *s {
        Some(s) => Some(s.to_string()),
        None => None,
    }
}

fn cenv(matches: &clap::ArgMatches) {
    let creds_file = matches.value_of("credentials").unwrap();
    let creds = credentials_from_file(creds_file).unwrap(); // FIXME

    let env_options = NewEnvironment {
        name: matches.value_of("name").unwrap().to_string(),
        description: optional_string(&matches.value_of("description")),
        size: matches.value_of("size").unwrap_or("0").parse::<u64>().unwrap(),
    };
    match create_environment(&creds, &env_options) {
        Ok(response) => {
            println!("{}",
                     to_string_pretty(&response)
                         .expect("Internal error: failed to format \
                                  create_environment response"))
        }
        Err(e) => println!("Failed to create environment {}", e),
    }
}

fn denv(matches: &clap::ArgMatches) {
    let info = discovery_service_info(matches);
    let env_id = writable_environment(&info).environment.environment_id;

    match delete_environment(&info.creds, &env_id) {
        Ok(response) => {
            println!("{}",
                     to_string_pretty(&response)
                         .expect("Internal error: failed to format \
                                  delete_environment response"))
        }
        Err(e) => println!("Failed to delete environment {}", e),
    }
}

fn ccol(matches: &clap::ArgMatches) {
    let info = discovery_service_info(matches);
    let env = writable_environment(&info);
    let env_id = env.environment.environment_id.clone();

    let col_options = NewCollection {
        name: matches.value_of("name").unwrap().to_string(),
        description: optional_string(&matches.value_of("description")),
        configuration_id: match matches.value_of("configuration_id") {
            Some(s) => Some(s.to_string()),
            None => newest_configuration(&env).configuration_id,
        },
    };

    match create_collection(&info.creds, &env_id, &col_options) {
        Ok(response) => {
            println!("{}",
                     to_string_pretty(&response)
                         .expect("Internal error: failed to format \
                                  create_collection response"))
        }
        Err(e) => println!("Failed to create collection {}", e),
    }
}

fn cconfig(matches: &clap::ArgMatches) {
    let info = discovery_service_info(matches);
    let env = writable_environment(&info);
    let env_id = env.environment.environment_id.clone();
    let config_filename =
        matches.value_of("configuration").unwrap().to_string();
    let config_file = std::fs::File::open(config_filename)
        .expect("Failed to read configuration JSON file");
    let config: Configuration = from_reader(config_file)
        .expect("Failed to parse configuration JSON");

    match create_configuration(&info.creds, &env_id, &config) {
        Ok(response) => {
            println!("{}",
                     to_string_pretty(&response)
                         .expect("Internal error: failed to format \
                                  create_collection response"))
        }
        Err(e) => println!("Failed to create collection {}", e),
    }
}

fn crawler(matches: &clap::ArgMatches) {
    let info = discovery_service_info(matches);
    let env = writable_environment(&info);

    let collection = newest_collection(&env);
    let config = configuration(&env, &collection.configuration_id);

    println!("# discovery_service.conf \
              generated by https://github.com/bruceadams/wdsapi
{{
    environment_id   = {:?} # {}
    collection_id    = {:?} # {}
    configuration_id = {:?} # {}

    base_url = {:?}
    credentials {{
            username = {:?}
            password = {:?}
    }}

    api_version = \"2016-11-07\"
    concurrent_upload_connection_limit = 2
    http_timeout = 125
    send_stats {{
            jvm = true
            os  = true
    }}
}}
",
             env.environment.environment_id,
             env.environment.name,
             collection.collection_id,
             collection.name,
             collection.configuration_id,
             config.name,
             info.creds.url,
             info.creds.username,
             info.creds.password);
}

fn main() {
    rayon::initialize(rayon::Configuration::new().set_num_threads(64))
        .expect("Failed to initialize thread pool");

    let matches = App::new("wdscli")
        .about("Basic administration for Watson Discovery Service.")
        .setting(AppSettings::SubcommandRequired)
        .subcommand(SubCommand::with_name("crawler-configuration")
            .visible_alias("cc")
            .about("Print out crawler configuration.")
            .arg(Arg::with_name("credentials")
                .required(true)
                .help("A JSON file containing service credentials.")))
        .subcommand(SubCommand::with_name("show")
            .about("Displays information about existing resources.")
            .arg(Arg::with_name("credentials")
                .required(true)
                .help("A JSON file containing service credentials.")))
        .subcommand(SubCommand::with_name("create-collection")
            .visible_alias("cl")
            .about("Create a new collection using the most recently created \
                    configuration")
            .arg(Arg::with_name("credentials")
                .required(true)
                .help("A JSON file containing service credentials."))
            .arg(Arg::with_name("name")
                .required(true)
                .help("The name of the collection."))
            .arg(Arg::with_name("description")
                .short("d")
                .short("desc")
                .takes_value(true)
                .help("Description text for the collection.")))
        .subcommand(SubCommand::with_name("create-configuration")
            .visible_alias("cn")
            .about("Create a new configuration.")
            .arg(Arg::with_name("credentials")
                .required(true)
                .help("A JSON file containing service credentials."))
            .arg(Arg::with_name("configuration")
                .required(true)
                .help("File containing the configuration JSON.")))
        .subcommand(SubCommand::with_name("create-environment")
            .visible_alias("ce")
            .about("Create a writable environment")
            .arg(Arg::with_name("credentials")
                .required(true)
                .help("A JSON file containing service credentials."))
            .arg(Arg::with_name("name")
                .required(true)
                .help("The name of the environment."))
            .arg(Arg::with_name("size")
                .short("s")
                .takes_value(true)
                .help("The size environment to create."))
            .arg(Arg::with_name("description")
                .short("d")
                .takes_value(true)
                .help("Description text for the environment.")))
        .subcommand(SubCommand::with_name("delete-environment")
            .visible_alias("de")
            .about("Delete the writable environment")
            .arg(Arg::with_name("credentials")
                .required(true)
                .help("A JSON file containing service credentials.")))
        .get_matches();

    match matches.subcommand() {
        ("show", Some(m)) => show(m),
        ("create-environment", Some(m)) => cenv(m),
        ("delete-environment", Some(m)) => denv(m),
        ("create-collection", Some(m)) => ccol(m),
        ("create-configuration", Some(m)) => cconfig(m),
        ("crawler-configuration", Some(m)) => crawler(m),
        _ => println!("Not implemented yet; sorry!"),
    }
}
<|endoftext|>


<commit_before>#![feature(vec_push_all)]

use std::{cmp, mem};

use self::pair::*;
use self::Leading::*;

mod pair;

#[derive(Copy, Clone)]
enum Leading {
    Top,
    Bot,
}

impl Leading {
    pub fn switched(self) -> Leading {
        match self {
            Top => Bot,
            Bot => Top,
        }
    }
}

struct Problem {
    pairs: Box<[SPair]>,
}

impl Problem {
    fn solve(&self, max_depth: u32) {
        let mut depth = 0;
        let mut max_set_size = 0;

        let mut current_working_set = Vec::new();
        let mut next_working_set = Vec::new();

        current_working_set.push(VPair::new());

        while depth <= max_depth {
            println!("Now at depth {}", depth);
            max_set_size = cmp::max(max_set_size, current_working_set.len());

            for e in current_working_set.iter() {
                for p in self.pairs.iter() {
                    if let Some(ne) = e.apply(p) {
                        if ne.is_complete() {
                            println!("success!");
                            println!("max set: {}", max_set_size);
                            return;
                        }

                        next_working_set.push(ne);
                    }
                }
            }

            mem::swap(&mut current_working_set, &mut next_working_set);
            next_working_set.clear();

            depth += 1;
        }
        println!("no success");
    }
}

fn main() {
    let p = Problem::from([("010", "0"), ("0", "01"), ("101", "0100")].as_ref());
    // let p = Problem::from([("1", "101"), ("10", "00"), ("011", "11")].as_ref());
    // let p = Problem::from([("001", "0"), ("01", "011"), ("01", "101"), ("10", "001")].as_ref());
    p.solve(300);
}

impl<'a> From<&'a [(&'a str, &'a str)]> for Problem {
    fn from(s: &'a [(&'a str, &'a str)]) -> Problem {
        let mut pairs = Vec::with_capacity(s.len());

        for &p in s {
            pairs.push(p.into());
        }

        Problem {
            pairs: pairs.into_boxed_slice(),
        }
    }
}
<commit_msg>remove max size counting<commit_after>#![feature(vec_push_all)]

use std::{cmp, mem};

use self::pair::*;
use self::Leading::*;

mod pair;

#[derive(Copy, Clone)]
enum Leading {
    Top,
    Bot,
}

impl Leading {
    pub fn switched(self) -> Leading {
        match self {
            Top => Bot,
            Bot => Top,
        }
    }
}

struct Problem {
    pairs: Box<[SPair]>,
}

impl Problem {
    fn solve(&self, max_depth: u32) {
        let mut depth = 0;

        let mut current_working_set = Vec::new();
        let mut next_working_set = Vec::new();

        current_working_set.push(VPair::new());

        while depth <= max_depth {
            println!("Now at depth {}", depth);

            for e in current_working_set.iter() {
                for p in self.pairs.iter() {
                    if let Some(ne) = e.apply(p) {
                        if ne.is_complete() {
                            println!("success!");
                            return;
                        }

                        next_working_set.push(ne);
                    }
                }
            }

            mem::swap(&mut current_working_set, &mut next_working_set);
            next_working_set.clear();

            depth += 1;
        }
        println!("no success");
    }
}

fn main() {
    let p = Problem::from([("010", "0"), ("0", "01"), ("101", "0100")].as_ref());
    // let p = Problem::from([("1", "101"), ("10", "00"), ("011", "11")].as_ref());
    // let p = Problem::from([("001", "0"), ("01", "011"), ("01", "101"), ("10", "001")].as_ref());
    p.solve(300);
}

impl<'a> From<&'a [(&'a str, &'a str)]> for Problem {
    fn from(s: &'a [(&'a str, &'a str)]) -> Problem {
        let mut pairs = Vec::with_capacity(s.len());

        for &p in s {
            pairs.push(p.into());
        }

        Problem {
            pairs: pairs.into_boxed_slice(),
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate websocat;

extern crate futures;
extern crate tokio_core;
extern crate tokio_stdin_stdout;

extern crate env_logger;

#[cfg(feature="openssl-probe")]
extern crate openssl_probe;

#[macro_use]
extern crate structopt;

use structopt::StructOpt;

use tokio_core::reactor::Core;

use websocat::{spec, Options, SpecifierClass, WebsocatConfiguration};

type Result<T> = std::result::Result<T, Box<std::error::Error>>;

#[derive(StructOpt, Debug)]
#[structopt(
    after_help = "
Basic examples:
  Command-line websocket client:
    websocat ws://echo.websocket.org/

  Listen websocket and redirect it to a TCP port:
    websocat ws-l:127.0.0.1:8080 tcp:127.0.0.1:5678

  See more examples with the --long-help option

Short list of specifiers (see --long-help):
  ws:// wss:// - inetd: ws-listen: inetd-ws: tcp: tcp-l: ws-c:
  autoreconnect: reuse: mirror: threadedstdio: clogged:
  literal: literalreply: assert: udp-connect: open-async:
  readfile: writefile: open-fd: unix-connect: unix-listen:
  unix-dgram: abstract-connect: abstract-listen:
  exec: sh-c:
", usage="websocat [FLAGS] [OPTIONS] <s1> [s2]"
)]
struct Opt {
    /// First, listening/connecting specifier. See --long-help for info about specifiers.
    s1: String,
    /// Second, connecting specifier
    s2: Option<String>,

    #[structopt(
        short = "u",
        long = "unidirectional",
        help = "Inhibit copying data from right specifier to left"
    )]
    unidirectional: bool,
    #[structopt(
        short = "U",
        long = "unidirectional-reverse",
        help = "Inhibit copying data from left specifier to right"
    )]
    unidirectional_reverse: bool,

    #[structopt(
        long = "exit-on-eof",
        short = "E",
        help = "Close a data transfer direction if the other one reached EOF"
    )]
    exit_on_eof: bool,

    #[structopt(
        short = "t", long = "text", help = "Send text WebSocket messages instead of binary"
    )]
    websocket_text_mode: bool,

    #[structopt(long = "oneshot", help = "Serve only once. Not to be confused with -1 (--one-message)")]
    oneshot: bool,

    #[structopt(long = "long-help", help = "Show full help aboput specifiers and examples")]
    longhelp: bool,

    #[structopt(
        long = "dump-spec",
        help = "Instead of running, dump the specifiers representation to stdout"
    )]
    dumpspec: bool,

    #[structopt(long = "protocol", help = "Specify Sec-WebSocket-Protocol: header")]
    websocket_protocol: Option<String>,

    #[structopt(long = "udp-oneshot", help = "udp-listen: replies only one packet per client")]
    udp_oneshot_mode: bool,

    #[structopt(long = "unlink", help = "Unlink listening UNIX socket before binding to it")]
    unlink_unix_socket: bool,

    #[structopt(
        long = "exec-args",
        raw(allow_hyphen_values = r#"true"#),
        help = "Arguments for the `exec:` specifier. Must be the last option, everything after it gets into the exec args list."
    )]
    exec_args: Vec<String>,

    #[structopt(
        long = "ws-c-uri", help = "URI to use for ws-c: specifier", default_value = "ws://0.0.0.0/"
    )]
    ws_c_uri: String,

    #[structopt(
        long = "linemode-retain-newlines",
        help = "In --line mode, don't chop off trailing \\n from messages"
    )]
    linemode_retain_newlines: bool,

    #[structopt(
        short = "-l", long = "--line", help = "Make each WebSocket message correspond to one line"
    )]
    linemode: bool,

    #[structopt(long="origin",help="Add Origin HTTP header to websocket client request")]
    origin: Option<String>,

    #[structopt(
        long="header",
        short="H",
        help="Add custom HTTP header to websocket client request. Separate header name and value with a colon and optionally a single space. Can be used multiple times.",
        parse(try_from_str="interpret_custom_header"),
    )]
    custom_headers: Vec<(String,Vec<u8>)>,

    #[structopt(long="websocket-version", help="Override the Sec-WebSocket-Version value")]
    websocket_version: Option<String>,

    #[structopt(long="no-close", short="n", help="Don't send Close message to websocket on EOF")]
    websocket_dont_close: bool,

    #[structopt(
        short="1",
        long="one-message",
        help="Send and/or receive only one message. Use with --no-close and/or -u/-U.",
    )]
    one_message : bool,

    // TODO: -v --quiet
}

// TODO: make it byte-oriented/OsStr?
fn interpret_custom_header(x:&str) -> Result<(String,Vec<u8>)> {
    let colon = x.find(':');
    let colon = if let Some(colon) = colon { colon } else {
        Err("Argument to --header must contain `:` character")?
    };
    let hn = &x[0..colon];
    let mut hv = &x[colon+1..];
    if hv.chars().next() == Some(' ') {
        hv = &x[colon+2..];
    }
    Ok((hn.to_owned(), hv.as_bytes().to_vec()))
}

fn longhelp() {
    // TODO: promote first alias to title
    println!(
        r#"(see also the usual --help message)

Positional arguments to websocat are generally called specifiers.
Specifiers are ways to obtain a connection from some string representation (i.e. address).

Specifiers may be argumentless (like `mirror:`), can accept an argument (which
may be some path or socket address, like `tcp:`), or can accept a subspecifier
(like `reuse:` or `autoreconnect:`).

Here is the full list of specifier classes in this WebSocat build:

"#
    );

    fn help1(sc: &SpecifierClass) {
        let n = sc.get_name().replace("Class", "");
        let prefixes = sc
            .get_prefixes()
            .iter()
            .map(|x| format!("`{}`", x))
            .collect::<Vec<_>>()
            .join(", ");
        println!("### {}\n\n* {}", n, prefixes);

        let help =
            sc
            .help()
            //.lines()
            //.map(|x|format!("    {}",x))
            //.collect::<Vec<_>>()
            //.join("\n")
            ;
        println!("{}\n", help);
    }

    macro_rules! my {
        ($x:expr) => {
            help1(&$x);
        };
    }

    list_of_all_specifier_classes!(my);

    println!(
        r#"

TODO:
  sctp:
  ssl:

Final example just for fun: wacky mode

    websocat ws-c:ws-l:ws-c:- tcp:127.0.0.1:5678

Connect to a websocket using stdin/stdout as a transport,
then accept a websocket connection over the previous websocket used as a transport,
then connect to a websocket using previous step as a transport,
then forward resulting connection to the TCP port.

(Excercise to the reader: manage to make it actually connect to 5678).
"#
    );
}

fn run() -> Result<()> {
    if std::env::args().nth(1).unwrap_or_default() == "--long-help" {
        longhelp();
        return Ok(());
    }

    let mut cmd = Opt::from_args();

    if cmd.longhelp {
        longhelp();
        return Ok(());
    }

    if false
    //    || cmd.oneshot
    {
        Err("This mode is not implemented")?
    }

    #[cfg(feature="openssl-probe")] {
        openssl_probe::init_ssl_cert_env_vars();
    }

    let mut opts = {
        macro_rules! opts {
            ($($o:ident)*) => {
                Options {
                    $($o : cmd.$o,)*
                }
            };
        }
        opts!(
            websocket_text_mode
            websocket_protocol
            udp_oneshot_mode
            unidirectional
            unidirectional_reverse
            exit_on_eof
            oneshot
            unlink_unix_socket
            exec_args
            ws_c_uri
            linemode_retain_newlines
            origin
            custom_headers
            websocket_version
            websocket_dont_close
            one_message
        )
    };

    let (s1, s2) = if let Some(ref cmds2) = cmd.s2 {
        (spec(&cmd.s1)?, spec(cmds2)?)
    } else {
        if ! (cmd.s1.starts_with("ws://") || cmd.s1.starts_with("wss://")) {
            // TODO: message for -s server mode
            eprintln!("Specify ws:// or wss:// URI to connect to a websocket");
            Err("Invalid command-line parameters")?;
        }
        // Easy mode
        cmd.linemode = true;
        opts.websocket_text_mode = true;
        if opts.websocket_protocol == None {
            opts.websocket_protocol = Some("tcp".to_owned());
        }
        (spec("-")?, spec(&cmd.s1)?)
    };

    let mut websocat = WebsocatConfiguration { opts, s1, s2 };

    if cmd.linemode {
        use websocat::lints::AutoInstallLinemodeConcern::*;
        websocat = match websocat.auto_install_linemode() {
            Ok(x) => x,
            Err((NoWebsocket,_)) => Err("No websocket usage is specified. Use line2msg: and msg2line: specifiers manually if needed.")?,
            Err((MultipleWebsocket,_)) => Err("Multiple websocket usages are specified. Use line2msg: and msg2line: specifiers manually if needed.")?,
            Err((AlreadyLine,_)) => Err("Can't auto-insert msg2line:/line2msg: if you have already manually specified some of them")?,
        }
    }

    while let Some(concern) = websocat.get_concern() {
        use websocat::lints::ConfigurationConcern::*;
        if concern == StdinToStdout {
            if cmd.dumpspec {
                println!("cat mode");
                return Ok(());
            }

            // Degenerate mode: just copy stdin to stdout and call it a day
            ::std::io::copy(&mut ::std::io::stdin(), &mut ::std::io::stdout())?;
            return Ok(());
        }

        if concern == DegenerateMode {
            if cmd.dumpspec {
                println!("noop");
            }
            return Ok(());
        }

        if concern == StdioConflict {
            Err("Too many usages of stdin/stdout")?;
        }

        if concern == NeedsStdioReuser {
            eprintln!("Warning: replies on stdio get directed at random connected client");
            websocat = websocat.auto_install_reuser();
            continue;
        }

        if concern == NeedsStdioReuser2 {
            websocat = websocat.auto_install_reuser();
            continue;
        }

        if concern == MultipleReusers {
            eprintln!("Specifier dump: {:?} {:?}", websocat.s1, websocat.s2);
            Err("Multiple reusers is not allowed")?;
        }
        break;
    }

    if cmd.dumpspec {
        println!("{:?}", websocat.s1);
        println!("{:?}", websocat.s2);
        println!("{:?}", websocat.opts);
        return Ok(());
    }

    let mut core = Core::new()?;

    let prog = websocat.serve(
        core.handle(),
        std::rc::Rc::new(|e| {
            eprintln!("websocat: {}", e);
        }),
    );
    core.run(prog).map_err(|()| "error running".to_string())?;
    Ok(())
}

fn main() {
    env_logger::init();
    let r = run();

    if let Err(e) = r {
        eprintln!("websocat: {}", e);
        ::std::process::exit(1);
    }
}
<commit_msg>Start reworking the --help and --long-help messages<commit_after>#[macro_use]
extern crate websocat;

extern crate futures;
extern crate tokio_core;
extern crate tokio_stdin_stdout;

extern crate env_logger;

#[cfg(feature="openssl-probe")]
extern crate openssl_probe;

#[macro_use]
extern crate structopt;

use structopt::StructOpt;

use tokio_core::reactor::Core;

use websocat::{spec, Options, SpecifierClass, WebsocatConfiguration};

type Result<T> = std::result::Result<T, Box<std::error::Error>>;

#[derive(StructOpt, Debug)]
#[structopt(
    after_help = "
Basic examples:
  Command-line websocket client:
    websocat ws://echo.websocket.org/

  Listen websocket and redirect it to a TCP port:
    websocat ws-l:127.0.0.1:8080 tcp:127.0.0.1:5678

  See more examples with the --long-help option

Short list of specifiers (see --long-help):
  ws:// wss:// - inetd: ws-listen: inetd-ws: tcp: tcp-l: ws-c:
  autoreconnect: reuse: mirror: threadedstdio: clogged:
  literal: literalreply: assert: udp-connect: open-async:
  readfile: writefile: open-fd: unix-connect: unix-listen:
  unix-dgram: abstract-connect: abstract-listen:
  exec: sh-c:
", usage="websocat [FLAGS] [OPTIONS] <addr1>          (simple mode)\n    websocat [FLAGS] [OPTIONS] <addr1> <addr2>  (advanced mode)"
)]
struct Opt {
    /// In simple mode, WebSocket URL to connect.
    /// In advanced mode first address (there are many kinds of addresses) to use.
    /// See --long-help for info about address types.
    /// If this is an address for listening, it will try serving multiple connections.
    addr1: String,
    /// In advanced mode, second address to connect.
    /// If this is an address for listening, it will accept only one connection.
    addr2: Option<String>,

    #[structopt(
        short = "u",
        long = "unidirectional",
        help = "Inhibit copying data from right specifier to left"
    )]
    unidirectional: bool,
    #[structopt(
        short = "U",
        long = "unidirectional-reverse",
        help = "Inhibit copying data from left specifier to right"
    )]
    unidirectional_reverse: bool,

    #[structopt(
        long = "exit-on-eof",
        short = "E",
        help = "Close a data transfer direction if the other one reached EOF"
    )]
    exit_on_eof: bool,

    #[structopt(
        short = "t", long = "text", help = "Send text WebSocket messages instead of binary"
    )]
    websocket_text_mode: bool,

    #[structopt(long = "oneshot", help = "Serve only once. Not to be confused with -1 (--one-message)")]
    oneshot: bool,

    #[structopt(
        long = "long-help",
        help = "Show the full help message, including list of all address types and advanced flags and options which are normally hidden from help (they have `[A]` marker in their help messages).",
    )]
    longhelp: bool,

    #[structopt(short = "h", long="help", help="Short short help message")]
    shorthelp: bool,

    #[structopt(
        long = "dump-spec",
        help = "[A] Instead of running, dump the specifiers representation to stdout",
    )]
    dumpspec: bool,

    #[structopt(long = "protocol", help = "Specify Sec-WebSocket-Protocol: header")]
    websocket_protocol: Option<String>,

    #[structopt(
        long = "udp-oneshot",
        help = "[A] udp-listen: replies only one packet per client",
    )]
    udp_oneshot_mode: bool,

    #[structopt(
        long = "unlink",
        help = "[A] Unlink listening UNIX socket before binding to it",
    )]
    unlink_unix_socket: bool,

    #[structopt(
        long = "exec-args",
        raw(allow_hyphen_values = r#"true"#),
        help = "[A] Arguments for the `exec:` specifier. Must be the last option, everything after it gets into the exec args list."
    )]
    exec_args: Vec<String>,

    #[structopt(
        long = "ws-c-uri",
        help = "[A] URI to use for ws-c: specifier",
        default_value = "ws://0.0.0.0/",
    )]
    ws_c_uri: String,

    #[structopt(
        long = "linemode-retain-newlines",
        help = "[A] In --line mode, don't chop off trailing \\n from messages",
    )]
    linemode_retain_newlines: bool,

    #[structopt(
        short = "-l", long = "--line", help = "Make each WebSocket message correspond to one line"
    )]
    linemode: bool,

    #[structopt(long="origin",help="Add Origin HTTP header to websocket client request")]
    origin: Option<String>,

    #[structopt(
        long="header",
        short="H",
        help="Add custom HTTP header to websocket client request. Separate header name and value with a colon and optionally a single space. Can be used multiple times.",
        parse(try_from_str="interpret_custom_header"),
    )]
    custom_headers: Vec<(String,Vec<u8>)>,

    #[structopt(long="websocket-version", help="Override the Sec-WebSocket-Version value")]
    websocket_version: Option<String>,

    #[structopt(long="no-close", short="n", help="Don't send Close message to websocket on EOF")]
    websocket_dont_close: bool,

    #[structopt(
        short="1",
        long="one-message",
        help="Send and/or receive only one message. Use with --no-close and/or -u/-U.",
    )]
    one_message : bool,

    // TODO: -v --quiet
}

// TODO: make it byte-oriented/OsStr?
fn interpret_custom_header(x:&str) -> Result<(String,Vec<u8>)> {
    let colon = x.find(':');
    let colon = if let Some(colon) = colon { colon } else {
        Err("Argument to --header must contain `:` character")?
    };
    let hn = &x[0..colon];
    let mut hv = &x[colon+1..];
    if hv.chars().next() == Some(' ') {
        hv = &x[colon+2..];
    }
    Ok((hn.to_owned(), hv.as_bytes().to_vec()))
}

fn shorthelp() {
    //use std::io::Write;
    use std::io::{BufRead,BufReader};
    let mut b = vec![];
    if let Err(_) = Opt::clap().write_help(&mut b) {
        eprintln!("Error displaying the help message");
    }
    let mut lines_to_display = vec![];
    let mut do_display = true;
    #[allow(non_snake_case)]
    let mut special_A_permit = false;
    for l in BufReader::new(&b[..]).lines() {
        if let Ok(l) = l {
            if l.trim().starts_with("--long-help") {
                special_A_permit = true;
            }
            if l.contains("[A]") {
                if special_A_permit {
                    special_A_permit = false;
                } else {
                    do_display = false;
                    if l.trim().starts_with("[A]") {
                        // Also retroactively retract the previous line
                        let nl = lines_to_display.len()-1;
                        lines_to_display.truncate(nl);
                    }
                }
            } else if l.trim().starts_with("-") {
                do_display = true;
            } else if l.trim().starts_with("--") {
                do_display = true;
            } else if l.is_empty() {
                do_display = true;
            }
            let mut additional_line = None;

            if l == "FLAGS:" {
                additional_line=Some(format!("    (some flags are hidden, see --long-help)"));
            }
            if l == "OPTIONS:" {
                additional_line=Some(format!("    (some options are hidden, see --long-help)"));
            }

            if do_display {
                lines_to_display.push(l);
                if let Some(x) = additional_line {
                    lines_to_display.push(x);
                }
            }
        }
    }
    for l in lines_to_display {
        println!("{}", l);
    }
    //let _ = std::io::stdout().write_all(&b);
}

fn longhelp() {
    //let q = Opt::from_iter(vec!["-"]);
    let mut a = Opt::clap();

    let _ = a.print_help();

    // TODO: promote first alias to title
    println!(
        r#"

Positional arguments to websocat are generally called specifiers.
Specifiers are ways to obtain a connection from some string representation (i.e. address).

Specifiers may be argumentless (like `mirror:`), can accept an argument (which
may be some path or socket address, like `tcp:`), or can accept a subspecifier
(like `reuse:` or `autoreconnect:`).

Here is the full list of specifier classes in this WebSocat build:

"#
    );

    fn help1(sc: &SpecifierClass) {
        let n = sc.get_name().replace("Class", "");
        let prefixes = sc
            .get_prefixes()
            .iter()
            .map(|x| format!("`{}`", x))
            .collect::<Vec<_>>()
            .join(", ");
        println!("### {}\n\n* {}", n, prefixes);

        let help =
            sc
            .help()
            //.lines()
            //.map(|x|format!("    {}",x))
            //.collect::<Vec<_>>()
            //.join("\n")
            ;
        println!("{}\n", help);
    }

    macro_rules! my {
        ($x:expr) => {
            help1(&$x);
        };
    }

    list_of_all_specifier_classes!(my);

    println!(
        r#"

TODO:
  sctp:
  ssl:

Final example just for fun: wacky mode

    websocat ws-c:ws-l:ws-c:- tcp:127.0.0.1:5678

Connect to a websocket using stdin/stdout as a transport,
then accept a websocket connection over the previous websocket used as a transport,
then connect to a websocket using previous step as a transport,
then forward resulting connection to the TCP port.

(Excercise to the reader: manage to make it actually connect to 5678).
"#
    );
}

fn run() -> Result<()> {
    if std::env::args().nth(1).unwrap_or_default() == "--long-help" {
        longhelp();
        return Ok(());
    }
    if vec!["-?","-h", "--help"].contains(&std::env::args().nth(1).unwrap_or_default().as_str()) {
        shorthelp();
        return Ok(());
    }

    let mut cmd = Opt::from_args();

    if cmd.longhelp {
        longhelp();
        return Ok(());
    }

    if cmd.shorthelp {
        shorthelp();
        return Ok(());
    }

    if false
    //    || cmd.oneshot
    {
        Err("This mode is not implemented")?
    }

    #[cfg(feature="openssl-probe")] {
        openssl_probe::init_ssl_cert_env_vars();
    }

    let mut opts = {
        macro_rules! opts {
            ($($o:ident)*) => {
                Options {
                    $($o : cmd.$o,)*
                }
            };
        }
        opts!(
            websocket_text_mode
            websocket_protocol
            udp_oneshot_mode
            unidirectional
            unidirectional_reverse
            exit_on_eof
            oneshot
            unlink_unix_socket
            exec_args
            ws_c_uri
            linemode_retain_newlines
            origin
            custom_headers
            websocket_version
            websocket_dont_close
            one_message
        )
    };

    let (s1, s2) = if let Some(ref cmds2) = cmd.addr2 {
        (spec(&cmd.addr1)?, spec(cmds2)?)
    } else {
        if ! (cmd.addr1.starts_with("ws://") || cmd.addr1.starts_with("wss://")) {
            // TODO: message for -s server mode
            eprintln!("Specify ws:// or wss:// URI to connect to a websocket");
            Err("Invalid command-line parameters")?;
        }
        // Easy mode
        cmd.linemode = true;
        opts.websocket_text_mode = true;
        if opts.websocket_protocol == None {
            opts.websocket_protocol = Some("tcp".to_owned());
        }
        (spec("-")?, spec(&cmd.addr1)?)
    };

    let mut websocat = WebsocatConfiguration { opts, s1, s2 };

    if cmd.linemode {
        use websocat::lints::AutoInstallLinemodeConcern::*;
        websocat = match websocat.auto_install_linemode() {
            Ok(x) => x,
            Err((NoWebsocket,_)) => Err("No websocket usage is specified. Use line2msg: and msg2line: specifiers manually if needed.")?,
            Err((MultipleWebsocket,_)) => Err("Multiple websocket usages are specified. Use line2msg: and msg2line: specifiers manually if needed.")?,
            Err((AlreadyLine,_)) => Err("Can't auto-insert msg2line:/line2msg: if you have already manually specified some of them")?,
        }
    }

    while let Some(concern) = websocat.get_concern() {
        use websocat::lints::ConfigurationConcern::*;
        if concern == StdinToStdout {
            if cmd.dumpspec {
                println!("cat mode");
                return Ok(());
            }

            // Degenerate mode: just copy stdin to stdout and call it a day
            ::std::io::copy(&mut ::std::io::stdin(), &mut ::std::io::stdout())?;
            return Ok(());
        }

        if concern == DegenerateMode {
            if cmd.dumpspec {
                println!("noop");
            }
            return Ok(());
        }

        if concern == StdioConflict {
            Err("Too many usages of stdin/stdout")?;
        }

        if concern == NeedsStdioReuser {
            eprintln!("Warning: replies on stdio get directed at random connected client");
            websocat = websocat.auto_install_reuser();
            continue;
        }

        if concern == NeedsStdioReuser2 {
            websocat = websocat.auto_install_reuser();
            continue;
        }

        if concern == MultipleReusers {
            eprintln!("Specifier dump: {:?} {:?}", websocat.s1, websocat.s2);
            Err("Multiple reusers is not allowed")?;
        }
        break;
    }

    if cmd.dumpspec {
        println!("{:?}", websocat.s1);
        println!("{:?}", websocat.s2);
        println!("{:?}", websocat.opts);
        return Ok(());
    }

    let mut core = Core::new()?;

    let prog = websocat.serve(
        core.handle(),
        std::rc::Rc::new(|e| {
            eprintln!("websocat: {}", e);
        }),
    );
    core.run(prog).map_err(|()| "error running".to_string())?;
    Ok(())
}

fn main() {
    env_logger::init();
    let r = run();

    if let Err(e) = r {
        eprintln!("websocat: {}", e);
        ::std::process::exit(1);
    }
}
<|endoftext|>


<commit_before>// rust version of breakfast tool
// BreakFast is a toolkit for detecting chromosomal rearrangements
// based on RNA-seq data.

use std::env;
use std::process::Command;

#[macro_use]
extern crate clap;
extern crate shells;
extern crate bio;

mod cli;
mod lib;
// struct for having breakfast options
struct BfOptions {
    anchor_len :    i32,
    max_frag_len:   i32,
    min_mapq:       i32,
    orientation:    &'static str,
    all_reads:      bool,
    discard_duplicates: &'static str,
    min_reads:      &'static str,
    freq_above:     i32,
}

fn main() {
  let defaults = BfOptions{ anchor_len : 0,
                            max_frag_len: 5000,
                            min_mapq: 15,
                            orientation:  "fr",
                            all_reads:  false,
                            discard_duplicates: "both-ends",
                            min_reads:    "0-0-0",
                            freq_above: 0};

  let mut anchor_len: i32   = defaults.anchor_len;
  let mut max_frag_len: i32 = defaults.max_frag_len;
  let mut min_mapq: i32     = defaults.min_mapq;
  let mut orientation       = String::from(defaults.orientation);
  let mut all_reads: bool   = defaults.all_reads;
  let mut discard_duplicates = String::from(defaults.discard_duplicates);
  let mut min_reads     = String::from(defaults.min_reads);
  let mut freq_above: i32 = defaults.freq_above;

  //arguments from src/cli.rs
  let matches = cli::build_cli().get_matches();
  if matches.is_present("anchor-len") {
      anchor_len = matches.value_of("anchor-len").unwrap().parse::<i32>().unwrap();
  }

  if matches.is_present("max-frag-len") {
      max_frag_len = matches.value_of("max-frag-len").unwrap().parse::<i32>().unwrap();
  }

  if matches.is_present("min-mapq") {
      min_mapq = matches.value_of("min-mapq").unwrap().parse::<i32>().unwrap();
  }

  if matches.is_present("orientation") {
      orientation = String::from(matches.value_of("orientation").unwrap());
  }

  if matches.is_present("all-reads") {
      all_reads = true;
  }

  if matches.is_present("discard-duplicates") {
      discard_duplicates = String::from(matches.value_of("discard-duplicates").unwrap());
  }

  if matches.is_present("min-reads") {
      min_reads = String::from(matches.value_of("min-reads").unwrap());
  }

  if matches.is_present("freq-above") {
      freq_above = matches.value_of("freq-above").unwrap().parse::<i32>().unwrap();
  }

  if let ("detect", Some(detect)) = matches.subcommand() {
      let bam_file = String::from(detect.value_of("bam_file").unwrap());
      let genome   = String::from(detect.value_of("genome").unwrap());
      let out_prefix  = String::from(detect.value_of("out_prefix").unwrap());

      detectf(bam_file, out_prefix, max_frag_len, min_mapq, orientation);
  }

  if let ("detectspecific", Some(detectspecific)) = matches.subcommand() {
      let bam_file = String::from(detectspecific.value_of("bam_file").unwrap());
      let genome   = String::from(detectspecific.value_of("genome").unwrap());
      let out_prefix  = String::from(detectspecific.value_of("out_prefix").unwrap());
      let donors  = String::from(detectspecific.value_of("donors").unwrap());
      let acceptors  = String::from(detectspecific.value_of("acceptors").unwrap());
  }

  println!("Hello, world!");
}

// DETECT //
//======= //

fn detectf(sam_path: String, out_prefix: String, max_frag_len: i32,
	min_mapq: i32, orientation: String) {
  println!("BreakFast DETECT Function Called");
  println!("{:?}\t{:?}\t{:?}\t{:?}\t{:?}", sam_path, out_prefix, max_frag_len, min_mapq, orientation);

  let extn = String::from(".discordant_pairs.tsv.gz");
  let out  = out_prefix + &extn;

  lib::mkdir(&out);
  println!("Searching for discordant read pairs ...");

  let lines = Command::new("sam")
          .arg("discordant")
          .arg("pairs")
          .arg("-q")
          .arg(&min_mapq.to_string())
          .arg(&sam_path)
          .arg(&max_frag_len.to_string())
          //.arg("|")
          //.arg("sort")
          //.arg("-k1,1")
          //.arg("-T")
          //.arg(&out)
          .spawn()
          .expect("SAM failed running");

      println!("{:?}", lines.stdout);
}
<commit_msg>fn detect_discordant_pairs working<commit_after>// rust version of breakfast tool
// BreakFast is a toolkit for detecting chromosomal rearrangements
// based on RNA-seq data.

use std::env;
use std::mem;
use std::path::Path;
use std::process::Command;

#[macro_use]
extern crate clap;
#[macro_use]
extern crate shells;
#[macro_use]
extern crate bio;
#[macro_use]
extern crate regex;

use regex::Regex;

mod cli;
mod lib;
// struct for having breakfast options
struct BfOptions {
    anchor_len :    i32,
    max_frag_len:   i32,
    min_mapq:       i32,
    orientation:    &'static str,
    all_reads:      bool,
    discard_duplicates: &'static str,
    min_reads:      &'static str,
    freq_above:     i32,
}

fn main() {
  let defaults = BfOptions{ anchor_len : 0,
                            max_frag_len: 5000,
                            min_mapq: 15,
                            orientation:  "fr",
                            all_reads:  false,
                            discard_duplicates: "both-ends",
                            min_reads:    "0-0-0",
                            freq_above: 0};

  let mut anchor_len: i32   = defaults.anchor_len;
  let mut max_frag_len: i32 = defaults.max_frag_len;
  let mut min_mapq: i32     = defaults.min_mapq;
  let mut orientation       = String::from(defaults.orientation);
  let mut all_reads: bool   = defaults.all_reads;
  let mut discard_duplicates = String::from(defaults.discard_duplicates);
  let mut min_reads     = String::from(defaults.min_reads);
  let mut freq_above: i32 = defaults.freq_above;

  //arguments from src/cli.rs
  let matches = cli::build_cli().get_matches();
  /*
  if matches.is_present("anchor-len") {
      anchor_len = matches.value_of("anchor-len").unwrap().parse::<i32>().unwrap();
  }

  if matches.is_present("max-frag-len") {
      max_frag_len = matches.value_of("max-frag-len").unwrap().parse::<i32>().unwrap();
  }

  if matches.is_present("min-mapq") {
      min_mapq = matches.value_of("min-mapq").unwrap().parse::<i32>().unwrap();
  }

  if matches.is_present("all-reads") {
      all_reads = true;
  }

  if matches.is_present("discard-duplicates") {
      discard_duplicates = String::from(matches.value_of("discard-duplicates").unwrap());
  }

  if matches.is_present("min-reads") {
      min_reads = String::from(matches.value_of("min-reads").unwrap());
  }

  if matches.is_present("freq-above") {
      freq_above = matches.value_of("freq-above").unwrap().parse::<i32>().unwrap();
  } */

  if let ("detect", Some(detect)) = matches.subcommand() {
      let bam_file = String::from(detect.value_of("bam_file").unwrap());
      let genome   = String::from(detect.value_of("genome").unwrap());
      let out_prefix  = String::from(detect.value_of("out_prefix").unwrap());

      if detect.is_present("orientation") {
          orientation = String::from(detect.value_of("orientation").unwrap());
      }
      detect_discordant_pairs(bam_file, out_prefix, max_frag_len, min_mapq, orientation);
  }

  if let ("detectspecific", Some(detectspecific)) = matches.subcommand() {
      let bam_file = String::from(detectspecific.value_of("bam_file").unwrap());
      let genome   = String::from(detectspecific.value_of("genome").unwrap());
      let out_prefix  = String::from(detectspecific.value_of("out_prefix").unwrap());
      let donors  = String::from(detectspecific.value_of("donors").unwrap());
      let acceptors  = String::from(detectspecific.value_of("acceptors").unwrap());
  }

  println!("Hello, world!");
}

// DETECT //
//======= //

fn detect_discordant_pairs(sam_path: String, out_prefix: String, max_frag_len: i32,
	min_mapq: i32, orientation: String) {
  println!("{:?}\t{:?}\t{:?}\t{:?}\t{:?}", sam_path, out_prefix, max_frag_len, min_mapq, orientation);

  let mut N = 0;
  let tmp = out_prefix.clone();
  let given_path = Path::new(&tmp);
  let mut sort_tmp_dir = Path::new("./");
  if given_path.is_absolute()  {
        sort_tmp_dir = given_path.parent().unwrap();
  }

  let extn = String::from(".discordant_pairs.tsv.gz");
  let out  = out_prefix + &extn;

  lib::mkdir(&out);
  println!("Searching for discordant read pairs ...");

  let (code, stdout, stderr) = sh!("sam discordant pairs --min-mapq={} {} {} | sort -k1,1 -T {:?}", min_mapq, sam_path, max_frag_len, sort_tmp_dir);

  let mut prev : Vec<&str> = Vec::new();
  for line in stdout.lines() {
      let mut cols: Vec<&str> = line.split('\t').collect();
      if cols.len() < 9 { continue; }

      let r1 = Regex::new(r"N").unwrap();
      let r2 = Regex::new(r"S").unwrap();

      if r1.is_match(cols[5]) || r2.is_match(cols[5]) { continue; }
      else if cols[0].ends_with("/1") || cols[0].ends_with("/2") {
          let tmp : Vec<&str> = cols[0].split('/').collect();
          cols[0] = tmp[0];
      }
      if prev.len() <= 0 { prev = cols.clone(); }
      else if prev.len() > 0 && cols[0] != prev[0] { prev = cols.clone(); }

      let flags = &cols[1].parse::<i32>().unwrap();
      let mut chr   = String::from(cols[2]);
      let mut mchr  = String::from(prev[2]);
      let mut strand = '-';
      let mut mstrand = '-';
      let mut pos  = cols[3].parse::<i32>().unwrap();
      let mut mpos = prev[3].parse::<i32>().unwrap();
      let mut rlen = cols[9].clone().len() as i32;
      let mut mrlen= prev[9].clone().len() as i32;

      if chr.starts_with("chr") {  chr = chr; }
      else { let prefix = String::from("chr"); chr = prefix + &chr;}

      if mchr.starts_with("chr") {  chr = chr ;}
      else { let prefix = String::from("chr"); mchr = prefix + &mchr;}

      if chr.contains("chrM") || mchr.contains("chrM") { continue;}

      if orientation == "fr" {
        if chr > mchr || (chr == mchr && pos > mpos) {
          mem::swap(&mut chr, &mut mchr);
          mem::swap(&mut pos, &mut mpos);
          mem::swap(&mut rlen, &mut mrlen);
          mem::swap(&mut strand, &mut mstrand);
        }
        if mstrand == '+' { mstrand = '-';}
        else { mstrand = '+'; }
      }

      else if orientation == "rf" {
        if chr > mchr || (chr == mchr && pos > mpos) {
          mem::swap(&mut chr, &mut mchr);
          mem::swap(&mut pos, &mut mpos);
          mem::swap(&mut rlen, &mut mrlen);
          mem::swap(&mut strand, &mut mstrand);
        }
        if strand == '+' { strand = '-';}
        else { strand = '+'; }
      }

      else if orientation == "ff" {
        if chr > mchr || (chr == mchr && pos > mpos) {
          mem::swap(&mut chr, &mut mchr);
          mem::swap(&mut pos, &mut mpos);
          mem::swap(&mut rlen, &mut mrlen);

          if mstrand == '-' { mstrand = '+';} else { mstrand = '-'; }
          if strand  == '-' { strand  = '+';} else { strand  = '-'; }
          mem::swap(&mut strand, &mut mstrand);
        }
      } else { panic!("Unsupported read orientation detected."); }

      if strand  == '-' { pos  +=  rlen - 1;}
      if mstrand == '-' { mpos += mrlen - 1;}

      println!("{}\t{}\t{}\t{}\t{}\t{}", chr, strand, pos, mchr, mstrand, mpos);
      N += 1;
    }
    println!("Found {:?} discordant mate pairs.", N);
}
<|endoftext|>