<commit_before>extern crate docopt;
extern crate rustc_serialize;

use docopt::Docopt;

const USAGE: &'static str = "
how-do-i-escape: Prints escape sequences for unicode graphemes

Usage:
  how-do-i-escape <grapheme>
  how-do-i-escape (--help | --version)

Options:
  -h, --help  Show this screen.
  --version   Show version.

Example:
  $ how-do-i-escape \u{00A7}
  css  = \"\\00A7\"
  html = §
  js   = \"\\u00A7\"
";

#[derive(RustcDecodable)]
struct Args {
    arg_grapheme: String
}

fn main() {
  let args: Args = Docopt::new(USAGE)
    .and_then(|d| d.help(true).version(Some("v0.1.0".to_string())).decode())
    .unwrap_or_else(|e| e.exit());

  if let Some(as_int) = first_grapheme_as_int(&args.arg_grapheme) {
    println!("css  = {}", as_css(as_int));
    println!("html = {}", as_html(as_int));
    println!("js   = {}", as_js(as_int));
  }
}

fn first_grapheme_as_int(grapheme: &str) -> Option<u32> {
  grapheme.chars().next().map(|c| c as u32)
}

fn as_css(i: u32) -> String {
  format!("\"\\{:01$X}\"", i, 4)
}

fn as_html(i: u32) -> String {
  format!("&#x{:01$X};", i, 4)
}

fn as_js(i: u32) -> String {
  if i <= 0xFFFF {
    format!("\"\\u{:01$X}\"", i, 4)
  } else {
    format!("\"\\u{{{:X}}}\"", i)
  }
}

#[cfg(test)]
mod tests {
  use super::{first_grapheme_as_int, as_css, as_html, as_js};

  #[test]
  fn test_first_grapheme_as_int() {
    assert!(first_grapheme_as_int("\u{00A7}") == Some(0xA7));
    assert!(first_grapheme_as_int("beef") == Some(98));
    assert!(first_grapheme_as_int("\u{10000}") == Some(0x10000));
    assert!(first_grapheme_as_int("\u{10FFFF}") == Some(0x10FFFF));
    assert!(first_grapheme_as_int("") == None);
  }

  #[test]
  fn test_as_css() {
    assert!(as_css(0) == r#""\0000""#);
    assert!(as_css(0xFFFF) == r#""\FFFF""#);
    assert!(as_css(0xBEEF) != r#""\beef""#);
    //assert!(as_css(0x10000) == ?);
  }

  #[test]
  fn test_as_html() {
    assert!(as_html(0) == r#"�"#);
    assert!(as_html(0xFFFF) == r#""#);
    assert!(as_html(0xBEEF) != r#"뻯"#);
    //assert!(as_html(0x10000) == ?);
  }

  #[test]
  fn test_as_js() {
    assert!(as_js(0) == r#""\u0000""#);
    assert!(as_js(0xFFFF) == r#""\uFFFF""#);
    assert!(as_js(0xBEEF) != r#""\ubeef""#);
    assert!(as_js(0x10000) == r#""\u{10000}""#);
    assert!(as_js(0x10FFFF) == r#""\u{10FFFF}""#);
    assert!(as_js(0xFFFFFFFF) == r#""\u{FFFFFFFF}""#);
  }
}
<commit_msg>Fixed graphemes that don't fit in a single code point<commit_after>extern crate docopt;
extern crate rustc_serialize;

use docopt::Docopt;

const USAGE: &'static str = "
how-do-i-escape: Prints escape sequences for unicode graphemes

Usage:
  how-do-i-escape <grapheme>
  how-do-i-escape (--help | --version)

Options:
  -h, --help  Show this screen.
  --version   Show version.

Example:
  $ how-do-i-escape \u{00A7}
  css  = \"\\00A7\"
  html = §
  js   = \"\\u00A7\"
";

#[derive(RustcDecodable)]
struct Args {
    arg_grapheme: String
}

fn main() {
  let args: Args = Docopt::new(USAGE)
    .and_then(|d| d.help(true).version(Some("v0.1.0".to_string())).decode())
    .unwrap_or_else(|e| e.exit());

  let grapheme = args.arg_grapheme;

  println!(r#"css  = "{}""#, escape_grapheme(&grapheme, as_css));
  println!(r#"html = {}"#, escape_grapheme(&grapheme, as_html));
  println!(r#"js   = "{}""#, escape_grapheme(&grapheme, as_js));
}

fn escape_grapheme<F>(grapheme: &str, int_to_escape_sequence: F) -> String
  where F: Fn(u32) -> String
{
  grapheme
    .chars()
    .map(|ch| ch as u32)
    .map(int_to_escape_sequence)
    .fold(String::new(), |c, s| {
      let mut copy = c;
      copy.push_str(&s);
      copy
    })
}

fn as_css(i: u32) -> String {
  format!("\\{:01$X}", i, 4)
}

fn as_html(i: u32) -> String {
  format!("&#x{:01$X};", i, 4)
}

fn as_js(i: u32) -> String {
  if i <= 0xFFFF {
    format!("\\u{:01$X}", i, 4)
  } else {
    format!("\\u{{{:X}}}", i)
  }
}

#[cfg(test)]
mod tests {
  use super::{as_css, as_html, as_js};

  #[test]
  fn test_as_css() {
    assert!(as_css(0) == r"\0000");
    assert!(as_css(0xFFFF) == r"\FFFF");
    assert!(as_css(0xBEEF) != r"\beef");
    //assert!(as_css(0x10000) == ?);
  }

  #[test]
  fn test_as_html() {
    assert!(as_html(0) == r"�");
    assert!(as_html(0xFFFF) == r"");
    assert!(as_html(0xBEEF) != r"뻯");
    //assert!(as_html(0x10000) == ?);
  }

  #[test]
  fn test_as_js() {
    assert!(as_js(0) == r"\u0000");
    assert!(as_js(0xFFFF) == r"\uFFFF");
    assert!(as_js(0xBEEF) != r"\ubeef");
    assert!(as_js(0x10000) == r"\u{10000}");
    assert!(as_js(0x10FFFF) == r"\u{10FFFF}");
    assert!(as_js(0xFFFFFFFF) == r"\u{FFFFFFFF}");
  }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate time;
extern crate image;

use std::mem;
use std::io;
use std::io::Write;

use glium::{DisplayBuild, Program, Surface, VertexBuffer, IndexBuffer};
use glium::texture::{Texture2d, RawImage2d, ClientFormat};
use glium::index::PrimitiveType;
use glium::glutin::{Event, ElementState, VirtualKeyCode, WindowBuilder};
use glium::glutin::{Touch, TouchPhase};
use glium::backend::Facade;
use glium::backend::glutin_backend::GlutinFacade;

// Our vertices are boring. We only ever draw 2 triangles
// covering the whole surface.
#[derive(Copy, Clone)]
struct Vertex {
    pos: [f32; 2],
}

implement_vertex!(Vertex, pos);

fn whole_surface_triangles<F>(facade: &F)
    -> (VertexBuffer<Vertex>, IndexBuffer<u8>)
    where F: Facade,
{
    let vertices = [
        Vertex { pos: [-1.0, -1.0] },
        Vertex { pos: [-1.0,  1.0] },
        Vertex { pos: [ 1.0,  1.0] },
        Vertex { pos: [ 1.0, -1.0] },
    ];

    let indices = [
        0, 1, 2,
        2, 3, 0,
    ];

    let vertex_buffer = VertexBuffer::new(facade, &vertices).unwrap();
    let index_buffer = IndexBuffer::new(facade,
                                        PrimitiveType::TrianglesList,
                                        &indices).unwrap();

    (vertex_buffer, index_buffer)
}

// Size in pixels for the feedback textures.
#[cfg(target_os = "android")]
const FEEDBACK_TEXTURE_SIZE: u32 = 1024;

#[cfg(not(target_os = "android"))]
const FEEDBACK_TEXTURE_SIZE: u32 = 2048;

// Create a feedback texture.
fn feedback_texture<F>(facade: &F) -> Texture2d
    where F: Facade,
{
    // Returns a texture with undefined contents.
    Texture2d::empty(facade,
                     FEEDBACK_TEXTURE_SIZE,
                     FEEDBACK_TEXTURE_SIZE).unwrap()
}

// Shaders.
#[macro_use]
mod shader_loader;

// Trivial vertex shader.
shader_loader!(vertex_shader_src, "shaders/vertex.glsl");

// Simple fragment shader, used to copy a texture to the screen.
shader_loader!(blit_shader_src, "shaders/blit.glsl");

// Fragment shader which runs video feedback between two textures.
shader_loader!(feedback_shader_src, "shaders/feedback.glsl");

// The screen and the feedback textures are interpreted as
// subsets of the complex plane:
//
//     (-SCALE to SCALE) + i*(-SCALE to SCALE)
//
const SCALE: f32 = 1.4;

// Convert a window position in pixels to a complex number.
//
// TODO: Is it slow to look up the size on every mouse move?
fn window_px_to_z(facade: &GlutinFacade, (x, y): (f32, f32))
    -> (f32, f32)
{
    let window = facade.get_window().unwrap();
    let (sx, sy) = window.get_inner_size().unwrap();

    ((x / ((sx-1) as f32) * 2.0 - 1.0) * SCALE,
     (y / ((sy-1) as f32) * 2.0 - 1.0) * SCALE)
}

// Take a screenshot.
fn screenshot(tex: &Texture2d) {
    let raw_image: RawImage2d<u8> = tex.read();
    assert_eq!(raw_image.format, ClientFormat::U8U8U8U8);

    let image: image::ImageBuffer<image::Rgba<u8>, &[u8]>
        = image::ImageBuffer::from_raw(
            FEEDBACK_TEXTURE_SIZE, FEEDBACK_TEXTURE_SIZE,
            &*raw_image.data).unwrap();

    let path_string = format!("az_shot_{}.png", time::precise_time_ns());
    match image.save(&path_string) {
        Ok(()) => println!("Saved screenshot {}", path_string),

        Err(e) => {
            let _ = write!(&mut io::stderr(),
                           "\nFAILED to save image {}: {}\n\n",
                           path_string, e);
        }
    }
}

#[cfg(target_os = "android")]
fn request_gl_version(bld: WindowBuilder) -> WindowBuilder {
    use glium::glutin::{GlRequest, Api};
    bld.with_gl(GlRequest::Specific(Api::OpenGlEs, (3, 1)))
}

#[cfg(not(target_os = "android"))]
fn request_gl_version(bld: WindowBuilder) -> WindowBuilder {
    bld
}

fn main() {
    // Create a glutin / glium window.
    let display_builder = WindowBuilder::new()
        .with_title("a z u r e s c e n s".to_owned())
        .with_vsync();

    let display = request_gl_version(display_builder).build_glium().unwrap();

    println!("OpenGL {:?}", display.get_opengl_version());
    println!("GLSL   {:?}", display.get_supported_glsl_version());

    // Create two textures for feedback.
    let mut read_texture  = feedback_texture(&display);
    let mut write_texture = feedback_texture(&display);

    // Prepare to draw triangles which cover a whole surface.
    let (vertex_buffer, index_buffer) = whole_surface_triangles(&display);
    let draw_params = Default::default();

    // Prepare shader programs.
    let vertex_shader_src = vertex_shader_src();

    let blit_program = Program::from_source(&display,
        &vertex_shader_src, &blit_shader_src(), None).unwrap();

    let feedback_program = Program::from_source(&display,
        &vertex_shader_src, &feedback_shader_src(), None).unwrap();

    // Clear the screen.
    let mut target = display.draw();
    target.clear_color(0.0, 0.0, 0.0, 1.0);
    target.finish().unwrap();

    // Initial value for the complex parameter 'c'.
    let mut param_c = (0.3, 0.3);

    // FPS tracking.
    let mut last_frame_time = time::precise_time_ns();
    let mut last_fps_output_time = last_frame_time;
    let mut smoothed_fps = 0.0;
    let fps_smoothing = 0.9;  // amount to keep for EWMA

    loop {
        // Run video feedback from one texture into the other.
        // We do this twice before drawing to the screen.
        // The reason is that each frame inverts colors and
        // we want to avoid a distracting blinky effect.
        for _ in 0..2 {
            {
                let uniforms = uniform! {
                    src: &read_texture,
                    scale: SCALE,
                    param_c: param_c,
                    param_t: time::precise_time_s() as f32,
                };

                let mut target = write_texture.as_surface();
                target.draw(&vertex_buffer, &index_buffer, &feedback_program,
                            &uniforms, &draw_params).unwrap();
            }

            mem::swap(&mut read_texture, &mut write_texture);
        }

        // Draw the most recently written texture to the screen.
        let uniforms = uniform! {
            src: &read_texture,
        };

        let mut target = display.draw();
        target.draw(&vertex_buffer, &index_buffer, &blit_program,
                    &uniforms, &draw_params).unwrap();
        target.finish().unwrap();

        // Update FPS.
        let this_frame_time = time::precise_time_ns();
        let instant_fps = 1e9 / ((this_frame_time - last_frame_time) as f32);
        smoothed_fps = fps_smoothing * smoothed_fps
                     + (1.0-fps_smoothing)*instant_fps;
        last_frame_time = this_frame_time;

        if (this_frame_time - last_fps_output_time) >= 5_000_000_000 {
            println!("Frames per second: {:7.2}", smoothed_fps);
            last_fps_output_time = this_frame_time;
        }

        // Handle events.
        for ev in display.poll_events() {
            match ev {
                Event::Closed => return,

                Event::MouseMoved(x, y) => {
                    // Update the parameter 'c' according to
                    // the mouse position.
                    param_c = window_px_to_z(&display, (x as f32, y as f32));
                }

                Event::Touch(t) => match t {
                      Touch { phase: TouchPhase::Started, location: (x, y), .. }
                    | Touch { phase: TouchPhase::Moved,   location: (x, y), .. } => {
                        param_c = window_px_to_z(&display, (x as f32, y as f32));
                    }

                    _ => (),
                },

                Event::KeyboardInput(ElementState::Pressed,
                                     _, Some(kc)) => match kc {
                    VirtualKeyCode::S => screenshot(&read_texture),
                    _ => (),
                },

                _ => (),
            }
        }
    }
}
<commit_msg>Use nearest-pixel sampling<commit_after>#[macro_use]
extern crate glium;
extern crate time;
extern crate image;

use std::mem;
use std::io;
use std::io::Write;

use glium::{DisplayBuild, Program, Surface, VertexBuffer, IndexBuffer};
use glium::texture::{Texture2d, RawImage2d, ClientFormat};
use glium::index::PrimitiveType;
use glium::glutin::{Event, ElementState, VirtualKeyCode, WindowBuilder};
use glium::glutin::{Touch, TouchPhase};
use glium::backend::Facade;
use glium::backend::glutin_backend::GlutinFacade;
use glium::uniforms::{Sampler, MagnifySamplerFilter};

// Our vertices are boring. We only ever draw 2 triangles
// covering the whole surface.
#[derive(Copy, Clone)]
struct Vertex {
    pos: [f32; 2],
}

implement_vertex!(Vertex, pos);

fn whole_surface_triangles<F>(facade: &F)
    -> (VertexBuffer<Vertex>, IndexBuffer<u8>)
    where F: Facade,
{
    let vertices = [
        Vertex { pos: [-1.0, -1.0] },
        Vertex { pos: [-1.0,  1.0] },
        Vertex { pos: [ 1.0,  1.0] },
        Vertex { pos: [ 1.0, -1.0] },
    ];

    let indices = [
        0, 1, 2,
        2, 3, 0,
    ];

    let vertex_buffer = VertexBuffer::new(facade, &vertices).unwrap();
    let index_buffer = IndexBuffer::new(facade,
                                        PrimitiveType::TrianglesList,
                                        &indices).unwrap();

    (vertex_buffer, index_buffer)
}

// Size in pixels for the feedback textures.
#[cfg(target_os = "android")]
const FEEDBACK_TEXTURE_SIZE: u32 = 1024;

#[cfg(not(target_os = "android"))]
const FEEDBACK_TEXTURE_SIZE: u32 = 2048;

// Create a feedback texture.
fn feedback_texture<F>(facade: &F) -> Texture2d
    where F: Facade,
{
    // Returns a texture with undefined contents.
    Texture2d::empty(facade,
                     FEEDBACK_TEXTURE_SIZE,
                     FEEDBACK_TEXTURE_SIZE).unwrap()
}

// Shaders.
#[macro_use]
mod shader_loader;

// Trivial vertex shader.
shader_loader!(vertex_shader_src, "shaders/vertex.glsl");

// Simple fragment shader, used to copy a texture to the screen.
shader_loader!(blit_shader_src, "shaders/blit.glsl");

// Fragment shader which runs video feedback between two textures.
shader_loader!(feedback_shader_src, "shaders/feedback.glsl");

// The screen and the feedback textures are interpreted as
// subsets of the complex plane:
//
//     (-SCALE to SCALE) + i*(-SCALE to SCALE)
//
const SCALE: f32 = 1.4;

// Convert a window position in pixels to a complex number.
//
// TODO: Is it slow to look up the size on every mouse move?
fn window_px_to_z(facade: &GlutinFacade, (x, y): (f32, f32))
    -> (f32, f32)
{
    let window = facade.get_window().unwrap();
    let (sx, sy) = window.get_inner_size().unwrap();

    ((x / ((sx-1) as f32) * 2.0 - 1.0) * SCALE,
     (y / ((sy-1) as f32) * 2.0 - 1.0) * SCALE)
}

// Take a screenshot.
fn screenshot(tex: &Texture2d) {
    let raw_image: RawImage2d<u8> = tex.read();
    assert_eq!(raw_image.format, ClientFormat::U8U8U8U8);

    let image: image::ImageBuffer<image::Rgba<u8>, &[u8]>
        = image::ImageBuffer::from_raw(
            FEEDBACK_TEXTURE_SIZE, FEEDBACK_TEXTURE_SIZE,
            &*raw_image.data).unwrap();

    let path_string = format!("az_shot_{}.png", time::precise_time_ns());
    match image.save(&path_string) {
        Ok(()) => println!("Saved screenshot {}", path_string),

        Err(e) => {
            let _ = write!(&mut io::stderr(),
                           "\nFAILED to save image {}: {}\n\n",
                           path_string, e);
        }
    }
}

#[cfg(target_os = "android")]
fn request_gl_version(bld: WindowBuilder) -> WindowBuilder {
    use glium::glutin::{GlRequest, Api};
    bld.with_gl(GlRequest::Specific(Api::OpenGlEs, (3, 1)))
}

#[cfg(not(target_os = "android"))]
fn request_gl_version(bld: WindowBuilder) -> WindowBuilder {
    bld
}

fn main() {
    // Create a glutin / glium window.
    let display_builder = WindowBuilder::new()
        .with_title("a z u r e s c e n s".to_owned())
        .with_vsync();

    let display = request_gl_version(display_builder).build_glium().unwrap();

    println!("OpenGL {:?}", display.get_opengl_version());
    println!("GLSL   {:?}", display.get_supported_glsl_version());

    // Create two textures for feedback.
    let mut read_texture  = feedback_texture(&display);
    let mut write_texture = feedback_texture(&display);

    // Prepare to draw triangles which cover a whole surface.
    let (vertex_buffer, index_buffer) = whole_surface_triangles(&display);
    let draw_params = Default::default();

    // Prepare shader programs.
    let vertex_shader_src = vertex_shader_src();

    let blit_program = Program::from_source(&display,
        &vertex_shader_src, &blit_shader_src(), None).unwrap();

    let feedback_program = Program::from_source(&display,
        &vertex_shader_src, &feedback_shader_src(), None).unwrap();

    // Clear the screen.
    let mut target = display.draw();
    target.clear_color(0.0, 0.0, 0.0, 1.0);
    target.finish().unwrap();

    // Initial value for the complex parameter 'c'.
    let mut param_c = (0.3, 0.3);

    // FPS tracking.
    let mut last_frame_time = time::precise_time_ns();
    let mut last_fps_output_time = last_frame_time;
    let mut smoothed_fps = 0.0;
    let fps_smoothing = 0.9;  // amount to keep for EWMA

    loop {
        // Run video feedback from one texture into the other.
        // We do this twice before drawing to the screen.
        // The reason is that each frame inverts colors and
        // we want to avoid a distracting blinky effect.
        for _ in 0..2 {
            {
                let uniforms = uniform! {
                    src: Sampler::new(&read_texture)
                             .magnify_filter(MagnifySamplerFilter::Nearest),
                    scale: SCALE,
                    param_c: param_c,
                    param_t: time::precise_time_s() as f32,
                };

                let mut target = write_texture.as_surface();
                target.draw(&vertex_buffer, &index_buffer, &feedback_program,
                            &uniforms, &draw_params).unwrap();
            }

            mem::swap(&mut read_texture, &mut write_texture);
        }

        // Draw the most recently written texture to the screen.
        let uniforms = uniform! {
            src: &read_texture,
        };

        let mut target = display.draw();
        target.draw(&vertex_buffer, &index_buffer, &blit_program,
                    &uniforms, &draw_params).unwrap();
        target.finish().unwrap();

        // Update FPS.
        let this_frame_time = time::precise_time_ns();
        let instant_fps = 1e9 / ((this_frame_time - last_frame_time) as f32);
        smoothed_fps = fps_smoothing * smoothed_fps
                     + (1.0-fps_smoothing)*instant_fps;
        last_frame_time = this_frame_time;

        if (this_frame_time - last_fps_output_time) >= 5_000_000_000 {
            println!("Frames per second: {:7.2}", smoothed_fps);
            last_fps_output_time = this_frame_time;
        }

        // Handle events.
        for ev in display.poll_events() {
            match ev {
                Event::Closed => return,

                Event::MouseMoved(x, y) => {
                    // Update the parameter 'c' according to
                    // the mouse position.
                    param_c = window_px_to_z(&display, (x as f32, y as f32));
                }

                Event::Touch(t) => match t {
                      Touch { phase: TouchPhase::Started, location: (x, y), .. }
                    | Touch { phase: TouchPhase::Moved,   location: (x, y), .. } => {
                        param_c = window_px_to_z(&display, (x as f32, y as f32));
                    }

                    _ => (),
                },

                Event::KeyboardInput(ElementState::Pressed,
                                     _, Some(kc)) => match kc {
                    VirtualKeyCode::S => screenshot(&read_texture),
                    _ => (),
                },

                _ => (),
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright © 2015, Peter Atashian
// Licensed under the MIT License <LICENSE.md>
#![feature(collections, env, io, process, std_misc)]

extern crate "winapi" as win;
extern crate "kernel32-sys" as k32;

use std::env::{args, current_dir, set_exit_status};
use std::ffi::{AsOsStr};
use std::io::{Error};
use std::os::windows::prelude::*;
use std::process::{Command};
use std::ptr::{null_mut};

static mut job_handle: win::HANDLE = 0 as win::HANDLE;

extern "system" fn handler(_: win::DWORD) -> win::BOOL {
    // If we get any sort of signal, just kill the job object
    assert!(unsafe { k32::TerminateJobObject(job_handle, 273) } != 0,
        "Failed to terminate job object: {}", Error::last_os_error());
    win::TRUE
}
fn main() {
    // We use the current directory as the job object name
    // This way we can clean up job objects lingering from previous builds
    let dir = current_dir().unwrap();
    let name: Vec<_> = dir.as_os_str().encode_wide().collect();
    // Replace \ with /, otherwise it interprets the name as a path
    let name = name.map_in_place(|c| if c == '\\' as u16 { '/' as u16 } else { c });
    let mut handle = unsafe { k32::CreateJobObjectW(null_mut(), name.as_ptr()) };
    assert!(handle != null_mut(), "Failed to create job object: {}", Error::last_os_error());
    if unsafe { k32::GetLastError() } == win::ERROR_ALREADY_EXISTS {
        // If there is a previous job object, kill it and then create a new one
        assert!(unsafe { k32::TerminateJobObject(handle, 9001) } != 0,
            "Failed to terminate existing job object: {}", Error::last_os_error());
        // We have to sleep otherwise this process might get killed in the above termination
        unsafe { k32::Sleep(1000) };
        handle = unsafe { k32::CreateJobObjectW(null_mut(), name.as_ptr()) };
        assert!(handle != null_mut(), "Failed to recreate job object: {}", Error::last_os_error());
    }
    unsafe { job_handle = handle };
    let process = unsafe { k32::GetCurrentProcess() };
    // Everything created from this process will be part of the job object
    assert!(unsafe { k32::AssignProcessToJobObject(handle, process) } != 0,
        "Failed to assign process to job object: {}", Error::last_os_error());
    // Set up a signal handler to kill the job object if things go south
    assert!(unsafe { k32::SetConsoleCtrlHandler(handler, win::TRUE) } != 0,
        "Failed to set signal handler: {}", Error::last_os_error());
    let args: Vec<_> = args().collect();
    // Actually spawn the command you really wanted
    let status = Command::new(&args[1]).args(&args[2..]).status().unwrap();
    assert!(unsafe { k32::TerminateJobObject(handle, 666) } != 0,
        "Failed to terminate job object leftovers: {}", Error::last_os_error());
    set_exit_status(status.code().unwrap())
}
<commit_msg>Use limit information to cleanup the job object processes.<commit_after>// Copyright © 2015, Peter Atashian
// Licensed under the MIT License <LICENSE.md>
#![feature(collections, env, io, process, std_misc)]

extern crate "winapi" as win;
extern crate "kernel32-sys" as k32;

use std::env::{args, current_dir, set_exit_status};
use std::ffi::{AsOsStr};
use std::io::{Error};
use std::mem::{size_of_val, zeroed};
use std::os::windows::prelude::*;
use std::process::{Command};
use std::ptr::{null_mut};

static mut job_handle: win::HANDLE = 0 as win::HANDLE;

extern "system" fn handler(_: win::DWORD) -> win::BOOL {
    // If we get any sort of signal, just kill the job object
    assert!(unsafe { k32::TerminateJobObject(job_handle, 273) } != 0,
        "Failed to terminate job object: {}", Error::last_os_error());
    win::TRUE
}
fn main() {
    // We use the current directory as the job object name
    // This way we can clean up job objects lingering from previous builds
    let dir = current_dir().unwrap();
    let name: Vec<_> = dir.as_os_str().encode_wide().collect();
    // Replace \ with /, otherwise it interprets the name as a path
    let name = name.map_in_place(|c| if c == '\\' as u16 { '/' as u16 } else { c });
    let mut handle = unsafe { k32::CreateJobObjectW(null_mut(), name.as_ptr()) };
    assert!(handle != null_mut(), "Failed to create job object: {}", Error::last_os_error());
    if unsafe { k32::GetLastError() } == win::ERROR_ALREADY_EXISTS {
        // If there is a previous job object, kill it and then create a new one
        assert!(unsafe { k32::TerminateJobObject(handle, 9001) } != 0,
            "Failed to terminate existing job object: {}", Error::last_os_error());
        // We have to sleep otherwise this process might get killed in the above termination
        unsafe { k32::Sleep(1000) };
        handle = unsafe { k32::CreateJobObjectW(null_mut(), name.as_ptr()) };
        assert!(handle != null_mut(), "Failed to recreate job object: {}", Error::last_os_error());
    }
    unsafe { job_handle = handle };
    // Automatically terminate job object when all handles to it close
    let mut info: win::JOBOBJECT_EXTENDED_LIMIT_INFORMATION = unsafe { zeroed() };
    info.BasicLimitInformation.LimitFlags = win::JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
    assert!(unsafe { k32::SetInformationJobObject(
            handle, win::JOBOBJECTINFOCLASS::JobObjectExtendedLimitInformation,
            &mut info as *mut _ as win::LPVOID, size_of_val(&info) as win::DWORD) } != 0,
        "Failed to set job object limit information: {}", Error::last_os_error());
    // Everything created from this process will be part of the job object
    let process = unsafe { k32::GetCurrentProcess() };
    assert!(unsafe { k32::AssignProcessToJobObject(handle, process) } != 0,
        "Failed to assign process to job object: {}", Error::last_os_error());
    // Set up a signal handler to kill the job object if things go south
    assert!(unsafe { k32::SetConsoleCtrlHandler(handler, win::TRUE) } != 0,
        "Failed to set signal handler: {}", Error::last_os_error());
    let args: Vec<_> = args().collect();
    // Actually spawn the command you really wanted
    let status = Command::new(&args[1]).args(&args[2..]).status().unwrap();
    set_exit_status(status.code().unwrap())
}
<|endoftext|>


<commit_before>extern crate nix;
extern crate colored;

mod util;
mod stats;

use std::cmp;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::collections::HashSet;
use nix::sys::statvfs::vfs::Statvfs;
use colored::*;

use util::{iec, bargraph};
use stats::Stats;

const FS_SPEC: usize = 0;
const FS_FILE: usize = 1;
const FS_VFSTYPE: usize = 2;

fn main() {
    let file = File::open("/proc/mounts").unwrap();
    let reader = BufReader::new(&file);

    let mut excludes = HashSet::new();
    let exclude_types = "cgroup autofs securityfs configfs pstore binfmt_misc debugfs \
                         hugetlbfs devpts mqueue proc sysfs";
    for t in exclude_types.split_whitespace() {
        excludes.insert(t);
    }

    let mut stats: Vec<Stats> = Vec::new();
    let mut max_width = 0;

    for line in reader.lines() {
        match line {
            Ok(line) => {
                let fields: Vec<&str> = line.split_whitespace().collect();
                if excludes.contains(fields[FS_VFSTYPE]) {
                    continue;
                }
                let statvfs = Statvfs::for_path(fields[FS_FILE]).unwrap();
                let size = statvfs.f_blocks * statvfs.f_bsize;
                let avail = statvfs.f_bavail * statvfs.f_bsize;

                let s = Stats::new(fields[FS_SPEC], size, avail, fields[FS_FILE]);

                max_width = cmp::max(max_width, s.filesystem.len());
                stats.push(s);
            },
            Err(_) => panic!(),
        }
    }

    let headers = ["Filesystem", "Size", "Used", "Avail", "Use%", "", "Mounted on"];
    let headers: Vec<ColoredString> = headers.into_iter().map(|x| x.yellow()).collect();
    println!("{:width$} {:>5} {:>5} {:>5} {:>5} {:20} {:16}",
             headers[0], headers[1], headers[2], headers[3],
             headers[4], headers[5], headers[6], width = max_width);

    for stat in stats {
        println!("{:width$} {:>5} {:>5} {:>5} {:>5.1} {:20} {:16}",
                 stat.filesystem, iec(stat.size), iec(stat.used), iec(stat.avail),
                 stat.percent, bargraph(stat.percent), stat.mount, width = max_width);
    }

}
<commit_msg>Ignore fusectl.<commit_after>extern crate nix;
extern crate colored;

mod util;
mod stats;

use std::cmp;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::collections::HashSet;
use nix::sys::statvfs::vfs::Statvfs;
use colored::*;

use util::{iec, bargraph};
use stats::Stats;

const FS_SPEC: usize = 0;
const FS_FILE: usize = 1;
const FS_VFSTYPE: usize = 2;

fn main() {
    let file = File::open("/proc/mounts").unwrap();
    let reader = BufReader::new(&file);

    let mut excludes = HashSet::new();
    let exclude_types = "cgroup autofs securityfs configfs pstore binfmt_misc debugfs \
                         hugetlbfs devpts mqueue proc sysfs fusectl";
    for t in exclude_types.split_whitespace() {
        excludes.insert(t);
    }

    let mut stats: Vec<Stats> = Vec::new();
    let mut max_width = 0;

    for line in reader.lines() {
        match line {
            Ok(line) => {
                let fields: Vec<&str> = line.split_whitespace().collect();
                if excludes.contains(fields[FS_VFSTYPE]) {
                    continue;
                }
                let statvfs = Statvfs::for_path(fields[FS_FILE]).unwrap();
                let size = statvfs.f_blocks * statvfs.f_bsize;
                let avail = statvfs.f_bavail * statvfs.f_bsize;

                let s = Stats::new(fields[FS_SPEC], size, avail, fields[FS_FILE]);

                max_width = cmp::max(max_width, s.filesystem.len());
                stats.push(s);
            },
            Err(_) => panic!(),
        }
    }

    let headers = ["Filesystem", "Size", "Used", "Avail", "Use%", "", "Mounted on"];
    let headers: Vec<ColoredString> = headers.into_iter().map(|x| x.yellow()).collect();
    println!("{:width$} {:>5} {:>5} {:>5} {:>5} {:20} {:16}",
             headers[0], headers[1], headers[2], headers[3],
             headers[4], headers[5], headers[6], width = max_width);

    for stat in stats {
        println!("{:width$} {:>5} {:>5} {:>5} {:>5.1} {:20} {:16}",
                 stat.filesystem, iec(stat.size), iec(stat.used), iec(stat.avail),
                 stat.percent, bargraph(stat.percent), stat.mount, width = max_width);
    }

}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate cgmath;
extern crate rusty_gauntlet;

use cgmath::Matrix4;
use cgmath::Vector2;
use cgmath::prelude::SquareMatrix;
use rusty_gauntlet::rendering::sprite;
use rusty_gauntlet::level::*;
use rusty_gauntlet::input::*;
use std::path::Path;
use rusty_gauntlet::rendering::text::TextRenderer;
use std::string::String;

static mut player_alive: bool = true;

fn on_damaged(_: &Entity, _: &Entity) {
    println!(" > The dragon bites!");
}
fn on_attacked(_: &Entity, _: &Entity) {
    println!(" > You poked the dragon with a stick!");
}
fn on_killed(_: &Entity) {
    println!(" > You died!");
    unsafe{ player_alive = false; }
}
fn on_collected(_: &Entity) {
    println!(" > You found a coin!");
}

fn main() {
    use glium::{DisplayBuild, Surface};
    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(800, 600)
        .with_title(format!("Rusty Gauntlet™"))
        .build_glium()
        .unwrap();

    let vertex_shader_src = r#"
        #version 140

        in vec2 _position;
        in vec2 _texcoord;
        in vec4 _color;

        out vec2 texcoord_;
        out vec4 color_;

        uniform mat4 projection;
        uniform mat4 view;
        uniform mat4 model;

        void main() {
            texcoord_ = _texcoord;
            color_ = _color;
            gl_Position = projection * view * model * vec4(_position, 0.0, 1.0);
        }
    "#;

    let fragment_shader_src = r#"
        #version 140

        in vec2 texcoord_;
        in vec4 color_;

        out vec4 color;

        uniform sampler2D sprite;

        void main() {
            color = texture(sprite, texcoord_);
        }
    "#;

    const SCREEN_WIDTH: f32 = 800.0;
    const SCREEN_HEIGHT: f32 = 600.0;
    let projection = cgmath::ortho::<f32>(0.0, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0, 0.1, 10.0);
    let view = Matrix4::<f32>::identity();

    let program = glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None)
        .unwrap();

    const TILE_SIZE: f32 = 32f32;
    let mut sprite_wall = sprite::SpriteBuilder::new()
        .half_extend(Vector2{ x: TILE_SIZE, y: TILE_SIZE })
        .texture_name("sprite_wall.png")
        .finalize(&display);
    let mut sprite_floor = sprite::SpriteBuilder::new()
        .half_extend(Vector2{ x: TILE_SIZE, y: TILE_SIZE })
        .texture_name("sprite_floor.png")
        .finalize(&display);
    let mut sprite_player = sprite::SpriteBuilder::new()
        .half_extend(Vector2{ x: TILE_SIZE, y: TILE_SIZE })
        .texture_name("sprite_player.png")
        .finalize(&display);
    let mut sprite_dragon = sprite::SpriteBuilder::new()
        .half_extend(Vector2{ x: TILE_SIZE, y: TILE_SIZE })
        .texture_name("sprite_dragon.png")
        .finalize(&display);
    let mut sprite_treasure = sprite::SpriteBuilder::new()
        .half_extend(Vector2{ x: TILE_SIZE, y: TILE_SIZE })
        .texture_name("sprite_treasure.png")
        .finalize(&display);

    let mut my_level = Level::new(Path::new("test_level.map"));
    my_level.on_player_damaged = Some(on_damaged);
    my_level.on_player_attacked = Some(on_attacked);
    my_level.on_player_killed = Some(on_killed);
    my_level.on_player_collected = Some(on_collected);

    let mut player_pos = my_level.get_player_pos().unwrap();
    /*
    let (pscore, php) = match my_level.get_entity(player_pos) {
        Some(Entity::Player{score,hp,..}) => (score,hp),
        _ => (0,0)
    };
    println!("Player score: {}\nPlayer HP: {}", pscore, php);
*/
    let mut input = Input::new(player_pos);

    let mut text_renderer = TextRenderer::new(
        &display,
        "font.otf",
        45
    );

    loop {
        let mut target = display.draw();
        target.clear_color(0.5, 0.6, 0.9, 1.0);

        let (px,py) = input.player_pos;
        let offset_x = SCREEN_WIDTH/2.0 - px as f32 *TILE_SIZE*2f32;
        let offset_y = SCREEN_HEIGHT/2.0 - py as f32 *TILE_SIZE*2f32;
        my_level.foreach(|x,y,tile| {
            let pos = Vector2{ x: offset_x + TILE_SIZE*2f32*x as f32, y: offset_y + TILE_SIZE*2f32*y as f32 };

            match tile.entity {
                Some(Entity::Player{..}) => {
                    sprite_player.set_position(pos);
                    sprite_player.draw(&mut target, &program, projection, view);
                },
                Some(Entity::Dragon{..}) =>  {
                    sprite_dragon.set_position(pos);
                    sprite_dragon.draw(&mut target, &program, projection, view);
                },
                Some(Entity::Treasure) => {
                    sprite_treasure.set_position(pos);
                    sprite_treasure.draw(&mut target, &program, projection, view);
                },
                None => {
                    match tile.tile_type {
                        TileType::Floor => {
                            sprite_floor.set_position(pos);
                            sprite_floor.draw(&mut target, &program, projection, view);
                        },
                        TileType::Wall => {
                            sprite_wall.set_position(pos);
                            sprite_wall.draw(&mut target, &program, projection, view);
                        },
                    }
                }
            };
        });

        let (pscore, php) = match my_level.get_entity(input.player_pos) {
            Some(Entity::Player{score,hp,..}) => (score,hp),
            _ => (0,0)
        };

        let coin_label = "Coin: ".to_string();
        let coin = pscore.to_string();
        let hp_label = "      Health; ".to_string();
        let hp = php.to_string();
        let final_label = coin_label + coin.as_str() + hp_label.as_str() + hp.as_str();
        text_renderer.draw(&mut target, final_label.as_str(), Vector2::<f32>{ x: 5.0, y: 590.0 });

        target.finish().unwrap();

        let alive = unsafe{ player_alive};
        if alive {
            //handle events
            let mut player_input = Some(true);
            //loop till player is moved
            //none means ends game
            //false means advance game
            //true means wait for next input
            while player_input.unwrap() {
                for ev in display.poll_events() {
                    player_input = input.process_input(ev, &mut my_level);
                }
                if player_input.is_none() {
                    return;
                }
            }
        }
    }
}
<commit_msg>Set clear color to wall color.<commit_after>#[macro_use]
extern crate glium;
extern crate cgmath;
extern crate rusty_gauntlet;

use cgmath::Matrix4;
use cgmath::Vector2;
use cgmath::prelude::SquareMatrix;
use rusty_gauntlet::rendering::sprite;
use rusty_gauntlet::level::*;
use rusty_gauntlet::input::*;
use std::path::Path;
use rusty_gauntlet::rendering::text::TextRenderer;
use std::string::String;

static mut player_alive: bool = true;

fn on_damaged(_: &Entity, _: &Entity) {
    println!(" > The dragon bites!");
}
fn on_attacked(_: &Entity, _: &Entity) {
    println!(" > You poked the dragon with a stick!");
}
fn on_killed(_: &Entity) {
    println!(" > You died!");
    unsafe{ player_alive = false; }
}
fn on_collected(_: &Entity) {
    println!(" > You found a coin!");
}

fn main() {
    use glium::{DisplayBuild, Surface};
    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(800, 600)
        .with_title(format!("Rusty Gauntlet™"))
        .build_glium()
        .unwrap();

    let vertex_shader_src = r#"
        #version 140

        in vec2 _position;
        in vec2 _texcoord;
        in vec4 _color;

        out vec2 texcoord_;
        out vec4 color_;

        uniform mat4 projection;
        uniform mat4 view;
        uniform mat4 model;

        void main() {
            texcoord_ = _texcoord;
            color_ = _color;
            gl_Position = projection * view * model * vec4(_position, 0.0, 1.0);
        }
    "#;

    let fragment_shader_src = r#"
        #version 140

        in vec2 texcoord_;
        in vec4 color_;

        out vec4 color;

        uniform sampler2D sprite;

        void main() {
            color = texture(sprite, texcoord_);
        }
    "#;

    const SCREEN_WIDTH: f32 = 800.0;
    const SCREEN_HEIGHT: f32 = 600.0;
    let projection = cgmath::ortho::<f32>(0.0, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0, 0.1, 10.0);
    let view = Matrix4::<f32>::identity();

    let program = glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None)
        .unwrap();

    const TILE_SIZE: f32 = 32f32;
    let mut sprite_wall = sprite::SpriteBuilder::new()
        .half_extend(Vector2{ x: TILE_SIZE, y: TILE_SIZE })
        .texture_name("sprite_wall.png")
        .finalize(&display);
    let mut sprite_floor = sprite::SpriteBuilder::new()
        .half_extend(Vector2{ x: TILE_SIZE, y: TILE_SIZE })
        .texture_name("sprite_floor.png")
        .finalize(&display);
    let mut sprite_player = sprite::SpriteBuilder::new()
        .half_extend(Vector2{ x: TILE_SIZE, y: TILE_SIZE })
        .texture_name("sprite_player.png")
        .finalize(&display);
    let mut sprite_dragon = sprite::SpriteBuilder::new()
        .half_extend(Vector2{ x: TILE_SIZE, y: TILE_SIZE })
        .texture_name("sprite_dragon.png")
        .finalize(&display);
    let mut sprite_treasure = sprite::SpriteBuilder::new()
        .half_extend(Vector2{ x: TILE_SIZE, y: TILE_SIZE })
        .texture_name("sprite_treasure.png")
        .finalize(&display);

    let mut my_level = Level::new(Path::new("test_level.map"));
    my_level.on_player_damaged = Some(on_damaged);
    my_level.on_player_attacked = Some(on_attacked);
    my_level.on_player_killed = Some(on_killed);
    my_level.on_player_collected = Some(on_collected);

    let mut player_pos = my_level.get_player_pos().unwrap();
    /*
    let (pscore, php) = match my_level.get_entity(player_pos) {
        Some(Entity::Player{score,hp,..}) => (score,hp),
        _ => (0,0)
    };
    println!("Player score: {}\nPlayer HP: {}", pscore, php);
*/
    let mut input = Input::new(player_pos);

    let mut text_renderer = TextRenderer::new(
        &display,
        "font.otf",
        45
    );

    loop {
        let mut target = display.draw();
        target.clear_color(0.24, 0.24, 0.24, 1.0);

        let (px,py) = input.player_pos;
        let offset_x = SCREEN_WIDTH/2.0 - px as f32 *TILE_SIZE*2f32;
        let offset_y = SCREEN_HEIGHT/2.0 - py as f32 *TILE_SIZE*2f32;
        my_level.foreach(|x,y,tile| {
            let pos = Vector2{ x: offset_x + TILE_SIZE*2f32*x as f32, y: offset_y + TILE_SIZE*2f32*y as f32 };

            match tile.entity {
                Some(Entity::Player{..}) => {
                    sprite_player.set_position(pos);
                    sprite_player.draw(&mut target, &program, projection, view);
                },
                Some(Entity::Dragon{..}) =>  {
                    sprite_dragon.set_position(pos);
                    sprite_dragon.draw(&mut target, &program, projection, view);
                },
                Some(Entity::Treasure) => {
                    sprite_treasure.set_position(pos);
                    sprite_treasure.draw(&mut target, &program, projection, view);
                },
                None => {
                    match tile.tile_type {
                        TileType::Floor => {
                            sprite_floor.set_position(pos);
                            sprite_floor.draw(&mut target, &program, projection, view);
                        },
                        TileType::Wall => {
                            sprite_wall.set_position(pos);
                            sprite_wall.draw(&mut target, &program, projection, view);
                        },
                    }
                }
            };
        });

        let (pscore, php) = match my_level.get_entity(input.player_pos) {
            Some(Entity::Player{score,hp,..}) => (score,hp),
            _ => (0,0)
        };

        let coin_label = "Coin: ".to_string();
        let coin = pscore.to_string();
        let hp_label = "      Health; ".to_string();
        let hp = php.to_string();
        let final_label = coin_label + coin.as_str() + hp_label.as_str() + hp.as_str();
        text_renderer.draw(&mut target, final_label.as_str(), Vector2::<f32>{ x: 5.0, y: 590.0 });

        target.finish().unwrap();

        let alive = unsafe{ player_alive};
        if alive {
            //handle events
            let mut player_input = Some(true);
            //loop till player is moved
            //none means ends game
            //false means advance game
            //true means wait for next input
            while player_input.unwrap() {
                for ev in display.poll_events() {
                    player_input = input.process_input(ev, &mut my_level);
                }
                if player_input.is_none() {
                    return;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Parse a docker-compose.yml file and print it to standard output in
//! normalized format.  Try running:
//!
//! ```sh
//! conductor docker-compose.in.yml docker-compose.yml
//! ```

extern crate docker_compose;
extern crate regex;
extern crate walkdir;

use docker_compose::v2 as dc;
use std::env;
use std::fs;
use std::io::{self, Write};
use std::path::Path;
use std::process;
use walkdir::{DirEntry, WalkDir};

use ext::service::ServiceExt;

#[macro_use] mod util;
mod ext;

/// Update a `docker-compose.yml` file in place.  `path` is a relative path
/// to this file from the conductor working directory, which we use to
/// resolve things.
fn update(file: &mut dc::File, path: &Path) -> Result<(), dc::Error> {
    // Get the directory from which we read this file, and use it to
    // construct some useful paths.
    let dir = try!(path.parent().ok_or_else(|| {
        err!("Can't get parent of {}", path.display())
    }));
    let env_file = try!(dir.strip_prefix("pods")).join("common.env");

    // Iterate over each name/server pair in the file using `iter_mut`, so
    // we can modify the services.
    for (_name, service) in file.services.iter_mut() {
        // Insert standard `env_file` entry (if the file actually exists).
        if env_file.exists() {
            service.env_files.insert(0, dc::value(env_file.clone()));
        }

        // Figure out where we'll keep the local checkout, if any.
        let build_dir = try!(service.local_build_dir());

        // If we have a local build directory, update the service to use it.
        if let Some(ref dir) = build_dir {
            if dir.exists() {
                // Make build dir path relative to `.output/pods`.
                let rel = Path::new("../../").join(dir);

                // Mount the local build directory as `/app` inside the
                // container.
                let mount = dc::VolumeMount::host(&rel, "/app");
                service.volumes.push(dc::value(mount));

                // Update the `build` field if present.
                if let Some(ref mut build) = service.build {
                    build.context = dc::value(dc::Context::Dir(rel.clone()));
                }
            }
        }
    }
    Ok(())
}

/// Should we copy this directory entry?
fn should_copy(entry: &DirEntry) -> bool {
    if !entry.file_type().is_file() {
        return false;
    }
    entry.file_name()
        .to_str()
        .map(|s| {
            !s.starts_with(".") && (s.ends_with(".yml") || s.ends_with(".env"))
        })
        .unwrap_or(false)
}

/// Our real `main` function.  This is a standard wrapper pattern: we put
/// all the real logic in a function that returns `Result` so that we can
/// use `try!` to handle errors, and we reserve `main` just for error
/// handling.
fn run() -> Result<(), dc::Error> {
    // Parse arguments.
    let args: Vec<_> = env::args().collect();
    if args.len() != 1 {
        return Err(err!("Usage: conductor"));
    }

    // We want to copy from "pods/" to ".conductor/".
    let dotdir = Path::new(".conductor");

    // Clean up our target directory.
    let dotdir_pods = dotdir.join("pods");
    if dotdir_pods.exists() {
        try!(fs::remove_dir_all(dotdir_pods));
    }

    // Walk over "pods/" recursively.
    for entry in WalkDir::new("pods") {
        let entry = try!(entry);
        if should_copy(&entry) {
            // Prefix "pods/" with ".conductor/" to get the output path.
            let in_path = entry.path();
            let out_path = dotdir.join(in_path);
            println!("Copying {} to {}", in_path.display(), out_path.display());

            // Make sure the destination directory exists.  It's OK to use
            // `unwrap` here because we know that `out_path` is not a file
            // system root because of how we constructed it above.
            try!(fs::create_dir_all(out_path.parent().unwrap()));

            // Make sure the destination file does not exist.  This is
            // reasonably safe because we do it under `.conductor`, which
            // is fair game.
            if out_path.exists() {
                try!(fs::remove_file(&out_path));
            }

            // Transform our file.  `unwrap` is safe because we know that
            // we have a real file extension thanks to `should_copy`.
            if in_path.extension().unwrap() == "yml" {
                let mut file = try!(dc::File::read_from_path(in_path));
                try!(update(&mut file, &in_path));
                try!(file.write_to_path(out_path));
            } else {
                try!(fs::copy(in_path, out_path));
            }
        }
    }

    Ok(())
}

fn main() {
    if let Err(ref err) = run() {
        // We use `unwrap` here to turn I/O errors into application panics.
        // If we can't print a message to stderr without an I/O error,
        // the situation is hopeless.
        write!(io::stderr(), "Error: {}", err).unwrap();
        process::exit(1);
    }
}
<commit_msg>Don't get confused by relative paths<commit_after>//! Parse a docker-compose.yml file and print it to standard output in
//! normalized format.  Try running:
//!
//! ```sh
//! conductor docker-compose.in.yml docker-compose.yml
//! ```

extern crate docker_compose;
extern crate regex;
extern crate walkdir;

use docker_compose::v2 as dc;
use std::env;
use std::fs;
use std::io::{self, Write};
use std::path::Path;
use std::process;
use walkdir::{DirEntry, WalkDir};

use ext::service::ServiceExt;

#[macro_use] mod util;
mod ext;

/// Update a `docker-compose.yml` file in place.  `path` is a relative path
/// to this file from the conductor working directory, which we use to
/// resolve things.
fn update(file: &mut dc::File, path: &Path) -> Result<(), dc::Error> {
    // Get the directory from which we read this file, and use it to
    // construct some useful paths.
    let dir = try!(path.parent().ok_or_else(|| {
        err!("Can't get parent of {}", path.display())
    }));
    let env_file = dir.join("common.env");

    // Iterate over each name/server pair in the file using `iter_mut`, so
    // we can modify the services.
    for (_name, service) in file.services.iter_mut() {
        // Insert standard `env_file` entry (if the file actually exists).
        if env_file.exists() {
            // Make our env file path relative to our top-level
            // `docker-compose.yml` file by removing `pods`, so
            // `docker-compose` doesn't get confused.
            let dc_rel = try!(env_file.strip_prefix("pods")).to_owned();
            service.env_files.insert(0, dc::value(dc_rel));
        }

        // Figure out where we'll keep the local checkout, if any.
        let build_dir = try!(service.local_build_dir());

        // If we have a local build directory, update the service to use it.
        if let Some(ref dir) = build_dir {
            if dir.exists() {
                // Make build dir path relative to `.output/pods`.
                let rel = Path::new("../../").join(dir);

                // Mount the local build directory as `/app` inside the
                // container.
                let mount = dc::VolumeMount::host(&rel, "/app");
                service.volumes.push(dc::value(mount));

                // Update the `build` field if present.
                if let Some(ref mut build) = service.build {
                    build.context = dc::value(dc::Context::Dir(rel.clone()));
                }
            }
        }
    }
    Ok(())
}

/// Should we copy this directory entry?
fn should_copy(entry: &DirEntry) -> bool {
    if !entry.file_type().is_file() {
        return false;
    }
    entry.file_name()
        .to_str()
        .map(|s| {
            !s.starts_with(".") && (s.ends_with(".yml") || s.ends_with(".env"))
        })
        .unwrap_or(false)
}

/// Our real `main` function.  This is a standard wrapper pattern: we put
/// all the real logic in a function that returns `Result` so that we can
/// use `try!` to handle errors, and we reserve `main` just for error
/// handling.
fn run() -> Result<(), dc::Error> {
    // Parse arguments.
    let args: Vec<_> = env::args().collect();
    if args.len() != 1 {
        return Err(err!("Usage: conductor"));
    }

    // We want to copy from "pods/" to ".conductor/".
    let dotdir = Path::new(".conductor");

    // Clean up our target directory.
    let dotdir_pods = dotdir.join("pods");
    if dotdir_pods.exists() {
        try!(fs::remove_dir_all(dotdir_pods));
    }

    // Walk over "pods/" recursively.
    for entry in WalkDir::new("pods") {
        let entry = try!(entry);
        if should_copy(&entry) {
            // Prefix "pods/" with ".conductor/" to get the output path.
            let in_path = entry.path();
            let out_path = dotdir.join(in_path);
            println!("Copying {} to {}", in_path.display(), out_path.display());

            // Make sure the destination directory exists.  It's OK to use
            // `unwrap` here because we know that `out_path` is not a file
            // system root because of how we constructed it above.
            try!(fs::create_dir_all(out_path.parent().unwrap()));

            // Make sure the destination file does not exist.  This is
            // reasonably safe because we do it under `.conductor`, which
            // is fair game.
            if out_path.exists() {
                try!(fs::remove_file(&out_path));
            }

            // Transform our file.  `unwrap` is safe because we know that
            // we have a real file extension thanks to `should_copy`.
            if in_path.extension().unwrap() == "yml" {
                let mut file = try!(dc::File::read_from_path(in_path));
                try!(update(&mut file, &in_path));
                try!(file.write_to_path(out_path));
            } else {
                try!(fs::copy(in_path, out_path));
            }
        }
    }

    Ok(())
}

fn main() {
    if let Err(ref err) = run() {
        // We use `unwrap` here to turn I/O errors into application panics.
        // If we can't print a message to stderr without an I/O error,
        // the situation is hopeless.
        write!(io::stderr(), "Error: {}", err).unwrap();
        process::exit(1);
    }
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;

use piston::window::WindowSettings;
use piston::event::*;
use glutin_window::GlutinWindow as Window;
use opengl_graphics::{ GlGraphics, OpenGL };
use piston::input::{ Button };
use piston::input::mouse::MouseButton;

pub struct Square {
    rotation: f64,   // Rotation for the square.
    position: [f64; 2],
    target: [f64; 2],
    selected: bool,
}

impl Square {
    fn new(position: [f64;2]) -> Square {
        println!("Create square at {:?}", position);
        Square {
            rotation: 0.0,
            position: position,
            target: position,
            selected: false
        }
    }
}

pub struct App {
    gl: GlGraphics, // OpenGL drawing backend.
    squares: Vec<Square>,
}

impl App {
    fn select(&mut self, position: &[f64;2]) {
        for s in &mut self.squares {
            s.selected = position[0]< s.position[0]+25.0 &&
                position[0]> s.position[0]-25.0 &&
                position[1]< s.position[1]+25.0 &&
                position[1]> s.position[1]-25.0;
        };
    }

    fn render(&mut self, args: &RenderArgs) {
        use graphics::*;

        const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
        const RED:   [f32; 4] = [1.0, 0.0, 0.0, 1.0];
        const BLUE:  [f32; 4] = [0.0, 0.0, 1.0, 1.0];
        let squares = &self.squares;

        self.gl.draw(args.viewport(), |c, gl| {
            // Clear the screen.
            clear(GREEN, gl);
            for s in squares.iter() {
                let square = rectangle::square(0.0, 0.0, 50.0);
                let transform = c.transform.trans(s.position[0], s.position[1])
                    .rot_rad(s.rotation)
                    .trans(-25.0, -25.0);

                // Draw the box RED if selected
                if s.selected {
                    rectangle(RED, square, transform, gl);
                } else {
                    rectangle(BLUE, square, transform, gl);
                }
            }
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        for s in &mut self.squares {
            // Rotate 2 radians per second.
            s.rotation += 2.0 * args.dt;

            let diff = [s.target[0]-s.position[0], s.target[1]-s.position[1]];
            s.position[0] += diff[0]/2.0*args.dt;
            s.position[1] += diff[1]/2.0*args.dt;
        }
    }

    fn move_selected(&mut self, position: [f64;2]) {
        for s in &mut self.squares {
            if s.selected {
                s.target = position;
            }
        }
    }
}

fn main() {
    let opengl = OpenGL::_3_2;

    // Create an Glutin window.
    let window = Window::new(
        WindowSettings::new(
            "spinning-square",
            [200, 200]
        )
        .exit_on_esc(true)
    );

    // Create a new game and run it.
    let mut app = App {
        gl: GlGraphics::new(opengl),
        squares: vec![Square::new([50.0, 50.0]), Square::new([100.0, 100.0])],
    };

    let mut cursor = [0.0,0.0];

    for e in window.events() {
        if let Some(r) = e.render_args() {
            app.render(&r);
        }
        if let Some(Button::Mouse(button)) = e.press_args() {
            match button {
                MouseButton::Left  => app.select(&cursor),
                MouseButton::Right => app.move_selected(cursor),
                _ => println!("Pressed mouse button '{:?}'", button),
            }
        }
        e.mouse_cursor(|x, y| {
            cursor = [x, y];
            println!("Mouse moved '{} {}'", x, y);
        });

        if let Some(u) = e.update_args() {
            app.update(&u);
        }
    }
}

<commit_msg>rename window and make it bigger by default<commit_after>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;

use piston::window::WindowSettings;
use piston::event::*;
use glutin_window::GlutinWindow as Window;
use opengl_graphics::{ GlGraphics, OpenGL };
use piston::input::{ Button };
use piston::input::mouse::MouseButton;

pub struct Square {
    rotation: f64,   // Rotation for the square.
    position: [f64; 2],
    target: [f64; 2],
    selected: bool,
}

impl Square {
    fn new(position: [f64;2]) -> Square {
        println!("Create square at {:?}", position);
        Square {
            rotation: 0.0,
            position: position,
            target: position,
            selected: false
        }
    }
}

pub struct App {
    gl: GlGraphics, // OpenGL drawing backend.
    squares: Vec<Square>,
}

impl App {
    fn select(&mut self, position: &[f64;2]) {
        for s in &mut self.squares {
            s.selected = position[0]< s.position[0]+25.0 &&
                position[0]> s.position[0]-25.0 &&
                position[1]< s.position[1]+25.0 &&
                position[1]> s.position[1]-25.0;
        };
    }

    fn render(&mut self, args: &RenderArgs) {
        use graphics::*;

        const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
        const RED:   [f32; 4] = [1.0, 0.0, 0.0, 1.0];
        const BLUE:  [f32; 4] = [0.0, 0.0, 1.0, 1.0];
        let squares = &self.squares;

        self.gl.draw(args.viewport(), |c, gl| {
            // Clear the screen.
            clear(GREEN, gl);
            for s in squares.iter() {
                let square = rectangle::square(0.0, 0.0, 50.0);
                let transform = c.transform.trans(s.position[0], s.position[1])
                    .rot_rad(s.rotation)
                    .trans(-25.0, -25.0);

                // Draw the box RED if selected
                if s.selected {
                    rectangle(RED, square, transform, gl);
                } else {
                    rectangle(BLUE, square, transform, gl);
                }
            }
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        for s in &mut self.squares {
            // Rotate 2 radians per second.
            s.rotation += 2.0 * args.dt;

            let diff = [s.target[0]-s.position[0], s.target[1]-s.position[1]];
            s.position[0] += diff[0]/2.0*args.dt;
            s.position[1] += diff[1]/2.0*args.dt;
        }
    }

    fn move_selected(&mut self, position: [f64;2]) {
        for s in &mut self.squares {
            if s.selected {
                s.target = position;
            }
        }
    }
}

fn main() {
    let opengl = OpenGL::_3_2;

    // Create an Glutin window.
    let window = Window::new(
        WindowSettings::new(
            "rpsrtsrs",
            [640, 480]
        )
        .exit_on_esc(true)
    );

    // Create a new game and run it.
    let mut app = App {
        gl: GlGraphics::new(opengl),
        squares: vec![Square::new([50.0, 50.0]), Square::new([100.0, 100.0])],
    };

    let mut cursor = [0.0,0.0];

    for e in window.events() {
        if let Some(r) = e.render_args() {
            app.render(&r);
        }
        if let Some(Button::Mouse(button)) = e.press_args() {
            match button {
                MouseButton::Left  => app.select(&cursor),
                MouseButton::Right => app.move_selected(cursor),
                _ => println!("Pressed mouse button '{:?}'", button),
            }
        }
        e.mouse_cursor(|x, y| {
            cursor = [x, y];
            println!("Mouse moved '{} {}'", x, y);
        });

        if let Some(u) = e.update_args() {
            app.update(&u);
        }
    }
}

<|endoftext|>


<commit_before>extern crate byteorder;
extern crate regex;
extern crate flate2;
extern crate getopts;
extern crate tempdir;
#[macro_use]
extern crate error_chain;

use std::fs::File;
use std::io;
use std::io::{BufReader, BufWriter};
use std::path::Path;
use std::env;
use std::process::exit;
use std::process::Command;

use getopts::Options;

use tempdir::TempDir;

pub mod data;
mod write;
mod read;
mod string_write;
mod string_read;
#[cfg(test)]
mod tests;

mod errors {
    error_chain!{
        foreign_links {
            Io(::std::io::Error);
            FromUtf8(::std::string::FromUtf8Error);
        }
    }
}
use errors::*;

fn main() {
    match run_cmdline() {
        Ok(ret) => {
            exit(ret);
        },
        Err(ref e) => {
            if let Some(backtrace) = e.backtrace() {
                eprintln!("{:?}", backtrace);
            }

            eprintln!("Error: {}", e);

            for e in e.iter().skip(1) {
                eprintln!("	caused by: {}", e);
            }

            eprintln!("For help, run with --help or read the manpage.");
            exit(1);
        },
    }
}

fn run_cmdline() -> Result<i32> {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optflagopt("e", "edit", "edit a NBT file with your $EDITOR.
    If [FILE] is specified, then that file is edited in place, but specifying --input and/or --output will override the input/output.
    If no file is specified, default to read from --input and writing to --output.", "FILE");
    opts.optflagopt("p", "print", "print NBT file to text format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optflagopt("r", "reverse", "reverse a file in text format to NBT format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optopt("i",
                "input",
                "specify the input file, defaults to stdin",
                "FILE");
    opts.optopt("o",
                "output",
                "specify the output file, defaults to stdout",
                "FILE");
    opts.optflag("h", "help", "print the help menu");
    opts.optflag("", "version", "print program version");

    let matches = opts.parse(&args[1..]).chain_err(|| "error parsing options")?;

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

    if matches.opt_present("version") {
        println!("{} {} {}",
                 env!("CARGO_PKG_NAME"),
                 env!("CARGO_PKG_VERSION"),
                 /* See build.rs for the git-revision.txt file */
                 include!(concat!(env!("OUT_DIR"), "/git-revision.txt")));
        println!("https://github.com/C4K3/nbted");
        return Ok(0);
    }

    let is_print: bool = matches.opt_present("print");
    let is_reverse: bool = matches.opt_present("reverse");
    let is_edit: bool = if matches.opt_present("edit") {
        true
    } else {
        /* If edit is not explicitly defined, it is the default action and is
         * selected if no other action is specified */
        (!(is_reverse || is_print))
    };

    /* Hopefully this is a simpler way of ensuring that only one action can be
     * taken than having a long logical expression */
    let mut action_count = 0;
    if is_print {
        action_count += 1;
    }
    if is_reverse {
        action_count += 1;
    }
    if is_edit {
        action_count += 1;
    }
    if action_count > 1 {
        bail!("You can only specify one action a time.");
    }

    /* Figure out the input file, by trying to read the arguments for all of
     * --input, --edit, --print and --reverse, prioritizing --input over the
     * other arguments, if none of the arguments are specified but there is a
     * free argument, use that, else we finally default to - (stdin) */
    let input = if let Some(x) = matches.opt_str("input") {
        x
    } else if let Some(x) = matches.opt_str("edit") {
        x
    } else if let Some(x) = matches.opt_str("print") {
        x
    } else if let Some(x) = matches.opt_str("reverse") {
        x
    } else if matches.free.len() == 1 {
        matches.free[0].clone()
    } else {
        /* stdin */
        "-".to_string()
    };

    let output = if let Some(x) = matches.opt_str("output") {
        x
    } else if let Some(x) = matches.opt_str("edit") {
        x
    } else if is_edit && matches.free.len() == 1 {
        /* Only want to default to the free argument if we're editing
         * (DO NOT WRITE BACK TO THE READ FILE UNLESS EDITING!) */
        matches.free[0].clone()
    } else {
        /* stdout */
        "-".to_string()
    };

    if matches.free.len() > 1 {
        bail!("nbted was given multiple arguments, but only supports editing one file at a time.");
    }

    if is_print {
        return print(&input, &output);
    } else if is_reverse {
        return reverse(&input, &output);
    } else if is_edit {
        return edit(&input, &output);
    } else {
        bail!("Internal error: No action selected. (Please report this.)");
    }
}

/// When the user wants to edit a specific file in place
fn edit(input: &str, output: &str) -> Result<i32> {

    /* First we read the NBT data from the input */
    let nbt = if input == "-" {
        // let mut f = BufReader::new(io::stdin());
        let f = io::stdin();
        let mut f = f.lock();
        read::read_file(&mut f).chain_err(|| "Unable to parse any NBT files from stdin")?
    } else {
        let path: &Path = Path::new(input);
        let f = File::open(path)
            .chain_err(|| format!("Unable to open file {}", input))?;
        let mut f = BufReader::new(f);

        read::read_file(&mut f).chain_err(
            || format!("Unable to parse {}, are you sure it's an NBT file?",
                       input))?
    };

    /* Then we create a temporary file and write the NBT data in text format
     * to the temporary file */
    let tmpdir = TempDir::new("nbted")
        .chain_err(|| "Unable to create temporary directory")?;

    let tmp = match Path::new(input).file_name() {
        Some(x) => {
            let mut x = x.to_os_string();
            x.push(".txt");
            x
        },
        None => bail!("Error reading file name"),
    };
    let tmp_path = tmpdir.path().join(tmp);

    {
        let mut f = File::create(&tmp_path)
            .chain_err(|| "Unable to create temporary file")?;

        string_write::write_file(&mut f, &nbt)
            .chain_err(|| "Unable to write temporary file")?;

        f.sync_all().chain_err(|| "Unable to synchronize file")?;
    }

    let new_nbt = {
        let mut new_nbt = open_editor(&tmp_path);

        while let Err(e) = new_nbt {
            eprintln!("Unable to parse edited file");
            for e in e.iter() {
                eprintln!("	caused by: {}", e);
            }
            eprintln!("Do you want to open the file for editing again? (y/N)");

            let mut line = String::new();
            io::stdin().read_line(&mut line)
                .chain_err(|| "Error reading from stdin. Nothing was changed")?;

            if line.trim() == "y" {
                new_nbt = open_editor(&tmp_path);
            } else {
                eprintln!("Exiting ... File is unchanged.");
                return Ok(0);
            }
        }

        new_nbt.expect("new_nbt was Error")
    };

    if nbt == new_nbt {
        eprintln!("No changes, will do nothing.");
        return Ok(0);
    }

    /* And finally we write the edited nbt (new_nbt) into the output file */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        match write::write_file(&mut f, &new_nbt) {
            Ok(()) => (),
            Err(_) => return Ok(1),
        }
    } else {
        let path: &Path = Path::new(output);
        let f = File::create(&path).chain_err(
            || format!("Unable to write to output NBT file {}. Nothing was changed",
                       output))?;
        let mut f = BufWriter::new(f);

        write::write_file(&mut f, &new_nbt).chain_err(
            || format!("Error writing NBT file {}. State of NBT file is unknown, consider restoring it from a backup.",
                       output))?;
    }

    eprintln!("File edited successfully.");
    Ok(0)
}

/// Open the user's $EDITOR on the temporary file, wait until the editor is
/// closed again, read the temporary file and attempt to parse it into NBT,
/// returning the result.
fn open_editor(tmp_path: &Path) -> Result<data::NBTFile> {
    let editor = match env::var("EDITOR") {
        Ok(x) => x,
        Err(_) => {
            match env::var("VISUAL") {
                Ok(x) => x,
                Err(_) => bail!("Unable to find $EDITOR"),
            }
        },
    };

    let mut cmd = Command::new(editor);
    cmd.arg(&tmp_path.as_os_str());
    let mut cmd = cmd.spawn().chain_err(|| "Error opening editor")?;

    match cmd.wait() {
        Ok(x) if x.success() => (),
        Ok(_) => bail!("Editor did not exit correctly"),
        Err(e) => {
            return Err(Error::with_chain(e, "Error executing editor"));
        },
    }

    /* Then we parse the text format in the temporary file into NBT */
    let mut f = File::open(&tmp_path).chain_err(
        || "Unable to read temporary file. Nothing was changed.")?;

    string_read::read_file(&mut f).map_err(|e| e.into())
}

/// When the user wants to print an NBT file to text format
fn print(input: &str, output: &str) -> Result<i32> {
    /* First we read a NBTFile from the input */
    let nbt = if input == "-" {
        let f = io::stdin();
        let mut f = f.lock();
        read::read_file(&mut f).chain_err(
            || format!("Unable to parse {}, are you sure it's an NBT file?",
                       input))?
    } else {
        let path: &Path = Path::new(input);
        let f = File::open(path).chain_err(
            || format!("Unable to open file {}", input))?;
        let mut f = BufReader::new(f);

        read::read_file(&mut f).chain_err(
            || format!("Unable to parse {}, are you sure it's an NBT file?",
                       input))?
    };

    /* Then we write the NBTFile to the output in text format */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        match string_write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(_) => return Ok(1),
        }
    } else {
        let path: &Path = Path::new(output);
        let f = File::create(&path).chain_err(
            || format!("Unable to write to output NBT file {}. Nothing was changed.",
                       output))?;
        let mut f = BufWriter::new(f);

        string_write::write_file(&mut f, &nbt).chain_err(
            || format!("Error writing NBT file {}. State of NBT file is unknown, consider restoring it from a backup.",
                       output))?;
    }

    Ok(0)
}

/// When the user wants to convert a text format file into an NBT file
fn reverse(input: &str, output: &str) -> Result<i32> {
    /* First we read the input file in the text format */
    let path: &Path = Path::new(input);
    let mut f = File::open(&path).chain_err(
        || format!("Unable to read text file {}",
                   input))?;

    let nbt = string_read::read_file(&mut f).chain_err(
        || format!("Unable to parse text file {}",
        input))?;

    /* Then we write the parsed NBT to the output file in NBT format */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        match write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(_) => return Ok(1),
        }
    } else {
        let path: &Path = Path::new(output);
        let f = File::create(&path).chain_err(
            || format!("Unable to write to output NBT file {}. Nothing was changed",
                       output))?;
        let mut f = BufWriter::new(f);

        write::write_file(&mut f, &nbt).chain_err(
            || format!("error writing to NBT FILE {}, state of NBT file is unknown, consider restoring it from a backup.",
                       output))?;
    }

    Ok(0)
}

fn print_usage(opts: Options) {
    let brief = "Usage: nbted [options] FILE";
    print!("{}", opts.usage(&brief));
    println!("\nThe default action, taken if no action is explicitly selected, is to --edit.");
    println!("\nFor detailed usage information, read the manpage.");
}
<commit_msg>Inline print_usage<commit_after>extern crate byteorder;
extern crate regex;
extern crate flate2;
extern crate getopts;
extern crate tempdir;
#[macro_use]
extern crate error_chain;

use std::fs::File;
use std::io;
use std::io::{BufReader, BufWriter};
use std::path::Path;
use std::env;
use std::process::exit;
use std::process::Command;

use getopts::Options;

use tempdir::TempDir;

pub mod data;
mod write;
mod read;
mod string_write;
mod string_read;
#[cfg(test)]
mod tests;

mod errors {
    error_chain!{
        foreign_links {
            Io(::std::io::Error);
            FromUtf8(::std::string::FromUtf8Error);
        }
    }
}
use errors::*;

fn main() {
    match run_cmdline() {
        Ok(ret) => {
            exit(ret);
        },
        Err(ref e) => {
            if let Some(backtrace) = e.backtrace() {
                eprintln!("{:?}", backtrace);
            }

            eprintln!("Error: {}", e);

            for e in e.iter().skip(1) {
                eprintln!("	caused by: {}", e);
            }

            eprintln!("For help, run with --help or read the manpage.");
            exit(1);
        },
    }
}

fn run_cmdline() -> Result<i32> {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optflagopt("e", "edit", "edit a NBT file with your $EDITOR.
    If [FILE] is specified, then that file is edited in place, but specifying --input and/or --output will override the input/output.
    If no file is specified, default to read from --input and writing to --output.", "FILE");
    opts.optflagopt("p", "print", "print NBT file to text format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optflagopt("r", "reverse", "reverse a file in text format to NBT format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optopt("i",
                "input",
                "specify the input file, defaults to stdin",
                "FILE");
    opts.optopt("o",
                "output",
                "specify the output file, defaults to stdout",
                "FILE");
    opts.optflag("h", "help", "print the help menu");
    opts.optflag("", "version", "print program version");

    let matches = opts.parse(&args[1..]).chain_err(|| "error parsing options")?;

    if matches.opt_present("h") {
        let brief = "Usage: nbted [options] FILE";
        print!("{}", opts.usage(&brief));
        println!("\nThe default action, taken if no action is explicitly selected, is to --edit.");
        println!("\nFor detailed usage information, read the manpage.");
        return Ok(0);
    }

    if matches.opt_present("version") {
        println!("{} {} {}",
                 env!("CARGO_PKG_NAME"),
                 env!("CARGO_PKG_VERSION"),
                 /* See build.rs for the git-revision.txt file */
                 include!(concat!(env!("OUT_DIR"), "/git-revision.txt")));
        println!("https://github.com/C4K3/nbted");
        return Ok(0);
    }

    let is_print: bool = matches.opt_present("print");
    let is_reverse: bool = matches.opt_present("reverse");
    let is_edit: bool = if matches.opt_present("edit") {
        true
    } else {
        /* If edit is not explicitly defined, it is the default action and is
         * selected if no other action is specified */
        (!(is_reverse || is_print))
    };

    /* Hopefully this is a simpler way of ensuring that only one action can be
     * taken than having a long logical expression */
    let mut action_count = 0;
    if is_print {
        action_count += 1;
    }
    if is_reverse {
        action_count += 1;
    }
    if is_edit {
        action_count += 1;
    }
    if action_count > 1 {
        bail!("You can only specify one action a time.");
    }

    /* Figure out the input file, by trying to read the arguments for all of
     * --input, --edit, --print and --reverse, prioritizing --input over the
     * other arguments, if none of the arguments are specified but there is a
     * free argument, use that, else we finally default to - (stdin) */
    let input = if let Some(x) = matches.opt_str("input") {
        x
    } else if let Some(x) = matches.opt_str("edit") {
        x
    } else if let Some(x) = matches.opt_str("print") {
        x
    } else if let Some(x) = matches.opt_str("reverse") {
        x
    } else if matches.free.len() == 1 {
        matches.free[0].clone()
    } else {
        /* stdin */
        "-".to_string()
    };

    let output = if let Some(x) = matches.opt_str("output") {
        x
    } else if let Some(x) = matches.opt_str("edit") {
        x
    } else if is_edit && matches.free.len() == 1 {
        /* Only want to default to the free argument if we're editing
         * (DO NOT WRITE BACK TO THE READ FILE UNLESS EDITING!) */
        matches.free[0].clone()
    } else {
        /* stdout */
        "-".to_string()
    };

    if matches.free.len() > 1 {
        bail!("nbted was given multiple arguments, but only supports editing one file at a time.");
    }

    if is_print {
        return print(&input, &output);
    } else if is_reverse {
        return reverse(&input, &output);
    } else if is_edit {
        return edit(&input, &output);
    } else {
        bail!("Internal error: No action selected. (Please report this.)");
    }
}

/// When the user wants to edit a specific file in place
fn edit(input: &str, output: &str) -> Result<i32> {

    /* First we read the NBT data from the input */
    let nbt = if input == "-" {
        // let mut f = BufReader::new(io::stdin());
        let f = io::stdin();
        let mut f = f.lock();
        read::read_file(&mut f).chain_err(|| "Unable to parse any NBT files from stdin")?
    } else {
        let path: &Path = Path::new(input);
        let f = File::open(path)
            .chain_err(|| format!("Unable to open file {}", input))?;
        let mut f = BufReader::new(f);

        read::read_file(&mut f).chain_err(
            || format!("Unable to parse {}, are you sure it's an NBT file?",
                       input))?
    };

    /* Then we create a temporary file and write the NBT data in text format
     * to the temporary file */
    let tmpdir = TempDir::new("nbted")
        .chain_err(|| "Unable to create temporary directory")?;

    let tmp = match Path::new(input).file_name() {
        Some(x) => {
            let mut x = x.to_os_string();
            x.push(".txt");
            x
        },
        None => bail!("Error reading file name"),
    };
    let tmp_path = tmpdir.path().join(tmp);

    {
        let mut f = File::create(&tmp_path)
            .chain_err(|| "Unable to create temporary file")?;

        string_write::write_file(&mut f, &nbt)
            .chain_err(|| "Unable to write temporary file")?;

        f.sync_all().chain_err(|| "Unable to synchronize file")?;
    }

    let new_nbt = {
        let mut new_nbt = open_editor(&tmp_path);

        while let Err(e) = new_nbt {
            eprintln!("Unable to parse edited file");
            for e in e.iter() {
                eprintln!("	caused by: {}", e);
            }
            eprintln!("Do you want to open the file for editing again? (y/N)");

            let mut line = String::new();
            io::stdin().read_line(&mut line)
                .chain_err(|| "Error reading from stdin. Nothing was changed")?;

            if line.trim() == "y" {
                new_nbt = open_editor(&tmp_path);
            } else {
                eprintln!("Exiting ... File is unchanged.");
                return Ok(0);
            }
        }

        new_nbt.expect("new_nbt was Error")
    };

    if nbt == new_nbt {
        eprintln!("No changes, will do nothing.");
        return Ok(0);
    }

    /* And finally we write the edited nbt (new_nbt) into the output file */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        match write::write_file(&mut f, &new_nbt) {
            Ok(()) => (),
            Err(_) => return Ok(1),
        }
    } else {
        let path: &Path = Path::new(output);
        let f = File::create(&path).chain_err(
            || format!("Unable to write to output NBT file {}. Nothing was changed",
                       output))?;
        let mut f = BufWriter::new(f);

        write::write_file(&mut f, &new_nbt).chain_err(
            || format!("Error writing NBT file {}. State of NBT file is unknown, consider restoring it from a backup.",
                       output))?;
    }

    eprintln!("File edited successfully.");
    Ok(0)
}

/// Open the user's $EDITOR on the temporary file, wait until the editor is
/// closed again, read the temporary file and attempt to parse it into NBT,
/// returning the result.
fn open_editor(tmp_path: &Path) -> Result<data::NBTFile> {
    let editor = match env::var("EDITOR") {
        Ok(x) => x,
        Err(_) => {
            match env::var("VISUAL") {
                Ok(x) => x,
                Err(_) => bail!("Unable to find $EDITOR"),
            }
        },
    };

    let mut cmd = Command::new(editor);
    cmd.arg(&tmp_path.as_os_str());
    let mut cmd = cmd.spawn().chain_err(|| "Error opening editor")?;

    match cmd.wait() {
        Ok(x) if x.success() => (),
        Ok(_) => bail!("Editor did not exit correctly"),
        Err(e) => {
            return Err(Error::with_chain(e, "Error executing editor"));
        },
    }

    /* Then we parse the text format in the temporary file into NBT */
    let mut f = File::open(&tmp_path).chain_err(
        || "Unable to read temporary file. Nothing was changed.")?;

    string_read::read_file(&mut f).map_err(|e| e.into())
}

/// When the user wants to print an NBT file to text format
fn print(input: &str, output: &str) -> Result<i32> {
    /* First we read a NBTFile from the input */
    let nbt = if input == "-" {
        let f = io::stdin();
        let mut f = f.lock();
        read::read_file(&mut f).chain_err(
            || format!("Unable to parse {}, are you sure it's an NBT file?",
                       input))?
    } else {
        let path: &Path = Path::new(input);
        let f = File::open(path).chain_err(
            || format!("Unable to open file {}", input))?;
        let mut f = BufReader::new(f);

        read::read_file(&mut f).chain_err(
            || format!("Unable to parse {}, are you sure it's an NBT file?",
                       input))?
    };

    /* Then we write the NBTFile to the output in text format */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        match string_write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(_) => return Ok(1),
        }
    } else {
        let path: &Path = Path::new(output);
        let f = File::create(&path).chain_err(
            || format!("Unable to write to output NBT file {}. Nothing was changed.",
                       output))?;
        let mut f = BufWriter::new(f);

        string_write::write_file(&mut f, &nbt).chain_err(
            || format!("Error writing NBT file {}. State of NBT file is unknown, consider restoring it from a backup.",
                       output))?;
    }

    Ok(0)
}

/// When the user wants to convert a text format file into an NBT file
fn reverse(input: &str, output: &str) -> Result<i32> {
    /* First we read the input file in the text format */
    let path: &Path = Path::new(input);
    let mut f = File::open(&path).chain_err(
        || format!("Unable to read text file {}",
                   input))?;

    let nbt = string_read::read_file(&mut f).chain_err(
        || format!("Unable to parse text file {}",
        input))?;

    /* Then we write the parsed NBT to the output file in NBT format */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        match write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(_) => return Ok(1),
        }
    } else {
        let path: &Path = Path::new(output);
        let f = File::create(&path).chain_err(
            || format!("Unable to write to output NBT file {}. Nothing was changed",
                       output))?;
        let mut f = BufWriter::new(f);

        write::write_file(&mut f, &nbt).chain_err(
            || format!("error writing to NBT FILE {}, state of NBT file is unknown, consider restoring it from a backup.",
                       output))?;
    }

    Ok(0)
}
<|endoftext|>