<commit_before>// Copyright (C) 2016 Mark Lee

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate hyper;
extern crate regex;
extern crate rquery;
extern crate semver;
extern crate serde;
extern crate serde_json;

use hyper::{Client, Get, Server};
use hyper::header::{Accept, ContentType};
use hyper::server::{Request, Response};
use hyper::uri::RequestUri::AbsolutePath;
use regex::Regex;
use rquery::Document;
use semver::Version;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::{Error, Read};

const DEFAULT_SERVER_PORT: u32 = 9000;
const MIN_BUNDLER_VERSION: &'static str = "1.11.0";
const RUBY_LANGPACK_RELEASES_URL: &'static str = "https://github.\
                                                  com/heroku/heroku-buildpack-ruby/releases.atom";

fn download_url(client: &Client, url: &str) -> Result<String, Error> {
    let mut resp = client.get(url).send().expect("Could not send HTTP request");
    let mut body = String::new();
    match resp.read_to_string(&mut body) {
        Err(error) => Err(error),
        _ => Ok(body),
    }
}

fn latest_buildpack_release(client: &Client) -> String {
    let xml = download_url(&client, RUBY_LANGPACK_RELEASES_URL)
                  .expect("Could not download Atom releases!");
    let atom_doc = Document::new_from_xml_string(&xml[..]).expect("Could not parse Atom releases!");
    let latest_tag = atom_doc.select("entry title")
                             .expect("Could not find latest buildpack tag!");
    latest_tag.text().clone()
}

fn bundler_version_from_ruby_buildpack(client: &Client) -> Option<String> {
    let ruby_langpack_url = format!("https://raw.githubusercontent.com/\
                                     heroku/heroku-buildpack-ruby/{}/lib/language_pack/\
                                     ruby.rb",
                                    latest_buildpack_release(&client));
    let ruby_file = &download_url(&client, &ruby_langpack_url[..])
                         .expect("Could not download ruby.rb!")[..];
    let regex = Regex::new(r#"BUNDLER_VERSION += "(.+?)""#).expect("Invalid regular expression!");
    if regex.is_match(ruby_file) {
        let captures = regex.captures(ruby_file).expect("Could not match?!");
        Some(captures.at(1).expect("Capture not found?!").to_owned())
    } else {
        None
    }
}

fn is_bundler_upgraded(client: &Client) -> bool {
    if let Some(buildpack_bundler_version_str) = bundler_version_from_ruby_buildpack(&client) {
        let min_version = Version::parse(MIN_BUNDLER_VERSION)
                              .expect("Could not parse min version!");
        let new_version = Version::parse(&buildpack_bundler_version_str[..])
                              .expect("Could not parse new version!");
        min_version < new_version
    } else {
        false
    }
}

fn determine_content_type(req: &Request) -> ContentType {
    if let Some(accept) = req.headers.get::<Accept>() {
        let mut use_json = false;
        for qitem in &accept.0 {
            let qitem_str = &format!("{}", qitem)[..];
            if qitem_str == "application/json" {
                use_json = true;
                break;
            }
        }

        if use_json {
            ContentType::json()
        } else {
            ContentType::html()
        }
    } else {
        ContentType::html()
    }
}

fn result_to_json(result: bool) -> String {
    let mut map = HashMap::new();
    map.insert("result".to_owned(), result);
    serde_json::to_string(&map).expect("Could not serialize result!")
}

fn result_to_html(result: bool) -> String {
    let result_str = if result {
        r#"
Yes
"#
    } else {
        r#"
No
"#
    };
    match File::open("index.html") {
        Ok(mut html_file) => {
            let mut html = String::new();
            html_file.read_to_string(&mut html).expect("Could not read HTML file!");
            html.replace("{{ is_bundler_upgraded }}", result_str)
                .replace("{{ MIN_BUNDLER_VERSION }}", MIN_BUNDLER_VERSION)
        }
        Err(error) => format!("HTML NOT FOUND: {}", error),
    }
}

fn server_port() -> String {
    match env::var("PORT") {
        Ok(port) => port,
        _ => format!("{}", DEFAULT_SERVER_PORT),
    }
}
}

fn main() {
    let server = Server::http(&format!("0.0.0.0:{}", server_port())[..])
                     .expect("Could not create server!");
    server.handle(|req: Request, mut res: Response| {
              match req.uri {
                  AbsolutePath(ref path) => {
                      match (&req.method, &path[..]) {
                          (&Get, "/") => {
                              let client = Client::new();
                              let result = is_bundler_upgraded(&client);
                              let content_type = determine_content_type(&req);
                              let data = match &format!("{}", content_type)[..] {
                                  "application/json; charset=utf-8" => result_to_json(result),
                                  _ => result_to_html(result),
                              };
                              res.headers_mut().set(content_type);
                              res.send(data.as_bytes()).expect("Could not set response body!")
                          }
                          _ => {
                              *res.status_mut() = hyper::NotFound;
                          }
                      }
                  }
                  _ => {
                      *res.status_mut() = hyper::BadRequest;
                  }
              }
          })
          .expect("Could not set up HTTP request handler!");
}
<commit_msg>Rename HTTP client and use io::Result<commit_after>// Copyright (C) 2016 Mark Lee

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate hyper;
extern crate regex;
extern crate rquery;
extern crate semver;
extern crate serde;
extern crate serde_json;

use hyper::{Client as HTTPClient, Get, Server};
use hyper::header::{Accept, ContentType};
use hyper::server::{Request, Response};
use hyper::uri::RequestUri::AbsolutePath;
use regex::Regex;
use rquery::Document;
use semver::Version;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io;
use std::io::Read;

const DEFAULT_SERVER_PORT: u32 = 9000;
const MIN_BUNDLER_VERSION: &'static str = "1.11.0";
const RUBY_LANGPACK_RELEASES_URL: &'static str = "https://github.\
                                                  com/heroku/heroku-buildpack-ruby/releases.atom";

fn download_url(http: &HTTPClient, url: &str) -> io::Result<String> {
    let mut resp = http.get(url).send().expect("Could not send HTTP request");
    let mut body = String::new();
    match resp.read_to_string(&mut body) {
        Err(error) => Err(error),
        _ => Ok(body),
    }
}

fn latest_buildpack_release(http: &HTTPClient) -> String {
    let xml = download_url(&http, RUBY_LANGPACK_RELEASES_URL)
                  .expect("Could not download Atom releases!");
    let atom_doc = Document::new_from_xml_string(&xml[..]).expect("Could not parse Atom releases!");
    let latest_tag = atom_doc.select("entry title")
                             .expect("Could not find latest buildpack tag!");
    latest_tag.text().clone()
}

fn bundler_version_from_ruby_buildpack(http: &HTTPClient) -> Option<String> {
    let ruby_langpack_url = format!("https://raw.githubusercontent.com/\
                                     heroku/heroku-buildpack-ruby/{}/lib/language_pack/\
                                     ruby.rb",
                                    latest_buildpack_release(&http));
    let ruby_file = &download_url(&http, &ruby_langpack_url[..])
                         .expect("Could not download ruby.rb!")[..];
    let regex = Regex::new(r#"BUNDLER_VERSION += "(.+?)""#).expect("Invalid regular expression!");
    if regex.is_match(ruby_file) {
        let captures = regex.captures(ruby_file).expect("Could not match?!");
        Some(captures.at(1).expect("Capture not found?!").to_owned())
    } else {
        None
    }
}

fn is_bundler_upgraded(http: &HTTPClient) -> bool {
    if let Some(buildpack_bundler_version_str) = bundler_version_from_ruby_buildpack(&http) {
        let min_version = Version::parse(MIN_BUNDLER_VERSION)
                              .expect("Could not parse min version!");
        let new_version = Version::parse(&buildpack_bundler_version_str[..])
                              .expect("Could not parse new version!");
        min_version < new_version
    } else {
        false
    }
}

fn determine_content_type(req: &Request) -> ContentType {
    if let Some(accept) = req.headers.get::<Accept>() {
        let mut use_json = false;
        for qitem in &accept.0 {
            let qitem_str = &format!("{}", qitem)[..];
            if qitem_str == "application/json" {
                use_json = true;
                break;
            }
        }

        if use_json {
            ContentType::json()
        } else {
            ContentType::html()
        }
    } else {
        ContentType::html()
    }
}

fn result_to_json(result: bool) -> String {
    let mut map = HashMap::new();
    map.insert("result".to_owned(), result);
    serde_json::to_string(&map).expect("Could not serialize result!")
}

fn result_to_html(result: bool) -> String {
    let result_str = if result {
        r#"
Yes
"#
    } else {
        r#"
No
"#
    };
    match File::open("index.html") {
        Ok(mut html_file) => {
            let mut html = String::new();
            html_file.read_to_string(&mut html).expect("Could not read HTML file!");
            html.replace("{{ is_bundler_upgraded }}", result_str)
                .replace("{{ MIN_BUNDLER_VERSION }}", MIN_BUNDLER_VERSION)
        }
        Err(error) => format!("HTML NOT FOUND: {}", error),
    }
}

fn server_port() -> String {
    match env::var("PORT") {
        Ok(port) => port,
        _ => format!("{}", DEFAULT_SERVER_PORT),
    }
}
}

fn main() {
    let server = Server::http(&format!("0.0.0.0:{}", server_port())[..])
                     .expect("Could not create server!");
    server.handle(|req: Request, mut res: Response| {
              match req.uri {
                  AbsolutePath(ref path) => {
                      match (&req.method, &path[..]) {
                          (&Get, "/") => {
                              let http = HTTPClient::new();
                              let result = is_bundler_upgraded(&http);
                              let content_type = determine_content_type(&req);
                              let data = match &format!("{}", content_type)[..] {
                                  "application/json; charset=utf-8" => result_to_json(result),
                                  _ => result_to_html(result),
                              };
                              res.headers_mut().set(content_type);
                              res.send(data.as_bytes()).expect("Could not set response body!")
                          }
                          _ => {
                              *res.status_mut() = hyper::NotFound;
                          }
                      }
                  }
                  _ => {
                      *res.status_mut() = hyper::BadRequest;
                  }
              }
          })
          .expect("Could not set up HTTP request handler!");
}
<|endoftext|>


<commit_before>extern crate gtk;

pub mod stack;
pub mod calc;

use gtk::prelude::*;
use gtk::{Builder, Button, Window, TextView};

fn map_number_btns(text_view: &TextView, nums_vec: &Vec<Button>) {
    let mut idx = 0;

    for num in nums_vec {
        let tv = text_view.clone();

        num.connect_clicked(move |_| {
            let _ = tv.get_buffer().unwrap().insert_at_cursor(&idx.to_string());
        });

        idx += 1;
    }
}

fn map_btn_insert_at_cursor(text_view: &TextView, btn: &Button, txt: &str) {
    let tv = text_view.clone();
    let txt_cpy: String = (*txt).to_string();

    btn.connect_clicked(move |_| {
        let buf = tv.get_buffer().unwrap();
        buf.insert_at_cursor(&txt_cpy);
    });
}

fn main() {
    if gtk::init().is_err() {
        println!("Failed to initialize GTK.");
        return;
    }

    let glade_src = include_str!("calc_win.glade");
    let builder = Builder::new_from_string(glade_src);

    let window: Window = builder.get_object("calc_app_win").unwrap();

    let text_view: TextView = builder.get_object("input_view").unwrap();
    let output_view: TextView = builder.get_object("output_view").unwrap();

    let nums_vec: Vec<Button> = vec![builder.get_object("btn_0").unwrap(),

                                     builder.get_object("btn_1").unwrap(),
                                     builder.get_object("btn_2").unwrap(),
                                     builder.get_object("btn_3").unwrap(),

                                     builder.get_object("btn_4").unwrap(),
                                     builder.get_object("btn_5").unwrap(),
                                     builder.get_object("btn_6").unwrap(),

                                     builder.get_object("btn_7").unwrap(),
                                     builder.get_object("btn_8").unwrap(),
                                     builder.get_object("btn_9").unwrap()];

    let btn_calc: Button = builder.get_object("btn_calc").unwrap();
    let btn_clear: Button = builder.get_object("btn_clear").unwrap();

    let btn_comma: Button = builder.get_object("btn_comma").unwrap();
    let btn_sub: Button = builder.get_object("btn_sub").unwrap();
    let btn_add: Button = builder.get_object("btn_add").unwrap();
    let btn_mul: Button = builder.get_object("btn_mul").unwrap();
    let btn_div: Button = builder.get_object("btn_div").unwrap();
    let btn_percent: Button = builder.get_object("btn_percent").unwrap();
    let btn_par_left: Button = builder.get_object("btn_par_left").unwrap();
    let btn_par_right: Button = builder.get_object("btn_par_right").unwrap();

    // let btn: Button = builder.get_object("btn1").unwrap();
    // let image: Image = builder.get_object("image1").unwrap();

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    // Map buttons
    map_number_btns(&text_view, &nums_vec);

    // Calc result
    let tv = text_view.clone();
    let tv_out = output_view.clone();

    btn_calc.connect_clicked(move |_| {
        let buf = tv.get_buffer().unwrap();
        let buf_out = tv_out.get_buffer().unwrap();

        let (begin, end) = buf.get_bounds();

        match calc::calc(&(buf.get_text(&begin, &end, true)).unwrap()) {
            Ok(x) => {
                let stringed = format!("= {}", x);
                buf_out.set_text(&stringed);
            },
            Err(x) => buf_out.set_text(&x)
        }

        // let stringed = format!("{}",
        //                        calc::calc(&(buf.get_text(&begin, &end, true)).unwrap()).unwrap());

    });

    // Clear text view
    let tv = text_view.clone();
    let tv_out = output_view.clone();

    btn_clear.connect_clicked(move |_| {
        let buf = tv.get_buffer().unwrap();
        let buf_out = tv_out.get_buffer().unwrap();

        buf.set_text("");
        buf_out.set_text("");
    });

    // Operators
    map_btn_insert_at_cursor(&text_view, &btn_comma, ".");

    map_btn_insert_at_cursor(&text_view, &btn_percent, "%");

    map_btn_insert_at_cursor(&text_view, &btn_sub, "-");
    map_btn_insert_at_cursor(&text_view, &btn_add, "+");

    map_btn_insert_at_cursor(&text_view, &btn_mul, "*");
    map_btn_insert_at_cursor(&text_view, &btn_div, "/");

    map_btn_insert_at_cursor(&text_view, &btn_par_left, "(");
    map_btn_insert_at_cursor(&text_view, &btn_par_right, ")");

    window.show_all();

    gtk::main();
}
<commit_msg>Added input mask, Enter handling<commit_after>extern crate gtk;

pub mod stack;
pub mod calc;

// use gdk::prelude::*;
use gtk::prelude::*;
use gtk::{Builder, Button, Window, TextView, TextBuffer};

fn map_number_btns(text_view: &TextView, nums_vec: &Vec<Button>) {
    let mut idx = 0;

    for num in nums_vec {
        let tv = text_view.clone();

        num.connect_clicked(move |_| {
            let _ = tv.get_buffer().unwrap().insert_at_cursor(&idx.to_string());
        });

        idx += 1;
    }
}

fn map_btn_insert_at_cursor(text_view: &TextView, btn: &Button, txt: &str) {
    let tv = text_view.clone();
    let txt_cpy: String = (*txt).to_string();

    btn.connect_clicked(move |_| {
        let buf = tv.get_buffer().unwrap();
        buf.insert_at_cursor(&txt_cpy);
    });
}

fn calc_and_set_result(in_buf: &TextBuffer, out_buf: &TextBuffer){
    let (begin, end) = in_buf.get_bounds();

    match calc::calc(&(in_buf.get_text(&begin, &end, true)).unwrap()) {
        Ok(x) => {
            let stringed = format!("= {}", x);
            out_buf.set_text(&stringed);
        },
        Err(x) => out_buf.set_text(&x)
    }
}

fn main() {
    if gtk::init().is_err() {
        println!("Failed to initialize GTK.");
        return;
    }

    let glade_src = include_str!("calc_win.glade");
    let builder = Builder::new_from_string(glade_src);

    let window: Window = builder.get_object("calc_app_win").unwrap();

    let text_view: TextView = builder.get_object("input_view").unwrap();
    let output_view: TextView = builder.get_object("output_view").unwrap();

    let nums_vec: Vec<Button> = vec![builder.get_object("btn_0").unwrap(),

                                     builder.get_object("btn_1").unwrap(),
                                     builder.get_object("btn_2").unwrap(),
                                     builder.get_object("btn_3").unwrap(),

                                     builder.get_object("btn_4").unwrap(),
                                     builder.get_object("btn_5").unwrap(),
                                     builder.get_object("btn_6").unwrap(),

                                     builder.get_object("btn_7").unwrap(),
                                     builder.get_object("btn_8").unwrap(),
                                     builder.get_object("btn_9").unwrap()];

    let btn_calc: Button = builder.get_object("btn_calc").unwrap();
    let btn_clear: Button = builder.get_object("btn_clear").unwrap();

    let btn_comma: Button = builder.get_object("btn_comma").unwrap();
    let btn_sub: Button = builder.get_object("btn_sub").unwrap();
    let btn_add: Button = builder.get_object("btn_add").unwrap();
    let btn_mul: Button = builder.get_object("btn_mul").unwrap();
    let btn_div: Button = builder.get_object("btn_div").unwrap();
    let btn_percent: Button = builder.get_object("btn_percent").unwrap();
    let btn_par_left: Button = builder.get_object("btn_par_left").unwrap();
    let btn_par_right: Button = builder.get_object("btn_par_right").unwrap();

    // let btn: Button = builder.get_object("btn1").unwrap();
    // let image: Image = builder.get_object("image1").unwrap();

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    //Clear output view on input view changed
    let tv = text_view.clone();
    let tv_out = output_view.clone();

    text_view.connect_key_press_event(move |_, key|{
        match key.get_keyval(){
            65293 | 65421 => { //ENTER, num lock enter button
                let buf = tv.get_buffer().unwrap();
                let buf_out = tv_out.get_buffer().unwrap();
                calc_and_set_result(&buf, &buf_out);
                Inhibit(true)
            },
            48...57 | 65...90 | 97...122 | 94 | 37 |
            46 | 42 | 47 | 65288 | 65456...65465 | 40 | 41 |
            65455 | 65450 | 65453 | 65451 | 65454
            => { //nums, letters, ^, %, ., *, /, space, backspace, num lock, (, )  keys
                tv_out.get_buffer().unwrap().set_text("");
                Inhibit(false)
            },
            _ =>{
                //println!("VAL {}",  key.get_keyval());
                Inhibit(true)
            }
        }
    });

    // Map buttons
    map_number_btns(&text_view, &nums_vec);

    // Calc result
    let tv = text_view.clone();
    let tv_out = output_view.clone();

    btn_calc.connect_clicked(move |_| {
        let buf = tv.get_buffer().unwrap();
        let buf_out = tv_out.get_buffer().unwrap();

        calc_and_set_result(&buf, &buf_out);
        // let stringed = format!("{}",
        //                        calc::calc(&(buf.get_text(&begin, &end, true)).unwrap()).unwrap());

    });

    // Clear text view
    let tv = text_view.clone();
    let tv_out = output_view.clone();

    btn_clear.connect_clicked(move |_| {
        let buf = tv.get_buffer().unwrap();
        let buf_out = tv_out.get_buffer().unwrap();

        buf.set_text("");
        buf_out.set_text("");
    });

    // Operators
    map_btn_insert_at_cursor(&text_view, &btn_comma, ".");

    map_btn_insert_at_cursor(&text_view, &btn_percent, "%");

    map_btn_insert_at_cursor(&text_view, &btn_sub, "-");
    map_btn_insert_at_cursor(&text_view, &btn_add, "+");

    map_btn_insert_at_cursor(&text_view, &btn_mul, "*");
    map_btn_insert_at_cursor(&text_view, &btn_div, "/");

    map_btn_insert_at_cursor(&text_view, &btn_par_left, "(");
    map_btn_insert_at_cursor(&text_view, &btn_par_right, ")");

    window.show_all();

    gtk::main();
}
<|endoftext|>


<commit_before>extern crate clipboard;
extern crate byteorder;

use clipboard::ClipboardContext;
use std::net::{TcpListener,TcpStream};
use std::io::{Error, ErrorKind, Result, Read,Write};
use std::thread;
use byteorder::{ReadBytesExt, WriteBytesExt,  LittleEndian};
use std::sync::mpsc::{Sender, Receiver,channel};
use std::str;
use std::time::Duration;

static HOST:&'static str = "127.0.0.1:24011";

fn run_reading(stream : &mut TcpStream,content : Sender<String>) -> Result<()>{
    loop {
        let length : u32 = try!(stream.read_u32::<LittleEndian>());
        let mut data = vec![0u8;length as usize];
        try!(stream.take(length as u64).read_to_end(&mut data));

        match String::from_utf8(data){
            Ok(s) => {
                let _ = content.send(s);
            }
            Err(_) => {
                println!("Failed to convert received content to string.");
            }
        };
        // try!(str::from_utf8(&data));
        // content.send(Some(other_content));
    }
}

fn run_sync(stream : TcpStream) -> Result<()>{
    let mut ctx = match ClipboardContext::new(){
        Ok(c) => c,
        Err(_) => return Err(Error::new(ErrorKind::Other,"Failed to create clipboard context"))
    };
    // println!("{}", ctx.get_contents().unwrap());
    //
    // ctx.set_contents("the new content".to_owned()).unwrap();
    let mut current_content = match ctx.get_contents(){
        Ok(s) => s,
        Err(_) => "".to_owned()
    };
    let (wx, rx) = channel::<String>();
    // // create thread which will read the stream for changes from outside, and apply changes to this system
    //
    thread::spawn(move||{run_reading(&mut stream.try_clone().unwrap(),wx)});

    loop{
        thread::sleep(Duration::new(1,0));
        match ctx.get_contents(){
            Ok(s) => {
                if s != current_content{
                    let data = s.as_bytes();
                    // stream.write(data);
                }
            }
            Err(_) => ()
        };

    }
}

fn try_run_client() -> Result<()>{
    let mut stream = try!(TcpStream::connect(&HOST));
    run_sync(stream)
}

fn run_server() -> Result<()> {
    let listener = try!(TcpListener::bind(HOST));

    for stream in listener.incoming(){
        match stream{
            Ok(stream) => {
                thread::spawn(move||{
                    println!("connected");
                    run_sync(stream)
                });
            }
            Err(e) => {
                println!("Connection failed {}",e );
            }
        }
    }

    drop(listener);
    Ok(())
}

fn main() {
    let res = match try_run_client(){
        Err(_) => {
            println!("Could not connect to server, creating own.");
            run_server()},
        _ => Ok(())
    };

    match res {
        Ok(_) => println!("done"),
        Err(e) => println!("Failed: {}", e),
    }

    // let mut ctx = ClipboardContext::new().unwrap();
    // println!("{}", ctx.get_contents().unwrap());
    //
    // ctx.set_contents("the new content".to_owned()).unwrap();
}
<commit_msg>Synchronising clipboards.<commit_after>extern crate clipboard;
extern crate byteorder;

use clipboard::ClipboardContext;
use std::net::{TcpListener,TcpStream};
use std::io::{Error, ErrorKind, Result, Read,Write};
use std::thread;
use byteorder::{ReadBytesExt, WriteBytesExt,  LittleEndian};
use std::sync::mpsc::{Sender, Receiver,channel};
use std::str;
use std::time::Duration;

static HOST:&'static str = "127.0.0.1:24011";

fn run_reading(stream : &mut TcpStream,content : Sender<String>) -> Result<()>{
    loop {
        println!("Waiting for a data");
        let length : u32 = try!(stream.read_u32::<LittleEndian>());
        println!("Got the data size: {}", length);
        let mut data = vec![0u8;length as usize];
        try!(stream.take(length as u64).read_to_end(&mut data));
        match String::from_utf8(data){
            Ok(s) => {
                println!("Received new content from the other side: {}", s);
                let _ = content.send(s);
            }
            Err(_) => {
                println!("Failed to convert received content to string.");
            }
        };
        // try!(str::from_utf8(&data));
        // content.send(Some(other_content));
    }
}

fn run_sync(stream : &mut TcpStream) -> Result<()>{
    let mut ctx = match ClipboardContext::new(){
        Ok(c) => c,
        Err(_) => return Err(Error::new(ErrorKind::Other,"Failed to create clipboard context"))
    };
    // println!("{}", ctx.get_contents().unwrap());
    //
    // ctx.set_contents("the new content".to_owned()).unwrap();
    let mut current_content = match ctx.get_contents(){
        Ok(s) => s,
        Err(_) => "".to_owned()
    };
    let (wx, rx) = channel::<String>();
    // // create thread which will read the stream for changes from outside, and apply changes to this system
    //
    let mut reading = stream.try_clone().unwrap();
    thread::spawn(move||{run_reading(&mut reading,wx)});
    let mut writer = stream.try_clone().unwrap();

    println!("initial clipboard value is: {}",current_content );

    loop{
        thread::sleep(Duration::new(1,0));
        println!("Checking for new content!");
        match ctx.get_contents(){
            Ok(s) => {

                if s != current_content{
                    println!("A new content, sending it to the other side: {}!={}",s,current_content);
                    current_content = s.clone();
                    let data = s.as_bytes();
                    try!(writer.write_u32::<LittleEndian>(data.len() as u32));
                    try!(writer.write(data));
                }
                match rx.try_recv(){
                    Ok(v) =>{
                        println!("Received a new value for cb: {}", v );
                        if v != current_content{
                            current_content = v.clone();
                            match ctx.set_contents(v){
                                Ok(_) => println!("Seting the new value as clipboard content."),
                                Err(_) => println!("Failde to set the new value as clipboard content.")
                            }
                        }
                    }
                    Err(_) => ()
                }
            }
            Err(_) => ()
        };

    }
}

fn try_run_client() -> Result<()>{
    let mut stream = try!(TcpStream::connect(&HOST));
    run_sync(&mut stream)
}

fn run_server() -> Result<()> {
    let listener = try!(TcpListener::bind(HOST));

    for stream in listener.incoming(){
        match stream{
            Ok(stream) => {
                thread::spawn(move||{
                    println!("connected");
                    run_sync(&mut stream.try_clone().unwrap())
                });
            }
            Err(e) => {
                println!("Connection failed {}",e );
            }
        }
    }

    drop(listener);
    Ok(())
}

fn main() {
    let res = match try_run_client(){
        Err(_) => {
            println!("Could not connect to server, creating own.");
            run_server()},
        _ => Ok(())
    };

    match res {
        Ok(_) => println!("done"),
        Err(e) => println!("Failed: {}", e),
    }

    // let mut ctx = ClipboardContext::new().unwrap();
    // println!("{}", ctx.get_contents().unwrap());
    //
    // ctx.set_contents("the new content".to_owned()).unwrap();
}
<|endoftext|>


<commit_before>#![recursion_limit = "1024"]

#[macro_use]
extern crate error_chain;
extern crate reqwest;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

mod errors;

use errors::*;

quick_main!(run);

fn run() -> Result<()> {
    let ip_info: IPInfo = reqwest::get("https://ipinfo.io/json")?.json().map_err(
        Error::from,
    )?;
    println!("{:?}", ip_info);
    Ok(())
}

#[derive(Debug, Deserialize)]
struct IPInfo {
    loc: String,
    city: String,
    region: String,
}
<commit_msg>Implement coordinate deserialization<commit_after>#![recursion_limit = "1024"]

#[macro_use]
extern crate error_chain;
extern crate reqwest;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

mod errors;

use std::result;

use serde::Deserialize;

use errors::*;

quick_main!(run);

fn run() -> Result<()> {
    let ip_info: IPInfo = reqwest::get("https://ipinfo.io/json")?.json().map_err(
        Error::from,
    )?;
    println!("{:?}", ip_info);
    Ok(())
}

#[derive(Debug)]
struct Coordinate {
    lat: f64,
    long: f64,
}

#[derive(Debug, Deserialize)]
struct IPInfo {
    #[serde(rename = "loc", deserialize_with = "coordinate_from_string")]
    location: Coordinate,
    city: String,
    region: String,
}

fn coordinate_from_string<'de, D>(deserializer: D) -> result::Result<Coordinate, D::Error>
where
    D: ::serde::Deserializer<'de>,
{
    let s = String::deserialize(deserializer)?;
    let mut split = s.split(',');
    let lat = split.next().and_then(|lat| lat.parse().ok()).ok_or_else(
        || {
            ::serde::de::Error::custom("")
        },
    )?;
    let long = split.next().and_then(|long| long.parse().ok()).ok_or_else(
        || {
            ::serde::de::Error::custom("")
        },
    )?;
    Ok(Coordinate { lat, long })
}
<|endoftext|>


<commit_before>extern crate websocket;

use std::str;
use std::sync::{Arc, Mutex};
use std::sync::mpsc;
use std::thread;

use websocket::{Server, Message, Sender, Receiver};
use websocket::header::WebSocketProtocol;
use websocket::message::Type;

fn main() {
	let server = Server::bind("0.0.0.0:2794").unwrap();

	let (dispatcher_tx, dispatcher_rx) = mpsc::channel::<String>();
	let client_senders: Arc<Mutex<Vec<mpsc::Sender<String>>>> = Arc::new(Mutex::new(vec![]));

	// dispatcher thread
	{
		let client_senders = client_senders.clone();
		thread::spawn(move || {
			while let Ok(msg) = dispatcher_rx.recv() {
				let mut removed_clients = Vec::new();
				for (i, sender) in client_senders.lock().unwrap().iter().enumerate() {
					match sender.send(msg.clone()) {
						Ok(_) => {},
						Err(_) => {
							// Could not send message because client thread closed
							removed_clients.push(i);
						}
					}
				}

				// Remove all clients that don't exist anymore
				for i in removed_clients {
					client_senders.lock().unwrap().swap_remove(i);
				}
			}
		});
	}

	// Options for removing element:
	// swap_remove <- efficient
	// remove <- ordering stays the same

	// client threads
	for connection in server {
		let dispatcher = dispatcher_tx.clone();
		let (client_tx, client_rx) = mpsc::channel();
		client_senders.lock().unwrap().push(client_tx);

		// Spawn a new thread for each connection.
		thread::spawn(move || {
			let request = connection.unwrap().read_request().unwrap(); // Get the request
			let headers = request.headers.clone(); // Keep the headers so we can check them

			request.validate().unwrap(); // Validate the request

			let mut response = request.accept(); // Form a response

			if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
				if protocols.contains(&("rust-websocket".to_string())) {
					// We have a protocol we want to use
					response.headers.set(WebSocketProtocol(vec!["rust-websocket".to_string()]));
				}
			}

			let mut client = response.send().unwrap(); // Send the response

			let ip = client.get_mut_sender()
				.get_mut()
				.peer_addr()
				.unwrap();

			println!("Connection from {}", ip);

			let message: Message = Message::text("SERVER: Connected.".to_string());
			client.send_message(&message).unwrap();

			let (mut sender, mut receiver) = client.split();

			let mut username = String::new();

			let(tx, rx) = mpsc::channel::<Message>();
			thread::spawn(move || {
				for message in receiver.incoming_messages() {
					if let Ok(message) = message {
						let message: Message = message;
						match message.opcode {
							Type::Close => {
								tx.send(message).unwrap();
								break;
							},
							_ => {
								tx.send(message).unwrap();
							}
						}
					}
					else {
						let message = Message::close();
						tx.send(message).unwrap();
						break;
					}
				}
			});

			loop {
				if let Ok(message) = rx.try_recv() {
					match message.opcode {
						Type::Close => {
							// Closes connection on both sides, doesn't check if client is still connected
							let message = Message::close();
							let _ = sender.send_message(&message);
							println!("Client {} disconnected", ip);
							return;
						},
						Type::Ping => {
							// This could be an issue if ping is sent and client dies, the server will panic!
							let message = Message::pong(message.payload);
							sender.send_message(&message).unwrap();
						},
						_ => {
							if username.is_empty() {
								let payload_bytes = &message.payload;
								let mut payload_string = match str::from_utf8(payload_bytes) {
									Ok(v) => v,
									Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
								};
								if payload_string.len() > 7 {
									match &payload_string[..7] {
										"/login " => {
											// Confirms login, if client dies the server doesnt give a fuck
											payload_string = &payload_string[7..].trim();
											username = String::from(payload_string);
											if !username.is_empty() {
												let msg_end = "'.".to_string();
												let msg_string = "SERVER: Logged in as '".to_string() + &username + &msg_end;
												let message: Message = Message::text(&msg_string[..	]);
												let _ = sender.send_message(&message);
											}
										},
										_ => { }
									}
								}
							}
							else {
								let payload_bytes = &message.payload;
								let payload_string = match str::from_utf8(payload_bytes) {
									Ok(v) => v,
									Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
								};
								let payload_string = payload_string.trim();
								if payload_string.len() > 0 {
									let msg_string = format!("MESSAGE: {}: {}", username, payload_string);
									dispatcher.send(msg_string).unwrap();
								}
							}
						}
					}
				}
				if let Ok(message) = client_rx.try_recv() {
					// Send message from dispatcher to sender, the server doesnt give a fuck when client is dead
					let message: Message = Message::text(message);
					let _ = sender.send_message(&message);
				}
			}
		});
	}
}
<commit_msg>Named all threads to make debugging easier.<commit_after>extern crate websocket;

use std::str;
use std::sync::{Arc, Mutex};
use std::sync::mpsc;
use std::thread;

use websocket::{Server, Message, Sender, Receiver};
use websocket::header::WebSocketProtocol;
use websocket::message::Type;

fn main() {
	let server = Server::bind("0.0.0.0:2794").unwrap();

	let (dispatcher_tx, dispatcher_rx) = mpsc::channel::<String>();
	let client_senders: Arc<Mutex<Vec<mpsc::Sender<String>>>> = Arc::new(Mutex::new(vec![]));

	// dispatcher thread
	{
		let client_senders = client_senders.clone();
		let _ = thread::Builder::new().name("dispatcher".to_string()).spawn(move || {
			while let Ok(msg) = dispatcher_rx.recv() {
				let mut removed_clients = Vec::new();
				for (i, sender) in client_senders.lock().unwrap().iter().enumerate() {
					match sender.send(msg.clone()) {
						Ok(_) => {},
						Err(_) => {
							// Could not send message because client thread closed
							removed_clients.push(i);
						}
					}
				}

				// Remove all clients that don't exist anymore
				for i in removed_clients {
					client_senders.lock().unwrap().swap_remove(i);
				}
			}
		});
	}

	// Options for removing element:
	// swap_remove <- efficient
	// remove <- ordering stays the same

	// client threads
	for connection in server {
		let dispatcher = dispatcher_tx.clone();
		let (client_tx, client_rx) = mpsc::channel();
		client_senders.lock().unwrap().push(client_tx);

		// Spawn a new thread for each connection.
		let _ = thread::Builder::new().name("client".to_string()).spawn(move || {
			let request = connection.unwrap().read_request().unwrap(); // Get the request
			let headers = request.headers.clone(); // Keep the headers so we can check them

			request.validate().unwrap(); // Validate the request

			let mut response = request.accept(); // Form a response

			if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
				if protocols.contains(&("rust-websocket".to_string())) {
					// We have a protocol we want to use
					response.headers.set(WebSocketProtocol(vec!["rust-websocket".to_string()]));
				}
			}

			let mut client = response.send().unwrap(); // Send the response

			let ip = client.get_mut_sender()
				.get_mut()
				.peer_addr()
				.unwrap();

			println!("Connection from {}", ip);

			let message: Message = Message::text("SERVER: Connected.".to_string());
			client.send_message(&message).unwrap();

			let (mut sender, mut receiver) = client.split();

			let mut username = String::new();

			let(tx, rx) = mpsc::channel::<Message>();
			let _ = thread::Builder::new().name("receiver".to_string()).spawn(move || {
				for message in receiver.incoming_messages() {
					if let Ok(message) = message {
						let message: Message = message;
						match message.opcode {
							Type::Close => {
								tx.send(message).unwrap();
								break;
							},
							_ => {
								tx.send(message).unwrap();
							}
						}
					}
					else {
						let message = Message::close();
						tx.send(message).unwrap();
						break;
					}
				}
			});

			loop {
				if let Ok(message) = rx.try_recv() {
					match message.opcode {
						Type::Close => {
							// Closes connection on both sides, doesn't check if client is still connected
							let message = Message::close();
							let _ = sender.send_message(&message);
							println!("Client {} disconnected", ip);
							return;
						},
						Type::Ping => {
							// This could be an issue if ping is sent and client dies, the server will panic!
							let message = Message::pong(message.payload);
							sender.send_message(&message).unwrap();
						},
						_ => {
							if username.is_empty() {
								let payload_bytes = &message.payload;
								let mut payload_string = match str::from_utf8(payload_bytes) {
									Ok(v) => v,
									Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
								};
								if payload_string.len() > 7 {
									match &payload_string[..7] {
										"/login " => {
											// Confirms login, if client dies the server doesnt give a fuck
											payload_string = &payload_string[7..].trim();
											username = String::from(payload_string);
											if !username.is_empty() {
												let msg_end = "'.".to_string();
												let msg_string = "SERVER: Logged in as '".to_string() + &username + &msg_end;
												let message: Message = Message::text(&msg_string[..	]);
												let _ = sender.send_message(&message);
											}
										},
										_ => { }
									}
								}
							}
							else {
								let payload_bytes = &message.payload;
								let payload_string = match str::from_utf8(payload_bytes) {
									Ok(v) => v,
									Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
								};
								let payload_string = payload_string.trim();
								if payload_string.len() > 0 {
									let msg_string = format!("MESSAGE: {}: {}", username, payload_string);
									dispatcher.send(msg_string).unwrap();
								}
							}
						}
					}
				}
				if let Ok(message) = client_rx.try_recv() {
					// Send message from dispatcher to sender, the server doesnt give a fuck when client is dead
					let message: Message = Message::text(message);
					let _ = sender.send_message(&message);
				}
			}
		});
	}
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

use std::ffi::OsString;
use std::fs::{File, OpenOptions};
use std::io::{self, Write};
use std::path::PathBuf;

use integrity_checker::database::{Features, Database, DiffSummary};
use integrity_checker::error;

enum Action {
    Build {
        db_path: OsString,
        dir_path: OsString,
        features: Features,
        threads: usize,
        force: bool,
    },
    Check {
        db_path: OsString,
        dir_path: OsString,
        features: Features,
        threads: usize,
    },
    Diff {
        old_path: OsString,
        new_path: OsString,
    },
    SelfCheck { db_path: OsString },
}

#[derive(Debug)]
enum ActionSummary {
    Built,
    Diff(DiffSummary),
}

fn validate_usize(s: String) -> Result<(), String> {
    s.parse::<usize>().map(|_| ()).map_err(|e| e.to_string())
}

trait DefaultFlags {
    fn add_default_flags(self) -> Self;
}

impl<'a, 'b> DefaultFlags for clap::App<'a, 'b> {
    fn add_default_flags(self) -> Self {
        self
            .arg(clap::Arg::with_name("threads")
                 .help("Number of threads to use")
                 .short("j").long("threads")
                 .takes_value(true)
                 .validator(validate_usize))
            .arg(clap::Arg::with_name("sha2")
                 .help("Enable use of SHA2-256/512 algorithm")
                 .long("sha2")
                 .overrides_with("no-sha2"))
            .arg(clap::Arg::with_name("no-sha2")
                 .help("Disable use of SHA2-256/512 algorithm")
                 .long("no-sha2")
                 .overrides_with("sha2"))
            .arg(clap::Arg::with_name("blake2")
                 .help("Enable use of BLAKE2b algorithm")
                 .long("blake2")
                 .overrides_with("no-blake2"))
            .arg(clap::Arg::with_name("no-blake2")
                 .help("Disable use of BLAKE2b algorithm")
                 .long("no-blake2")
                 .overrides_with("blake2"))
    }
}

fn parse_features(matches: &clap::ArgMatches) -> Features {
    let defaults = Features::default();

    let sha2 = if matches.is_present("sha2") {
        true
    } else if matches.is_present("no-sha2") {
        false
    } else {
        defaults.sha2
    };

    let blake2b = if matches.is_present("blake2") {
        true
    } else if matches.is_present("no-blake2") {
        false
    } else {
        defaults.blake2b
    };

    Features { sha2: sha2, blake2b: blake2b }
}

fn parse_threads(matches: &clap::ArgMatches) -> usize {
    match matches.value_of("threads") {
        None => 1, // FIXME: Pick a reasonable number of threads
        Some(threads) => threads.parse().unwrap(),
    }
}

fn parse_args() -> Action {
    let matches = clap::App::new("Integrity Checker")
        .version(crate_version!())
        .setting(clap::AppSettings::SubcommandRequiredElseHelp)
        .subcommand(clap::SubCommand::with_name("build")
                    .about("Creates an integrity database from a directory")
                    .arg(clap::Arg::with_name("database")
                         .help("Path of integrity database to create")
                         .required(true)
                         .index(1))
                    .arg(clap::Arg::with_name("path")
                         .help("Path of file or directory to scan")
                         .required(true)
                         .index(2))
                    .arg(clap::Arg::with_name("force")
                         .help("Overwrite existing file")
                         .short("f").long("force"))
                    .add_default_flags())
        .subcommand(clap::SubCommand::with_name("check")
                    .about("Check an integrity database against a directory")
                    .arg(clap::Arg::with_name("database")
                         .help("Path of integrity database to read")
                         .required(true)
                         .index(1))
                    .arg(clap::Arg::with_name("path")
                         .help("Path of file or directory to scan")
                         .required(true)
                         .index(2))
                    .add_default_flags())
        .subcommand(clap::SubCommand::with_name("diff")
                    .about("Compare two integrity databases")
                    .arg(clap::Arg::with_name("old")
                         .help("Path of old integrity database")
                         .required(true)
                         .index(1))
                    .arg(clap::Arg::with_name("new")
                         .help("Path of new integrity database")
                         .required(true)
                         .index(2)))
        .subcommand(clap::SubCommand::with_name("selfcheck")
                    .about("Check the internal consistency of an integrity database")
                    .arg(clap::Arg::with_name("database")
                         .help("Path of integrity database to read")
                         .required(true)
                         .index(1)))
        .after_help("RETURN CODE: \
                    \n    0       Success \
                    \n    1       Changes \
                    \n    2       Suspicious changes \
                    \n   -1       Error")
        .get_matches();
    match matches.subcommand() {
        ("build", Some(submatches)) => Action::Build {
            db_path: submatches.value_of_os("database").unwrap().to_owned(),
            dir_path: submatches.value_of_os("path").unwrap().to_owned(),
            features: parse_features(submatches),
            threads: parse_threads(submatches),
            force: submatches.is_present("force"),
        },
        ("check", Some(submatches)) => Action::Check {
            db_path: submatches.value_of_os("database").unwrap().to_owned(),
            dir_path: submatches.value_of_os("path").unwrap().to_owned(),
            features: parse_features(submatches),
            threads: parse_threads(submatches),
        },
        ("diff", Some(submatches)) => Action::Diff {
            old_path: submatches.value_of_os("old").unwrap().to_owned(),
            new_path: submatches.value_of_os("new").unwrap().to_owned(),
        },
        ("selfcheck", Some(submatches)) => Action::SelfCheck {
            db_path: submatches.value_of_os("database").unwrap().to_owned(),
        },
        _ => unreachable!(),
    }
}

fn driver() -> Result<ActionSummary, error::Error> {
    let action = parse_args();
    match action {
        Action::Build { db_path, dir_path, features, threads, force } => {
            let mut json_path = PathBuf::from(&db_path);
            json_path.set_extension("json.gz");
            // Truncate only when force is set
            let f = OpenOptions::new()
                .write(true)
                .create(true)
                .truncate(true)
                .create_new(!force)
                .open(json_path)?;

            let database = Database::build(&dir_path, features, threads, true)?;
            database.dump_json(f, features)?;

            Ok(ActionSummary::Built)
        }
        Action::Check { db_path, dir_path, features, threads } => {
            let mut json_path = PathBuf::from(&db_path);
            json_path.set_extension("json.gz");
            let f = File::open(json_path)?;
            let database = Database::load_json(f)?;
            Ok(ActionSummary::Diff(database.check(&dir_path, features, threads)?))
        }
        Action::Diff { old_path, new_path } => {
            let mut json_old_path = PathBuf::from(&old_path);
            json_old_path.set_extension("json.gz");
            let mut json_new_path = PathBuf::from(&new_path);
            json_new_path.set_extension("json.gz");
            let f_old = File::open(json_old_path)?;
            let f_new = File::open(json_new_path)?;
            let old = Database::load_json(f_old)?;
            let new = Database::load_json(f_new)?;
            Ok(ActionSummary::Diff(old.show_diff(&new)))
        }
        Action::SelfCheck { db_path } => {
            let mut json_path = PathBuf::from(&db_path);
            json_path.set_extension("json.gz");
            let f = File::open(json_path)?;
            Database::load_json(f)?;
            Ok(ActionSummary::Diff(DiffSummary::NoChanges))
        }
    }
}

fn main() {
    ::std::process::exit(match driver() {
       Ok(action_summary) => match action_summary {
           ActionSummary::Built => 0,
           ActionSummary::Diff(DiffSummary::NoChanges) => 0,
           ActionSummary::Diff(DiffSummary::Changes) => 1,
           ActionSummary::Diff(DiffSummary::Suspicious) => 2,
       },
       Err(err) => {
           writeln!(io::stderr(), "error: {:?}", err).unwrap();
           -1
       },
    });
}
<commit_msg>Do not change the db name as passed from the CLI, solves #5 (#6)<commit_after>#[macro_use]
extern crate clap;

use std::ffi::OsString;
use std::fs::{File, OpenOptions};
use std::io::{self, Write};

use integrity_checker::database::{Features, Database, DiffSummary};
use integrity_checker::error;

enum Action {
    Build {
        db_path: OsString,
        dir_path: OsString,
        features: Features,
        threads: usize,
        force: bool,
    },
    Check {
        db_path: OsString,
        dir_path: OsString,
        features: Features,
        threads: usize,
    },
    Diff {
        old_path: OsString,
        new_path: OsString,
    },
    SelfCheck { db_path: OsString },
}

#[derive(Debug)]
enum ActionSummary {
    Built,
    Diff(DiffSummary),
}

fn validate_usize(s: String) -> Result<(), String> {
    s.parse::<usize>().map(|_| ()).map_err(|e| e.to_string())
}

trait DefaultFlags {
    fn add_default_flags(self) -> Self;
}

impl<'a, 'b> DefaultFlags for clap::App<'a, 'b> {
    fn add_default_flags(self) -> Self {
        self
            .arg(clap::Arg::with_name("threads")
                 .help("Number of threads to use")
                 .short("j").long("threads")
                 .takes_value(true)
                 .validator(validate_usize))
            .arg(clap::Arg::with_name("sha2")
                 .help("Enable use of SHA2-256/512 algorithm")
                 .long("sha2")
                 .overrides_with("no-sha2"))
            .arg(clap::Arg::with_name("no-sha2")
                 .help("Disable use of SHA2-256/512 algorithm")
                 .long("no-sha2")
                 .overrides_with("sha2"))
            .arg(clap::Arg::with_name("blake2")
                 .help("Enable use of BLAKE2b algorithm")
                 .long("blake2")
                 .overrides_with("no-blake2"))
            .arg(clap::Arg::with_name("no-blake2")
                 .help("Disable use of BLAKE2b algorithm")
                 .long("no-blake2")
                 .overrides_with("blake2"))
    }
}

fn parse_features(matches: &clap::ArgMatches) -> Features {
    let defaults = Features::default();

    let sha2 = if matches.is_present("sha2") {
        true
    } else if matches.is_present("no-sha2") {
        false
    } else {
        defaults.sha2
    };

    let blake2b = if matches.is_present("blake2") {
        true
    } else if matches.is_present("no-blake2") {
        false
    } else {
        defaults.blake2b
    };

    Features { sha2: sha2, blake2b: blake2b }
}

fn parse_threads(matches: &clap::ArgMatches) -> usize {
    match matches.value_of("threads") {
        None => 1, // FIXME: Pick a reasonable number of threads
        Some(threads) => threads.parse().unwrap(),
    }
}

fn parse_args() -> Action {
    let matches = clap::App::new("Integrity Checker")
        .version(crate_version!())
        .setting(clap::AppSettings::SubcommandRequiredElseHelp)
        .subcommand(clap::SubCommand::with_name("build")
                    .about("Creates an integrity database from a directory")
                    .arg(clap::Arg::with_name("database")
                         .help("Path of integrity database to create")
                         .required(true)
                         .index(1))
                    .arg(clap::Arg::with_name("path")
                         .help("Path of file or directory to scan")
                         .required(true)
                         .index(2))
                    .arg(clap::Arg::with_name("force")
                         .help("Overwrite existing file")
                         .short("f").long("force"))
                    .add_default_flags())
        .subcommand(clap::SubCommand::with_name("check")
                    .about("Check an integrity database against a directory")
                    .arg(clap::Arg::with_name("database")
                         .help("Path of integrity database to read")
                         .required(true)
                         .index(1))
                    .arg(clap::Arg::with_name("path")
                         .help("Path of file or directory to scan")
                         .required(true)
                         .index(2))
                    .add_default_flags())
        .subcommand(clap::SubCommand::with_name("diff")
                    .about("Compare two integrity databases")
                    .arg(clap::Arg::with_name("old")
                         .help("Path of old integrity database")
                         .required(true)
                         .index(1))
                    .arg(clap::Arg::with_name("new")
                         .help("Path of new integrity database")
                         .required(true)
                         .index(2)))
        .subcommand(clap::SubCommand::with_name("selfcheck")
                    .about("Check the internal consistency of an integrity database")
                    .arg(clap::Arg::with_name("database")
                         .help("Path of integrity database to read")
                         .required(true)
                         .index(1)))
        .after_help("RETURN CODE: \
                    \n    0       Success \
                    \n    1       Changes \
                    \n    2       Suspicious changes \
                    \n   -1       Error")
        .get_matches();
    match matches.subcommand() {
        ("build", Some(submatches)) => Action::Build {
            db_path: submatches.value_of_os("database").unwrap().to_owned(),
            dir_path: submatches.value_of_os("path").unwrap().to_owned(),
            features: parse_features(submatches),
            threads: parse_threads(submatches),
            force: submatches.is_present("force"),
        },
        ("check", Some(submatches)) => Action::Check {
            db_path: submatches.value_of_os("database").unwrap().to_owned(),
            dir_path: submatches.value_of_os("path").unwrap().to_owned(),
            features: parse_features(submatches),
            threads: parse_threads(submatches),
        },
        ("diff", Some(submatches)) => Action::Diff {
            old_path: submatches.value_of_os("old").unwrap().to_owned(),
            new_path: submatches.value_of_os("new").unwrap().to_owned(),
        },
        ("selfcheck", Some(submatches)) => Action::SelfCheck {
            db_path: submatches.value_of_os("database").unwrap().to_owned(),
        },
        _ => unreachable!(),
    }
}

fn driver() -> Result<ActionSummary, error::Error> {
    let action = parse_args();
    match action {
        Action::Build { db_path, dir_path, features, threads, force } => {
            // Truncate only when force is set
            let f = OpenOptions::new()
                .write(true)
                .create(true)
                .truncate(true)
                .create_new(!force)
                .open(&db_path)?;

            let database = Database::build(&dir_path, features, threads, true)?;
            database.dump_json(f, features)?;

            Ok(ActionSummary::Built)
        }
        Action::Check { db_path, dir_path, features, threads } => {
            let f = File::open(&db_path)?;
            let database = Database::load_json(f)?;
            Ok(ActionSummary::Diff(database.check(&dir_path, features, threads)?))
        }
        Action::Diff { old_path, new_path } => {
            let f_old = File::open(&old_path)?;
            let f_new = File::open(&new_path)?;
            let old = Database::load_json(f_old)?;
            let new = Database::load_json(f_new)?;
            Ok(ActionSummary::Diff(old.show_diff(&new)))
        }
        Action::SelfCheck { db_path } => {
            let f = File::open(&db_path)?;
            Database::load_json(f)?;
            Ok(ActionSummary::Diff(DiffSummary::NoChanges))
        }
    }
}

fn main() {
    ::std::process::exit(match driver() {
       Ok(action_summary) => match action_summary {
           ActionSummary::Built => 0,
           ActionSummary::Diff(DiffSummary::NoChanges) => 0,
           ActionSummary::Diff(DiffSummary::Changes) => 1,
           ActionSummary::Diff(DiffSummary::Suspicious) => 2,
       },
       Err(err) => {
           writeln!(io::stderr(), "error: {:?}", err).unwrap();
           -1
       },
    });
}
<|endoftext|>


<commit_before>mod parser;

/// Imprime mensagem de ajuda
fn print_help() {
    println!("Ta querendo ajuda, cumpade?");
    println!("O uso é o seguinte: birl [opções] [arquivo ou arquivos]");
    println!("Cê pode passar mais de um arquivo, só que apenas um pode ter a seção \"SHOW\", que \
              é");
    println!("o ponto de partida do teu programa.");
    println!("As opções são as seguintes:");
    println!("\t-a ou --ajuda-o-maluco-ta-doente       : Imprime essa mensagem de ajuda");
    println!("\t-v ou --vers[ã ou a]o-dessa-porra      : Imprime a versão do programa");
    println!("\t-e ou --ele-que-a-gente-quer [comando] : Imprime uma mensagem de ajuda para o \
              comando");
    println!("\t-j ou --jaula [nome]                   : Diz ao interpretador pra usar outro \
              ponto de partida. Padrão: SHOW");
}

/// Versão numérica
pub static BIRLSCRIPT_VERSION: &'static str = "0.1.3";
/// Release, como alfa, beta, etc
pub static BIRLSCRIPT_RELEASE: &'static str = "ALFA";

/// Imprime a mensagem de versão
fn print_version() {
    println!("Versão dessa porra, cumpade:");
    println!("Interpretador BIRLSCRIPT v{} - {}",
             BIRLSCRIPT_VERSION,
             BIRLSCRIPT_RELEASE);
    println!("Copyleft(ɔ) 2016 Rafael R Nakano - Nenhum direito reservado");
}

/// Coleção de parametros passados ao interpretador
enum Param {
    /// Pedido para printar versão
    PrintVersion,
    /// Pedido para printar ajuda
    PrintHelp,
    /// Pedido para printar ajuda com um comando
    CommandHelp(String),
    /// Pedido para modificar o ponto de partida
    CustomInit(String),
    /// Arquivo passado para interpretação
    InputFile(String),
}

/// Faz parsing dos comandos passados e retorna uma lista deles
fn get_params() -> Vec<Param> {
    use std::env;
    let mut ret: Vec<Param> = vec![];
    let mut params = env::args();
    if params.len() > 2 {
        loop {
            let p = match params.next() {
                Some(v) => v,
                None => break,
            };
            match p.as_str() {
                "-a" |
                "--ajuda-o-maluco-ta-doente" => ret.push(Param::PrintHelp),
                "-v" |
                "--versão-dessa-porra" |
                "--versao-dessa-porra" => ret.push(Param::PrintVersion),
                "-e" |
                "--ele-que-a-gente-quer" => {
                    let cmd = match params.next() {
                        Some(name) => name,
                        None => {
                            println!("Erro: a flag \"-e ou --ele-que-a-gente-quer\" espera um \
                                      valor.");
                            break;
                        }
                    };
                    ret.push(Param::CommandHelp(cmd));
                }
                "-j" | "--jaula" => {
                    let section = match params.next() {
                        Some(sect) => sect,
                        None => {
                            println!("Erro: a flag \"-j ou --jaula\" espera um valor.");
                            break;
                        }
                    };
                    ret.push(Param::CustomInit(section));
                }
                _ => ret.push(Param::InputFile(p)),
            }
        }
    }
    ret
}

/// Printa ajuda para um comando
fn command_help(_command: &str) {}

fn main() {
    let params = get_params();
    let mut files: Vec<String> = vec![];
    for p in params {
        match p {
            Param::PrintVersion => print_version(),
            Param::PrintHelp => print_help(),
            Param::CommandHelp(cmd) => command_help(&cmd),
            // TODO: Adicionar nas flags do interpretador a jaula customizada
            Param::CustomInit(_init) => {}
            Param::InputFile(file) => files.push(file),
        }
    }
    if files.len() > 0 {
        let mut units: Vec<parser::Unit> = vec![];
        for file in files {
            units.push(parser::parse(&file));
        }
    }
}
<commit_msg>Faz-se possivel ver a documentação de cada comando<commit_after>mod parser;
mod commands;

/// Imprime mensagem de ajuda
fn print_help() {
    println!("Ta querendo ajuda, cumpade?");
    println!("O uso é o seguinte: birl [opções] [arquivo ou arquivos]");
    println!("Cê pode passar mais de um arquivo, só que apenas um pode ter a seção \"SHOW\", que \
              é");
    println!("o ponto de partida do teu programa.");
    println!("As opções são as seguintes:");
    println!("\t-a ou --ajuda-o-maluco-ta-doente       : Imprime essa mensagem de ajuda");
    println!("\t-v ou --vers[ã ou a]o-dessa-porra      : Imprime a versão do programa");
    println!("\t-e ou --ele-que-a-gente-quer [comando] : Imprime uma mensagem de ajuda para o \
              comando");
    println!("\t-j ou --jaula [nome]                   : Diz ao interpretador pra usar outro \
              ponto de partida. Padrão: SHOW");
}

/// Versão numérica
pub static BIRLSCRIPT_VERSION: &'static str = "0.1.3";
/// Release, como alfa, beta, etc
pub static BIRLSCRIPT_RELEASE: &'static str = "ALFA";

/// Imprime a mensagem de versão
fn print_version() {
    println!("Versão dessa porra, cumpade:");
    println!("Interpretador BIRLSCRIPT v{} - {}",
             BIRLSCRIPT_VERSION,
             BIRLSCRIPT_RELEASE);
    println!("Copyleft(ɔ) 2016 Rafael R Nakano - Nenhum direito reservado");
}

/// Coleção de parametros passados ao interpretador
enum Param {
    /// Pedido para printar versão
    PrintVersion,
    /// Pedido para printar ajuda
    PrintHelp,
    /// Pedido para printar ajuda com um comando
    CommandHelp(String),
    /// Pedido para modificar o ponto de partida
    CustomInit(String),
    /// Arquivo passado para interpretação
    InputFile(String),
}

/// Faz parsing dos comandos passados e retorna uma lista deles
fn get_params() -> Vec<Param> {
    use std::env;
    let mut ret: Vec<Param> = vec![];
    let mut params = env::args();
    // Se o proximo argumento é um valor que deve ser ignorado
    let mut next_is_val = false;
    if params.len() > 2 {
        loop {
            let p = match params.next() {
                Some(v) => v,
                None => break,
            };
            if next_is_val {
                next_is_val = false;
                continue;
            }
            match p.as_str() {
                "-a" |
                "--ajuda-o-maluco-ta-doente" => ret.push(Param::PrintHelp),
                "-v" |
                "--versão-dessa-porra" |
                "--versao-dessa-porra" => ret.push(Param::PrintVersion),
                "-e" |
                "--ele-que-a-gente-quer" => {
                    next_is_val = true;
                    let cmd = match params.next() {
                        Some(name) => name,
                        None => {
                            println!("Erro: a flag \"-e ou --ele-que-a-gente-quer\" espera um \
                                      valor.");
                            break;
                        }
                    };
                    ret.push(Param::CommandHelp(cmd));
                }
                "-j" | "--jaula" => {
                    next_is_val = true;
                    let section = match params.next() {
                        Some(sect) => sect,
                        None => {
                            println!("Erro: a flag \"-j ou --jaula\" espera um valor.");
                            break;
                        }
                    };
                    ret.push(Param::CustomInit(section));
                }
                _ => ret.push(Param::InputFile(p)),
            }
        }
    }
    ret
}

/// Printa ajuda para um comando
fn command_help(command: &str) {
    use parser::kw::*;
    use commands::*;
    let doc = match command {
        KW_MOVE => doc_move(),
        KW_CLEAR => doc_clear(),
        KW_XOR => doc_xor(),
        _ => String::new(),
    };
    println!("{}", doc);
}

fn main() {
    let params = get_params();
    let mut files: Vec<String> = vec![];
    for p in params {
        match p {
            Param::PrintVersion => print_version(),
            Param::PrintHelp => print_help(),
            Param::CommandHelp(cmd) => command_help(&cmd),
            // TODO: Adicionar nas flags do interpretador a jaula customizada
            Param::CustomInit(_init) => {}
            Param::InputFile(file) => files.push(file),
        }
    }
    if files.len() > 0 {
        let mut units: Vec<parser::Unit> = vec![];
        for file in files {
            units.push(parser::parse(&file));
        }
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
use rustc_serialize::json;

use std::fmt;
use std::env;

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

use std::thread;
use std::sync::{Mutex, Arc};
use std::process::Command;

extern crate ansi_term;
use ansi_term::Colour;

struct WorkConf {
    project: String,
    operate: String,
    head:    String,
}

impl fmt::Debug for WorkConf {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "WorkConf:{}\"project\": {}, \"operate\": {}, \"head\": {}{}",
            "{", self.project, self.operate, self.head, "}")
    }
}

// Automatically generate `RustcDecodable` and `RustcEncodable` trait
// implementations
#[derive(RustcDecodable, RustcEncodable)]
struct DeployConf {
    user: String,
    path: String,
    hosts_conf: Vec<String>,
}

fn usage(argv_0: &String) {
    println!("\n{}", Colour::Cyan.bold().paint("-----USAGE----"));
    println!("{} {} {}             {}",
        Colour::Green.bold().paint(argv_0.to_string()),
        Colour::Blue.bold().paint("project"),
        Colour::Yellow.bold().paint("deploy"),
        Colour::Red.paint("deploy project with latest <head>."));
    println!("{} {} {} {}    {}\n",
        Colour::Green.bold().paint(argv_0.to_string()),
        Colour::Blue.bold().paint("project"),
        Colour::Yellow.bold().paint("rollback"),
        Colour::Purple.bold().paint("<head>"),
        Colour::Red.paint("rollback with <head>."));
    std::process::exit(0);
}

static DEBUG: bool = false;

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

    if argc < 3 {
        usage(&args[0]);
    }

    // 处理命令行参数
    let project = args[1].to_string();
    let operate = args[2].to_string();
    if ("deploy".to_string() != operate && "rollback".to_string() != operate) || ("rollback".to_string() == operate && argc < 4) {
        usage(&args[0]);
    }

    let head = if argc > 3 { args[3].to_string() } else { "".to_string() };

    let work_conf = WorkConf{
        project: project,
        operate: operate,
        head:    head,
    };
    if DEBUG { println!("{:?}", work_conf); }

    let config_filename = format!("./conf/{}.json", work_conf.project);
    if DEBUG { println!("config_filename: {}", config_filename); }

    let mut data = String::new();
    let mut f = File::open(config_filename)
        .ok()
        .expect("Can NOT open file.");
    f.read_to_string(&mut data)
        .ok()
        .expect("Can NOT read cofing file.");
    if DEBUG { println!("deploy_conf: {}", data)}
    let deploy_conf: DeployConf = json::decode(&data)
        .ok()
        .expect("Can NOT parse JSON config data.");
    if DEBUG { println!("JSON: {}", json::encode(&deploy_conf).unwrap()); }

    let mut hosts_conf = Vec::new();
    let hosts_len = deploy_conf.hosts_conf.len();
    for index in 0 .. hosts_len {
        hosts_conf.push(deploy_conf.hosts_conf[index].clone());
    }
    let mutex_ct = Arc::new(Mutex::new(vec![1]));

    println!("          ===== {} ======\n", Colour::Blue.bold().paint(work_conf.project.to_string()));

    let handles: Vec<_> = hosts_conf.into_iter().map(|host| {
        let user = deploy_conf.user.clone();
        let path = deploy_conf.path.clone();
        let operate = work_conf.operate.clone();
        let head    = work_conf.head.clone();
        let mutex_ct= mutex_ct.clone();
        thread::spawn(move || {
            let cmd = if "deploy".to_string() == operate {
                format!("ssh {}@{} \"cd {} && git pull && git log -1 | awk '{{if (\\$1 ~/commit/) {{print \\$2}}}}' 2>&1\"",
                user, host, path)
            } else {
                format!("ssh {}@{} \"cd {} && git reset --hard {} && git log -1 | awk '{{if (\\$1 ~/commit/) {{print \\$2}}}}' 2>&1\"",
                user, host, path, head)
            };
            if DEBUG { println!("CMD: {}", cmd); }
            let output = Command::new("sh")
                .arg("-c")
                .arg(cmd)
                .output()
                .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

            let user_at_host = format!("{}{}{}",
                Colour::Green.bold().paint(user.to_string()),
                Colour::Red.bold().paint("@"),
                Colour::Cyan.bold().paint(host.to_string()));
            // 解决多线程穿插输出的问题
            let mut output_buf = "".to_string();
            output_buf = output_buf + &(format!("--- {} {} for {} ---\n",
                Colour::Cyan.bold().paint("START"),
                Colour::Purple.bold().paint(operate.to_string()), user_at_host));
            if Some(0) == output.status.code() {
                output_buf = output_buf + &(format!("{}\n", String::from_utf8_lossy(&output.stdout)));
                output_buf = output_buf + &(format!("{} {} for {}\n",
                    Colour::Purple.bold().paint(operate.to_string()),
                    Colour::Green.bold().paint("SUCCESS"),
                    user_at_host));
            } else {
                output_buf = output_buf + &(format!("{} {}\n", Colour::Red.bold().paint("stderr:"),String::from_utf8_lossy(&output.stderr)));
                output_buf = output_buf + &(format!("{} {} for {}\n",
                    Colour::Purple.bold().paint(operate.to_string()),
                    Colour::Red.bold().paint("FAIL!"),
                    user_at_host));
            }
            output_buf = output_buf + &(format!("--- {} ---\n\n", Colour::Cyan.bold().paint("END")));

            {
                let _ct = mutex_ct.lock().unwrap();
                if DEBUG { println!("status: {:?}", output.status.code()); }
                println!("{}", output_buf);
            }
        })
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
}
<commit_msg>去掉一个换行,让输出更紧凑.<commit_after>extern crate rustc_serialize;
use rustc_serialize::json;

use std::fmt;
use std::env;

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

use std::thread;
use std::sync::{Mutex, Arc};
use std::process::Command;

extern crate ansi_term;
use ansi_term::Colour;

struct WorkConf {
    project: String,
    operate: String,
    head:    String,
}

impl fmt::Debug for WorkConf {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "WorkConf:{}\"project\": {}, \"operate\": {}, \"head\": {}{}",
            "{", self.project, self.operate, self.head, "}")
    }
}

// Automatically generate `RustcDecodable` and `RustcEncodable` trait
// implementations
#[derive(RustcDecodable, RustcEncodable)]
struct DeployConf {
    user: String,
    path: String,
    hosts_conf: Vec<String>,
}

fn usage(argv_0: &String) {
    println!("\n{}", Colour::Cyan.bold().paint("-----USAGE----"));
    println!("{} {} {}             {}",
        Colour::Green.bold().paint(argv_0.to_string()),
        Colour::Blue.bold().paint("project"),
        Colour::Yellow.bold().paint("deploy"),
        Colour::Red.paint("deploy project with latest <head>."));
    println!("{} {} {} {}    {}\n",
        Colour::Green.bold().paint(argv_0.to_string()),
        Colour::Blue.bold().paint("project"),
        Colour::Yellow.bold().paint("rollback"),
        Colour::Purple.bold().paint("<head>"),
        Colour::Red.paint("rollback with <head>."));
    std::process::exit(0);
}

static DEBUG: bool = false;

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

    if argc < 3 {
        usage(&args[0]);
    }

    // 处理命令行参数
    let project = args[1].to_string();
    let operate = args[2].to_string();
    if ("deploy".to_string() != operate && "rollback".to_string() != operate) || ("rollback".to_string() == operate && argc < 4) {
        usage(&args[0]);
    }

    let head = if argc > 3 { args[3].to_string() } else { "".to_string() };

    let work_conf = WorkConf{
        project: project,
        operate: operate,
        head:    head,
    };
    if DEBUG { println!("{:?}", work_conf); }

    let config_filename = format!("./conf/{}.json", work_conf.project);
    if DEBUG { println!("config_filename: {}", config_filename); }

    let mut data = String::new();
    let mut f = File::open(config_filename)
        .ok()
        .expect("Can NOT open file.");
    f.read_to_string(&mut data)
        .ok()
        .expect("Can NOT read cofing file.");
    if DEBUG { println!("deploy_conf: {}", data)}
    let deploy_conf: DeployConf = json::decode(&data)
        .ok()
        .expect("Can NOT parse JSON config data.");
    if DEBUG { println!("JSON: {}", json::encode(&deploy_conf).unwrap()); }

    let mut hosts_conf = Vec::new();
    let hosts_len = deploy_conf.hosts_conf.len();
    for index in 0 .. hosts_len {
        hosts_conf.push(deploy_conf.hosts_conf[index].clone());
    }
    let mutex_ct = Arc::new(Mutex::new(vec![1]));

    println!("          ===== {} ======\n", Colour::Blue.bold().paint(work_conf.project.to_string()));

    let handles: Vec<_> = hosts_conf.into_iter().map(|host| {
        let user = deploy_conf.user.clone();
        let path = deploy_conf.path.clone();
        let operate = work_conf.operate.clone();
        let head    = work_conf.head.clone();
        let mutex_ct= mutex_ct.clone();
        thread::spawn(move || {
            let cmd = if "deploy".to_string() == operate {
                format!("ssh {}@{} \"cd {} && git pull && git log -1 | awk '{{if (\\$1 ~/commit/) {{print \\$2}}}}' 2>&1\"",
                user, host, path)
            } else {
                format!("ssh {}@{} \"cd {} && git reset --hard {} && git log -1 | awk '{{if (\\$1 ~/commit/) {{print \\$2}}}}' 2>&1\"",
                user, host, path, head)
            };
            if DEBUG { println!("CMD: {}", cmd); }
            let output = Command::new("sh")
                .arg("-c")
                .arg(cmd)
                .output()
                .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

            let user_at_host = format!("{}{}{}",
                Colour::Green.bold().paint(user.to_string()),
                Colour::Red.bold().paint("@"),
                Colour::Cyan.bold().paint(host.to_string()));
            // 解决多线程穿插输出的问题
            let mut output_buf = "".to_string();
            output_buf = output_buf + &(format!("--- {} {} for {} ---\n",
                Colour::Cyan.bold().paint("START"),
                Colour::Purple.bold().paint(operate.to_string()), user_at_host));
            if Some(0) == output.status.code() {
                output_buf = output_buf + &(format!("{}\n", String::from_utf8_lossy(&output.stdout)));
                output_buf = output_buf + &(format!("{} {} for {}\n",
                    Colour::Purple.bold().paint(operate.to_string()),
                    Colour::Green.bold().paint("SUCCESS"),
                    user_at_host));
            } else {
                output_buf = output_buf + &(format!("{} {}\n", Colour::Red.bold().paint("stderr:"),String::from_utf8_lossy(&output.stderr)));
                output_buf = output_buf + &(format!("{} {} for {}\n",
                    Colour::Purple.bold().paint(operate.to_string()),
                    Colour::Red.bold().paint("FAIL!"),
                    user_at_host));
            }
            output_buf = output_buf + &(format!("--- {} ---\n", Colour::Cyan.bold().paint("END")));

            {
                let _ct = mutex_ct.lock().unwrap();
                if DEBUG { println!("status: {:?}", output.status.code()); }
                println!("{}", output_buf);
            }
        })
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate lodepng;

struct Pixel {r: u8, g: u8, b: u8}

static h : u32 = 10;
static w : u32 = 10;
static pixel_count : uint = (w*h) as uint;

fn main() {
    let path = &Path::new("test.png");

    let pixel_data = [Pixel {r: 0, g: 0, b: 0}, ..pixel_count];
    let mut data = [0u8, ..pixel_count*3u];
    assert!(pixel_data.len()*3 == data.len());
    for (i, p) in pixel_data.iter().enumerate() {
        data[i*3 + 0] = p.r;
        data[i*3 + 1] = p.g;
        data[i*3 + 2] = p.b;
    }
    match lodepng::encode_file(path, data, w, h, lodepng::LCT_RGB, 8) {
        Err(e) => fail!("Error writing: {}", e),
        Ok(_)  => (),
    }
}
<commit_msg>Render pixels concurrently<commit_after>extern crate lodepng;

use std::comm;
//use std::sync::Arc;

#[deriving(Clone, Show)]
struct Point {x: u32, y: u32}
#[deriving(Clone, Show)]
struct Pixel {r: u8, g: u8, b: u8}
#[deriving(Clone, Show)]
struct Rect {origin: Point, width: u32, height: u32}
struct RectIter {rect: Rect, position: Point}

impl Rect {
    fn iter(&self) -> RectIter {
        RectIter {rect: *self,
                  position: Point {x: 0, y: 0}}
    }
}
impl Add<Point, Point> for Point {
    fn add(&self, rhs: &Point) -> Point {
        Point {x: self.x + rhs.x,
               y: self.y + rhs.y}
    }
}

impl Iterator<Point> for RectIter {
    fn next(&mut self) -> Option<Point> {
        if self.position.y >= self.rect.height {
            return None;
        }
        let value = self.position;
        self.position.x += 1;
        if self.position.x >= self.rect.width {
            self.position.x = 0;
            self.position.y += 1;
        }
        Some(self.rect.origin + value)
    }
}

static h : u32 = 512;
static w : u32 = 512;
static pixel_count : uint = (w*h) as uint;

fn main() {
    let mut data = [0u8, ..pixel_count*3u];
    let (tx, rx) = comm::channel();
    let mut points = Vec::with_capacity(pixel_count);

    for x in range(0, w) {
        for y in range(0, h) {
            points.push(Point {x: x, y: y});
        }
    }

    let proc_tx = tx.clone();
    let rect = Rect {origin: Point {x: 0, y: 0},
                     width: w, height: h};
    spawn(proc() {
        for point in rect.iter() {
            proc_tx.send((point, render(point)));
        }
    });

    //let done = true;
    for _ in range(0, pixel_count) {
        let (point, pixel) = rx.recv();
        let index : uint = ((point.x + point.y * w) * 3) as uint;
        data[index + 0] = pixel.r;
        data[index + 1] = pixel.g;
        data[index + 2] = pixel.b;
    }

    let path = &Path::new("test.png");
    match lodepng::encode_file(path, data, w, h, lodepng::LCT_RGB, 8) {
        Err(e) => fail!("Error writing: {}", e),
        Ok(_)  => (),
    }
}

fn render(point: Point) -> Pixel {
    Pixel {r: (point.x % 256) as u8,
           g: (point.y % 256) as u8,
           b: 128}
}
<|endoftext|>


<commit_before>use std::mem;
use std::str::FromStr;

#[derive(Clone, Copy, Debug)]
enum Stone {
    Flat,
    Standing,
    Capstone,
}

#[derive(Clone, Copy, Debug)]
enum Player {
    One,
    Two,
}

#[derive(Clone, Copy, Debug)]
struct Piece {
    stone: Stone,
    owner: Player,
}

#[derive(Clone, Debug)]
struct Cell {
    pieces: Vec<Piece>,
}

impl Cell {
    fn new() -> Cell {
        Cell { pieces: vec![] }
    }

    fn len(&self) -> usize {
        self.pieces.len()
    }

    fn add_piece(&mut self, piece: Piece) -> () {
        // TODO: Stacking checks
        self.pieces.push(piece);
    }

    fn place_piece(&mut self, piece: Piece) -> () {
        assert!(self.pieces.len() == 0,
                "Cannot place stone on top of existing stone.");
        self.pieces.push(piece);
    }
}

enum Direction {
    Right,
    Left,
    Up,
    Down,
}

impl Direction {
    fn adjust(&self, x: usize, y: usize, offset: usize) -> (usize, usize) {
        match self {
            &Direction::Right => (x + offset, y),
            &Direction::Left => (x - offset, y),
            &Direction::Up => (x, y + offset),
            &Direction::Down => (x, y - offset),
        }
    }
}

enum Turn {
    Placement {
        x: usize,
        y: usize,
        piece: Piece,
    },
    Slide {
        x: usize,
        y: usize,
        direction: Direction,
        offsets: Vec<usize>,
    },
}

impl FromStr for Turn {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.len() < 4 {
            return Err(());
        }
        let mut chars = s.chars();
        let letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
        let numbers = ['1', '2', '3', '4', '5', '6', '7', '8'];
        let grid_x = chars.next().unwrap();
        let grid_y = chars.next().unwrap();
        let x = match letters.iter().position(|c| *c == grid_x) {
            Some(num) => num,
            None => return Err(()),
        };
        let y = match numbers.iter().position(|c| *c == grid_y) {
            Some(num) => num,
            None => return Err(()),
        };
        let turn = chars.next().unwrap();
        if "FSC".contains(turn) {
            let stone = match turn {
                'F' => Stone::Flat,
                'S' => Stone::Standing,
                'C' => Stone::Capstone,
                _ => return Err(()),
            };
            let player = match chars.next() {
                Some('1') => Player::One,
                Some('2') => Player::Two,
                _ => return Err(()),
            };

            Ok(Turn::Placement {
                x: x,
                y: y,
                piece: Piece {
                    owner: player,
                    stone: stone,
                },
            })
        } else if "RLUD".contains(turn) {
            let direction = match turn {
                'R' => Direction::Right,
                'L' => Direction::Left,
                'U' => Direction::Up,
                'D' => Direction::Down,
                _ => return Err(()),
            };
            let offsets: Vec<usize> = chars.map(|c| c.to_digit(10).unwrap() as usize).collect();

            Ok(Turn::Slide {
                x: x,
                y: y,
                direction: direction,
                offsets: offsets,
            })
        } else {
            Err(())
        }

    }
}

fn play(turn: &Turn, board: &mut Board) -> () {
    match turn {
        &Turn::Placement { x, y, piece } => {
            board.grid[x][y].place_piece(piece);
        }
        &Turn::Slide { x, y, ref direction, ref offsets } => {
            assert!(offsets.len() == board.grid[x][y].len(),
                    "Trying to move a different number of pieces than exist.");

            let cell = mem::replace(&mut board.grid[x][y], Cell::new());
            let points = offsets.iter().map(|z| direction.adjust(x, y, *z));
            for (point, piece) in points.zip(cell.pieces.iter()) {
                let (x, y) = point;
                board.grid[x][y].add_piece(*piece);
            }
        }
    }
}

#[derive(Debug)]
struct Board {
    grid: Vec<Vec<Cell>>,
}

impl Board {
    fn new(board_size: usize) -> Board {
        Board { grid: vec![vec![Cell::new(); board_size]; board_size] }
    }
}

fn main() {
    let mut game = Board::new(4);
    play(&("a1S1".parse::<Turn>().unwrap()), &mut game);
    play(&("a2F2".parse::<Turn>().unwrap()), &mut game);
    play(&("a1U1".parse::<Turn>().unwrap()), &mut game);
    play(&("a2R12".parse::<Turn>().unwrap()), &mut game);
    println!("{:#?}", game);
    println!("{:#?}", "a1F1".parse::<Turn>());
    println!("{:#?}", "a1D1".parse::<Turn>());
}
<commit_msg>Add Point struct to clean up code<commit_after>use std::mem;
use std::str::FromStr;

#[derive(Clone, Copy, Debug)]
enum Stone {
    Flat,
    Standing,
    Capstone,
}

#[derive(Clone, Copy, Debug)]
enum Player {
    One,
    Two,
}

#[derive(Clone, Copy, Debug)]
struct Piece {
    stone: Stone,
    owner: Player,
}

impl FromStr for Piece {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.len() < 4 {
            return Err(());
        }
        let mut chars = s.chars();
        let turn = chars.nth(2).unwrap();
        if "FSC".contains(turn) {
            let stone = match turn {
                'F' => Stone::Flat,
                'S' => Stone::Standing,
                'C' => Stone::Capstone,
                _ => return Err(()),
            };
            let player = match chars.next() {
                Some('1') => Player::One,
                Some('2') => Player::Two,
                _ => return Err(()),
            };

            Ok(Piece {
                stone: stone,
                owner: player,
            })
        } else {
            Err(())
        }
    }

}
#[derive(Clone, Debug)]
struct Cell {
    pieces: Vec<Piece>,
}

impl Cell {
    fn new() -> Cell {
        Cell { pieces: vec![] }
    }

    fn len(&self) -> usize {
        self.pieces.len()
    }

    fn add_piece(&mut self, piece: Piece) -> () {
        // TODO: Stacking checks
        self.pieces.push(piece);
    }

    fn place_piece(&mut self, piece: Piece) -> () {
        assert!(self.pieces.len() == 0,
                "Cannot place stone on top of existing stone.");
        self.pieces.push(piece);
    }
}

#[derive(Debug)]
enum Direction {
    Right,
    Left,
    Up,
    Down,
}

impl Direction {
    fn adjust(&self, point: &Point, offset: usize) -> Point {
        match self {
            &Direction::Right => Point { x: point.x + offset, y: point.y },
            &Direction::Left => Point { x: point.x - offset, y: point.y },
            &Direction::Up => Point { x: point.x, y: point.y + offset },
            &Direction::Down => Point { x: point.x, y: point.y - offset },
        }
    }
}

#[derive(Debug)]
enum Turn {
    Placement {
        point: Point,
        piece: Piece,
    },
    Slide {
        point: Point,
        direction: Direction,
        offsets: Vec<usize>,
    },
}

impl FromStr for Turn {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.len() < 4 {
            return Err(());
        }
        let point = match s.parse::<Point>() {
            Ok(p) => p,
            Err(_) => return Err(())
        };
        let mut chars = s.chars();
        let turn = chars.nth(2).unwrap();
        if let Ok(piece) = s.parse::<Piece>() {
            Ok(Turn::Placement {
                point: point,
                piece: piece,
            })
        } else {
            let direction = match turn {
                'R' => Direction::Right,
                'L' => Direction::Left,
                'U' => Direction::Up,
                'D' => Direction::Down,
                _ => return Err(()),
            };
            let offsets = chars.map(|c| c.to_digit(10).unwrap() as usize)
                               .collect();

            Ok(Turn::Slide {
                point: point,
                direction: direction,
                offsets: offsets,
            })
        }

    }
}

fn play(turn: &Turn, board: &mut Board) -> () {
    match turn {
        &Turn::Placement { ref point, ref piece } => {
            board.at(point).place_piece(*piece);
        }
        &Turn::Slide { ref point, ref direction, ref offsets } => {
            assert!(offsets.len() == board.at(point).len(),
                    "Trying to move a different number of pieces than exist.");

            let cell = mem::replace(board.at(point), Cell::new());
            let points = offsets.iter().map(|z| direction.adjust(point, *z));
            for (point, piece) in points.zip(cell.pieces.iter()) {
                board.at(&point).add_piece(*piece);
            }
        }
    }
}

#[derive(Debug)]
struct Point {
    x: usize,
    y: usize,
}

impl FromStr for Point {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.len() < 2 {
            return Err(());
        }
        let mut chars = s.chars();
        let letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
        let numbers = ['1', '2', '3', '4', '5', '6', '7', '8'];
        let grid_x = chars.next().unwrap();
        let grid_y = chars.next().unwrap();
        let x = match letters.iter().position(|c| *c == grid_x) {
            Some(num) => num,
            None => return Err(()),
        };
        let y = match numbers.iter().position(|c| *c == grid_y) {
            Some(num) => num,
            None => return Err(()),
        };
        Ok(Point { x: x, y: y })
    }

}

#[derive(Debug)]
struct Board {
    grid: Vec<Vec<Cell>>,
}

impl Board {
    fn new(board_size: usize) -> Board {
        Board { grid: vec![vec![Cell::new(); board_size]; board_size] }
    }

    fn at(&mut self, point: &Point) -> &mut Cell {
        &mut self.grid[point.x][point.y]
    }
}

fn main() {
    let mut game = Board::new(4);
    play(&("a1S1".parse::<Turn>().unwrap()), &mut game);
    play(&("a2F2".parse::<Turn>().unwrap()), &mut game);
    play(&("a1U1".parse::<Turn>().unwrap()), &mut game);
    play(&("a2R12".parse::<Turn>().unwrap()), &mut game);
    println!("{:#?}", game);
    println!("{:#?}", "a1F1".parse::<Turn>());
    println!("{:#?}", "a1D1".parse::<Turn>());
}
<|endoftext|>