<commit_before>use cgmath;
use glium;
use glutin;
use std;
use rand;
use time;

use scene;

fn cl_float3(x: f32, y: f32, z: f32) -> scene::cl_float3 {
  scene::cl_float3::new([x, y, z])
}

fn solid_color(r: f32, g: f32, b: f32) -> scene::texture::T {
  scene::texture::SolidColor(cl_float3(r, g, b)).to_texture()
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RGB {
  pub r: f32,
  pub g: f32,
  pub b: f32,
}

unsafe impl Send for RGB {}

unsafe impl glium::texture::PixelValue for RGB {
  fn get_format() -> glium::texture::ClientFormat {
    glium::texture::ClientFormat::F32F32F32
  }
}

pub const WINDOW_WIDTH: u32 = 800;
pub const WINDOW_HEIGHT: u32 = 600;

pub fn main() {
  use glium::DisplayBuild;

  let window =
    glutin::WindowBuilder::new()
    .with_dimensions(WINDOW_WIDTH, WINDOW_HEIGHT)
    .build_glium()
    .unwrap();

  let mut scene =
    scene::T {
      objects       :
        vec!(
          // red ball
          scene::Object { center: cl_float3(-4.0,   -1.0,  -5.0), radius:   1.0, emittance:  0.0, reflectance: 1.0, transmittance: 0.0, diffuseness: 1.0 , texture: solid_color(1.0, 0.0, 0.0) },
          // blue ball
          scene::Object { center: cl_float3(-0.5,   -1.0,  -5.0), radius:   1.0, emittance:  0.0, reflectance: 0.1, transmittance: 0.9, diffuseness: 0.01, texture: solid_color(0.0, 0.6, 1.0) },
          // frosted glass ball
          scene::Object { center: cl_float3(-0.7,   -0.5,  -1.5), radius:   0.5, emittance:  0.0, reflectance: 0.1, transmittance: 0.8, diffuseness: 0.04, texture: solid_color(0.9, 0.9, 1.0) },
          // glass ball
          scene::Object { center: cl_float3( 0.2,   -0.5,  -1.0), radius:   0.5, emittance:  0.0, reflectance: 0.1, transmittance: 0.9, diffuseness: 0.0 , texture: solid_color(0.9, 0.9, 1.0) },
          // brass ball
          scene::Object { center: cl_float3( 3.0,    1.5, -10.0), radius:   4.0, emittance:  0.0, reflectance: 1.0, transmittance: 0.0, diffuseness: 0.1 , texture: solid_color(1.0, 0.4, 0.1) },
          // small mirror ball
          scene::Object { center: cl_float3( 3.0,   -1.0,  -3.5), radius:   1.0, emittance:  0.0, reflectance: 0.9, transmittance: 0.0, diffuseness: 0.0 , texture: solid_color(1.0, 1.0, 1.0) },
          // light
          scene::Object { center: cl_float3(-9.0,   10.0,   0.0), radius:   1.0, emittance:  1.0, reflectance: 0.0, transmittance: 1.0, diffuseness: 0.0 , texture: solid_color(0.9, 0.9, 1.0) },
          // walls
          scene::Object { center: cl_float3( 0.0,    0.0,   0.0), radius:  20.0, emittance:  0.2, reflectance: 0.0, transmittance: 0.0, diffuseness: 1.0 , texture: solid_color(1.0, 1.0, 1.0) },
          // floor
          scene::Object { center: cl_float3( 0.0, -102.0,   0.0), radius: 100.0, emittance:  0.0, reflectance: 1.0, transmittance: 0.0, diffuseness: 0.02, texture: scene::texture::Wood::to_texture() },
        ),
      fovy          : std::f32::consts::FRAC_PI_2,
      eye           : cgmath::Vector3::new(0.0, 0.0,  0.0),
      look          : cgmath::Vector3::new(0.0, 0.0, -1.0),
      up            : cgmath::Vector3::new(0.0, 1.0,  0.0),
    };

  let scale = 1 << 0;
  let w = scale * WINDOW_WIDTH;
  let h = scale * WINDOW_HEIGHT;

  let mut make_random_seed: rand::XorShiftRng =
    rand::SeedableRng::from_seed([0x12345678, 0x9abcdef0, 0x89765432, 0x12324121]);

  loop {
    let before = time::precise_time_ns();
    let rendered = scene.render(w, h, rand::Rng::next_u64(&mut make_random_seed));
    let after = time::precise_time_ns();
    println!("Render took {:?}ms", (after - before) as f32 / 1_000_000.0);

    let texture =
      glium::texture::Texture2d::with_format(
        &window,
        glium::texture::RawImage2d {
          data: std::borrow::Cow::Owned(rendered),
          width: w,
          height: h,
          format: glium::texture::ClientFormat::F32F32F32,
        },
        glium::texture::UncompressedFloatFormat::F32F32F32,
        glium::texture::MipmapsOption::AutoGeneratedMipmaps,
      )
      .unwrap();

    draw_from_texture(&window, &texture);

    for event in window.poll_events() {
      match event {
        glutin::Event::Closed => return,
        glutin::Event::KeyboardInput(_, _, Some(key)) => {
          println!("hello world");
          match key {
            glutin::VirtualKeyCode::W => scene.eye = scene.eye + scene.look,
            glutin::VirtualKeyCode::S => scene.eye = scene.eye - scene.look,
            _ => {},
          }
        },
        _ => {},
      }
    }
  }
}

fn draw_from_texture(
  window: &glium::backend::glutin_backend::GlutinFacade,
  texture: &glium::texture::Texture2d,
) -> Result<(), ()>
{
  use glium::Surface;

  // building the vertex buffer, which contains all the vertices that we will draw
  let vertex_buffer = {
    #[derive(Copy, Clone)]
    struct Vertex {
      position: [f32; 2],
      tex_coords: [f32; 2],
    }

    implement_vertex!(Vertex, position, tex_coords);

    glium::VertexBuffer::new(
      window,
      &[
        Vertex { position: [-1.0, -1.0], tex_coords: [0.0, 0.0] },
        Vertex { position: [-1.0,  1.0], tex_coords: [0.0, 1.0] },
        Vertex { position: [ 1.0,  1.0], tex_coords: [1.0, 1.0] },
        Vertex { position: [ 1.0, -1.0], tex_coords: [1.0, 0.0] }
      ]
    ).unwrap()
  };

  // building the index buffer
  let index_buffer =
    glium::IndexBuffer::new(
      window,
      glium::index::PrimitiveType::TriangleStrip,
      &[1 as u16, 2, 0, 3],
    ).unwrap();

  // compiling shaders and linking them together
  let program = program!(window,
    330 => {
      vertex: "
        #version 330

        uniform mat4 matrix;

        in vec2 position;
        in vec2 tex_coords;

        out vec2 v_tex_coords;

        void main() {
          gl_Position = matrix * vec4(position, 0.0, 1.0);
          v_tex_coords = tex_coords;
        }
      ",

      fragment: "
        #version 330
        uniform sampler2D tex;
        in vec2 v_tex_coords;
        out vec4 f_color;

        void main() {
          f_color = texture(tex, v_tex_coords);
        }
      "
    },
  ).unwrap();

  // building the uniforms
  let uniforms = uniform! {
    matrix: [
      [1.0, 0.0, 0.0, 0.0],
      [0.0, 1.0, 0.0, 0.0],
      [0.0, 0.0, 1.0, 0.0],
      [0.0, 0.0, 0.0, 1.0f32]
    ],
    tex:
      glium::uniforms::Sampler::new(texture)
      .magnify_filter(glium::uniforms::MagnifySamplerFilter::Linear)
      .minify_filter(glium::uniforms::MinifySamplerFilter::LinearMipmapLinear)
  };

  let draw_parameters =
    glium::DrawParameters {
      depth:
        glium::Depth {
          test: glium::DepthTest::Overwrite,
          write: false,
          .. Default::default()
        },
      blend:
        glium::Blend {
          color:
            glium::BlendingFunction::Addition {
              source: glium::LinearBlendingFactor::ConstantColor,
              destination: glium::LinearBlendingFactor::OneMinusConstantColor,
            },
          alpha: glium::BlendingFunction::AlwaysReplace,
          constant_value: (0.0, 0.0, 0.0, 0.0),
        },
      .. Default::default()
    };

  let mut target = window.draw();
  target.draw(
    &vertex_buffer,
    &index_buffer,
    &program,
    &uniforms,
    &draw_parameters,
  ).unwrap();
  target.finish().unwrap();

  Ok(())
}
<commit_msg>gradual blending<commit_after>use cgmath;
use glium;
use glutin;
use std;
use rand;
use time;

use scene;

fn cl_float3(x: f32, y: f32, z: f32) -> scene::cl_float3 {
  scene::cl_float3::new([x, y, z])
}

fn solid_color(r: f32, g: f32, b: f32) -> scene::texture::T {
  scene::texture::SolidColor(cl_float3(r, g, b)).to_texture()
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RGB {
  pub r: f32,
  pub g: f32,
  pub b: f32,
}

unsafe impl Send for RGB {}

unsafe impl glium::texture::PixelValue for RGB {
  fn get_format() -> glium::texture::ClientFormat {
    glium::texture::ClientFormat::F32F32F32
  }
}

pub const WINDOW_WIDTH: u32 = 800;
pub const WINDOW_HEIGHT: u32 = 600;

pub fn main() {
  use glium::DisplayBuild;

  let window =
    glutin::WindowBuilder::new()
    .with_dimensions(WINDOW_WIDTH, WINDOW_HEIGHT)
    .build_glium()
    .unwrap();

  let mut scene =
    scene::T {
      objects       :
        vec!(
          // red ball
          scene::Object { center: cl_float3(-4.0,   -1.0,  -5.0), radius:   1.0, emittance:  0.0, reflectance: 1.0, transmittance: 0.0, diffuseness: 1.0 , texture: solid_color(1.0, 0.0, 0.0) },
          // blue ball
          scene::Object { center: cl_float3(-0.5,   -1.0,  -5.0), radius:   1.0, emittance:  0.0, reflectance: 0.1, transmittance: 0.9, diffuseness: 0.01, texture: solid_color(0.0, 0.6, 1.0) },
          // frosted glass ball
          scene::Object { center: cl_float3(-0.7,   -0.5,  -1.5), radius:   0.5, emittance:  0.0, reflectance: 0.1, transmittance: 0.8, diffuseness: 0.04, texture: solid_color(0.9, 0.9, 1.0) },
          // glass ball
          scene::Object { center: cl_float3( 0.2,   -0.5,  -1.0), radius:   0.5, emittance:  0.0, reflectance: 0.1, transmittance: 0.9, diffuseness: 0.0 , texture: solid_color(0.9, 0.9, 1.0) },
          // brass ball
          scene::Object { center: cl_float3( 3.0,    1.5, -10.0), radius:   4.0, emittance:  0.0, reflectance: 1.0, transmittance: 0.0, diffuseness: 0.1 , texture: solid_color(1.0, 0.4, 0.1) },
          // small mirror ball
          scene::Object { center: cl_float3( 3.0,   -1.0,  -3.5), radius:   1.0, emittance:  0.0, reflectance: 0.9, transmittance: 0.0, diffuseness: 0.0 , texture: solid_color(1.0, 1.0, 1.0) },
          // light
          scene::Object { center: cl_float3(-9.0,   10.0,   0.0), radius:   1.0, emittance:  1.0, reflectance: 0.0, transmittance: 1.0, diffuseness: 0.0 , texture: solid_color(0.9, 0.9, 1.0) },
          // walls
          scene::Object { center: cl_float3( 0.0,    0.0,   0.0), radius:  20.0, emittance:  0.2, reflectance: 0.0, transmittance: 0.0, diffuseness: 1.0 , texture: solid_color(1.0, 1.0, 1.0) },
          // floor
          scene::Object { center: cl_float3( 0.0, -102.0,   0.0), radius: 100.0, emittance:  0.0, reflectance: 1.0, transmittance: 0.0, diffuseness: 0.02, texture: scene::texture::Wood::to_texture() },
        ),
      fovy          : std::f32::consts::FRAC_PI_2,
      eye           : cgmath::Vector3::new(0.0, 0.0,  0.0),
      look          : cgmath::Vector3::new(0.0, 0.0, -1.0),
      up            : cgmath::Vector3::new(0.0, 1.0,  0.0),
    };

  let scale = 1 << 0;
  let w = scale * WINDOW_WIDTH;
  let h = scale * WINDOW_HEIGHT;

  let mut make_random_seed: rand::XorShiftRng =
    rand::SeedableRng::from_seed([0x12345678, 0x9abcdef0, 0x89765432, 0x12324121]);

  let framebuffer_texture =
    glium::texture::Texture2d::new(
      &window,
      glium::texture::RawImage2d {
        width: w,
        height: h,
        format: glium::texture::ClientFormat::F32F32F32,
        data: std::borrow::Cow::Owned(std::iter::repeat((0.0, 0.0, 0.0)).take((w*h) as usize).collect()),
      },
    ).unwrap();

  let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::new(&window, &framebuffer_texture).unwrap();

  loop {
    let before = time::precise_time_ns();
    let rendered = scene.render(w, h, rand::Rng::next_u64(&mut make_random_seed));
    let after = time::precise_time_ns();
    println!("Render took {:?}ms", (after - before) as f32 / 1_000_000.0);

    let rendered =
      glium::texture::Texture2d::with_format(
        &window,
        glium::texture::RawImage2d {
          data: std::borrow::Cow::Owned(rendered),
          width: w,
          height: h,
          format: glium::texture::ClientFormat::F32F32F32,
        },
        glium::texture::UncompressedFloatFormat::F32F32F32,
        glium::texture::MipmapsOption::NoMipmap,
      )
      .unwrap();

    let draw_parameters =
      glium::DrawParameters {
        depth:
          glium::Depth {
            test: glium::DepthTest::Overwrite,
            write: false,
            .. Default::default()
          },
        blend:
          glium::Blend {
            color:
              glium::BlendingFunction::Addition {
                source: glium::LinearBlendingFactor::ConstantColor,
                destination: glium::LinearBlendingFactor::OneMinusConstantColor,
              },
            alpha: glium::BlendingFunction::AlwaysReplace,
            constant_value: (0.1, 0.1, 0.1, 0.0),
          },
        .. Default::default()
      };

    let source =
      glium::uniforms::Sampler::new(&rendered)
      .magnify_filter(glium::uniforms::MagnifySamplerFilter::Linear)
      .minify_filter(glium::uniforms::MinifySamplerFilter::LinearMipmapLinear);

    draw(&window, source, &mut framebuffer, &draw_parameters);

    let draw_parameters =
      glium::DrawParameters {
        depth:
          glium::Depth {
            test: glium::DepthTest::Overwrite,
            write: false,
            .. Default::default()
          },
        blend:
          glium::Blend {
            color: glium::BlendingFunction::AlwaysReplace,
            alpha: glium::BlendingFunction::AlwaysReplace,
            constant_value: (0.0, 0.0, 0.0, 0.0),
          },
        .. Default::default()
      };

    let source =
      glium::uniforms::Sampler::new(&framebuffer_texture)
      .magnify_filter(glium::uniforms::MagnifySamplerFilter::Linear)
      .minify_filter(glium::uniforms::MinifySamplerFilter::Linear);

    let mut target = window.draw();
    glium::Surface::clear(&mut target, None, Some((0.0, 0.0, 0.0, 1.0)), false, None, None);
    draw(&window, source, &mut target, &draw_parameters);
    target.finish();

    for event in window.poll_events() {
      match event {
        glutin::Event::Closed => return,
        glutin::Event::KeyboardInput(_, _, Some(key)) => {
          match key {
            glutin::VirtualKeyCode::W => scene.eye = scene.eye + scene.look,
            glutin::VirtualKeyCode::S => scene.eye = scene.eye - scene.look,
            _ => {},
          }
        },
        _ => {},
      }
    }
  }
}

fn draw<'a, Dest: glium::Surface>(
  window: &glium::backend::glutin_backend::GlutinFacade,
  source: glium::uniforms::Sampler<'a, glium::Texture2d>,
  destination: &mut Dest,
  draw_parameters: &glium::DrawParameters,
) {
  // building the vertex buffer, which contains all the vertices that we will draw
  let vertex_buffer = {
    #[derive(Copy, Clone)]
    struct Vertex {
      position: [f32; 2],
      tex_coords: [f32; 2],
    }

    implement_vertex!(Vertex, position, tex_coords);

    glium::VertexBuffer::new(
      window,
      &[
      Vertex { position: [-1.0, -1.0], tex_coords: [0.0, 0.0] },
      Vertex { position: [-1.0,  1.0], tex_coords: [0.0, 1.0] },
      Vertex { position: [ 1.0,  1.0], tex_coords: [1.0, 1.0] },
      Vertex { position: [ 1.0, -1.0], tex_coords: [1.0, 0.0] }
      ]
    ).unwrap()
  };

  // building the index buffer
  let index_buffer =
    glium::IndexBuffer::new(
      window,
      glium::index::PrimitiveType::TriangleStrip,
      &[1 as u16, 2, 0, 3],
    ).unwrap();

  // compiling shaders and linking them together
  let program =
    program!(
      window,
      330 => {
        vertex: "
          #version 330

          uniform mat4 matrix;

          in vec2 position;
          in vec2 tex_coords;

          out vec2 v_tex_coords;

          void main() {
            gl_Position = matrix * vec4(position, 0.0, 1.0);
            v_tex_coords = tex_coords;
          }
        ",

        fragment: "
          #version 330
          uniform sampler2D tex;
          in vec2 v_tex_coords;
          out vec4 f_color;

          void main() {
            f_color = texture(tex, v_tex_coords);
          }
        "
      },
    ).unwrap();

  // building the uniforms
  let uniforms = uniform! {
    matrix: [
      [1.0, 0.0, 0.0, 0.0],
      [0.0, 1.0, 0.0, 0.0],
      [0.0, 0.0, 1.0, 0.0],
      [0.0, 0.0, 0.0, 1.0f32]
    ],
    tex: source,
  };

  destination.draw(
    &vertex_buffer,
    &index_buffer,
    &program,
    &uniforms,
    &draw_parameters,
  ).unwrap();
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::io;
use std::fs::File;
use std::collections::HashMap;
use std::string::String;
use std::vec::Vec;
use std::path::Path;
use std::ptr;
use std::net::{TcpListener, TcpStream};

struct CacheItem{
    value: *mut u8,
    size: i32
}

struct CacheOperation{
    commands: Vec<char>,
    key: String,
    value: Vec<u8>
}

impl CacheOperation{

    fn new_from_string(cache_op_str: &String) -> CacheOperation {
        let mut cache_op = CacheOperation{
            commands:Vec::new(),
            key:String::new(),
            value:Vec::new()
        };
        let mut idx = 0;
        let mut chars_iter = cache_op_str.chars();
        let mut parsed_cmds = false;
        for c in chars_iter {
            idx += 1;
            let is_tok = c == '$' || c == ':';
            if c == '$'{
                parsed_cmds = true;
            } else if c == ':'{
                cache_op.value = String::from(&cache_op_str[idx..]).into_bytes();
                break;
            }
            if parsed_cmds && !is_tok{
                cache_op.key.push(c);
            }else if !is_tok{
               cache_op.commands.push(c);
            }
        }
        return cache_op;
    }
}

struct Cache{
    map_internal : HashMap<String, Vec<u8>>
}

impl Cache{

    fn new() -> Cache{
        return Cache{
            map_internal: HashMap::new()
        }
    }

    fn cache_item( &mut self, key: String, val: Vec<u8>){
        println!("Writing to cache: key={:?} val={:?}", key, val);
        self.map_internal.insert(key, val);
    }

}

fn handle_client(stream: &mut TcpStream, cache:&mut Cache) {
    let mut buf: Vec<u8> = Vec::new();
    stream.read_to_end( &mut buf );
    let buf_str:String = String::from_utf8(buf).unwrap();
    if buf_str.len() > 0 {
        let mut cache_op:CacheOperation = CacheOperation::new_from_string(&buf_str);
        print!("cmds = {:?}, key = {}, value {:?}", cache_op.commands, cache_op.key, cache_op.value );
        io::stdout().flush().unwrap();
    }else{
        panic!("Empty cache operation");
    }
}

fn read_value_from_cache( key:&String, cache:&Cache){

}

fn write_stream_str_to_cache(stream_str:String, cache:&mut Cache){
    let mut key:String = String::from("");
    let mut val:String = String::from("");
    let mut idx = 0;
    let mut chars_iter = stream_str.chars();
    chars_iter.next(); // Consume command
    for c in chars_iter {
        idx += 1;
        if c == ':'{
            val = String::from(&stream_str[idx..]);
            break;
        }
        key.push(c);
    }
    let bytes = val.into_bytes();
    cache.cache_item( key, bytes);
}

fn main() {

    let listener:TcpListener = TcpListener::bind("127.0.0.1:8080").unwrap();
    let mut cache:Cache = Cache::new();

    // accept connections and process them, spawning a new thread for each one
    for stream in listener.incoming() {
        match stream {
            Ok(mut stream) => {
                handle_client(&mut stream, &mut cache);
            }
                Err(e) => { /* connection failed */ }
            }

    }

    let file_res = make_cache();
    if file_res.is_err() {
        panic!("Could not create cache file");
    }
    let mut cache_file = file_res.unwrap();
    let write_res = cache_file.write_all(b"test");
    if write_res.is_err() {
        panic!("Could not write to cache");
    }
    read_index(cache_file);
}

fn make_cache() -> Result<File, std::io::Error>{
    return File::create("cache.txt");
}

fn read_index(mut cache_file: File) -> HashMap<String, i32> {
    let path = Path::new("cache.txt");
    let mut file = match File::open(&path) {
        // The `description` method of `io::Error` returns a string that
        // describes the error
        Err(why) => panic!("couldn't open"),
        Ok(file) => file,
    };
    let mut buf:Vec<u8> = Vec::new();
    file.read_to_end(&mut buf);
    for char in buf {
        println!("{}", char);
    }

    return HashMap::new();
}

<commit_msg>Work on writing and reading to cache<commit_after>use std::io::prelude::*;
use std::io;
use std::fs::File;
use std::collections::HashMap;
use std::string::String;
use std::vec::Vec;
use std::path::Path;
use std::ptr;
use std::net::{TcpListener, TcpStream};
use std::thread;

struct CacheOperation{
    commands: Vec<char>,
    value: String
}

impl CacheOperation{

    fn new_from_string(cache_op_str: &String) -> CacheOperation {
        let mut cache_op = CacheOperation{
            commands:Vec::new(),
            value:String::new()
        };
        let mut idx = 0;
        let chars_iter = cache_op_str.chars();
        for c in chars_iter {
            idx += 1;
            if c == '$'{
                cache_op.value = String::from(&cache_op_str[idx..]);
                break;
            }
            cache_op.commands.push(c);
        }
        return cache_op;
    }
}

struct Cache{
    map_internal : HashMap<String, Vec<u8>>
}

impl Cache{

    fn new() -> Cache{
        return Cache{
            map_internal: HashMap::new()
        }
    }

    fn cache_item( &mut self, key: String, val: Vec<u8>){
        println!("Writing to cache: key={:?} val={:?}", key, val);
        self.map_internal.insert(key, val);
    }

    fn read_item( &self, key:String ) -> Option<&Vec<u8>>{
        //println!("Reading value from cache: key:{}, value:{:?}", key, self.map_internal.get(key));
        return self.map_internal.get(&key);
    }

}

fn handle_client(mut stream: &mut TcpStream, mut cache:&mut Cache) {

    stream.set_nodelay(true);
    println!("Before Read");

    io::stdout().flush().unwrap();

    let mut buf_arr:[u8; 64] = [0; 64];
    stream.read(&mut buf_arr);

    let mut size_str = String::new();
    let mut size_idx:usize = 0;
    for i in 0..64{
        size_idx += 1;
        if buf_arr[i] == '|' as u8{
            break;
        }
        size_str.push(buf_arr[i as usize] as char);
    }

    println!("Size {}", size_str);
    io::stdout().flush().unwrap();

    let upper_idx:usize = size_str.parse::<i32>().unwrap() as usize;
    let msg_buf = buf_arr;
    let mut buf_temp: Vec<u8> = msg_buf.to_vec();
    let mut buf: Vec<u8> = buf_temp.drain(size_idx..upper_idx).collect();

    println!("buf {:?}", buf);
    io::stdout().flush().unwrap();

    stream.flush().unwrap();

    let buf_str:String = String::from_utf8(buf).unwrap();
    if buf_str.len() > 0 {

        let cache_op:CacheOperation = CacheOperation::new_from_string(&buf_str);

        print!("cmds = {:?}, value = {}", cache_op.commands, cache_op.value );
        io::stdout().flush().unwrap();

        if cache_op.commands.len() > 0 {

            let prim_cmd:char = cache_op.commands[0];

            match prim_cmd{
                'W' => write_stream_str_to_cache(cache_op.value, &mut cache),
                'R' => read_value_from_cache( cache_op.value, &mut cache, &mut stream),
                _ => panic!("Invalid cache command")
            }
        }
    }else{
        panic!("Empty cache operation");
    }
}

fn read_value_from_cache( key:String, cache:&Cache, stream: &mut TcpStream){
    let cache_opt = cache.read_item(String::from("a"));

    match cache_opt{
        Some(val)=> {
            println!("Writing to stream {:?}", val);
            io::stdout().flush().unwrap();
            stream.write(&val[0..val.len()]);
            stream.flush();
        },
        None =>{
            stream.write(&[65,65,65,65]);
            stream.flush();
        }
    }
}

fn write_stream_str_to_cache(stream_str:String, cache:&mut Cache){
    let mut key:String = String::from("");
    let mut val:String = String::from("");
    let mut idx = 0;
    let mut chars_iter = stream_str.chars();
    for c in chars_iter {
        idx += 1;
        if c == ':'{
            val = String::from(&stream_str[idx..]);
            break;
        }
        key.push(c);
    }
    let bytes = val.into_bytes();
    cache.cache_item( key, bytes);
}

fn main() {

    let listener:TcpListener = TcpListener::bind("127.0.0.1:8080").unwrap();
    let mut cache:Cache = Cache::new();

    // accept connections and process them, spawning a new thread for each one
    for stream in listener.incoming() {
        match stream {
            Ok(mut stream) => {
                //thread::spawn(||{
                println!("Connection");
                io::stdout().flush().unwrap();
                loop{
                    handle_client(&mut stream, &mut cache);
                }
                //});
            }
            Err(e) => { /* connection failed */ }
        }

    }

    let file_res = make_cache();
    if file_res.is_err() {
        panic!("Could not create cache file");
    }
    let mut cache_file = file_res.unwrap();
    let write_res = cache_file.write_all(b"test");
    if write_res.is_err() {
        panic!("Could not write to cache");
    }
    read_index(cache_file);
}

fn make_cache() -> Result<File, std::io::Error>{
    return File::create("cache.txt");
}

fn read_index(mut cache_file: File) -> HashMap<String, i32> {
    let path = Path::new("cache.txt");
    let mut file = match File::open(&path) {
        // The `description` method of `io::Error` returns a string that
        // describes the error
        Err(why) => panic!("couldn't open"),
        Ok(file) => file,
    };
    let mut buf:Vec<u8> = Vec::new();
    file.read_to_end(&mut buf);
    for char in buf {
        println!("{}", char);
    }

    return HashMap::new();
}

<|endoftext|>


<commit_before>#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

mod logger;
mod toml_file;
mod git;
mod changelog;
mod commit_analyzer;
mod cargo;
mod error;
mod github;
mod config;
mod utils;

extern crate rustc_serialize;
extern crate toml;
extern crate regex;
extern crate semver;
extern crate docopt;
extern crate git2;
extern crate clog;
extern crate hyper;
extern crate hubcaps;
extern crate url;
extern crate travis_after_all;
extern crate env_logger;

use docopt::Docopt;
use commit_analyzer::CommitType;
use config::ConfigBuilder;
use std::process;
use semver::Version;
use std::{env,fs};
use std::path::Path;
use std::error::Error;
use std::thread;
use std::time::Duration;
use travis_after_all::Build;
use utils::user_repo_from_url;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USERAGENT: &'static str = concat!("semantic-rs/", env!("CARGO_PKG_VERSION"));
const USAGE: &'static str = "
semantic.rs 🚀

Usage:
  semantic-rs [options]
  semantic-rs --version

Options:
  -h --help              Show this screen.
  --version              Show version.
  -p PATH, --path=PATH   Specifies the repository path. [default: .]
  -w W, --write=W        Write changes to files (default: yes if CI is set, otherwise no).
  -r R, --release=R      Create release on GitHub and publish on crates.io (only in write mode) [default: yes].
  -b B, --branch=B       The branch on which releases should happen. [default: master].
";

const COMMITTER_ERROR_MESSAGE: &'static str = r"
A release commit needs a committer name and email address.
We tried fetching it from different locations, but couldn't find one.

Committer information is taken from the following environment variables, if set:

GIT_COMMITTER_NAME
GIT_COMMITTER_EMAIL

If none is set the normal git config is tried in the following order:

Local repository config
User config
Global config";

macro_rules! print_exit {
    ($fmt:expr) => {{
        logger::stderr($fmt);
        process::exit(1);
    }};
    ($fmt:expr, $($arg:tt)*) => {{
        logger::stderr(format!($fmt, $($arg)*));
        process::exit(1);
    }};
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_path: String,
    flag_write: Option<String>,
    flag_version: bool,
    flag_release: String,
    flag_branch: String,
}

fn string_to_bool(answer: &str) -> bool {
    match &answer.to_lowercase()[..] {
        "yes" | "true" | "1" => true,
        _ => false
    }
}

fn version_bump(version: &Version, bump: CommitType) -> Option<Version> {
    let mut version = version.clone();
    match bump {
        CommitType::Unknown => return None,
        CommitType::Patch => version.increment_patch(),
        CommitType::Minor => version.increment_minor(),
        CommitType::Major => version.increment_major(),
    }

    Some(version)
}

fn ci_env_set() -> bool {
    env::var("CI").is_ok()
}

fn current_branch(repo: &git2::Repository) -> Option<String> {
    if let Ok(branch) = env::var("TRAVIS_BRANCH") {
        return Some(branch)
    }

    let head = repo.head().expect("No HEAD found for repository");

    if head.is_branch() {
        let short = head.shorthand().expect("No branch name found");
        return Some(short.into());
    }

    None
}

fn is_release_branch(current: &str, release: &str) -> bool {
    if let Ok(pr) = env::var("TRAVIS_PULL_REQUEST") {
        if pr != "false" {
            return false;
        }
    }

    current == release
}

fn push_to_github(config: &config::Config, tag_name: &str) {
    logger::stdout("Pushing new commit and tag");
    git::push(&config, &tag_name)
        .unwrap_or_else(|err| print_exit!("Failed to push git: {:?}", err));

    logger::stdout("Waiting a tiny bit, so GitHub can store the git tag");
    thread::sleep(Duration::from_secs(1));
}

fn release_on_github(config: &config::Config, tag_message: &str, tag_name: &str) {
    if github::can_release(&config) {
        logger::stdout("Creating GitHub release");
        github::release(&config, &tag_name, &tag_message)
            .unwrap_or_else(|err| print_exit!("Failed to create GitHub release: {:?}", err));
    } else {
        logger::stdout("Project not hosted on GitHub. Skipping release step");
    }
}

fn release_on_cratesio(config: &config::Config) {
    logger::stdout("Publishing crate on crates.io");
    if !cargo::publish(&config.repository_path, &config.cargo_token.as_ref().unwrap()) {
        print_exit!("Failed to publish on crates.io");
    }
}

fn generate_changelog(repository_path: &str, version: &Version, new_version: &String) -> String {
    logger::stdout(format!("New version would be: {}", new_version));
    logger::stdout("Would write the following Changelog:");
    match changelog::generate(repository_path, &version.to_string(), new_version) {
        Ok(log) => log,
        Err(err) => {
            logger::stderr(format!("Generating Changelog failed: {:?}", err));
            process::exit(1)
        }
    }
}

fn write_changelog(repository_path: &str, version: &Version, new_version: &str) {
    logger::stdout("Writing Changelog");
    changelog::write(repository_path, &version.to_string(), &new_version)
        .unwrap_or_else(|err| print_exit!("Writing Changelog failed: {:?}", err));
}

fn print_changelog(changelog: &str) {
    logger::stdout("====================================");
    logger::stdout(changelog);
    logger::stdout("====================================");
    logger::stdout("Would create annotated git tag");
}

fn package_crate(config: &config::Config, repository_path: &str, new_version: &str) {
    if config.release_mode {
        logger::stdout("Updating lockfile");
        if !cargo::update_lockfile(repository_path) {
            print_exit!("`cargo fetch` failed. See above for the cargo error message.");
        }
    }

    logger::stdout("Package crate");
    if !cargo::package(repository_path) {
        print_exit!("`cargo package` failed. See above for the cargo error message.");
    }

    git::commit_files(&config, &new_version)
        .unwrap_or_else(|err| print_exit!("Committing files failed: {:?}", err));
}

fn main() {
    env_logger::init().expect("Can't instantiate env logger");

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    let mut config_builder = ConfigBuilder::new();

    if args.flag_version {
        println!("semantic.rs 🚀 -- v{}", VERSION);
        process::exit(0);
    }

    // If write mode is requested OR denied,
    // adhere to the user's wish,
    // otherwise we decide based on whether we are running in CI.
    let write_mode = match args.flag_write {
        None => ci_env_set(),
        Some(ref flag) => string_to_bool(flag)
    };

    // We can only release, if we are allowed to write
    let release_mode = write_mode && string_to_bool(&args.flag_release);

    config_builder.write(write_mode);
    config_builder.release(release_mode);
    config_builder.branch(args.flag_branch);

    println!("semantic.rs 🚀");

    logger::stdout("Analyzing your repository");
    let path = Path::new(&args.flag_path);
    let path = fs::canonicalize(path)
        .unwrap_or_else(|_| print_exit!("Path does not exist or a component is not a directory"));
    let repository_path = path.to_str()
        .unwrap_or_else(|| print_exit!("Path is not valid unicode"));

    let repo = match git2::Repository::open(repository_path) {
        Ok(repo) => repo,
        Err(e) => {
            logger::stderr(format!("Could not open the git repository: {:?}", e));
            process::exit(1);
        }
    };

    config_builder.repository_path(repository_path.to_owned());

    // extra scope scope to make sure borrow of `repo` is dropped
    {
        let signature = match git::get_signature(&repo) {
            Ok(sig) => sig,
            Err(e) => {
                logger::stderr(format!("Failed to get the committer's name and email address: {}", e.description()));
                logger::stderr(COMMITTER_ERROR_MESSAGE);
                process::exit(1);
            }
        };

        config_builder.signature(signature.to_owned());
    }

    // In case we are in write-mode AND release mode,
    // we will make sure we got all configuration settings
    if write_mode && release_mode {
        let remote_or_none = repo.find_remote("origin");
        match remote_or_none {
            Ok(remote) => {
                let url = remote.url().expect("Remote URL is not valid UTF-8").to_owned();
                let (user, repo_name) = user_repo_from_url(&url)
                    .unwrap_or_else(|e| print_exit!("Could not extract user and repository name from URL: {:?}", e));
                config_builder.user(user);
                config_builder.repository_name(repo_name);

                if github::is_github_url(&url) {
                    let gh_token = env::var("GH_TOKEN")
                        .unwrap_or_else(|err| print_exit!("GH_TOKEN not set: {:?}", err));
                    config_builder.gh_token(gh_token);
                }

                let cargo_token = env::var("CARGO_TOKEN")
                    .unwrap_or_else(|err| print_exit!("CARGO_TOKEN not set: {:?}", err));

                config_builder.cargo_token(cargo_token);
            },
            Err(err) => {
                logger::warn(format!("Could not determine the origin remote url: {:?}", err));
                logger::warn("semantic-rs can't push changes or create a release on GitHub");
            }
        }
    }

    config_builder.repository(repo);
    let config = config_builder.build();

    let branch = current_branch(&config.repository)
        .unwrap_or_else(|| print_exit!("Could not determine current branch."));

    if !is_release_branch(&branch, &config.branch) {
        println!("Current branch is '{}', releases are only done from branch '{}'", branch, config.branch);
        println!("No release done from a pull request either.");
        process::exit(0);
    }

    if config.release_mode && ci_env_set() {
        let build_run = Build::from_env()
            .unwrap_or_else(|e| print_exit!("CI mode, but can't check other builds. Error: {:?}", e));

        if !build_run.is_leader() {
            println!("Not the build leader. Nothing to do. Bye.");
            process::exit(0);
        }

        println!("I am the build leader. Waiting for other jobs to finish.");
        match build_run.wait_for_others() {
            Ok(()) => println!("Other jobs finished and succeeded. Doing my work now."),
            Err(travis_after_all::Error::FailedBuilds) => {
                print_exit!("Some builds failed. Stopping here.");
            },
            Err(e) => print_exit!("Waiting for other builds failed Reason: {:?}", e),
        }
    }

    let version = toml_file::read_from_file(&config.repository_path)
        .unwrap_or_else(|err| print_exit!("Reading `Cargo.toml` failed: {:?}", err));

    let version = Version::parse(&version).expect("Not a valid version");
    logger::stdout(format!("Current version: {}", version.to_string()));

    logger::stdout("Analyzing commits");

    let bump = git::version_bump_since_latest(&config.repository);
    if write_mode {
        logger::stdout(format!("Commits analyzed. Bump will be {:?}", bump));
    } else {
        logger::stdout(format!("Commits analyzed. Bump would be {:?}", bump));
    }
    let new_version = match version_bump(&version, bump) {
        Some(new_version) => new_version.to_string(),
        None => {
            logger::stdout("No version bump. Nothing to do.");
            process::exit(0);
        }
    };

    if !config.write_mode {
        let changelog = generate_changelog(repository_path, &version, &new_version);
        print_changelog(&changelog);
    } else {
        logger::stdout(format!("New version: {}", new_version));

        toml_file::write_new_version(repository_path, &new_version)
            .unwrap_or_else(|err| print_exit!("Writing `Cargo.toml` failed: {:?}", err));

        write_changelog(&repository_path, &version, &new_version);
        package_crate(&config, &repository_path, &new_version);

        logger::stdout("Creating annotated git tag");
        let tag_message = changelog::generate(repository_path, &version.to_string(), &new_version)
            .unwrap_or_else(|err| print_exit!("Can't generate changelog: {:?}", err));

        let tag_name = format!("v{}", new_version);
        git::tag(&config, &tag_name, &tag_message)
            .unwrap_or_else(|err| print_exit!("Failed to create git tag: {:?}", err));

        if config.release_mode && config.can_push() {
            push_to_github(&config, &tag_name);
            release_on_github(&config, &tag_message, &tag_name);
            release_on_cratesio(&config);
            println!("{} v{} is released. 🚀🚀🚀", config.repository_name.unwrap(), new_version);
        }
    }
}
<commit_msg>Auto merge of #97 - semantic-rs:commit-then-package, r=badboy<commit_after>#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

mod logger;
mod toml_file;
mod git;
mod changelog;
mod commit_analyzer;
mod cargo;
mod error;
mod github;
mod config;
mod utils;

extern crate rustc_serialize;
extern crate toml;
extern crate regex;
extern crate semver;
extern crate docopt;
extern crate git2;
extern crate clog;
extern crate hyper;
extern crate hubcaps;
extern crate url;
extern crate travis_after_all;
extern crate env_logger;

use docopt::Docopt;
use commit_analyzer::CommitType;
use config::ConfigBuilder;
use std::process;
use semver::Version;
use std::{env,fs};
use std::path::Path;
use std::error::Error;
use std::thread;
use std::time::Duration;
use travis_after_all::Build;
use utils::user_repo_from_url;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USERAGENT: &'static str = concat!("semantic-rs/", env!("CARGO_PKG_VERSION"));
const USAGE: &'static str = "
semantic.rs 🚀

Usage:
  semantic-rs [options]
  semantic-rs --version

Options:
  -h --help              Show this screen.
  --version              Show version.
  -p PATH, --path=PATH   Specifies the repository path. [default: .]
  -w W, --write=W        Write changes to files (default: yes if CI is set, otherwise no).
  -r R, --release=R      Create release on GitHub and publish on crates.io (only in write mode) [default: yes].
  -b B, --branch=B       The branch on which releases should happen. [default: master].
";

const COMMITTER_ERROR_MESSAGE: &'static str = r"
A release commit needs a committer name and email address.
We tried fetching it from different locations, but couldn't find one.

Committer information is taken from the following environment variables, if set:

GIT_COMMITTER_NAME
GIT_COMMITTER_EMAIL

If none is set the normal git config is tried in the following order:

Local repository config
User config
Global config";

macro_rules! print_exit {
    ($fmt:expr) => {{
        logger::stderr($fmt);
        process::exit(1);
    }};
    ($fmt:expr, $($arg:tt)*) => {{
        logger::stderr(format!($fmt, $($arg)*));
        process::exit(1);
    }};
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_path: String,
    flag_write: Option<String>,
    flag_version: bool,
    flag_release: String,
    flag_branch: String,
}

fn string_to_bool(answer: &str) -> bool {
    match &answer.to_lowercase()[..] {
        "yes" | "true" | "1" => true,
        _ => false
    }
}

fn version_bump(version: &Version, bump: CommitType) -> Option<Version> {
    let mut version = version.clone();
    match bump {
        CommitType::Unknown => return None,
        CommitType::Patch => version.increment_patch(),
        CommitType::Minor => version.increment_minor(),
        CommitType::Major => version.increment_major(),
    }

    Some(version)
}

fn ci_env_set() -> bool {
    env::var("CI").is_ok()
}

fn current_branch(repo: &git2::Repository) -> Option<String> {
    if let Ok(branch) = env::var("TRAVIS_BRANCH") {
        return Some(branch)
    }

    let head = repo.head().expect("No HEAD found for repository");

    if head.is_branch() {
        let short = head.shorthand().expect("No branch name found");
        return Some(short.into());
    }

    None
}

fn is_release_branch(current: &str, release: &str) -> bool {
    if let Ok(pr) = env::var("TRAVIS_PULL_REQUEST") {
        if pr != "false" {
            return false;
        }
    }

    current == release
}

fn push_to_github(config: &config::Config, tag_name: &str) {
    logger::stdout("Pushing new commit and tag");
    git::push(&config, &tag_name)
        .unwrap_or_else(|err| print_exit!("Failed to push git: {:?}", err));

    logger::stdout("Waiting a tiny bit, so GitHub can store the git tag");
    thread::sleep(Duration::from_secs(1));
}

fn release_on_github(config: &config::Config, tag_message: &str, tag_name: &str) {
    if github::can_release(&config) {
        logger::stdout("Creating GitHub release");
        github::release(&config, &tag_name, &tag_message)
            .unwrap_or_else(|err| print_exit!("Failed to create GitHub release: {:?}", err));
    } else {
        logger::stdout("Project not hosted on GitHub. Skipping release step");
    }
}

fn release_on_cratesio(config: &config::Config) {
    logger::stdout("Publishing crate on crates.io");
    if !cargo::publish(&config.repository_path, &config.cargo_token.as_ref().unwrap()) {
        print_exit!("Failed to publish on crates.io");
    }
}

fn generate_changelog(repository_path: &str, version: &Version, new_version: &String) -> String {
    logger::stdout(format!("New version would be: {}", new_version));
    logger::stdout("Would write the following Changelog:");
    match changelog::generate(repository_path, &version.to_string(), new_version) {
        Ok(log) => log,
        Err(err) => {
            logger::stderr(format!("Generating Changelog failed: {:?}", err));
            process::exit(1)
        }
    }
}

fn write_changelog(repository_path: &str, version: &Version, new_version: &str) {
    logger::stdout("Writing Changelog");
    changelog::write(repository_path, &version.to_string(), &new_version)
        .unwrap_or_else(|err| print_exit!("Writing Changelog failed: {:?}", err));
}

fn print_changelog(changelog: &str) {
    logger::stdout("====================================");
    logger::stdout(changelog);
    logger::stdout("====================================");
    logger::stdout("Would create annotated git tag");
}

fn package_crate(config: &config::Config, repository_path: &str, new_version: &str) {
    if config.release_mode {
        logger::stdout("Updating lockfile");
        if !cargo::update_lockfile(repository_path) {
            print_exit!("`cargo fetch` failed. See above for the cargo error message.");
        }
    }

    git::commit_files(&config, &new_version)
        .unwrap_or_else(|err| print_exit!("Committing files failed: {:?}", err));

    logger::stdout("Package crate");
    if !cargo::package(repository_path) {
        print_exit!("`cargo package` failed. See above for the cargo error message.");
    }
}

fn main() {
    env_logger::init().expect("Can't instantiate env logger");

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    let mut config_builder = ConfigBuilder::new();

    if args.flag_version {
        println!("semantic.rs 🚀 -- v{}", VERSION);
        process::exit(0);
    }

    // If write mode is requested OR denied,
    // adhere to the user's wish,
    // otherwise we decide based on whether we are running in CI.
    let write_mode = match args.flag_write {
        None => ci_env_set(),
        Some(ref flag) => string_to_bool(flag)
    };

    // We can only release, if we are allowed to write
    let release_mode = write_mode && string_to_bool(&args.flag_release);

    config_builder.write(write_mode);
    config_builder.release(release_mode);
    config_builder.branch(args.flag_branch);

    println!("semantic.rs 🚀");

    logger::stdout("Analyzing your repository");
    let path = Path::new(&args.flag_path);
    let path = fs::canonicalize(path)
        .unwrap_or_else(|_| print_exit!("Path does not exist or a component is not a directory"));
    let repository_path = path.to_str()
        .unwrap_or_else(|| print_exit!("Path is not valid unicode"));

    let repo = match git2::Repository::open(repository_path) {
        Ok(repo) => repo,
        Err(e) => {
            logger::stderr(format!("Could not open the git repository: {:?}", e));
            process::exit(1);
        }
    };

    config_builder.repository_path(repository_path.to_owned());

    // extra scope scope to make sure borrow of `repo` is dropped
    {
        let signature = match git::get_signature(&repo) {
            Ok(sig) => sig,
            Err(e) => {
                logger::stderr(format!("Failed to get the committer's name and email address: {}", e.description()));
                logger::stderr(COMMITTER_ERROR_MESSAGE);
                process::exit(1);
            }
        };

        config_builder.signature(signature.to_owned());
    }

    // In case we are in write-mode AND release mode,
    // we will make sure we got all configuration settings
    if write_mode && release_mode {
        let remote_or_none = repo.find_remote("origin");
        match remote_or_none {
            Ok(remote) => {
                let url = remote.url().expect("Remote URL is not valid UTF-8").to_owned();
                let (user, repo_name) = user_repo_from_url(&url)
                    .unwrap_or_else(|e| print_exit!("Could not extract user and repository name from URL: {:?}", e));
                config_builder.user(user);
                config_builder.repository_name(repo_name);

                if github::is_github_url(&url) {
                    let gh_token = env::var("GH_TOKEN")
                        .unwrap_or_else(|err| print_exit!("GH_TOKEN not set: {:?}", err));
                    config_builder.gh_token(gh_token);
                }

                let cargo_token = env::var("CARGO_TOKEN")
                    .unwrap_or_else(|err| print_exit!("CARGO_TOKEN not set: {:?}", err));

                config_builder.cargo_token(cargo_token);
            },
            Err(err) => {
                logger::warn(format!("Could not determine the origin remote url: {:?}", err));
                logger::warn("semantic-rs can't push changes or create a release on GitHub");
            }
        }
    }

    config_builder.repository(repo);
    let config = config_builder.build();

    let branch = current_branch(&config.repository)
        .unwrap_or_else(|| print_exit!("Could not determine current branch."));

    if !is_release_branch(&branch, &config.branch) {
        println!("Current branch is '{}', releases are only done from branch '{}'", branch, config.branch);
        println!("No release done from a pull request either.");
        process::exit(0);
    }

    if config.release_mode && ci_env_set() {
        let build_run = Build::from_env()
            .unwrap_or_else(|e| print_exit!("CI mode, but can't check other builds. Error: {:?}", e));

        if !build_run.is_leader() {
            println!("Not the build leader. Nothing to do. Bye.");
            process::exit(0);
        }

        println!("I am the build leader. Waiting for other jobs to finish.");
        match build_run.wait_for_others() {
            Ok(()) => println!("Other jobs finished and succeeded. Doing my work now."),
            Err(travis_after_all::Error::FailedBuilds) => {
                print_exit!("Some builds failed. Stopping here.");
            },
            Err(e) => print_exit!("Waiting for other builds failed Reason: {:?}", e),
        }
    }

    let version = toml_file::read_from_file(&config.repository_path)
        .unwrap_or_else(|err| print_exit!("Reading `Cargo.toml` failed: {:?}", err));

    let version = Version::parse(&version).expect("Not a valid version");
    logger::stdout(format!("Current version: {}", version.to_string()));

    logger::stdout("Analyzing commits");

    let bump = git::version_bump_since_latest(&config.repository);
    if write_mode {
        logger::stdout(format!("Commits analyzed. Bump will be {:?}", bump));
    } else {
        logger::stdout(format!("Commits analyzed. Bump would be {:?}", bump));
    }
    let new_version = match version_bump(&version, bump) {
        Some(new_version) => new_version.to_string(),
        None => {
            logger::stdout("No version bump. Nothing to do.");
            process::exit(0);
        }
    };

    if !config.write_mode {
        let changelog = generate_changelog(repository_path, &version, &new_version);
        print_changelog(&changelog);
    } else {
        logger::stdout(format!("New version: {}", new_version));

        toml_file::write_new_version(repository_path, &new_version)
            .unwrap_or_else(|err| print_exit!("Writing `Cargo.toml` failed: {:?}", err));

        write_changelog(&repository_path, &version, &new_version);
        package_crate(&config, &repository_path, &new_version);

        logger::stdout("Creating annotated git tag");
        let tag_message = changelog::generate(repository_path, &version.to_string(), &new_version)
            .unwrap_or_else(|err| print_exit!("Can't generate changelog: {:?}", err));

        let tag_name = format!("v{}", new_version);
        git::tag(&config, &tag_name, &tag_message)
            .unwrap_or_else(|err| print_exit!("Failed to create git tag: {:?}", err));

        if config.release_mode && config.can_push() {
            push_to_github(&config, &tag_name);
            release_on_github(&config, &tag_message, &tag_name);
            release_on_cratesio(&config);
            println!("{} v{} is released. 🚀🚀🚀", config.repository_name.unwrap(), new_version);
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
mod macros;

mod git;

extern crate getopts;
extern crate hyper;
extern crate oauth2;
extern crate queryst;
extern crate rustc_serialize;
extern crate tempdir;
extern crate unicase;
extern crate url;
extern crate uuid;

use getopts::Options;
use hyper::header;
use hyper::net::Openssl;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;
use oauth2::Config;
use rustc_serialize::Encodable;
use rustc_serialize::json::{self, Json};
use queryst::parse;
use std::collections::{HashMap, HashSet};
use std::env;
use std::error::Error;
use std::io::Read;
use std::string::String;
use std::sync::{Arc, Mutex};
use unicase::UniCase;
use url::{parse_path, Url};
use self::uuid::Uuid;

fn main() {
    let (listen_address, ssl, oauth_config, oauth_redirect_path, whitelisted_domains) = parse_flags();

    let handler = Handler{
        oauth_config: oauth_config,
        oauth_redirect_path: oauth_redirect_path,
        whitelisted_domains: whitelisted_domains,
        redirect_uris: Arc::new(Mutex::new(HashMap::new())),
    };

    println!("Listening on {}", listen_address);
    if ssl.is_some() {
        Server::https(&listen_address[..], ssl.unwrap()).unwrap().handle(handler).unwrap();
    } else {
        Server::http(&listen_address[..]).unwrap().handle(handler).unwrap();
    }
}

fn parse_flags() -> (String, Option<Openssl>, oauth2::Config, String, HashSet<String>) {
    let mut opts = Options::new();

    opts.optopt("p", "port", "Port on which to listen", "3000");
    opts.optopt("i", "interface", "Interface on which to listen", "0.0.0.0");

    opts.optflag("s", "ssl", "Whether to listen for HTTPS or just HTTP");
    opts.optopt("c", "certfile", "SSL certificate file", "/path/to/foo.crt");
    opts.optopt("k", "keyfile", "SSL key file", "/path/to/foo.key");

    opts.optopt("h", "host_and_port", "Hostname and port", "127.0.0.1:443");
    opts.optopt("", "oauth_client_id", "Github oauth client ID", "clientid");
    opts.optopt("", "oauth_client_secret", "Github oauth client secret", "clientsecret");
    opts.optopt("", "oauth_redirect_path", "Github oauth redirect URL", "/oauth/redirect");

    opts.optopt("d", "whitelisted_domains", "Hostname and port of domains to which to allow redirection (comma-separated)", "");

    let args: Vec<String> = env::args().collect();
    let matches = opts.parse(&args[1..]).unwrap();
    let interface = matches.opt_str("i").unwrap_or("0.0.0.0".to_owned());
    let port = matches.opt_str("p").unwrap_or("3000".to_owned());

    let ssl = match matches.opt_present("s") {
        true => Some(Openssl::with_cert_and_key(matches.opt_str("c").unwrap(), matches.opt_str("k").unwrap()).unwrap()),
        false => None,
    };

    let mut oauth_config = oauth2::Config::new(
        &matches.opt_str("oauth_client_id").unwrap(),
        &matches.opt_str("oauth_client_secret").unwrap(),
        "https://github.com/login/oauth/authorize",
        "https://github.com/login/oauth/access_token"
    );
    let oauth_redirect_path = matches.opt_str("oauth_redirect_path").unwrap();
    oauth_config.redirect_url = format!("https://{}{}", matches.opt_str("host_and_port").unwrap(), oauth_redirect_path);

    let whitelisted_domains = matches.opt_str("d").unwrap()
        .split(",")
        .map(|x| x.to_string())
        .collect();

    let host_and_port = format!("{}:{}", interface, port);
    return (host_and_port, ssl, oauth_config, oauth_redirect_path, whitelisted_domains);
}

struct Handler {
    oauth_config: oauth2::Config,
    oauth_redirect_path: String,
    whitelisted_domains: HashSet<String>,
    redirect_uris: Arc<Mutex<HashMap<String, String>>>,
}

impl hyper::server::Handler for Handler {
    fn handle(&self, req: Request, mut res: Response) {
        let (path, qs) = match req.uri {
            AbsolutePath(ref p) => match parse_path(p) {
                Ok((path, qs, _)) => (format!("/{}", path.join("/")), qs),
                Err(err) => { self.error(res, err.description()); return },
            },
            _ => { self.not_found(res); return },
        };

        res.headers_mut().set(header::AccessControlAllowOrigin::Any);
        res.headers_mut().set(header::AccessControlAllowHeaders(vec![UniCase("content-type".to_owned())]));

        if req.method == hyper::method::Method::Options {
            return
        }

        match &path[..] {
            "/squashmerge" => match req.method {
                hyper::Post => { self.handle_request(req, res, Handler::handle_squash_request) },
                _ => self.not_allowed(res)
            },
            "/rewritehistory" => match req.method {
                hyper::Post => { self.handle_request(req, res, Handler::handle_rewrite_history_request) },
                _ => self.not_allowed(res),
            },
            "/oauth/authorize" => match req.method {
                hyper::Get => self.handle_oauth_authorize_request(qs, res),
                _ => self.not_allowed(res),
            },
            _ => {
                if path == &self.oauth_redirect_path[..] {
                    match req.method {
                        hyper::Get => match qs {
                            Some(q) => self.handle_oauth_exchange_request(&q, res),
                            None => self.bad_request(res, "Missing querstring"),
                        },
                        _ => self.not_allowed(res),
                    }
                } else {
                    self.not_found(res);
                }
            },
        };
    }
}

impl Handler {
    fn handle_request<F>(&self, mut req: Request, res: Response, handler: F)
        where F : Fn(&str) -> Result<String, String> {

        let mut body_string = String::new();
        let err = req.read_to_string(&mut body_string);
        if err.is_err() {
            self.error(res, &err.err().unwrap().description());
            return;
        }

        match handler(&body_string) {
            Ok(sha) => self.send_json(res, &ShaResponse { sha: &sha, merged: true }),
            Err(err) => self.error(res, &err),
        };
    }

    fn handle_squash_request(body_string: &str) -> Result<String, String> {
        let body = try_or_string!(Json::from_str(body_string));

        return git::squash_merge(
            get_json_string!(body, "base_repo"),
            get_json_string!(body, "base_branch"),
            get_json_string!(body, "head_repo"),
            get_json_string!(body, "head_branch"),
            get_json_string!(body, "commit_message"),
            get_json_string!(body, "username"),
            get_json_string!(body, "password"),
            get_json_string!(body, "committer_name"),
            get_json_string!(body, "committer_email"),
        );
    }

    fn handle_rewrite_history_request(body_string: &str) -> Result<String, String> {
        let body = try_or_string!(Json::from_str(body_string));

        return git::rewrite_history(
            get_json_string!(body, "repo"),
            get_json_string!(body, "branch"),
            get_json_string!(body, "baseline_repo"),
            get_json_string!(body, "baseline_branch"),
            get_json_string!(body, "commit_message"),
            get_json_string!(body, "username"),
            get_json_string!(body, "password"),
            get_json_string!(body, "committer_name"),
            get_json_string!(body, "committer_email"),
        );
    }

    fn handle_oauth_authorize_request(&self, qs: Option<String>, mut res: Response) {
        let uuid = Uuid::new_v4().to_hyphenated_string();

        let redirect_uri = self.get_redirect_uri(&qs);

        if redirect_uri.is_none() {
            self.bad_request(res, "Missing redirect_uri");
            return;
        }

        let mut uris = self.redirect_uris.lock().unwrap();
        uris.insert(uuid.clone(), redirect_uri.unwrap().to_owned());

        // TODO: Implement clone for oauth2::Config
        let mut oauth_config = oauth2::Config::new(
            &self.oauth_config.client_id,
            &self.oauth_config.client_secret,
            &self.oauth_config.auth_url.to_string(),
            &self.oauth_config.token_url.to_string(),
        );
        oauth_config.redirect_url = self.oauth_config.redirect_url.clone();
        oauth_config.scopes.extend(self.get_scopes(&qs));

        let _ = *res.status_mut() = StatusCode::Found;
        res.headers_mut().set(header::Location(oauth_config.authorize_url(uuid).to_string()));
    }

    fn handle_oauth_exchange_request(&self, qs: &str, res: Response) {
        let obj = match parse(qs) {
            Ok(q) => q,
            Err(err) => { self.error(res, &format!("Error parsing querystring: {}", err.message)); return },
        };
        let code = match obj.find("code") {
            Some(c) => match c.as_string() {
                Some(c) => c,
                None => { self.error(res, "code not a string"); return },
            },
            None => { self.error(res, "No code present"); return },
        };
        let state = match obj.find("state") {
            Some(c) => match c.as_string() {
                Some(c) => c,
                None => { self.error(res, "state not a string"); return },
            },
            None => { self.error(res, "No state present"); return },
        };
        let token = self.oauth_config.exchange(code.to_owned());
        match token {
            Ok(tok) => self.respond_with_token(res, state, &tok.access_token),
            Err(tok) => self.error(res, &format!("Error exchanging token: {}", tok)),
        };
    }

    fn respond_with_token(&self, mut res: Response, uuid: &str, token: &str) {
        let mut uris = self.redirect_uris.lock().unwrap();
        match uris.remove(uuid) {
            Some(uri) => {
                let _ = *res.status_mut() = StatusCode::Found;
                // TODO: Form URI better
                res.headers_mut().set(header::Location(format!("{}?token={}", uri, token)));
            },
            None => { self.bad_request(res, "Unknown caller"); },
        };
    }

    fn send_json<T: Encodable>(&self, mut res: Response, obj: &T) {
        match json::encode(obj) {
            Ok(o) => { let _ = res.send(o.as_bytes()); },
            Err(_) => {
                let _ = *res.status_mut() = StatusCode::InternalServerError;
                let _ = res.send("{\"message\": \"error serializing response\"}".as_bytes());
            },
        };
    }

    fn get_redirect_uri(&self, qs: &Option<String>) -> Option<String> {
        let string = self.get_string_qs(qs, "redirect_uri");
        if string.is_none() {
            return string
        }

        let url = Url::parse(&string.clone().unwrap());
        match url {
            Ok(u) => {
                if &u.scheme != "https" {
                    return None;
                }
                let domain = u.domain();
                if domain.is_none() {
                    return None;
                }
                if !self.is_whitelisted_domain(domain.unwrap()) {
                    return None;
                }
            },
            Err(_) => { return None; },
        };
        return string;
    }

    fn is_whitelisted_domain(&self, domain: &str) -> bool {
        return self.whitelisted_domains.contains(&domain.to_owned());
    }

    fn get_scopes(&self, qs: &Option<String>) -> Vec<String> {
        let val = self.get_string_qs(qs, "scopes")
            .clone()
            .unwrap_or("".to_owned());
        return val
            .split(",")
            .map(|x| x.to_string())
            .collect();
    }

    fn get_string_qs(&self, qs: &Option<String>, key: &str) -> Option<String> {
        let kv = match qs.clone() {
            Some(q) => match parse(&q) {
                Ok(kv) => kv,
                Err(_) => return None,
            },
            None => return None,
        };
        return kv.find(key)
            .and_then(|v| v.as_string())
            .and_then(|v| Some(v.to_owned().clone()));
    }

    fn error(&self, mut res: Response, description: &str) {
        let _ = *res.status_mut() = StatusCode::InternalServerError;
        self.send_json(res, &ErrorResponse { message: description });
    }

    fn bad_request(&self, mut res: Response, reason: &str) {
        let _ = *res.status_mut() = StatusCode::BadRequest;
        self.send_json(res, &ErrorResponse { message: &format!("Bad request: {}", reason) });
    }

    fn not_allowed(&self, mut res: Response) {
        let _ = *res.status_mut() = StatusCode::MethodNotAllowed;
    }

    fn not_found(&self, mut res: Response) {
        let _ = *res.status_mut() = StatusCode::NotFound;
    }
}

#[derive(RustcEncodable)]
struct ShaResponse<'a> {
    sha: &'a str,
    merged: bool,
}

#[derive(RustcEncodable)]
struct ErrorResponse<'a> {
    message: &'a str,
}
<commit_msg>Fix error message<commit_after>#[macro_use]
mod macros;

mod git;

extern crate getopts;
extern crate hyper;
extern crate oauth2;
extern crate queryst;
extern crate rustc_serialize;
extern crate tempdir;
extern crate unicase;
extern crate url;
extern crate uuid;

use getopts::Options;
use hyper::header;
use hyper::net::Openssl;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;
use oauth2::Config;
use rustc_serialize::Encodable;
use rustc_serialize::json::{self, Json};
use queryst::parse;
use std::collections::{HashMap, HashSet};
use std::env;
use std::error::Error;
use std::io::Read;
use std::string::String;
use std::sync::{Arc, Mutex};
use unicase::UniCase;
use url::{parse_path, Url};
use self::uuid::Uuid;

fn main() {
    let (listen_address, ssl, oauth_config, oauth_redirect_path, whitelisted_domains) = parse_flags();

    let handler = Handler{
        oauth_config: oauth_config,
        oauth_redirect_path: oauth_redirect_path,
        whitelisted_domains: whitelisted_domains,
        redirect_uris: Arc::new(Mutex::new(HashMap::new())),
    };

    println!("Listening on {}", listen_address);
    if ssl.is_some() {
        Server::https(&listen_address[..], ssl.unwrap()).unwrap().handle(handler).unwrap();
    } else {
        Server::http(&listen_address[..]).unwrap().handle(handler).unwrap();
    }
}

fn parse_flags() -> (String, Option<Openssl>, oauth2::Config, String, HashSet<String>) {
    let mut opts = Options::new();

    opts.optopt("p", "port", "Port on which to listen", "3000");
    opts.optopt("i", "interface", "Interface on which to listen", "0.0.0.0");

    opts.optflag("s", "ssl", "Whether to listen for HTTPS or just HTTP");
    opts.optopt("c", "certfile", "SSL certificate file", "/path/to/foo.crt");
    opts.optopt("k", "keyfile", "SSL key file", "/path/to/foo.key");

    opts.optopt("h", "host_and_port", "Hostname and port", "127.0.0.1:443");
    opts.optopt("", "oauth_client_id", "Github oauth client ID", "clientid");
    opts.optopt("", "oauth_client_secret", "Github oauth client secret", "clientsecret");
    opts.optopt("", "oauth_redirect_path", "Github oauth redirect URL", "/oauth/redirect");

    opts.optopt("d", "whitelisted_domains", "Hostname and port of domains to which to allow redirection (comma-separated)", "");

    let args: Vec<String> = env::args().collect();
    let matches = opts.parse(&args[1..]).unwrap();
    let interface = matches.opt_str("i").unwrap_or("0.0.0.0".to_owned());
    let port = matches.opt_str("p").unwrap_or("3000".to_owned());

    let ssl = match matches.opt_present("s") {
        true => Some(Openssl::with_cert_and_key(matches.opt_str("c").unwrap(), matches.opt_str("k").unwrap()).unwrap()),
        false => None,
    };

    let mut oauth_config = oauth2::Config::new(
        &matches.opt_str("oauth_client_id").unwrap(),
        &matches.opt_str("oauth_client_secret").unwrap(),
        "https://github.com/login/oauth/authorize",
        "https://github.com/login/oauth/access_token"
    );
    let oauth_redirect_path = matches.opt_str("oauth_redirect_path").unwrap();
    oauth_config.redirect_url = format!("https://{}{}", matches.opt_str("host_and_port").unwrap(), oauth_redirect_path);

    let whitelisted_domains = matches.opt_str("d").unwrap()
        .split(",")
        .map(|x| x.to_string())
        .collect();

    let host_and_port = format!("{}:{}", interface, port);
    return (host_and_port, ssl, oauth_config, oauth_redirect_path, whitelisted_domains);
}

struct Handler {
    oauth_config: oauth2::Config,
    oauth_redirect_path: String,
    whitelisted_domains: HashSet<String>,
    redirect_uris: Arc<Mutex<HashMap<String, String>>>,
}

impl hyper::server::Handler for Handler {
    fn handle(&self, req: Request, mut res: Response) {
        let (path, qs) = match req.uri {
            AbsolutePath(ref p) => match parse_path(p) {
                Ok((path, qs, _)) => (format!("/{}", path.join("/")), qs),
                Err(err) => { self.error(res, err.description()); return },
            },
            _ => { self.not_found(res); return },
        };

        res.headers_mut().set(header::AccessControlAllowOrigin::Any);
        res.headers_mut().set(header::AccessControlAllowHeaders(vec![UniCase("content-type".to_owned())]));

        if req.method == hyper::method::Method::Options {
            return
        }

        match &path[..] {
            "/squashmerge" => match req.method {
                hyper::Post => { self.handle_request(req, res, Handler::handle_squash_request) },
                _ => self.not_allowed(res)
            },
            "/rewritehistory" => match req.method {
                hyper::Post => { self.handle_request(req, res, Handler::handle_rewrite_history_request) },
                _ => self.not_allowed(res),
            },
            "/oauth/authorize" => match req.method {
                hyper::Get => self.handle_oauth_authorize_request(qs, res),
                _ => self.not_allowed(res),
            },
            _ => {
                if path == &self.oauth_redirect_path[..] {
                    match req.method {
                        hyper::Get => match qs {
                            Some(q) => self.handle_oauth_exchange_request(&q, res),
                            None => self.bad_request(res, "Missing querstring"),
                        },
                        _ => self.not_allowed(res),
                    }
                } else {
                    self.not_found(res);
                }
            },
        };
    }
}

impl Handler {
    fn handle_request<F>(&self, mut req: Request, res: Response, handler: F)
        where F : Fn(&str) -> Result<String, String> {

        let mut body_string = String::new();
        let err = req.read_to_string(&mut body_string);
        if err.is_err() {
            self.error(res, &err.err().unwrap().description());
            return;
        }

        match handler(&body_string) {
            Ok(sha) => self.send_json(res, &ShaResponse { sha: &sha, merged: true }),
            Err(err) => self.error(res, &err),
        };
    }

    fn handle_squash_request(body_string: &str) -> Result<String, String> {
        let body = try_or_string!(Json::from_str(body_string));

        return git::squash_merge(
            get_json_string!(body, "base_repo"),
            get_json_string!(body, "base_branch"),
            get_json_string!(body, "head_repo"),
            get_json_string!(body, "head_branch"),
            get_json_string!(body, "commit_message"),
            get_json_string!(body, "username"),
            get_json_string!(body, "password"),
            get_json_string!(body, "committer_name"),
            get_json_string!(body, "committer_email"),
        );
    }

    fn handle_rewrite_history_request(body_string: &str) -> Result<String, String> {
        let body = try_or_string!(Json::from_str(body_string));

        return git::rewrite_history(
            get_json_string!(body, "repo"),
            get_json_string!(body, "branch"),
            get_json_string!(body, "baseline_repo"),
            get_json_string!(body, "baseline_branch"),
            get_json_string!(body, "commit_message"),
            get_json_string!(body, "username"),
            get_json_string!(body, "password"),
            get_json_string!(body, "committer_name"),
            get_json_string!(body, "committer_email"),
        );
    }

    fn handle_oauth_authorize_request(&self, qs: Option<String>, mut res: Response) {
        let uuid = Uuid::new_v4().to_hyphenated_string();

        let redirect_uri = self.get_redirect_uri(&qs);

        if redirect_uri.is_none() {
            self.bad_request(res, "Missing or bad redirect_uri");
            return;
        }

        let mut uris = self.redirect_uris.lock().unwrap();
        uris.insert(uuid.clone(), redirect_uri.unwrap().to_owned());

        // TODO: Implement clone for oauth2::Config
        let mut oauth_config = oauth2::Config::new(
            &self.oauth_config.client_id,
            &self.oauth_config.client_secret,
            &self.oauth_config.auth_url.to_string(),
            &self.oauth_config.token_url.to_string(),
        );
        oauth_config.redirect_url = self.oauth_config.redirect_url.clone();
        oauth_config.scopes.extend(self.get_scopes(&qs));

        let _ = *res.status_mut() = StatusCode::Found;
        res.headers_mut().set(header::Location(oauth_config.authorize_url(uuid).to_string()));
    }

    fn handle_oauth_exchange_request(&self, qs: &str, res: Response) {
        let obj = match parse(qs) {
            Ok(q) => q,
            Err(err) => { self.error(res, &format!("Error parsing querystring: {}", err.message)); return },
        };
        let code = match obj.find("code") {
            Some(c) => match c.as_string() {
                Some(c) => c,
                None => { self.error(res, "code not a string"); return },
            },
            None => { self.error(res, "No code present"); return },
        };
        let state = match obj.find("state") {
            Some(c) => match c.as_string() {
                Some(c) => c,
                None => { self.error(res, "state not a string"); return },
            },
            None => { self.error(res, "No state present"); return },
        };
        let token = self.oauth_config.exchange(code.to_owned());
        match token {
            Ok(tok) => self.respond_with_token(res, state, &tok.access_token),
            Err(tok) => self.error(res, &format!("Error exchanging token: {}", tok)),
        };
    }

    fn respond_with_token(&self, mut res: Response, uuid: &str, token: &str) {
        let mut uris = self.redirect_uris.lock().unwrap();
        match uris.remove(uuid) {
            Some(uri) => {
                let _ = *res.status_mut() = StatusCode::Found;
                // TODO: Form URI better
                res.headers_mut().set(header::Location(format!("{}?token={}", uri, token)));
            },
            None => { self.bad_request(res, "Unknown caller"); },
        };
    }

    fn send_json<T: Encodable>(&self, mut res: Response, obj: &T) {
        match json::encode(obj) {
            Ok(o) => { let _ = res.send(o.as_bytes()); },
            Err(_) => {
                let _ = *res.status_mut() = StatusCode::InternalServerError;
                let _ = res.send("{\"message\": \"error serializing response\"}".as_bytes());
            },
        };
    }

    fn get_redirect_uri(&self, qs: &Option<String>) -> Option<String> {
        let string = self.get_string_qs(qs, "redirect_uri");
        if string.is_none() {
            return string
        }

        let url = Url::parse(&string.clone().unwrap());
        match url {
            Ok(u) => {
                if &u.scheme != "https" {
                    return None;
                }
                let domain = u.domain();
                if domain.is_none() {
                    return None;
                }
                if !self.is_whitelisted_domain(domain.unwrap()) {
                    return None;
                }
            },
            Err(_) => { return None; },
        };
        return string;
    }

    fn is_whitelisted_domain(&self, domain: &str) -> bool {
        return self.whitelisted_domains.contains(&domain.to_owned());
    }

    fn get_scopes(&self, qs: &Option<String>) -> Vec<String> {
        let val = self.get_string_qs(qs, "scopes")
            .clone()
            .unwrap_or("".to_owned());
        return val
            .split(",")
            .map(|x| x.to_string())
            .collect();
    }

    fn get_string_qs(&self, qs: &Option<String>, key: &str) -> Option<String> {
        let kv = match qs.clone() {
            Some(q) => match parse(&q) {
                Ok(kv) => kv,
                Err(_) => return None,
            },
            None => return None,
        };
        return kv.find(key)
            .and_then(|v| v.as_string())
            .and_then(|v| Some(v.to_owned().clone()));
    }

    fn error(&self, mut res: Response, description: &str) {
        let _ = *res.status_mut() = StatusCode::InternalServerError;
        self.send_json(res, &ErrorResponse { message: description });
    }

    fn bad_request(&self, mut res: Response, reason: &str) {
        let _ = *res.status_mut() = StatusCode::BadRequest;
        self.send_json(res, &ErrorResponse { message: &format!("Bad request: {}", reason) });
    }

    fn not_allowed(&self, mut res: Response) {
        let _ = *res.status_mut() = StatusCode::MethodNotAllowed;
    }

    fn not_found(&self, mut res: Response) {
        let _ = *res.status_mut() = StatusCode::NotFound;
    }
}

#[derive(RustcEncodable)]
struct ShaResponse<'a> {
    sha: &'a str,
    merged: bool,
}

#[derive(RustcEncodable)]
struct ErrorResponse<'a> {
    message: &'a str,
}
<|endoftext|>


<commit_before>extern crate comrak;
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate time;

mod directives;
mod evaluator;
mod lex;
mod parse;

use std::env;
use parse::parse;
use evaluator::Evaluator;

fn main() {
    let mut evaluator = Evaluator::new();
    evaluator.register("md", Box::new(directives::Markdown::new()));
    evaluator.register("table", Box::new(directives::Dummy::new()));
    evaluator.register("version", Box::new(directives::Version::new("3.4.0")));
    evaluator.register("note",
                       Box::new(directives::Admonition::new("Note", "note")));
    evaluator.register("warning",
                       Box::new(directives::Admonition::new("Warning", "warning")));
    evaluator.register("insert", Box::new(directives::Dummy::new()));
    evaluator.register("definition-list", Box::new(directives::Dummy::new()));
    evaluator.register("manual",
                       Box::new(directives::LinkTemplate::new("https://docs.mongodb.com/manual")));
    evaluator.register("definition-list",
                       Box::new(directives::DefinitionList::new()));

    evaluator.register("concat", Box::new(directives::Concat::new()));

    let start_time = time::precise_time_ns();
    for argument in env::args().skip(1) {
        let node = parse(&argument);
        let output = evaluator.evaluate(&node);
        println!("{}", output);

    }

    println!("Took {} seconds",
             (time::precise_time_ns() - start_time) as f64 / (1_000_000_000 as f64));
}
<commit_msg>Remove duplicate definition-list registration<commit_after>extern crate comrak;
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate time;

mod directives;
mod evaluator;
mod lex;
mod parse;

use std::env;
use parse::parse;
use evaluator::Evaluator;

fn main() {
    let mut evaluator = Evaluator::new();
    evaluator.register("md", Box::new(directives::Markdown::new()));
    evaluator.register("table", Box::new(directives::Dummy::new()));
    evaluator.register("version", Box::new(directives::Version::new("3.4.0")));
    evaluator.register("note",
                       Box::new(directives::Admonition::new("Note", "note")));
    evaluator.register("warning",
                       Box::new(directives::Admonition::new("Warning", "warning")));
    evaluator.register("insert", Box::new(directives::Dummy::new()));
    evaluator.register("manual",
                       Box::new(directives::LinkTemplate::new("https://docs.mongodb.com/manual")));
    evaluator.register("definition-list",
                       Box::new(directives::DefinitionList::new()));

    evaluator.register("concat", Box::new(directives::Concat::new()));

    let start_time = time::precise_time_ns();
    for argument in env::args().skip(1) {
        let node = parse(&argument);
        let output = evaluator.evaluate(&node);
        println!("{}", output);

    }

    println!("Took {} seconds",
             (time::precise_time_ns() - start_time) as f64 / (1_000_000_000 as f64));
}
<|endoftext|>


<commit_before>#![cfg_attr(test, allow(dead_code))]

mod byte_conversion;
mod byte_manipulation;
mod english_scoring;

fn guess_single_xor_char_decode(bytes: &Vec<u8>) -> (u16, Vec<u8>) {
	let mut top_score = 0;
	let mut top_decode = vec![];
	for x in 0..255 {
		let mut spin: Vec<u8> = vec![];
		while spin.len() < bytes.len() {
			spin.push(x);
		}

		let decoded = byte_manipulation::xor_byte_streams(&bytes, &spin);
		let score = english_scoring::score_combined(&decoded);
		if score > top_score {
			top_score = score;
			top_decode = decoded;
		}
	}

	(top_score, top_decode)
}

fn problem_3() {
	// http://cryptopals.com/sets/1/challenges/3/
	use byte_conversion::*;
	let encoded = hex_to_bytes("1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736");

	let (top_score, top_decode) = guess_single_xor_char_decode(&encoded);

	println!("Best guess: `{}`, with a score of {}.", bytes_to_readable_text(&top_decode), top_score);
}

fn problem_4() {
	// http://cryptopals.com/sets/1/challenges/4/
	use std::error::Error;
	use std::fs::File;
	use std::io::prelude::*;
	use std::path::Path;
	use byte_conversion::*;

	// Create a path to the desired file
    let path = Path::new("C:\\Users\\Topher\\Dropbox\\Public\\Programming\\Matasano\\matasano-crypto-challenges\\res\\4.txt");
    let display = path.display();

    // Open the path in read-only mode, returns `io::Result<File>`
    let mut file = match File::open(&path) {
        // The `description` method of `io::Error` returns a string that
        // describes the error
        Err(why) => panic!("couldn't open {}: {}", display,
                                                   Error::description(&why)),
        Ok(file) => file,
    };

    // Read the file contents into a string, returns `io::Result<usize>`
    let mut s = String::new();
    match file.read_to_string(&mut s) {
        Err(why) => panic!("couldn't read {}: {}", display, Error::description(&why)),
        Ok(_) => {},
    }

	let mut top_score = 0;
	let mut top_decode = vec![];
    for line in s.split("\n") {
    	let (score, decoded) = guess_single_xor_char_decode(&hex_to_bytes(line));

		if score > top_score {
			top_score = score;
			top_decode = decoded.clone();
		}

    }

    println!("\n\n\n{} -      `{}`", top_score, bytes_to_readable_text(&top_decode));
}

fn problem_6() {
	// http://cryptopals.com/sets/1/challenges/6/
}

fn main() {
	println!("Running.");
}<commit_msg>Added utility read_file function<commit_after>#![cfg_attr(test, allow(dead_code))]

mod byte_conversion;
mod byte_manipulation;
mod english_scoring;

fn guess_single_xor_char_decode(bytes: &Vec<u8>) -> (u16, Vec<u8>) {
	let mut top_score = 0;
	let mut top_decode = vec![];
	for x in 0..255 {
		let mut spin: Vec<u8> = vec![];
		while spin.len() < bytes.len() {
			spin.push(x);
		}

		let decoded = byte_manipulation::xor_byte_streams(&bytes, &spin);
		let score = english_scoring::score_combined(&decoded);
		if score > top_score {
			top_score = score;
			top_decode = decoded;
		}
	}

	(top_score, top_decode)
}

fn read_file(location: &str) -> String {
	use std::error::Error;
	use std::fs::File;
	use std::io::prelude::*;
	use std::path::Path;

	// Create a path to the desired file
    let path = Path::new(location);
    let display = path.display();

    // Open the path in read-only mode, returns `io::Result<File>`
    let mut file = match File::open(&path) {
        // The `description` method of `io::Error` returns a string that
        // describes the error
        Err(why) => panic!("couldn't open {}: {}", display,
                                                   Error::description(&why)),
        Ok(file) => file,
    };

    // Read the file contents into a string, returns `io::Result<usize>`
    let mut file_data = String::new();
    match file.read_to_string(&mut file_data) {
        Err(why) => panic!("couldn't read {}: {}", display, Error::description(&why)),
        Ok(_) => {},
    }

    file_data
}

fn problem_3() {
	// http://cryptopals.com/sets/1/challenges/3/
	use byte_conversion::*;
	let encoded = hex_to_bytes("1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736");

	let (top_score, top_decode) = guess_single_xor_char_decode(&encoded);

	println!("Best guess: `{}`, with a score of {}.", bytes_to_readable_text(&top_decode), top_score);
}

fn problem_4() {
	// http://cryptopals.com/sets/1/challenges/4/

	use byte_conversion::*;

	let s = read_file("C:\\Users\\Topher\\Dropbox\\Public\\Programming\\Matasano\\matasano-crypto-challenges\\res\\4.txt");

	let mut top_score = 0;
	let mut top_decode = vec![];
    for line in s.split("\n") {
    	let (score, decoded) = guess_single_xor_char_decode(&hex_to_bytes(line));

		if score > top_score {
			top_score = score;
			top_decode = decoded.clone();
		}

    }

    println!("\n\n\n{} -      `{}`", top_score, bytes_to_readable_text(&top_decode));
}

fn problem_6() {
	// http://cryptopals.com/sets/1/challenges/6/
}

fn main() {
	println!("Running.");

	problem_4();

	for keysize in 2..40 {

		//let  Vec<u8>
	}

}<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::io::{BufRead, BufReader};

fn print_help() {
    println!("-h : help");
    println!("-f : files to read, comma separated list");
}

enum HotfixType {
    OnDemand(Option<String>),
    Level(Option<String>),
    Patch
}

fn main() {
    let mut files = None;
    for arg in env::args() {
        let arg = arg.split('=').collect::<Vec<&str>>();
        match arg[0] {
            "-h" => { // Help
                print_help();
                return;
            },
            "-f" => { // Files
                files = Some(arg[1].split(',').map(|x| (Path::new(x).to_path_buf(), File::open(x).unwrap())).collect::<Vec<(PathBuf, File)>>());
            },
            _ => {
            }
        }
    }
    if let None = files {
        print_help();
        return;
    }
    let files = files.unwrap();
    if files.len() == 0 {
        print_help();
        return;
    }

    let mut keys = Vec::new();
    let mut values = Vec::new();

    let mut on_demand_index = 1;
    let mut level_index = 1;
    let mut patch_index = 1;

    let mut current_type = HotfixType::Patch;

    for file in files {
        let prefix = file.0.file_name().unwrap().to_str().unwrap().splitn(2, ".").next().unwrap();
        let file = BufReader::new(file.1);

        for line in file.lines().filter_map(|result| result.ok()) {
            match line.chars().nth(0) {
                Some('#') | Some('\n') | Some('\r') | None => {
                    continue;
                },
                _ => {
                }
            }
            let mut parts = line.splitn(2, " ");
            let command = parts.next().unwrap().to_lowercase();
            let data = parts.next().unwrap();
            match command.as_str() {
                "set" => {
                    let mut parts = data.splitn(3, " ");
                    match &current_type {
                        &HotfixType::Level(ref x) => {
                            keys.push(format!("SparkLevelPatchEntry-{}{}", prefix, level_index));
                            values.push(format!("{},{},{},,{}", x.clone().unwrap_or("".to_string()), parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap()));
                            level_index += 1;
                        },
                        &HotfixType::OnDemand(ref x) => {
                            keys.push(format!("SparkOnDemandPatchEntry-{}{}", prefix, on_demand_index));
                            values.push(format!("{},{},{},,{}", x.clone().unwrap_or("".to_string()), parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap()));
                            on_demand_index += 1;
                        },
                        &HotfixType::Patch => {
                            keys.push(format!("SparkPatchEntry-{}{}", prefix, patch_index));
                            values.push(format!("{},{},,{}", parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap()));
                            patch_index += 1;
                        }
                    }
                },
                "set_cmp" => {
                    let mut parts = data.splitn(4, " ");
                    match &current_type {
                        &HotfixType::Level(ref x) => {
                            keys.push(format!("SparkLevelPatchEntry-{}{}", prefix, level_index));
                            values.push(format!("{},{},{},{},{}", x.clone().unwrap_or("".to_string()), parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap()));
                            level_index += 1;
                        },
                        &HotfixType::OnDemand(ref x) => {
                            keys.push(format!("SparkOnDemandPatchEntry-{}{}", prefix, on_demand_index));
                            values.push(format!("{},{},{},{},{}", x.clone().unwrap_or("".to_string()), parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap()));
                            on_demand_index += 1;
                        },
                        &HotfixType::Patch => {
                            keys.push(format!("SparkPatchEntry-{}{}", prefix, patch_index));
                            values.push(format!("{},{},{},{}", parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap()));
                            patch_index += 1;
                        }
                    }
                },
                "start" => {
                    // Level, OnDemand, and Patch
                    let mut parts = data.splitn(2, " ");
                    let command = parts.next().unwrap().to_lowercase();
                    match command.as_str() {
                        "ondemand" => {
                            let package = parts.next().unwrap();
                            current_type = HotfixType::OnDemand(if package.to_lowercase() == "none" {
                                None
                            } else {
                                Some(package.to_string())
                            });
                        },
                        "level" => {
                            let package = parts.next().unwrap();
                            current_type = HotfixType::Level(if package.to_lowercase() == "none" {
                                None
                            } else {
                                Some(package.to_string())
                            });
                        },
                        "patch" => {
                            current_type = HotfixType::Patch;
                        },
                        _ => {
                        }
                    }
                },
                _ => {
                }
            }
        }
    }
    print!("set Transient.SparkServiceConfiguration_6 Keys (");
    for i in 0..keys.len() {
        if i != 0 {
            print!(",");
        }
        print!("\"{}\"", keys[i]);
    }
    println!(")\r");
    println!("\r");
    println!("\r");
    print!("set Transient.SparkServiceConfiguration_6 Values (");
    for i in 0..values.len() {
        if i != 0 {
            print!(",");
        }
        print!("\"{}\"", values[i]);
    }
    println!(")\r");
}
<commit_msg>Changed from unwrap to expect, now prints some info about what went wrong<commit_after>use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::io::{BufRead, BufReader};

fn print_help() {
    println!("-h : help");
    println!("-f : files to read, comma separated list");
}

enum HotfixType {
    OnDemand(Option<String>),
    Level(Option<String>),
    Patch
}

fn main() {
    let mut files = None;
    for arg in env::args() {
        let arg = arg.split('=').collect::<Vec<&str>>();
        match arg[0] {
            "-h" => { // Help
                print_help();
                return;
            },
            "-f" => { // Files
                files = Some(arg[1].split(',').map(|x| (Path::new(x).to_path_buf(), File::open(x).expect(&format!("Can't find file: {}", x)))).collect::<Vec<(PathBuf, File)>>());
            },
            _ => {
            }
        }
    }
    if let None = files {
        print_help();
        return;
    }
    let files = files.unwrap();
    if files.len() == 0 {
        print_help();
        return;
    }

    let mut keys = Vec::new();
    let mut values = Vec::new();

    let mut on_demand_index = 1;
    let mut level_index = 1;
    let mut patch_index = 1;

    let mut current_type = HotfixType::Patch;

    for file in files {
        let prefix = file.0.file_name().expect("File name not found").to_str().expect("File name not unicode").splitn(2, ".").next().expect("File has no name");
        let file = BufReader::new(file.1);

        for line in file.lines().filter_map(|result| result.ok()) {
            match line.chars().nth(0) {
                Some('#') | Some('\n') | Some('\r') | None => {
                    continue;
                },
                _ => {
                }
            }
            let mut parts = line.splitn(2, " ");
            let command = parts.next().expect(&format!("Syntax error: {}", line)).to_lowercase();
            let data = parts.next().expect(&format!("Syntax error: {}", line));
            match command.as_str() {
                "set" => {
                    let mut parts = data.splitn(3, " ");
                    match &current_type {
                        &HotfixType::Level(ref x) => {
                            keys.push(format!("SparkLevelPatchEntry-{}{}", prefix, level_index));
                            values.push(format!("{},{},{},,{}", x.clone().unwrap_or("".to_string()), parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line))));
                            level_index += 1;
                        },
                        &HotfixType::OnDemand(ref x) => {
                            keys.push(format!("SparkOnDemandPatchEntry-{}{}", prefix, on_demand_index));
                            values.push(format!("{},{},{},,{}", x.clone().unwrap_or("".to_string()), parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line))));
                            on_demand_index += 1;
                        },
                        &HotfixType::Patch => {
                            keys.push(format!("SparkPatchEntry-{}{}", prefix, patch_index));
                            values.push(format!("{},{},,{}", parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line))));
                            patch_index += 1;
                        }
                    }
                },
                "set_cmp" => {
                    let mut parts = data.splitn(4, " ");
                    match &current_type {
                        &HotfixType::Level(ref x) => {
                            keys.push(format!("SparkLevelPatchEntry-{}{}", prefix, level_index));
                            values.push(format!("{},{},{},{},{}", x.clone().unwrap_or("".to_string()), parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line))));
                            level_index += 1;
                        },
                        &HotfixType::OnDemand(ref x) => {
                            keys.push(format!("SparkOnDemandPatchEntry-{}{}", prefix, on_demand_index));
                            values.push(format!("{},{},{},{},{}", x.clone().unwrap_or("".to_string()), parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line))));
                            on_demand_index += 1;
                        },
                        &HotfixType::Patch => {
                            keys.push(format!("SparkPatchEntry-{}{}", prefix, patch_index));
                            values.push(format!("{},{},{},{}", parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line)), parts.next().expect(&format!("Syntax error: {}", line))));
                            patch_index += 1;
                        }
                    }
                },
                "start" => {
                    // Level, OnDemand, and Patch
                    let mut parts = data.splitn(2, " ");
                    let command = parts.next().expect(&format!("Syntax error: {}", line)).to_lowercase();
                    match command.as_str() {
                        "ondemand" => {
                            let package = parts.next().expect(&format!("Syntax error: {}", line));
                            current_type = HotfixType::OnDemand(if package.to_lowercase() == "none" {
                                None
                            } else {
                                Some(package.to_string())
                            });
                        },
                        "level" => {
                            let package = parts.next().expect(&format!("Syntax error: {}", line));
                            current_type = HotfixType::Level(if package.to_lowercase() == "none" {
                                None
                            } else {
                                Some(package.to_string())
                            });
                        },
                        "patch" => {
                            current_type = HotfixType::Patch;
                        },
                        _ => {
                        }
                    }
                },
                _ => {
                }
            }
        }
    }
    print!("set Transient.SparkServiceConfiguration_6 Keys (");
    for i in 0..keys.len() {
        if i != 0 {
            print!(",");
        }
        print!("\"{}\"", keys[i]);
    }
    println!(")\r");
    println!("\r");
    println!("\r");
    print!("set Transient.SparkServiceConfiguration_6 Values (");
    for i in 0..values.len() {
        if i != 0 {
            print!(",");
        }
        print!("\"{}\"", values[i]);
    }
    println!(")\r");
}
<|endoftext|>