<commit_before>#![feature(iter_arith)]
#![feature(convert, fs_mode)]
#![feature(slice_splits, vec_resize)]

extern crate ansi_term;
extern crate datetime;
extern crate getopts;
extern crate libc;
extern crate locale;
extern crate natord;
extern crate num_cpus;
extern crate number_prefix;
extern crate pad;
extern crate scoped_threadpool;
extern crate term_grid;
extern crate unicode_width;
extern crate users;

#[cfg(feature="git")]
extern crate git2;

use std::env;
use std::path::{Component, Path};
use std::process;

use dir::Dir;
use file::File;
use options::{Options, View};

mod colours;
mod column;
mod dir;
mod feature;
mod file;
mod filetype;
mod options;
mod output;
mod term;

#[cfg(not(test))]
struct Exa {
    options: Options,
}

#[cfg(not(test))]
impl Exa {
    fn new(options: Options) -> Exa {
        Exa { options: options }
    }

    fn run(&mut self, args_file_names: &[String]) {
        let mut files = Vec::new();
        let mut dirs = Vec::new();

        for file_name in args_file_names.iter() {
            match File::from_path(Path::new(&file_name), None) {
                Err(e) => {
                    println!("{}: {}", file_name, e);
                },
                Ok(f) => {
                    if f.is_directory() && !self.options.dir_action.treat_dirs_as_files() {
                        match f.to_dir(self.options.should_scan_for_git()) {
                            Ok(d) => dirs.push(d),
                            Err(e) => println!("{}: {}", file_name, e),
                        }
                    }
                    else {
                        files.push(f);
                    }
                },
            }
        }

        let any_files = files.is_empty();
        self.print_files(None, files);

        let is_only_dir = dirs.len() == 1;
        self.print_dirs(dirs, any_files, is_only_dir);
    }

    fn print_dirs(&self, dir_files: Vec<Dir>, mut first: bool, is_only_dir: bool) {
        for dir in dir_files {

            // Put a gap between directories, or between the list of files and the
            // first directory.
            if first {
                first = false;
            }
            else {
                print!("\n");
            }

            if !is_only_dir {
                println!("{}:", dir.path.display());
            }

            let mut children = Vec::new();
            for file in dir.files() {
                match file {
                    Ok(file)       => children.push(file),
                    Err((path, e)) => println!("[{}: {}]", path.display(), e),
                }
            };

            self.options.filter_files(&mut children);
            self.options.sort_files(&mut children);

            if let Some(recurse_opts) = self.options.dir_action.recurse_options() {
                let depth = dir.path.components().filter(|&c| c != Component::CurDir).count() + 1;
                if !recurse_opts.tree && !recurse_opts.is_too_deep(depth) {

                    let mut child_dirs = Vec::new();
                    for child_dir in children.iter().filter(|f| f.is_directory()) {
                        match child_dir.to_dir(false) {
                            Ok(d)  => child_dirs.push(d),
                            Err(e) => println!("{}: {}", child_dir.path.display(), e),
                        }
                    }

                    self.print_files(Some(&dir), children);

                    if !child_dirs.is_empty() {
                        self.print_dirs(child_dirs, false, false);
                    }

                    continue;
                }
            }

            self.print_files(Some(&dir), children);

        }
    }

    fn print_files(&self, dir: Option<&Dir>, files: Vec<File>) {
        match self.options.view {
            View::Grid(g)         => g.view(&files),
            View::Details(d)      => d.view(dir, files),
            View::GridDetails(gd) => gd.view(dir, &files),
            View::Lines(l)        => l.view(&files),
        }
    }
}

#[cfg(not(test))]
fn main() {
    let args: Vec<String> = env::args().skip(1).collect();

    match Options::getopts(&args) {
        Ok((options, paths)) => {
            let mut exa = Exa::new(options);
            exa.run(&paths);
        },
        Err(e) => {
            println!("{}", e);
            process::exit(e.error_code());
        },
    };
}
<commit_msg>It's hardly worth giving Exa its own constructor<commit_after>#![feature(iter_arith)]
#![feature(convert, fs_mode)]
#![feature(slice_splits, vec_resize)]

extern crate ansi_term;
extern crate datetime;
extern crate getopts;
extern crate libc;
extern crate locale;
extern crate natord;
extern crate num_cpus;
extern crate number_prefix;
extern crate pad;
extern crate scoped_threadpool;
extern crate term_grid;
extern crate unicode_width;
extern crate users;

#[cfg(feature="git")]
extern crate git2;

use std::env;
use std::path::{Component, Path};
use std::process;

use dir::Dir;
use file::File;
use options::{Options, View};

mod colours;
mod column;
mod dir;
mod feature;
mod file;
mod filetype;
mod options;
mod output;
mod term;

struct Exa {
    options: Options,
}

impl Exa {
    fn run(&mut self, args_file_names: &[String]) {
        let mut files = Vec::new();
        let mut dirs = Vec::new();

        for file_name in args_file_names.iter() {
            match File::from_path(Path::new(&file_name), None) {
                Err(e) => {
                    println!("{}: {}", file_name, e);
                },
                Ok(f) => {
                    if f.is_directory() && !self.options.dir_action.treat_dirs_as_files() {
                        match f.to_dir(self.options.should_scan_for_git()) {
                            Ok(d) => dirs.push(d),
                            Err(e) => println!("{}: {}", file_name, e),
                        }
                    }
                    else {
                        files.push(f);
                    }
                },
            }
        }

        let any_files = files.is_empty();
        self.print_files(None, files);

        let is_only_dir = dirs.len() == 1;
        self.print_dirs(dirs, any_files, is_only_dir);
    }

    fn print_dirs(&self, dir_files: Vec<Dir>, mut first: bool, is_only_dir: bool) {
        for dir in dir_files {

            // Put a gap between directories, or between the list of files and the
            // first directory.
            if first {
                first = false;
            }
            else {
                print!("\n");
            }

            if !is_only_dir {
                println!("{}:", dir.path.display());
            }

            let mut children = Vec::new();
            for file in dir.files() {
                match file {
                    Ok(file)       => children.push(file),
                    Err((path, e)) => println!("[{}: {}]", path.display(), e),
                }
            };

            self.options.filter_files(&mut children);
            self.options.sort_files(&mut children);

            if let Some(recurse_opts) = self.options.dir_action.recurse_options() {
                let depth = dir.path.components().filter(|&c| c != Component::CurDir).count() + 1;
                if !recurse_opts.tree && !recurse_opts.is_too_deep(depth) {

                    let mut child_dirs = Vec::new();
                    for child_dir in children.iter().filter(|f| f.is_directory()) {
                        match child_dir.to_dir(false) {
                            Ok(d)  => child_dirs.push(d),
                            Err(e) => println!("{}: {}", child_dir.path.display(), e),
                        }
                    }

                    self.print_files(Some(&dir), children);

                    if !child_dirs.is_empty() {
                        self.print_dirs(child_dirs, false, false);
                    }

                    continue;
                }
            }

            self.print_files(Some(&dir), children);

        }
    }

    fn print_files(&self, dir: Option<&Dir>, files: Vec<File>) {
        match self.options.view {
            View::Grid(g)         => g.view(&files),
            View::Details(d)      => d.view(dir, files),
            View::GridDetails(gd) => gd.view(dir, &files),
            View::Lines(l)        => l.view(&files),
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().skip(1).collect();

    match Options::getopts(&args) {
        Ok((options, paths)) => {
            let mut exa = Exa { options: options };
            exa.run(&paths);
        },
        Err(e) => {
            println!("{}", e);
            process::exit(e.error_code());
        },
    };
}
<|endoftext|>


<commit_before>extern crate ansi_term;
extern crate argparse;
extern crate hyper;
extern crate libsnatch;

use ansi_term::Colour::{Green, Yellow, Red};
use argparse::{ArgumentParser, Store, StoreTrue};
use hyper::client::Client;
use libsnatch::{Bytes, Chunks};
use libsnatch::client::GetResponse;
use libsnatch::contentlength::GetContentLength;
use libsnatch::download::download_chunks;
use libsnatch::http_version::ValidateHttpVersion;
use libsnatch::write::write_file;
use std::fs::File;
use std::io;
use std::sync::{Arc, Mutex};
use std::path::Path;
use std::process::exit;

fn main() {

    let mut file = String::from("");
    let mut threads: usize = 4;
    let mut url = String::from("");
    let mut verbose = false;

    {
        let mut argparse = ArgumentParser::new();
        argparse.set_description("Snatch, a simple, fast and interruptable download accelerator, \
                                  written in Rust.");
        argparse.refer(&mut file)
            .add_option(&["-f", "--file"],
                        Store,
                        "The local file to save the remote content file");
        argparse.refer(&mut threads)
            .add_option(&["-t", "--threads"],
                        Store,
                        "Number of threads available to download");
        argparse.refer(&mut url)
            .add_option(&["-u", "--url"], Store, "Remote content URL to download")
            .required();
        argparse.refer(&mut verbose)
            .add_option(&["-v", "--verbose"], StoreTrue, "Verbose mode");
        argparse.parse_args_or_exit();
    }

    let hyper_client = Client::new();

    // Get the first response from the server
    let client_response = hyper_client.get_head_response(&url).unwrap();

    print!("# Waiting a response from the remote server... ");

    if !client_response.version.greater_than_http_11() {
        println!("{}",
                 Yellow.bold()
                     .paint("OK (HTTP version <= 1.0 detected)"));
    } else {
        println!("{}", Green.bold().paint("OK !"));
    }

    // If no filename has been given, infer it
    if file == "" {
        file = match url.split('/').last() {
            Some(filename) => String::from(filename),
            None => String::from("index.html"),
        }
    }

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

    if local_path.exists() {
        if local_path.is_dir() {
            panic!(Red.bold()
                .paint("[ERROR] The local path to store the remote content is already exists, \
                        and is a directory!"));
        }
        println!("{}",
                 Red.bold()
                     .paint("[WARNING] The path to store the file already exists! Do you want \
                             to override it? [y/N]"));
        {
            let mut user_input = String::new();
            io::stdin()
                .read_line(&mut user_input)
                .ok()
                .expect("[ERROR] Couldn't read line!");
            user_input = String::from(user_input.trim());
            if !(user_input == "y" || user_input == "Y") {
                exit(0);
            }
        }
    }

    let remote_content_length = match client_response.headers.get_content_length() {
        Some(remote_content_length) => remote_content_length,
        None => {
            println!("{}",
                     Red.bold()
                         .paint("[ERROR] Cannot get the content length of the remote content, \
                                 from the server."));
            exit(1);
        }
    };

    println!("# Remote content length: {:?} MB",
             (remote_content_length / 1000000) as Bytes);

    let mut core_chunks = Chunks::with_capacity(threads);

    for _ in 0..threads {
        core_chunks.push(Vec::new());
    }

    let mut shared_chunks = Arc::new(Mutex::new(core_chunks));

    download_chunks(remote_content_length,
                    &mut shared_chunks,
                    threads as u64,
                    &url);

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

    match write_file(&mut local_file, &shared_chunks) {
        Ok(()) => println!("{}", Green.bold().paint("Chunks have been successfuly saved!")),
        Err(error) => println!("[ERROR] {}", error),
    }

}
<commit_msg>Correct syntax to check for empty strings<commit_after>extern crate ansi_term;
extern crate argparse;
extern crate hyper;
extern crate libsnatch;

use ansi_term::Colour::{Green, Yellow, Red};
use argparse::{ArgumentParser, Store, StoreTrue};
use hyper::client::Client;
use libsnatch::{Bytes, Chunks};
use libsnatch::client::GetResponse;
use libsnatch::contentlength::GetContentLength;
use libsnatch::download::download_chunks;
use libsnatch::http_version::ValidateHttpVersion;
use libsnatch::write::write_file;
use std::fs::File;
use std::io;
use std::sync::{Arc, Mutex};
use std::path::Path;
use std::process::exit;

fn main() {

    let mut file = String::from("");
    let mut threads: usize = 4;
    let mut url = String::from("");
    let mut verbose = false;

    {
        let mut argparse = ArgumentParser::new();
        argparse.set_description("Snatch, a simple, fast and interruptable download accelerator, \
                                  written in Rust.");
        argparse.refer(&mut file)
            .add_option(&["-f", "--file"],
                        Store,
                        "The local file to save the remote content file");
        argparse.refer(&mut threads)
            .add_option(&["-t", "--threads"],
                        Store,
                        "Number of threads available to download");
        argparse.refer(&mut url)
            .add_option(&["-u", "--url"], Store, "Remote content URL to download")
            .required();
        argparse.refer(&mut verbose)
            .add_option(&["-v", "--verbose"], StoreTrue, "Verbose mode");
        argparse.parse_args_or_exit();
    }

    let hyper_client = Client::new();

    // Get the first response from the server
    let client_response = hyper_client.get_head_response(&url).unwrap();

    print!("# Waiting a response from the remote server... ");

    if !client_response.version.greater_than_http_11() {
        println!("{}",
                 Yellow.bold()
                     .paint("OK (HTTP version <= 1.0 detected)"));
    } else {
        println!("{}", Green.bold().paint("OK !"));
    }

    // If no filename has been given, infer it
    if file.is_empty() {
        file = match url.split('/').last() {
            Some(filename) => String::from(filename),
            None => String::from("index.html"),
        }
    }

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

    if local_path.exists() {
        if local_path.is_dir() {
            panic!(Red.bold()
                .paint("[ERROR] The local path to store the remote content is already exists, \
                        and is a directory!"));
        }
        println!("{}",
                 Red.bold()
                     .paint("[WARNING] The path to store the file already exists! Do you want \
                             to override it? [y/N]"));
        {
            let mut user_input = String::new();
            io::stdin()
                .read_line(&mut user_input)
                .ok()
                .expect("[ERROR] Couldn't read line!");
            user_input = String::from(user_input.trim());
            if !(user_input == "y" || user_input == "Y") {
                exit(0);
            }
        }
    }

    let remote_content_length = match client_response.headers.get_content_length() {
        Some(remote_content_length) => remote_content_length,
        None => {
            println!("{}",
                     Red.bold()
                         .paint("[ERROR] Cannot get the content length of the remote content, \
                                 from the server."));
            exit(1);
        }
    };

    println!("# Remote content length: {:?} MB",
             (remote_content_length / 1000000) as Bytes);

    let mut core_chunks = Chunks::with_capacity(threads);

    for _ in 0..threads {
        core_chunks.push(Vec::new());
    }

    let mut shared_chunks = Arc::new(Mutex::new(core_chunks));

    download_chunks(remote_content_length,
                    &mut shared_chunks,
                    threads as u64,
                    &url);

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

    match write_file(&mut local_file, &shared_chunks) {
        Ok(()) => println!("{}", Green.bold().paint("Chunks have been successfuly saved!")),
        Err(error) => println!("[ERROR] {}", error),
    }

}
<|endoftext|>


<commit_before>enum Tetromino {
    I,
    O,
    T,
    J,
    L,
    S,
    Z,
}

struct Block {
    shape: Tetromino,
}

impl Block {
    fn new(tetris: Tetromino) -> Block {
        Block {
            shape: tetris,
        }
    }
}

fn main() {
    println!("Hello, world!");

    let x = Block::new(Tetromino::T);

    match x.shape {
        Tetromino::I => println!("I shape"),
        Tetromino::O => println!("O shape"),
        Tetromino::T => println!("T shape"),
        Tetromino::J => println!("J shape"),
        Tetromino::L => println!("L shape"),
        Tetromino::S => println!("S shape"),
        Tetromino::Z => println!("Z shape"),
    }
}
<commit_msg>Adds Board struct and uses vector to store board data<commit_after>enum Tetromino {
    I,
    O,
    T,
    J,
    L,
    S,
    Z,
}

struct Block {
    shape: Tetromino,
    anchor: (i32, i32),
}

impl Block {
    fn new(tetris: Tetromino) -> Block {
        Block {
            shape: tetris,
            anchor: (-1, -1),
        }
    }
}

struct Board {
    filled: bool,
}

impl Board {
    fn new(width: i32, height: i32) -> Vec<Vec<Board>> {

        let mut board: Vec<Vec<Board>> = Vec::new();
        for w in 0..width {

            let mut innerBoard: Vec<Board> = Vec::new();
            for h in 0..height {
                innerBoard.push(Board { filled: false });
            }

            board.push(innerBoard);
        }

        return board;
    }
}

fn main() {
    println!("Hello, world!");
    let width = 7;
    let height = 4;

    let mut board = Board::new(width, height);
    let mut blocks: Vec<Block> = vec![
        Block::new(Tetromino::I),
        Block::new(Tetromino::I),
        Block::new(Tetromino::T),
        Block::new(Tetromino::T),
        Block::new(Tetromino::S),
        Block::new(Tetromino::Z),
        Block::new(Tetromino::L)
    ];

    let x = &blocks[6];

    match x.shape {
        Tetromino::I => println!("I shape"),
        Tetromino::O => println!("O shape"),
        Tetromino::T => println!("T shape"),
        Tetromino::J => println!("J shape"),
        Tetromino::L => println!("L shape"),
        Tetromino::S => println!("S shape"),
        Tetromino::Z => println!("Z shape"),
    }
}

<|endoftext|>


<commit_before>extern crate iron;
extern crate router;
extern crate rustc_serialize;

use std::io::Read;
use std::sync::{Arc, Mutex};
use std::collections::HashMap;

use iron::prelude::*;
use iron::status;
use router::Router;
use rustc_serialize::json::{self, Json};

#[derive(Debug)]
struct Document {
    data: Json,
}

impl Document {
    fn from_json(data: Json) -> Document {
        Document{
            data: data,
        }
    }
}

#[derive(Debug)]
enum Filter {
    Not(Box<Filter>),
    Or(Vec<Filter>),
    And(Vec<Filter>),
    Term(String, String),
}

impl Filter {
    fn matches(&self, doc: &Document) -> bool {
        match *self {
            Filter::Not(ref filter) => !filter.matches(doc),
            Filter::Or(ref filters) => {
                for filter in filters.iter() {
                    if (filter.matches(doc)) {
                        return true;
                    }
                }

                false
            },
            Filter::And(ref filters) => {
                for filter in filters.iter() {
                    if (!filter.matches(doc)) {
                        return false;
                    }
                }

                true
            },
            Filter::Term(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    if let Json::String(ref field_value) = *field_value {
                        return field_value == value
                    }
                }

                false
            }
        }
    }
}

#[derive(Debug)]
struct Mapping {
    pub docs: HashMap<String, Document>,
}

impl Mapping {
    fn new() -> Mapping {
        Mapping{
            docs: HashMap::new(),
        }
    }
}

#[derive(Debug)]
struct Index {
    pub mappings: HashMap<&'static str, Mapping>,
}

impl Index {
    fn new() -> Index {
        Index{
            mappings: HashMap::new(),
        }
    }
}

fn index_not_found_response() -> Response {
    let mut response = Response::with((status::NotFound, "{\"message\": \"Index not found\"}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    return response;
}

fn main() {
    let indices = Arc::new(Mutex::new(HashMap::new()));
    let mut wagtail_index = Index::new();
    wagtail_index.mappings.insert("wagtaildocs_document", Mapping::new());
    indices.lock().unwrap().insert("wagtaildemo".to_owned(), wagtail_index);

    let f = Filter::Or(vec![
        Filter::Term("title".to_owned(), "test".to_owned()),
        Filter::Term("title".to_owned(), "foo".to_owned()),
    ]);

    println!("{:?}", f);

    let mut router = Router::new();

    router.get("/", |_: &mut Request| -> IronResult<Response> {
        Ok(Response::with((status::Ok, "Hello World!")))
    });

    {
        let indices = indices.clone();

        router.get("/:index/_count", move |req: &mut Request| -> IronResult<Response> {
            // URL parameters
            let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

            // Lock index array
            let indices = indices.lock().unwrap();

            // Find index
            let index = match indices.get(index_name) {
                Some(index) => index,
                None => {
                    return Ok(index_not_found_response());
                }
            };

            // Load query from body
            let mut payload = String::new();
            req.body.read_to_string(&mut payload).unwrap();

            let data = if !payload.is_empty() {
                Some(match Json::from_str(&payload) {
                    Ok(data) => data,
                    Err(error) => {
                        // TODO: What specifically is bad about the JSON?
                        let mut response = Response::with((status::BadRequest, "{\"message\": \"Couldn't parse JSON\"}"));
                        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                        return Ok(response);
                    }
                })
            } else {
                None
            };

            // TODO: Run query

            // Temporary count and return numbers
            let mut count = 0;
            for mapping in index.mappings.values() {
                count += mapping.docs.len();
            }

            let mut response = Response::with((status::Ok, format!("{{\"count\": {}}}", count)));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            Ok(response)
        });
    }

    {
        let indices = indices.clone();

        router.get("/:index/_search", move |req: &mut Request| -> IronResult<Response> {
            // URL parameters
            let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

            // Lock index array
            let indices = indices.lock().unwrap();

            // Find index
            let index = match indices.get(index_name) {
                Some(index) => index,
                None => {
                    return Ok(index_not_found_response());
                }
            };

            // Load query from body
            let mut payload = String::new();
            req.body.read_to_string(&mut payload).unwrap();

            let data = if !payload.is_empty() {
                Some(match Json::from_str(&payload) {
                    Ok(data) => data,
                    Err(error) => {
                        // TODO: What specifically is bad about the JSON?
                        let mut response = Response::with((status::BadRequest, "{\"message\": \"Couldn't parse JSON\"}"));
                        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                        return Ok(response);
                    }
                })
            } else {
                None
            };

            // TODO: Run query

            let mut response = Response::with((status::Ok, "{\"hits\": {\"total\": 0, \"hits\": []}}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            Ok(response)
        });
    }

    {
        let indices = indices.clone();

        router.get("/:index/:mapping/:doc", move |req: &mut Request| -> IronResult<Response> {
            // URL parameters
            let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");
            let mapping_name = req.extensions.get::<Router>().unwrap().find("mapping").unwrap_or("");
            let doc_id = req.extensions.get::<Router>().unwrap().find("doc").unwrap_or("");

            // Lock index array
            let indices = indices.lock().unwrap();

            // Find index
            let index = match indices.get(index_name) {
                Some(index) => index,
                None => {
                    return Ok(index_not_found_response());
                }
            };

            // Find mapping
            let mapping = match index.mappings.get(mapping_name) {
                Some(mapping) => mapping,
                None => {
                    let mut response = Response::with((status::NotFound, "{\"message\": \"Mapping not found\"}"));
                    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                    return Ok(response);
                }
            };

            // Find document
            let doc = match mapping.docs.get(doc_id) {
                Some(doc) => doc,
                None => {
                    let mut response = Response::with((status::NotFound, "{\"message\": \"Document not found\"}"));
                    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                    return Ok(response);
                }
            };

            let mut response = Response::with((status::Ok, json::encode(&doc.data).unwrap()));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            Ok(response)
        });
    }

    {
        let indices = indices.clone();

        router.put("/:index/:mapping/:doc", move |req: &mut Request| -> IronResult<Response> {
            // URL parameters
            let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");
            let mapping_name = req.extensions.get::<Router>().unwrap().find("mapping").unwrap_or("");
            let ref doc_id = req.extensions.get::<Router>().unwrap().find("doc").unwrap_or("");

            // Lock index array
            let mut indices = indices.lock().unwrap();

            // Find index
            let mut index = match indices.get_mut(index_name) {
                Some(index) => index,
                None => {
                    return Ok(index_not_found_response());
                }
            };

            // Find mapping
            let mut mapping = match index.mappings.get_mut(mapping_name) {
                Some(mapping) => mapping,
                None => {
                    let mut response = Response::with((status::NotFound, "{\"message\": \"Mapping not found\"}"));
                    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                    return Ok(response);
                }
            };

            // Load data from body
            let mut payload = String::new();
            req.body.read_to_string(&mut payload).unwrap();

            let data = if !payload.is_empty() {
                Some(match Json::from_str(&payload) {
                    Ok(data) => data,
                    Err(error) => {
                        // TODO: What specifically is bad about the JSON?
                        let mut response = Response::with((status::BadRequest, "{\"message\": \"Couldn't parse JSON\"}"));
                        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                        return Ok(response);
                    }
                })
            } else {
                None
            };

            // Create and insert document
            if let Some(data) = data {
                let doc = Document::from_json(data);
                println!("{:?}", f.matches(&doc));
                mapping.docs.insert(doc_id.clone().to_owned(), doc);
            }

            let mut response = Response::with((status::Ok, "{}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            Ok(response)
        });
    }

    {
        let indices = indices.clone();

        router.put("/:index", move |req: &mut Request| -> IronResult<Response> {
            // URL parameters
            let ref index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

            // Lock index array
            let mut indices = indices.lock().unwrap();

            // Load data from body
            let mut payload = String::new();
            req.body.read_to_string(&mut payload).unwrap();

            let data = if !payload.is_empty() {
                Some(match Json::from_str(&payload) {
                    Ok(data) => data,
                    Err(error) => {
                        // TODO: What specifically is bad about the JSON?
                        let mut response = Response::with((status::BadRequest, "{\"message\": \"Couldn't parse JSON\"}"));
                        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                        return Ok(response);
                    }
                })
            } else {
                None
            };

            // Create index
            indices.insert(index_name.clone().to_owned(), Index::new());

            let mut response = Response::with((status::Ok, "{\"acknowledged\": true}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            Ok(response)
        });
    }

    Iron::new(router).http("localhost:9200").unwrap();
}
<commit_msg>Basic implementation of put mapping API<commit_after>extern crate iron;
extern crate router;
extern crate rustc_serialize;

use std::io::Read;
use std::sync::{Arc, Mutex};
use std::collections::HashMap;

use iron::prelude::*;
use iron::status;
use router::Router;
use rustc_serialize::json::{self, Json};

#[derive(Debug)]
struct Document {
    data: Json,
}

impl Document {
    fn from_json(data: Json) -> Document {
        Document{
            data: data,
        }
    }
}

#[derive(Debug)]
enum Filter {
    Not(Box<Filter>),
    Or(Vec<Filter>),
    And(Vec<Filter>),
    Term(String, String),
}

impl Filter {
    fn matches(&self, doc: &Document) -> bool {
        match *self {
            Filter::Not(ref filter) => !filter.matches(doc),
            Filter::Or(ref filters) => {
                for filter in filters.iter() {
                    if (filter.matches(doc)) {
                        return true;
                    }
                }

                false
            },
            Filter::And(ref filters) => {
                for filter in filters.iter() {
                    if (!filter.matches(doc)) {
                        return false;
                    }
                }

                true
            },
            Filter::Term(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    if let Json::String(ref field_value) = *field_value {
                        return field_value == value
                    }
                }

                false
            }
        }
    }
}

#[derive(Debug)]
struct Mapping {
    pub docs: HashMap<String, Document>,
}

impl Mapping {
    fn new() -> Mapping {
        Mapping{
            docs: HashMap::new(),
        }
    }
}

#[derive(Debug)]
struct Index {
    pub mappings: HashMap<String, Mapping>,
}

impl Index {
    fn new() -> Index {
        Index{
            mappings: HashMap::new(),
        }
    }
}

fn index_not_found_response() -> Response {
    let mut response = Response::with((status::NotFound, "{\"message\": \"Index not found\"}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    return response;
}

fn main() {
    let indices = Arc::new(Mutex::new(HashMap::new()));
    let mut wagtail_index = Index::new();
    wagtail_index.mappings.insert("wagtaildocs_document".to_owned(), Mapping::new());
    indices.lock().unwrap().insert("wagtaildemo".to_owned(), wagtail_index);

    let f = Filter::Or(vec![
        Filter::Term("title".to_owned(), "test".to_owned()),
        Filter::Term("title".to_owned(), "foo".to_owned()),
    ]);

    println!("{:?}", f);

    let mut router = Router::new();

    router.get("/", |_: &mut Request| -> IronResult<Response> {
        Ok(Response::with((status::Ok, "Hello World!")))
    });

    {
        let indices = indices.clone();

        router.get("/:index/_count", move |req: &mut Request| -> IronResult<Response> {
            // URL parameters
            let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

            // Lock index array
            let indices = indices.lock().unwrap();

            // Find index
            let index = match indices.get(index_name) {
                Some(index) => index,
                None => {
                    return Ok(index_not_found_response());
                }
            };

            // Load query from body
            let mut payload = String::new();
            req.body.read_to_string(&mut payload).unwrap();

            let data = if !payload.is_empty() {
                Some(match Json::from_str(&payload) {
                    Ok(data) => data,
                    Err(error) => {
                        // TODO: What specifically is bad about the JSON?
                        let mut response = Response::with((status::BadRequest, "{\"message\": \"Couldn't parse JSON\"}"));
                        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                        return Ok(response);
                    }
                })
            } else {
                None
            };

            // TODO: Run query

            // Temporary count and return numbers
            let mut count = 0;
            for mapping in index.mappings.values() {
                count += mapping.docs.len();
            }

            let mut response = Response::with((status::Ok, format!("{{\"count\": {}}}", count)));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            Ok(response)
        });
    }

    {
        let indices = indices.clone();

        router.get("/:index/_search", move |req: &mut Request| -> IronResult<Response> {
            // URL parameters
            let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

            // Lock index array
            let indices = indices.lock().unwrap();

            // Find index
            let index = match indices.get(index_name) {
                Some(index) => index,
                None => {
                    return Ok(index_not_found_response());
                }
            };

            // Load query from body
            let mut payload = String::new();
            req.body.read_to_string(&mut payload).unwrap();

            let data = if !payload.is_empty() {
                Some(match Json::from_str(&payload) {
                    Ok(data) => data,
                    Err(error) => {
                        // TODO: What specifically is bad about the JSON?
                        let mut response = Response::with((status::BadRequest, "{\"message\": \"Couldn't parse JSON\"}"));
                        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                        return Ok(response);
                    }
                })
            } else {
                None
            };

            // TODO: Run query

            let mut response = Response::with((status::Ok, "{\"hits\": {\"total\": 0, \"hits\": []}}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            Ok(response)
        });
    }

    {
        let indices = indices.clone();

        router.get("/:index/:mapping/:doc", move |req: &mut Request| -> IronResult<Response> {
            // URL parameters
            let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");
            let mapping_name = req.extensions.get::<Router>().unwrap().find("mapping").unwrap_or("");
            let doc_id = req.extensions.get::<Router>().unwrap().find("doc").unwrap_or("");

            // Lock index array
            let indices = indices.lock().unwrap();

            // Find index
            let index = match indices.get(index_name) {
                Some(index) => index,
                None => {
                    return Ok(index_not_found_response());
                }
            };

            // Find mapping
            let mapping = match index.mappings.get(mapping_name) {
                Some(mapping) => mapping,
                None => {
                    let mut response = Response::with((status::NotFound, "{\"message\": \"Mapping not found\"}"));
                    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                    return Ok(response);
                }
            };

            // Find document
            let doc = match mapping.docs.get(doc_id) {
                Some(doc) => doc,
                None => {
                    let mut response = Response::with((status::NotFound, "{\"message\": \"Document not found\"}"));
                    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                    return Ok(response);
                }
            };

            let mut response = Response::with((status::Ok, json::encode(&doc.data).unwrap()));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            Ok(response)
        });
    }

    {
        let indices = indices.clone();

        router.put("/:index/:mapping/:doc", move |req: &mut Request| -> IronResult<Response> {
            // URL parameters
            let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");
            let mapping_name = req.extensions.get::<Router>().unwrap().find("mapping").unwrap_or("");
            let ref doc_id = req.extensions.get::<Router>().unwrap().find("doc").unwrap_or("");

            // Lock index array
            let mut indices = indices.lock().unwrap();

            // Find index
            let mut index = match indices.get_mut(index_name) {
                Some(index) => index,
                None => {
                    return Ok(index_not_found_response());
                }
            };

            // Find mapping
            let mut mapping = match index.mappings.get_mut(mapping_name) {
                Some(mapping) => mapping,
                None => {
                    let mut response = Response::with((status::NotFound, "{\"message\": \"Mapping not found\"}"));
                    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                    return Ok(response);
                }
            };

            // Load data from body
            let mut payload = String::new();
            req.body.read_to_string(&mut payload).unwrap();

            let data = if !payload.is_empty() {
                Some(match Json::from_str(&payload) {
                    Ok(data) => data,
                    Err(error) => {
                        // TODO: What specifically is bad about the JSON?
                        let mut response = Response::with((status::BadRequest, "{\"message\": \"Couldn't parse JSON\"}"));
                        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                        return Ok(response);
                    }
                })
            } else {
                None
            };

            // Create and insert document
            if let Some(data) = data {
                let doc = Document::from_json(data);
                println!("{:?}", f.matches(&doc));
                mapping.docs.insert(doc_id.clone().to_owned(), doc);
            }

            let mut response = Response::with((status::Ok, "{}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            Ok(response)
        });
    }

    {
        let indices = indices.clone();

        router.put("/:index", move |req: &mut Request| -> IronResult<Response> {
            // URL parameters
            let ref index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

            // Lock index array
            let mut indices = indices.lock().unwrap();

            // Load data from body
            let mut payload = String::new();
            req.body.read_to_string(&mut payload).unwrap();

            let data = if !payload.is_empty() {
                Some(match Json::from_str(&payload) {
                    Ok(data) => data,
                    Err(error) => {
                        // TODO: What specifically is bad about the JSON?
                        let mut response = Response::with((status::BadRequest, "{\"message\": \"Couldn't parse JSON\"}"));
                        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                        return Ok(response);
                    }
                })
            } else {
                None
            };

            // Create index
            indices.insert(index_name.clone().to_owned(), Index::new());

            let mut response = Response::with((status::Ok, "{\"acknowledged\": true}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            Ok(response)
        });
    }

    {
        let indices = indices.clone();

        router.put("/:index/_mapping/:mapping", move |req: &mut Request| -> IronResult<Response> {
            // URL parameters
            let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");
            let ref mapping_name = req.extensions.get::<Router>().unwrap().find("mapping").unwrap_or("");

            // Lock index array
            let mut indices = indices.lock().unwrap();

            // Find index
            let mut index = match indices.get_mut(index_name) {
                Some(index) => index,
                None => {
                    return Ok(index_not_found_response());
                }
            };

            // Load data from body
            let mut payload = String::new();
            req.body.read_to_string(&mut payload).unwrap();

            let data = if !payload.is_empty() {
                Some(match Json::from_str(&payload) {
                    Ok(data) => data,
                    Err(error) => {
                        // TODO: What specifically is bad about the JSON?
                        let mut response = Response::with((status::BadRequest, "{\"message\": \"Couldn't parse JSON\"}"));
                        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                        return Ok(response);
                    }
                })
            } else {
                None
            };

            // Insert mapping
            index.mappings.insert(mapping_name.clone().to_owned(), Mapping::new());

            let mut response = Response::with((status::Ok, "{\"acknowledged\": true}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            Ok(response)
        });
    }

    Iron::new(router).http("localhost:9200").unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2015 Corey Farwell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/* TODO:
 *  * redirect root url
 *  * add watermark? url to repo?
 *  * update git repo?
 *  * serverside caching? redis?
 */

use std::collections::{HashMap, HashSet};
use std::env;
use std::io::{Write, Read};
use std::process::{Command, Stdio};

use tiny_http::{Header, Response};

extern crate crates_index;
extern crate tiny_http;

static INDEX_LOCAL_PATH: &'static str = "crates.io-index";

struct DotBuilder {
    buf: String,
}

impl DotBuilder {
    fn new_digraph(name: &str) -> Self {
        DotBuilder{buf: format!("digraph \"{}\" {}", name, "{")}
    }

    fn set_ratio(&mut self, ratio: &str) {
        self.buf.push_str(&format!("ratio={};", ratio))
    }

    fn set_node_attrs(&mut self, node: &str, attrs: &str) {
        self.buf.push_str(&format!("\"{}\" [{}];", node, attrs));
    }

    fn add_edge(&mut self, from: &str, to: &str) {
        self.buf.push_str(&format!("\"{}\" -> \"{}\";", from, to));
    }

    fn finish(&mut self) {
        self.buf.push_str("}");
    }

    fn as_bytes(&self) -> &[u8] {
       self.buf.as_bytes()
    }
}

fn build_dot(crate_name: &str, dep_map: &HashMap<String, Vec<String>>) -> Vec<u8> {
    let mut crate_names = vec![crate_name];

    let mut dot = DotBuilder::new_digraph(crate_name);
    dot.set_ratio("0.75");
    dot.set_node_attrs(crate_name, "root=true,style=filled,fillcolor=grey");

    // Which dependencies we've already seen
    let mut seen_set = HashSet::new();

    while let Some(crate_name) = crate_names.pop() {
        if seen_set.contains(crate_name as &str) {
            continue;
        }
        seen_set.insert(crate_name);
        for crate_dep in dep_map.get(crate_name).unwrap() {
            dot.add_edge(crate_name, crate_dep);
            if !seen_set.contains(crate_dep as &str) {
                crate_names.push(crate_dep);
            }
        }
    }
    dot.finish();

    let child = Command::new("dot").arg("-Tpng").stdin(Stdio::piped()).stdout(Stdio::piped()).spawn().unwrap();
    child.stdin.unwrap().write_all(dot.as_bytes()).unwrap();

    let mut ret = vec![];
    child.stdout.unwrap().read_to_end(&mut ret).unwrap();
    ret
}

fn main() {
    let index = crates_index::CratesIndex::new(INDEX_LOCAL_PATH.into());
    if !index.exists() {
        println!("Cloning crates.io-index");
        index.clone_index();
    }

    let dep_map = index.dependency_map();

    let port = match env::var("PORT") {
        Ok(p) => p.parse::<u16>().unwrap(),
        Err(..) => 8000,
    };

    let server = tiny_http::ServerBuilder::new().with_port(port).build().unwrap();

    println!("Server listening on port {}", port);
    for req in server.incoming_requests() {
        let response = {
            let crate_name = req.url().trim_left_matches("/");
            if dep_map.get(crate_name).is_some() {
                let data = build_dot(crate_name, &dep_map);
                let content_type_header = "Content-Type: image/png".parse::<Header>().unwrap();
                let cache_control_header = "cache-control: no-cache".parse::<Header>().unwrap();
                Response::from_data(data).with_header(content_type_header)
                                         .with_header(cache_control_header)
            } else {
                Response::from_string("could not find crate").with_status_code(400)
            }
        };
        req.respond(response);
    }
}
<commit_msg>Move PNG DOT generation into DOT builder struct<commit_after>// Copyright 2015 Corey Farwell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/* TODO:
 *  * redirect root url
 *  * add watermark? url to repo?
 *  * update git repo?
 *  * serverside caching? redis?
 */

use std::collections::{HashMap, HashSet};
use std::env;
use std::io::{Write, Read};
use std::process::{Command, Stdio};

use tiny_http::{Header, Response};

extern crate crates_index;
extern crate tiny_http;

static INDEX_LOCAL_PATH: &'static str = "crates.io-index";

struct DotBuilder {
    buf: String,
}

impl DotBuilder {
    fn new_digraph(name: &str) -> Self {
        DotBuilder{buf: format!("digraph \"{}\" {}", name, "{")}
    }

    fn set_ratio(&mut self, ratio: &str) {
        self.buf.push_str(&format!("ratio={};", ratio))
    }

    fn set_node_attrs(&mut self, node: &str, attrs: &str) {
        self.buf.push_str(&format!("\"{}\" [{}];", node, attrs));
    }

    fn add_edge(&mut self, from: &str, to: &str) {
        self.buf.push_str(&format!("\"{}\" -> \"{}\";", from, to));
    }

    fn finish(&mut self) {
        self.buf.push_str("}");
    }

    fn png_bytes(&self) -> Vec<u8> {
        let child = Command::new("dot").arg("-Tpng")
                                       .stdin(Stdio::piped()).stdout(Stdio::piped())
                                       .spawn().unwrap();
        child.stdin.unwrap().write_all(self.buf.as_bytes()).unwrap();
        let mut ret = vec![];
        child.stdout.unwrap().read_to_end(&mut ret).unwrap();
        ret
    }
}

fn build_dot(crate_name: &str, dep_map: &HashMap<String, Vec<String>>) -> Vec<u8> {
    let mut crate_names = vec![crate_name];

    let mut dot = DotBuilder::new_digraph(crate_name);
    dot.set_ratio("0.75");
    dot.set_node_attrs(crate_name, "root=true,style=filled,fillcolor=grey");

    // Which dependencies we've already seen
    let mut seen_set = HashSet::new();

    while let Some(crate_name) = crate_names.pop() {
        if seen_set.contains(crate_name as &str) {
            continue;
        }
        seen_set.insert(crate_name);
        for crate_dep in dep_map.get(crate_name).unwrap() {
            dot.add_edge(crate_name, crate_dep);
            if !seen_set.contains(crate_dep as &str) {
                crate_names.push(crate_dep);
            }
        }
    }
    dot.finish();

    dot.png_bytes()
}

fn main() {
    let index = crates_index::CratesIndex::new(INDEX_LOCAL_PATH.into());
    if !index.exists() {
        println!("Cloning crates.io-index");
        index.clone_index();
    }

    let dep_map = index.dependency_map();

    let port = match env::var("PORT") {
        Ok(p) => p.parse::<u16>().unwrap(),
        Err(..) => 8000,
    };

    let server = tiny_http::ServerBuilder::new().with_port(port).build().unwrap();

    println!("Server listening on port {}", port);
    for req in server.incoming_requests() {
        let response = {
            let crate_name = req.url().trim_left_matches("/");
            if dep_map.get(crate_name).is_some() {
                let data = build_dot(crate_name, &dep_map);
                let content_type_header = "Content-Type: image/png".parse::<Header>().unwrap();
                let cache_control_header = "cache-control: no-cache".parse::<Header>().unwrap();
                Response::from_data(data).with_header(content_type_header)
                                         .with_header(cache_control_header)
            } else {
                Response::from_string("could not find crate").with_status_code(400)
            }
        };
        req.respond(response);
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate log;

extern crate ansi_term;
use ansi_term::Colour::{Black, Red, Green, Yellow, Blue, Purple, Cyan, Fixed};
use ansi_term::Style::Plain;

use std::num::{FromPrimitive};
use std::os;
use std::io::File;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::iter::{range_step, count};

fn vec_to_string(input: &Vec<char>) -> String {
    input.iter().map(|&c| { c }).collect()
}

// Index source
struct InputSource {
    haystack: Vec<char>,
    indexed_haystack: HashMap<char, Vec<usize>>,
}

fn index_chars(input: &Vec<char>) -> HashMap<char, Vec<usize>> {
    let mut indexed_haystack = HashMap::new();
    for (idx, &c) in input.iter().enumerate() {
        match indexed_haystack.entry(c) {
            Vacant(entry) => { entry.insert(vec![idx]); },
            Occupied(mut entry) => { (*entry.get_mut()).push(idx); }
        }
    }

    indexed_haystack
}

impl InputSource {
    fn new(haystack: Vec<char>) -> InputSource {
        let indexed_haystack = index_chars(&haystack);

        InputSource {
            haystack: haystack,
            indexed_haystack: indexed_haystack,
        }
    }

    fn search_for_anywhere<'a>(&'a self, needle: &'a Vec<char>) -> Option<EDS> {
        EDS::new(self, needle)
    }

    fn search_for<'a>(&'a self, needle: &'a Vec<char>, start_options: Vec<usize>, step_options: Vec<i64>) -> Option<EDS> {
        EDS::new(self, needle)
    }
}

// This is a struct for doing the searching
struct EDS<'a, 'b> {
    source: &'a InputSource,

    // String to search for
    needle: &'b Vec<char>,

    first_poses: Vec<usize>,
    second_poses: Vec<usize>,

    // keep track of state between runs
    first_poses_idx: usize,
    second_poses_idx: usize,

}

impl<'a, 'b> Iterator for EDS<'a, 'b> {
    // (start, offset)
    type Item = (usize, i64);

    // This actually does the searching
    fn next(&mut self) -> Option<(usize, i64)> {
        debug!("Start of next call");
        let len_first_poses = self.first_poses.len();
        let len_second_poses = self.second_poses.len();

        if self.first_poses_idx == len_first_poses {
            debug!("Reached end, finishing");
            // reached the end
            return None;
        }

        let len_needle = self.needle.len();
        let len_haystack = self.source.haystack.len();
        let mut have_done_one_loop = false;
        let first_run = (self.first_poses_idx == 0 && self.second_poses_idx == 0);

        loop {
            debug!("Start of loop");
            // Starts off at 0/0, and we don't want to increment it the first time
            if ! (self.first_poses_idx == 0 && self.second_poses_idx == 0 && !have_done_one_loop) {
                debug!("Incrementing counters");
                if self.second_poses_idx == len_second_poses - 1 {
                    self.second_poses_idx = 0;
                    self.first_poses_idx += 1;
                } else{
                    self.second_poses_idx += 1;
                }
            }
            have_done_one_loop = true;
            if self.first_poses_idx == len_first_poses {
                debug!("Reached end, finishing");
                // reached the end
                return None;
            }

            debug!("first_poses_idx {} second_poses_idx {}", self.first_poses_idx, self.second_poses_idx);
            let first_pos = self.first_poses[self.first_poses_idx];
            let second_pos = self.second_poses[self.second_poses_idx];
            debug!("first_pos {} second_pos {}", first_pos, second_pos);

            let step: i64 = (second_pos as i64) - (first_pos as i64);
            if step == 1 {
                continue;
            }
            let positions: Vec<i64> = std::iter::count(first_pos as i64, step as i64).take(len_needle).collect();
            //let positions: Vec<i64> = range_step(first_pos as i64, step*len_needle, step).collect();
            debug!("Start {} step {}", first_pos, step);
            if positions.iter().any(|&x| { x<0 }) {
                // TODO there's probably a better maths way to do this
                continue;
            }
            let positions: Vec<usize> = positions.iter().map(|&x| { FromPrimitive::from_i64(x).unwrap() }).collect();
            debug!("positions {:?}", positions);
            if positions.len() == 0 {
                // WTF
                continue;
            }

            if positions[positions.len()-1] > len_haystack - 1 {
                debug!("Past end");
                continue;
            }
            if positions.iter().map(|&c| { &self.source.haystack[c] }).zip(self.needle.iter()).all(|(&a, &b)| { a == b }) {
                //println!("Found starting at {} with step of {}", first_pos, step);
                return Some((first_pos, step));
            }
        }
        None
    }
}

impl<'a, 'b> EDS<'a, 'b> {
    fn new(source: &'a InputSource, needle: &'b Vec<char>) -> Option<EDS<'a, 'b>> {
        if needle.len() < 3 {
            return None;
        }
        let first_poses;
        match source.indexed_haystack.get(&needle[0]) {
            None => { return None ; }
            Some(ref entries) => {
                first_poses = (**entries).clone();
            }
        }

        let second_poses;
        match source.indexed_haystack.get(&needle[1]) {
            None => { return None ; }
            Some(ref entries) => {
                second_poses = (**entries).clone();
            }
        }

        let result = EDS {
            needle: needle, source: source,
            first_poses: first_poses, second_poses: second_poses,
            first_poses_idx: 0, second_poses_idx: 0,
        };

        return Some(result);

    }
}

fn print_results(source: &InputSource, start: usize, step: i64, len: usize) {
    let total_rows = (len + 2) as i64;
    let width: usize = 31; // 15 + 1 + 15
    let start_i = start as i64;

    for row_num in range(0, total_rows) {
        for idx in range(0, width as i64) {
            let source_idx = (row_num-1)*step + start_i - 15 + idx;
            let this_char = if source_idx < 0 { ' ' } else { source.haystack[source_idx as usize] };
            if idx == 15 && row_num != 0 && row_num != total_rows -1 {
                print!("{}", Red.paint(this_char.to_string().as_slice()));
            } else {
                print!("{}", Plain.paint(this_char.to_string().as_slice()));
            }
        }
        print!("\n");

    }

}

fn only_alphanumeric(input: String) -> Vec<char> {
    input.chars().filter(|c| { c.is_alphabetic() }).map(|c| { c.to_lowercase() }).collect()
}

fn main() {
    let file_to_search = &os::args()[1];
    println!("Reading in {}", file_to_search);
    let haystack: Vec<char> = only_alphanumeric(File::open(&Path::new(file_to_search)).read_to_string().unwrap());
    let source = InputSource::new(haystack);

    let needle = (&os::args()[2]).to_string();
    println!("Looking for {}", needle);
    let needle = only_alphanumeric(needle);
    let len_needle = needle.len();

    let has_second_arg = os::args().len() == 4;
    let needle2;
    let len_needle2;
    if has_second_arg {
        needle2 = only_alphanumeric((&os::args()[3]).to_string());
        let needle2_string: String = vec_to_string(&needle2);
        println!("Looking also for {}", needle2_string);
        len_needle2 = needle2.len();
    } else {
        needle2 = vec![];
    }

    match source.search_for_anywhere(&needle) {
        None => {
            println!("Cannot look for this string");
        }
        Some(eds_searcher) => {
            for (start, step) in eds_searcher.take(10) {
                println!("Found starting at {} with step of {}", start, step);
                print_results(&source, start, step, len_needle);
                if has_second_arg {
                    // now try to find the second needle2
                    match source.search_for_anywhere(&needle2) {
                        None => {
                            println!("Cannot look for {:?}", vec_to_string(&needle2));
                        }
                        Some(needle2_searcher) => {
                            for (start2, step2) in needle2_searcher.take(1) {
                                println!("Found {:?} starting at {} with step of {}", vec_to_string(&needle2), start2, step2);

                            }
                        }
                    }
                }
            }
        }
    }

}
<commit_msg>make work with modern rust<commit_after>#[macro_use] extern crate log;

extern crate ansi_term;
use ansi_term::Colour::{Black, Red, Green, Yellow, Blue, Purple, Cyan, Fixed};
use ansi_term::Style;

use std::num::{FromPrimitive};
use std::os;
use std::io::File;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::iter::{range_step, count};

fn vec_to_string(input: &Vec<char>) -> String {
    input.iter().map(|&c| { c }).collect()
}

// Index source
struct InputSource {
    haystack: Vec<char>,
    indexed_haystack: HashMap<char, Vec<usize>>,
}

fn index_chars(input: &Vec<char>) -> HashMap<char, Vec<usize>> {
    let mut indexed_haystack = HashMap::new();
    for (idx, &c) in input.iter().enumerate() {
        match indexed_haystack.entry(c) {
            Vacant(entry) => { entry.insert(vec![idx]); },
            Occupied(mut entry) => { (*entry.get_mut()).push(idx); }
        }
    }

    indexed_haystack
}

impl InputSource {
    fn new(haystack: Vec<char>) -> InputSource {
        let indexed_haystack = index_chars(&haystack);

        InputSource {
            haystack: haystack,
            indexed_haystack: indexed_haystack,
        }
    }

    fn search_for_anywhere<'a>(&'a self, needle: &'a Vec<char>) -> Option<EDS> {
        EDS::new(self, needle)
    }

    fn search_for<'a>(&'a self, needle: &'a Vec<char>, start_options: Vec<usize>, step_options: Vec<i64>) -> Option<EDS> {
        EDS::new(self, needle)
    }
}

// This is a struct for doing the searching
struct EDS<'a, 'b> {
    source: &'a InputSource,

    // String to search for
    needle: &'b Vec<char>,

    first_poses: Vec<usize>,
    second_poses: Vec<usize>,

    // keep track of state between runs
    first_poses_idx: usize,
    second_poses_idx: usize,

}

impl<'a, 'b> Iterator for EDS<'a, 'b> {
    // (start, offset)
    type Item = (usize, i64);

    // This actually does the searching
    fn next(&mut self) -> Option<(usize, i64)> {
        debug!("Start of next call");
        let len_first_poses = self.first_poses.len();
        let len_second_poses = self.second_poses.len();

        if self.first_poses_idx == len_first_poses {
            debug!("Reached end, finishing");
            // reached the end
            return None;
        }

        let len_needle = self.needle.len();
        let len_haystack = self.source.haystack.len();
        let mut have_done_one_loop = false;
        let first_run = (self.first_poses_idx == 0 && self.second_poses_idx == 0);

        loop {
            debug!("Start of loop");
            // Starts off at 0/0, and we don't want to increment it the first time
            if ! (self.first_poses_idx == 0 && self.second_poses_idx == 0 && !have_done_one_loop) {
                debug!("Incrementing counters");
                if self.second_poses_idx == len_second_poses - 1 {
                    self.second_poses_idx = 0;
                    self.first_poses_idx += 1;
                } else{
                    self.second_poses_idx += 1;
                }
            }
            have_done_one_loop = true;
            if self.first_poses_idx == len_first_poses {
                debug!("Reached end, finishing");
                // reached the end
                return None;
            }

            debug!("first_poses_idx {} second_poses_idx {}", self.first_poses_idx, self.second_poses_idx);
            let first_pos = self.first_poses[self.first_poses_idx];
            let second_pos = self.second_poses[self.second_poses_idx];
            debug!("first_pos {} second_pos {}", first_pos, second_pos);

            let step: i64 = (second_pos as i64) - (first_pos as i64);
            if step == 1 {
                continue;
            }
            let positions: Vec<i64> = std::iter::count(first_pos as i64, step as i64).take(len_needle).collect();
            //let positions: Vec<i64> = range_step(first_pos as i64, step*len_needle, step).collect();
            debug!("Start {} step {}", first_pos, step);
            if positions.iter().any(|&x| { x<0 }) {
                // TODO there's probably a better maths way to do this
                continue;
            }
            let positions: Vec<usize> = positions.iter().map(|&x| { FromPrimitive::from_i64(x).unwrap() }).collect();
            debug!("positions {:?}", positions);
            if positions.len() == 0 {
                // WTF
                continue;
            }

            if positions[positions.len()-1] > len_haystack - 1 {
                debug!("Past end");
                continue;
            }
            if positions.iter().map(|&c| { &self.source.haystack[c] }).zip(self.needle.iter()).all(|(&a, &b)| { a == b }) {
                //println!("Found starting at {} with step of {}", first_pos, step);
                return Some((first_pos, step));
            }
        }
        None
    }
}

impl<'a, 'b> EDS<'a, 'b> {
    fn new(source: &'a InputSource, needle: &'b Vec<char>) -> Option<EDS<'a, 'b>> {
        if needle.len() < 3 {
            return None;
        }
        let first_poses;
        match source.indexed_haystack.get(&needle[0]) {
            None => { return None ; }
            Some(ref entries) => {
                first_poses = (**entries).clone();
            }
        }

        let second_poses;
        match source.indexed_haystack.get(&needle[1]) {
            None => { return None ; }
            Some(ref entries) => {
                second_poses = (**entries).clone();
            }
        }

        let result = EDS {
            needle: needle, source: source,
            first_poses: first_poses, second_poses: second_poses,
            first_poses_idx: 0, second_poses_idx: 0,
        };

        return Some(result);

    }
}

fn print_results(source: &InputSource, start: usize, step: i64, len: usize) {
    let total_rows = (len + 2) as i64;
    let width: usize = 31; // 15 + 1 + 15
    let start_i = start as i64;

    for row_num in range(0, total_rows) {
        for idx in range(0, width as i64) {
            let source_idx = (row_num-1)*step + start_i - 15 + idx;
            let this_char = if source_idx < 0 { ' ' } else { source.haystack[source_idx as usize] };
            if idx == 15 && row_num != 0 && row_num != total_rows -1 {
                print!("{}", Red.paint(this_char.to_string().as_slice()));
            } else {
                print!("{}", Style::default().paint(this_char.to_string().as_slice()));
            }
        }
        print!("\n");

    }

}

fn only_alphanumeric(input: String) -> Vec<char> {
    input.chars().filter(|c| { c.is_alphabetic() }).map(|c| { c.to_lowercase() }).collect()
}

fn main() {
    let file_to_search = &os::args()[1];
    println!("Reading in {}", file_to_search);
    let haystack: Vec<char> = only_alphanumeric(File::open(&Path::new(file_to_search)).read_to_string().unwrap());
    let source = InputSource::new(haystack);

    let needle = (&os::args()[2]).to_string();
    println!("Looking for {}", needle);
    let needle = only_alphanumeric(needle);
    let len_needle = needle.len();

    let has_second_arg = os::args().len() == 4;
    let needle2;
    let len_needle2;
    if has_second_arg {
        needle2 = only_alphanumeric((&os::args()[3]).to_string());
        let needle2_string: String = vec_to_string(&needle2);
        println!("Looking also for {}", needle2_string);
        len_needle2 = needle2.len();
    } else {
        needle2 = vec![];
    }

    match source.search_for_anywhere(&needle) {
        None => {
            println!("Cannot look for this string");
        }
        Some(eds_searcher) => {
            for (start, step) in eds_searcher.take(10) {
                println!("Found starting at {} with step of {}", start, step);
                print_results(&source, start, step, len_needle);
                if has_second_arg {
                    // now try to find the second needle2
                    match source.search_for_anywhere(&needle2) {
                        None => {
                            println!("Cannot look for {:?}", vec_to_string(&needle2));
                        }
                        Some(needle2_searcher) => {
                            for (start2, step2) in needle2_searcher.take(1) {
                                println!("Found {:?} starting at {} with step of {}", vec_to_string(&needle2), start2, step2);

                            }
                        }
                    }
                }
            }
        }
    }

}
<|endoftext|>


<commit_before>extern crate getopts;

use std::process::{Command, Stdio, Child};
use std::io;
use std::io::{Read, Write};
use std::env;

use getopts::{Options, Matches};

#[derive(Debug)]
enum DeleteOption {
    Local,
    Remote,
    Both
}

impl DeleteOption {
    fn new(opts: Matches) -> DeleteOption {
        return if opts.opt_present("l") {
            DeleteOption::Local
        } else if opts.opt_present("r") {
            DeleteOption::Remote
        } else {
            DeleteOption::Both
        };
    }

    fn warning_message(&self) -> String {
        let source = match self {
            &DeleteOption::Local => "locally:",
            &DeleteOption::Remote => "remotely:",
            &DeleteOption::Both => "locally and remotely:",
        };
        "The following branches will be deleted ".to_owned() + source
    }
}

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

    let mut opts = Options::new();
    opts.optflag("l", "local", "only delete local branches");
    opts.optflag("r", "remote", "only delete remote branches");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(e) => {
            println!("{}", e);
            print_usage(opts);
            return;
        }
    };

    if matches.opt_present("h") {
        print_usage(opts);
        return;
    }

    let branches = merged_branches();

    // Early return if there's nothing to delete
    if branches.len() == 0 {
        println!("No branches to delete, you're clean!");
        return;
    }

    let del_opt = DeleteOption::new(matches);

    print_warning(&branches, &del_opt);

    let mut input = String::new();
    io::stdin().read_line(&mut input).unwrap();

    match input.to_lowercase().as_ref() {
        "y\n" => (),
        "yes\n" => (),
        _ => return,
    }

    match delete_branches(&branches, del_opt) {
        Ok(ref msg) => println!("\n{}", msg),
        Err(ref msg) => println!("\n{}", msg),
    }
}

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

fn print_warning(branches: &String, del_opt: &DeleteOption) {
    println!("{}", del_opt.warning_message());
    println!("{}", format_columns(branches));
    print!("Continue? (yN) ");
    io::stdout().flush().unwrap();
}

fn format_columns(branches: &String) -> String {
    let split = branches.split("\n");
    let vec: Vec<&str> = split.collect();

    if vec.len() < 51 {
        return branches.to_owned();
    }

    let col_count = vec.len() / 50 + 1;
    let mut spacer = String::new();
    for _ in (0..35) {
        spacer = spacer + " "
    }

    let rows = vec.chunks(col_count)
        .map(|chunk| chunk.join(&spacer)).collect::<Vec<String>>();

    rows.join("\n").trim().to_owned()
}

fn merged_branches() -> String {
    let grep = spawn_piped(vec!["grep", "-vE", "(\\* master|\\smaster)"]);

    let gbranch = Command::new("git")
        .args(&["branch", "--merged", "master"])
        .output()
        .unwrap_or_else(|e| { panic!("ERR: {}", e) });

    {
        grep.stdin.unwrap().write_all(&gbranch.stdout).unwrap();
    }

    let mut s = String::new();
    grep.stdout.unwrap().read_to_string(&mut s).unwrap();
    trim_entries(s)
}

fn delete_branches(branches: &String, options: DeleteOption) -> Result<String, String> {
    ensure_master();

    let output = match options {
        DeleteOption::Local => delete_local_branches(branches).unwrap(),
        DeleteOption::Remote => delete_remote_branches(branches).unwrap(),
        DeleteOption::Both => {
            let out1 = delete_remote_branches(branches).unwrap();
            let out2 = delete_local_branches(branches).unwrap();
            ["Remote:".to_owned(), out1, "Local:".to_owned(), out2].join("\n")
        },
    };

    Ok(output)
}

fn delete_local_branches(branches: &String) -> Result<String, String> {
    let xargs = spawn_piped(vec!["xargs", "git", "branch", "-d"]);

    {
        xargs.stdin.unwrap().write_all(branches.as_bytes()).unwrap()
    }

    let mut s = String::new();
    xargs.stdout.unwrap().read_to_string(&mut s).unwrap();
    Ok(s)
}

fn delete_remote_branches(branches: &String) -> Result<String, String> {
    let xargs = spawn_piped(vec!["xargs", "git", "push", "origin", "--delete"]);

    {
        xargs.stdin.unwrap().write_all(branches.as_bytes()).unwrap()
    }

    let mut stdout = String::new();
    xargs.stdout.unwrap().read_to_string(&mut stdout).unwrap();

    let mut stderr = String::new();
    xargs.stderr.unwrap().read_to_string(&mut stderr).unwrap();

    let split = stderr.split("\n");
    let vec: Vec<&str> = split.collect();
    let mut failed_remotes = vec![];
    for s in vec {
        if s.contains("error: unable to delete '") {
            let branch = s.trim_left_matches("error: unable to delete '")
                .trim_right_matches("': remote ref does not exist");

            failed_remotes.push(branch.to_owned() + " was already deleted in the remote.");
        }
    };
    let output = failed_remotes.join("\n") + &stdout;

    Ok(output)
}

fn ensure_master() {
    let current_branch_command = Command::new("git")
        .args(&["rev-parse", "--abbrev-ref", "HEAD"])
        .output()
        .unwrap_or_else(|e| { panic!("ERR: {}", e) });

    let current_branch = String::from_utf8(current_branch_command.stdout).unwrap();

    if current_branch.trim() != "master" {
        panic!("Please run this command from the master branch");
    }
}

fn trim_entries(entries: String) -> String {
    let split = entries.split("\n");
    let vec: Vec<&str> = split.collect();
    let trimmed_vec: Vec<&str> = vec.iter().map(|s| s.trim()).collect();
    trimmed_vec.join("\n").trim_right_matches("\n").to_owned()
}

fn spawn_piped(args: Vec<&'static str>) -> Child {
    let cmd = args[0];
    Command::new(cmd)
        .args(&args[1..])
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()
        .unwrap_or_else(|e| { panic!("ERR: {}", e) })
}

#[cfg(test)]
mod test {
    use super::trim_entries;
    use super::format_columns;
    use super::print_warning;
    use super::DeleteOption;
    use super::spawn_piped;

    use std::io::{Read, Write};

    use getopts::{Options};

    #[test]
    fn test_trim_entries() {
        assert_eq!("branch", trim_entries(" branch ".to_owned()));
        assert_eq!("branch", trim_entries(" branch\n".to_owned()));
        assert_eq!("branch1\nbranch2\nbranch3", trim_entries(" branch1 \n branch2 \n branch3 ".to_owned()));
    }

    #[test]
    fn test_format_columns() {
        let mut input = String::new();
        for _ in (0..49) {
            input = input + "branch\n"
        }

        let expected =
"\
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
\
";

        assert_eq!(expected, format_columns(&input));

        let mut input = String::new();
        for _ in (0..51) {
            input = input + "branch\n"
        }

        let expected =
"\
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch\
";

        assert_eq!(expected, format_columns(&input));
    }

    #[test]
    fn test_print_warning() {
        print_warning(&"branch".to_owned(), &DeleteOption::Both);
    }

    #[test]
    fn test_delete_option_new() {
        let mut opts = Options::new();
        opts.optflag("l", "local", "only delete local branches");
        opts.optflag("r", "remote", "only delete remote branches");
        opts.optflag("h", "help", "print this help menu");

        // opts throws away the first elem, because it expects it to be the
        // path of the executable
        let args = vec!["./target/debug/git-clean", "-l"];

        let matches = match opts.parse(&args[1..]) {
            Ok(m) => { m }
            Err(_) => { return }
        };

        match DeleteOption::new(matches) {
            DeleteOption::Local => (),
            other @ _ => panic!("Expected a DeleteOption::Local, but found: {:?}", other),
        };

        let args = vec!["./target/debug/git-clean", "-r"];

        let matches = match opts.parse(&args[1..]) {
            Ok(m) => { m }
            Err(_) => { return }
        };

        match DeleteOption::new(matches) {
            DeleteOption::Remote => (),
            other @ _ => panic!("Expected a DeleteOption::Remote, but found: {:?}", other),
        };

        let args = vec!["./target/debug/git-clean"];

        let matches = match opts.parse(&args[1..]) {
            Ok(m) => { m }
            Err(_) => { return }
        };

        match DeleteOption::new(matches) {
            DeleteOption::Both => (),
            other @ _ => panic!("Expected a DeleteOption::Both, but found: {:?}", other),
        };
    }

    #[test]
    fn test_spawn_piped() {
        let echo = spawn_piped(vec!["grep", "foo"]);

        {
            echo.stdin.unwrap().write_all("foo\nbar\nbaz".as_bytes()).unwrap()
        }

        let mut stdout = String::new();
        echo.stdout.unwrap().read_to_string(&mut stdout).unwrap();

        assert_eq!(stdout, "foo\n");
    }

    #[test]
    fn test_warning_message() {
        assert_eq!("The following branches will be deleted locally:", DeleteOption::Local.warning_message());
        assert_eq!("The following branches will be deleted remotely:", DeleteOption::Remote.warning_message());
        assert_eq!("The following branches will be deleted locally and remotely:", DeleteOption::Both.warning_message());
    }
}
<commit_msg>GitOptions<commit_after>extern crate getopts;

use std::process::{Command, Stdio, Child};
use std::io;
use std::io::{Read, Write};
use std::env;

use getopts::{Options, Matches};

enum DeleteOption {
    Local,
    Remote,
    Both,
}

impl DeleteOption {
    fn new(opts: Matches) -> DeleteOption {
        return if opts.opt_present("l") {
            DeleteOption::Local
        } else if opts.opt_present("r") {
            DeleteOption::Remote
        } else {
            DeleteOption::Both
        };
    }

    fn warning_message(&self) -> String {
        let source = match self {
            &DeleteOption::Local => "locally:",
            &DeleteOption::Remote => "remotely:",
            &DeleteOption::Both => "locally and remotely:",
        };
        "The following branches will be deleted ".to_owned() + source
    }
}

struct Branches {
    string: String,
    vec: Vec<String>
}

impl Branches {
    fn new(branches: &String) -> Branches {
        let split = branches.split("\n");
        let vec: Vec<&str> = split.collect();
        let trimmed_vec: Vec<String> = vec.iter().map(|s| s.trim().to_owned()).collect();
        let trimmed_string = trimmed_vec.join("\n").trim_right_matches("\n").to_owned();

        Branches {
            string: trimmed_string,
            vec: trimmed_vec,
        }
    }

    fn format_columns(&self) -> String {
        if self.vec.len() < 51 {
            return self.string.clone();
        }

        let col_count = self.vec.len() / 50 + 1;
        let spacer = "                                   ";

        let rows = self.vec.chunks(col_count)
            .map(|chunk| chunk.join(spacer)).collect::<Vec<String>>();

        rows.join("\n").trim().to_owned()
    }
}

struct GitOptions {
    remote: String,
    base_branch: String
}

impl GitOptions {
    fn new(opts: &Matches) -> GitOptions {
        let remote = match opts.opt_str("R") {
            Some(remote) => remote,
            None => "origin".to_owned(),
        };
        let base_branch = match opts.opt_str("b") {
            Some(branch) => branch,
            None => "master".to_owned(),
        };

        GitOptions {
            remote: remote,
            base_branch: base_branch,
        }
    }
}

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

    let mut opts = Options::new();
    opts.optflag("l", "locals", "only delete local branches");
    opts.optflag("r", "remotes", "only delete remote branches");
    opts.optopt("R", "", "changes the git remote used (default is origin)", "REMOTE");
    opts.optopt("b", "", "changes the base for merged branches (default is master)", "BRANCH");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(e) => {
            println!("{}", e);
            print_usage(opts);
            return;
        }
    };

    if matches.opt_present("h") {
        print_usage(opts);
        return;
    }

    let git_options = GitOptions::new(&matches);

    let branches = merged_branches(&git_options);

    // Early return if there's nothing to delete
    if branches.string.len() == 0 {
        println!("No branches to delete, you're clean!");
        return;
    }

    let del_opt = DeleteOption::new(matches);

    print_warning(&branches, &del_opt);

    // Read the user's response on continuing
    let mut input = String::new();
    io::stdin().read_line(&mut input).unwrap();

    match input.to_lowercase().as_ref() {
        "y\n" => (),
        "yes\n" => (),
        _ => return,
    }

    ensure_base_branch(&git_options);

    match delete_branches(&branches, del_opt, &git_options) {
        Ok(ref msg) => println!("\n{}", msg),
        Err(ref msg) => println!("\n{}", msg),
    }
}

fn print_usage(opts: Options) {
    print!("{}", opts.usage("Usage: git-clean [options]"));
}

fn print_warning(branches: &Branches, del_opt: &DeleteOption) {
    println!("{}", del_opt.warning_message());
    println!("{}", branches.format_columns());
    print!("Continue? (yN) ");
    io::stdout().flush().unwrap();
}

fn merged_branches(git_options: &GitOptions) -> Branches {
    let base_branch = &git_options.base_branch;
    let regex = "(\\* ".to_owned() + base_branch + "|\\s" + base_branch + ")";
    let grep = spawn_piped(vec!["grep", "-vE", &regex]);

    let gbranch = Command::new("git")
        .args(&["branch", "--merged", base_branch])
        .output()
        .unwrap_or_else(|e| { panic!("ERR: {}", e) });

    {
        grep.stdin.unwrap().write_all(&gbranch.stdout).unwrap();
    }

    let mut s = String::new();
    grep.stdout.unwrap().read_to_string(&mut s).unwrap();

    Branches::new(&s)
}

fn delete_branches(branches: &Branches, options: DeleteOption, git_options: &GitOptions) -> Result<String, String> {
    let output = match options {
        DeleteOption::Local => delete_local_branches(&branches.string).unwrap(),
        DeleteOption::Remote => delete_remote_branches(&branches.string, git_options).unwrap(),
        DeleteOption::Both => {
            let out1 = delete_remote_branches(&branches.string, git_options).unwrap();
            let out2 = delete_local_branches(&branches.string).unwrap();
            ["Remote:".to_owned(), out1, "Local:".to_owned(), out2].join("\n")
        },
    };

    Ok(output)
}

fn delete_local_branches(branches: &String) -> Result<String, String> {
    let xargs = spawn_piped(vec!["xargs", "git", "branch", "-d"]);

    {
        xargs.stdin.unwrap().write_all(branches.as_bytes()).unwrap()
    }

    let mut s = String::new();
    xargs.stdout.unwrap().read_to_string(&mut s).unwrap();
    Ok(s)
}

fn delete_remote_branches(branches: &String, git_options: &GitOptions) -> Result<String, String> {
    let xargs = spawn_piped(vec!["xargs", "git", "push", &git_options.remote, "--delete"]);

    {
        xargs.stdin.unwrap().write_all(branches.as_bytes()).unwrap()
    }

    let mut stdout = String::new();
    xargs.stdout.unwrap().read_to_string(&mut stdout).unwrap();

    let mut stderr = String::new();
    xargs.stderr.unwrap().read_to_string(&mut stderr).unwrap();

    let split = stderr.split("\n");
    let vec: Vec<&str> = split.collect();
    let mut failed_remotes = vec![];
    for s in vec {
        if s.contains("error: unable to delete '") {
            let branch = s.trim_left_matches("error: unable to delete '")
                .trim_right_matches("': remote ref does not exist");

            failed_remotes.push(branch.to_owned() + " was already deleted in the remote.");
        }
    };
    let output = failed_remotes.join("\n") + &stdout;

    Ok(output)
}

fn ensure_base_branch(git_options: &GitOptions) {
    let current_branch_command = Command::new("git")
        .args(&["rev-parse", "--abbrev-ref", "HEAD"])
        .output()
        .unwrap_or_else(|e| { panic!("ERR: {}", e) });

    let current_branch = String::from_utf8(current_branch_command.stdout).unwrap();

    if current_branch.trim() != git_options.base_branch {
        panic!("Please run this command from the branch: ".to_owned() + &git_options.base_branch);
    }
}

fn spawn_piped(args: Vec<&str>) -> Child {
    let cmd = args[0];
    Command::new(cmd)
        .args(&args[1..])
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()
        .unwrap_or_else(|e| { panic!("ERR: {}", e) })
}

#[cfg(test)]
mod test {
    use super::trim_entries;
    use super::format_columns;
    use super::print_warning;
    use super::DeleteOption;
    use super::spawn_piped;

    use std::io::{Read, Write};

    use getopts::{Options};

    #[test]
    fn test_trim_entries() {
        assert_eq!("branch", trim_entries(" branch ".to_owned()));
        assert_eq!("branch", trim_entries(" branch\n".to_owned()));
        assert_eq!("branch1\nbranch2\nbranch3", trim_entries(" branch1 \n branch2 \n branch3 ".to_owned()));
    }

    #[test]
    fn test_format_columns() {
        let mut input = String::new();
        for _ in (0..49) {
            input = input + "branch\n"
        }

        let expected =
"\
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
branch
\
";

        assert_eq!(expected, format_columns(&input));

        let mut input = String::new();
        for _ in (0..51) {
            input = input + "branch\n"
        }

        let expected =
"\
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch                                   branch
branch\
";

        assert_eq!(expected, format_columns(&input));
    }

    #[test]
    fn test_print_warning() {
        print_warning(&"branch".to_owned(), &DeleteOption::Both);
    }

    #[test]
    fn test_delete_option_new() {
        let mut opts = Options::new();
        opts.optflag("l", "local", "only delete local branches");
        opts.optflag("r", "remote", "only delete remote branches");
        opts.optflag("h", "help", "print this help menu");

        // opts throws away the first elem, because it expects it to be the
        // path of the executable
        let args = vec!["./target/debug/git-clean", "-l"];

        let matches = match opts.parse(&args[1..]) {
            Ok(m) => { m }
            Err(_) => { return }
        };

        match DeleteOption::new(matches) {
            DeleteOption::Local => (),
            other @ _ => panic!("Expected a DeleteOption::Local, but found: {:?}", other),
        };

        let args = vec!["./target/debug/git-clean", "-r"];

        let matches = match opts.parse(&args[1..]) {
            Ok(m) => { m }
            Err(_) => { return }
        };

        match DeleteOption::new(matches) {
            DeleteOption::Remote => (),
            other @ _ => panic!("Expected a DeleteOption::Remote, but found: {:?}", other),
        };

        let args = vec!["./target/debug/git-clean"];

        let matches = match opts.parse(&args[1..]) {
            Ok(m) => { m }
            Err(_) => { return }
        };

        match DeleteOption::new(matches) {
            DeleteOption::Both => (),
            other @ _ => panic!("Expected a DeleteOption::Both, but found: {:?}", other),
        };
    }

    #[test]
    fn test_spawn_piped() {
        let echo = spawn_piped(vec!["grep", "foo"]);

        {
            echo.stdin.unwrap().write_all("foo\nbar\nbaz".as_bytes()).unwrap()
        }

        let mut stdout = String::new();
        echo.stdout.unwrap().read_to_string(&mut stdout).unwrap();

        assert_eq!(stdout, "foo\n");
    }

    #[test]
    fn test_warning_message() {
        assert_eq!("The following branches will be deleted locally:", DeleteOption::Local.warning_message());
        assert_eq!("The following branches will be deleted remotely:", DeleteOption::Remote.warning_message());
        assert_eq!("The following branches will be deleted locally and remotely:", DeleteOption::Both.warning_message());
    }
}
<|endoftext|>


<commit_before>#![feature(global_allocator)]
#![feature(allocator_api)]

#[macro_use]
extern crate log;
extern crate log4rs;

#[macro_use]
extern crate lazy_static;

//#![feature(alloc_system)]
//extern crate alloc_system;

use std::heap::System;

#[global_allocator]
static ALLOCATOR: System = System;

mod logging;
mod tcp;
mod core;

use core::StoppableCore;

fn main() {
	// read logging parameters
	logging::init_logging("config/log4rs.yaml");

	info!("starting process ");

	tcp::init();

	if false {
		logging::unittestlogger();
	}

	let core = core::StoppableCore::new().unwrap();
	let timeout = std::time::Duration::from_secs(10);
	core.run_timeout(timeout).unwrap();

	info!("ending gracefully");
}
<commit_msg>conditional build on openwrt vs regular<commit_after>// openwrt needs a special allocator since uClibc does not support jemalloc.
// define openwrt as simple condition
#![cfg_attr(all(feature = "nightly", target="arm-unknown-linux-gnueabi"), cfg(uClibc = "1"))]

#![cfg_attr(feature = "uClibc", feature(global_allocator))]
#![cfg_attr(feature = "uClibc", feature(allocator_api))]

#[macro_use]
extern crate lazy_static;

#[cfg(uClibc)]
use std::heap::System;

#[cfg(uClibc)]
#[global_allocator]
static ALLOCATOR: System = System;

#[macro_use]
extern crate log;
extern crate log4rs;

mod logging;
mod tcp;
mod core;

use core::StoppableCore;

fn main() {
	// read logging parameters
	logging::init_logging("config/log4rs.yaml");

	info!("starting process ");

	tcp::init();

	if false {
		logging::unittestlogger();
	}

	let core = core::StoppableCore::new().unwrap();
	let timeout = std::time::Duration::from_secs(10);
	core.run_timeout(timeout).unwrap();

	info!("ending gracefully");
}
<|endoftext|>