<commit_before>// See LICENSE file for copyright and license details.

use std;
use gl;
use gl::types::{
  GLfloat,
  GLint,
  GLuint,
};
use cgmath::vector::{
  Vec3,
  Vec2,
};
use glh = gl_helpers;
use map::TileIterator;
use color::Color3;
use camera::Camera;
use geom::Geom;
use misc::read_file;

pub struct TilePicker {
  program: GLuint,
  color_buffer_obj: GLuint,
  mat_id: GLint,
  vertex_buffer_obj: GLuint,
  vertex_data: ~[Vec3<GLfloat>],
  color_data: ~[Color3],
}

impl TilePicker {
  pub fn new() -> TilePicker {
    let picker = TilePicker {
      color_buffer_obj: 0,
      program: 0,
      vertex_buffer_obj: 0,
      mat_id: 0,
      vertex_data: ~[],
      color_data: ~[],
    };
    picker
  }

  pub fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
    glh::delete_buffer(self.vertex_buffer_obj);
    glh::delete_buffer(self.color_buffer_obj);
  }

  fn build_hex_mesh_for_picking(&mut self, geom: &Geom) {
    for tile_pos in TileIterator::new() {
      let pos3d = geom.map_pos_to_world_pos(tile_pos).extend(0.0);
      for num in range(0, 6) {
        let vertex = geom.index_to_hex_vertex(num);
        let next_vertex = geom.index_to_hex_vertex(num + 1);
        let col_x = tile_pos.x as f32 / 255.0;
        let col_y = tile_pos.y as f32 / 255.0;
        let c_data = &mut self.color_data;
        let v_data = &mut self.vertex_data;
        let color = Color3{r: col_x, g: col_y, b: 1.0};
        v_data.push(pos3d + vertex.extend(0.0));
        c_data.push(color);
        v_data.push(pos3d + next_vertex.extend(0.0));
        c_data.push(color);
        v_data.push(pos3d + Vec3::zero());
        c_data.push(color);
      }
    }
  }

  pub fn init(&mut self, geom: &Geom) {
    self.build_hex_mesh_for_picking(geom);
    self.program = glh::compile_program(
      read_file(&Path::new("pick.vs.glsl")),
      read_file(&Path::new("pick.fs.glsl")),
    );
    gl::UseProgram(self.program);
    self.vertex_buffer_obj = glh::gen_buffer();
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer_obj);
    glh::fill_current_coord_vbo(self.vertex_data);
    let pos_attr = glh::get_attr(self.program, "position");
    gl::EnableVertexAttribArray(pos_attr);
    glh::vertex_attrib_pointer(pos_attr);
    self.color_buffer_obj = glh::gen_buffer();
    gl::BindBuffer(gl::ARRAY_BUFFER, self.color_buffer_obj);
    glh::fill_current_color_vbo(self.color_data);
    let color_attr = glh::get_attr(self.program, "color");
    gl::EnableVertexAttribArray(color_attr);
    glh::vertex_attrib_pointer(color_attr);
    self.mat_id = glh::get_uniform(self.program, "mvp_mat");
  }

  fn _pick_tile(
    &self,
    win_size: (i32, i32),
    mouse_pos: Vec2<i32>
  ) -> Option<Vec2<i32>> {
    let (_, height) = win_size;
    let reverted_y = height - mouse_pos.y;
    let data: [u8, ..4] = [0, 0, 0, 0]; // mut
    unsafe {
      let data_ptr = std::cast::transmute(&data[0]);
      gl::ReadPixels(
        mouse_pos.x, reverted_y, 1, 1,
        gl::RGBA,
        gl::UNSIGNED_BYTE,
        data_ptr
      );
    }
    if data[2] != 0 {
      Some(Vec2{x: data[0] as i32, y: data[1] as i32})
    } else {
      None
    }
  }

  pub fn pick_tile(
    &mut self,
    win_size: (i32, i32),
    camera: &Camera,
    mouse_pos: Vec2<i32>
  ) -> Option<Vec2<i32>> {
    gl::UseProgram(self.program);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer_obj);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.color_buffer_obj);
    glh::uniform_mat4f(self.mat_id, &camera.mat());
    gl::ClearColor(0.0, 0.0, 0.0, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);
    glh::draw_mesh(self.vertex_data.len() as int);
    self._pick_tile(win_size, mouse_pos)
  }
}

impl Drop for TilePicker {
  fn drop(&mut self) {
    self.cleanup_opengl();
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>tile_picker.rs: Moved build_hex_mesh_...() from class<commit_after>// See LICENSE file for copyright and license details.

use std;
use gl;
use gl::types::{
  GLfloat,
  GLint,
  GLuint,
};
use cgmath::vector::{
  Vec3,
  Vec2,
};
use glh = gl_helpers;
use map::TileIterator;
use color::Color3;
use camera::Camera;
use geom::Geom;
use misc::read_file;

fn build_hex_map_mesh(geom: &Geom) -> (~[Vec3<GLfloat>], ~[Color3]) {
  let mut c_data = ~[];
  let mut v_data = ~[];
  for tile_pos in TileIterator::new() {
    let pos3d = geom.map_pos_to_world_pos(tile_pos).extend(0.0);
    for num in range(0, 6) {
      let vertex = geom.index_to_hex_vertex(num);
      let next_vertex = geom.index_to_hex_vertex(num + 1);
      let col_x = tile_pos.x as f32 / 255.0;
      let col_y = tile_pos.y as f32 / 255.0;
      let color = Color3{r: col_x, g: col_y, b: 1.0};
      v_data.push(pos3d + vertex.extend(0.0));
      c_data.push(color);
      v_data.push(pos3d + next_vertex.extend(0.0));
      c_data.push(color);
      v_data.push(pos3d + Vec3::zero());
      c_data.push(color);
    }
  }
  (v_data, c_data)
}

pub struct TilePicker {
  program: GLuint,
  color_buffer_obj: GLuint,
  mat_id: GLint,
  vertex_buffer_obj: GLuint,
  vertex_data: ~[Vec3<GLfloat>],
  color_data: ~[Color3],
}

impl TilePicker {
  pub fn new() -> TilePicker {
    let picker = TilePicker {
      color_buffer_obj: 0,
      program: 0,
      vertex_buffer_obj: 0,
      mat_id: 0,
      vertex_data: ~[],
      color_data: ~[],
    };
    picker
  }

  pub fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
    glh::delete_buffer(self.vertex_buffer_obj);
    glh::delete_buffer(self.color_buffer_obj);
  }

  pub fn init(&mut self, geom: &Geom) {
    let (vertex_data, color_data) =  build_hex_map_mesh(geom);
    self.vertex_data = vertex_data;
    self.color_data = color_data;
    self.program = glh::compile_program(
      read_file(&Path::new("pick.vs.glsl")),
      read_file(&Path::new("pick.fs.glsl")),
    );
    gl::UseProgram(self.program);
    self.vertex_buffer_obj = glh::gen_buffer();
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer_obj);
    glh::fill_current_coord_vbo(self.vertex_data);
    let pos_attr = glh::get_attr(self.program, "position");
    gl::EnableVertexAttribArray(pos_attr);
    glh::vertex_attrib_pointer(pos_attr);
    self.color_buffer_obj = glh::gen_buffer();
    gl::BindBuffer(gl::ARRAY_BUFFER, self.color_buffer_obj);
    glh::fill_current_color_vbo(self.color_data);
    let color_attr = glh::get_attr(self.program, "color");
    gl::EnableVertexAttribArray(color_attr);
    glh::vertex_attrib_pointer(color_attr);
    self.mat_id = glh::get_uniform(self.program, "mvp_mat");
  }

  fn _pick_tile(
    &self,
    win_size: (i32, i32),
    mouse_pos: Vec2<i32>
  ) -> Option<Vec2<i32>> {
    let (_, height) = win_size;
    let reverted_y = height - mouse_pos.y;
    let data: [u8, ..4] = [0, 0, 0, 0]; // mut
    unsafe {
      let data_ptr = std::cast::transmute(&data[0]);
      gl::ReadPixels(
        mouse_pos.x, reverted_y, 1, 1,
        gl::RGBA,
        gl::UNSIGNED_BYTE,
        data_ptr
      );
    }
    if data[2] != 0 {
      Some(Vec2{x: data[0] as i32, y: data[1] as i32})
    } else {
      None
    }
  }

  pub fn pick_tile(
    &mut self,
    win_size: (i32, i32),
    camera: &Camera,
    mouse_pos: Vec2<i32>
  ) -> Option<Vec2<i32>> {
    gl::UseProgram(self.program);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer_obj);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.color_buffer_obj);
    glh::uniform_mat4f(self.mat_id, &camera.mat());
    gl::ClearColor(0.0, 0.0, 0.0, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);
    glh::draw_mesh(self.vertex_data.len() as int);
    self._pick_tile(win_size, mouse_pos)
  }
}

impl Drop for TilePicker {
  fn drop(&mut self) {
    self.cleanup_opengl();
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>


<commit_before>use ::{color, Rgba, V2, Rect, ToColor, FromColor, Anchor};
use ::text;
use super::canvas::{Canvas, FONT_H};
use super::canvas_util::{CanvasUtil};

/// Text line alignment.
pub enum Align {
    Left,
    Right,
    Center
}

/// Structure for rendering text to a canvas.
pub struct Fonter<'a, 'b: 'a> {
    canvas: &'a mut Canvas<'b>,
    anchor: Anchor,
    align: Align,
    color: Rgba,
    z: f32,
    max_lines: Option<usize>,
    border: Option<Rgba>,
    max_width: Option<f32>,
    /// (Text, width) pairs.
    lines: Vec<(String, f32)>,
    longest_line_width: f32,
}

impl<'a, 'b> Fonter<'a, 'b> {
    pub fn new(canvas: &'a mut Canvas<'b>) -> Fonter<'a, 'b> {
        Fonter {
            canvas: canvas,
            anchor: Anchor::TopLeft,
            align: Align::Left,
            color: FromColor::from_color(&color::WHITE),
            z: 0.1,
            max_lines: None,
            border: None,
            max_width: None,
            lines: vec![(String::new(), 0.0)],
            longest_line_width: 0.0,
        }
    }

    /// Set the point of the text box which draw offset will anchor to.
    pub fn anchor(mut self, anchor: Anchor) -> Fonter<'a, 'b> {
        self.anchor = anchor; self
    }

    /// Set the text alignment
    pub fn align(mut self, align: Align) -> Fonter<'a, 'b> {
        self.align = align; self
    }

    /// Set text color. The default color is white.
    pub fn color<C: ToColor>(mut self, color: &C) -> Fonter<'a, 'b> {
        self.color = FromColor::from_color(color); self
    }

    /// Set border color. Before this is set, the drawn text will not be drawn
    /// with a border.
    pub fn border<C: ToColor>(mut self, color: &C) -> Fonter<'a, 'b> {
        self.border = Some(FromColor::from_color(color)); self
    }

    /// Set the z-layer to draw in.
    pub fn layer(mut self, z: f32) -> Fonter<'a, 'b> {
        self.z = z; self
    }

    /// Set the maximum width of the text area in pixels
    pub fn width(mut self, w: f32) -> Fonter<'a, 'b> {
        self.max_width = Some(w); self
    }

    /// Set the maximum number of lines to draw (lines of text before this are
    /// dropped).
    pub fn max_lines(mut self, max_lines: usize) -> Fonter<'a, 'b> {
        self.max_lines = Some(max_lines);
        self.cull_lines();
        self
    }

    /// Append to the fonter text.
    pub fn text(mut self, txt: String) -> Fonter<'a, 'b> {
        assert!(self.lines.len() > 0);
        // The last line can be added to, snip it off.
        let mut new_txt = format!("{}{}", self.lines[self.lines.len() - 1].0, txt);
        let new_len = self.lines.len() - 1;
        self.lines.truncate(new_len);
        if let Some(w) = self.max_width {
            new_txt = text::wrap_lines(&new_txt[..], &|c| self.canvas.char_width(c), w);
        }

        let new_lines: Vec<(String, f32)> = new_txt.split('\n').map(|s| (s.to_string(), self.str_width(s))).collect();
        self.lines.extend(new_lines.into_iter());
        assert!(self.lines.len() > 0);

        self.cull_lines();
        self
    }

    fn cull_lines(&mut self) {
        if let Some(n) = self.max_lines {
            if self.lines.len() > n {
                let new_len = self.lines.len() - n;
                self.lines = self.lines.split_off(new_len);
            }
        }
        self.set_longest_width();
    }

    fn set_longest_width(&mut self) {
        self.longest_line_width = self.lines.iter().map(|x| x.1)
            .fold(0.0, |a, w| if w > a { w } else { a });
    }

    /// Render the fonter text to canvas.
    pub fn draw(&mut self, offset: V2<f32>) {
        let anchor_points = Rect(
            V2(0.0, 0.0),
            V2(self.longest_line_width,
               (self.lines.len() * FONT_H as usize) as f32));
        let offset = offset - anchor_points.point(self.anchor);
        // TODO Anchoring
        for (row, s) in self.lines.iter().enumerate() {
            let y = offset.1 + FONT_H as f32 + row as f32 * FONT_H as f32;
            let line_width = s.1;
            let mut x = offset.0 + match self.align {
                Align::Left => 0.0,
                Align::Right => (self.longest_line_width - line_width),
                Align::Center => (self.longest_line_width - line_width) / 2.0,
            };
            for c in s.0.chars() {
                self.canvas.draw_char(c, V2(x, y), self.z, &self.color, self.border.as_ref());
                x += self.canvas.char_width(c);
            }
        }
    }

    fn str_width(&self, s: &str) -> f32 {
        s.chars().fold(0.0, |a, c| a + self.canvas.char_width(c))
    }

}
<commit_msg>Hack around unstable split_off<commit_after>use ::{color, Rgba, V2, Rect, ToColor, FromColor, Anchor};
use ::text;
use super::canvas::{Canvas, FONT_H};
use super::canvas_util::{CanvasUtil};

/// Text line alignment.
pub enum Align {
    Left,
    Right,
    Center
}

/// Structure for rendering text to a canvas.
pub struct Fonter<'a, 'b: 'a> {
    canvas: &'a mut Canvas<'b>,
    anchor: Anchor,
    align: Align,
    color: Rgba,
    z: f32,
    max_lines: Option<usize>,
    border: Option<Rgba>,
    max_width: Option<f32>,
    /// (Text, width) pairs.
    lines: Vec<(String, f32)>,
    longest_line_width: f32,
}

impl<'a, 'b> Fonter<'a, 'b> {
    pub fn new(canvas: &'a mut Canvas<'b>) -> Fonter<'a, 'b> {
        Fonter {
            canvas: canvas,
            anchor: Anchor::TopLeft,
            align: Align::Left,
            color: FromColor::from_color(&color::WHITE),
            z: 0.1,
            max_lines: None,
            border: None,
            max_width: None,
            lines: vec![(String::new(), 0.0)],
            longest_line_width: 0.0,
        }
    }

    /// Set the point of the text box which draw offset will anchor to.
    pub fn anchor(mut self, anchor: Anchor) -> Fonter<'a, 'b> {
        self.anchor = anchor; self
    }

    /// Set the text alignment
    pub fn align(mut self, align: Align) -> Fonter<'a, 'b> {
        self.align = align; self
    }

    /// Set text color. The default color is white.
    pub fn color<C: ToColor>(mut self, color: &C) -> Fonter<'a, 'b> {
        self.color = FromColor::from_color(color); self
    }

    /// Set border color. Before this is set, the drawn text will not be drawn
    /// with a border.
    pub fn border<C: ToColor>(mut self, color: &C) -> Fonter<'a, 'b> {
        self.border = Some(FromColor::from_color(color)); self
    }

    /// Set the z-layer to draw in.
    pub fn layer(mut self, z: f32) -> Fonter<'a, 'b> {
        self.z = z; self
    }

    /// Set the maximum width of the text area in pixels
    pub fn width(mut self, w: f32) -> Fonter<'a, 'b> {
        self.max_width = Some(w); self
    }

    /// Set the maximum number of lines to draw (lines of text before this are
    /// dropped).
    pub fn max_lines(mut self, max_lines: usize) -> Fonter<'a, 'b> {
        self.max_lines = Some(max_lines);
        self.cull_lines();
        self
    }

    /// Append to the fonter text.
    pub fn text(mut self, txt: String) -> Fonter<'a, 'b> {
        assert!(self.lines.len() > 0);
        // The last line can be added to, snip it off.
        let mut new_txt = format!("{}{}", self.lines[self.lines.len() - 1].0, txt);
        let new_len = self.lines.len() - 1;
        self.lines.truncate(new_len);
        if let Some(w) = self.max_width {
            new_txt = text::wrap_lines(&new_txt[..], &|c| self.canvas.char_width(c), w);
        }

        let new_lines: Vec<(String, f32)> = new_txt.split('\n').map(|s| (s.to_string(), self.str_width(s))).collect();
        self.lines.extend(new_lines.into_iter());
        assert!(self.lines.len() > 0);

        self.cull_lines();
        self
    }

    fn cull_lines(&mut self) {
        if let Some(n) = self.max_lines {
            // XXX: Removing items one-by-one from a Vec is iffy
            // performance, but the usual use case here should have only
            // one or two lines beyond the limit. The unstable
            // Vec::split_off method would be a more generally effective
            // approach here.
            while self.lines.len() > n {
                self.lines.remove(0);
            }
        }
        self.set_longest_width();
    }

    fn set_longest_width(&mut self) {
        self.longest_line_width = self.lines.iter().map(|x| x.1)
            .fold(0.0, |a, w| if w > a { w } else { a });
    }

    /// Render the fonter text to canvas.
    pub fn draw(&mut self, offset: V2<f32>) {
        let anchor_points = Rect(
            V2(0.0, 0.0),
            V2(self.longest_line_width,
               (self.lines.len() * FONT_H as usize) as f32));
        let offset = offset - anchor_points.point(self.anchor);
        // TODO Anchoring
        for (row, s) in self.lines.iter().enumerate() {
            let y = offset.1 + FONT_H as f32 + row as f32 * FONT_H as f32;
            let line_width = s.1;
            let mut x = offset.0 + match self.align {
                Align::Left => 0.0,
                Align::Right => (self.longest_line_width - line_width),
                Align::Center => (self.longest_line_width - line_width) / 2.0,
            };
            for c in s.0.chars() {
                self.canvas.draw_char(c, V2(x, y), self.z, &self.color, self.border.as_ref());
                x += self.canvas.char_width(c);
            }
        }
    }

    fn str_width(&self, s: &str) -> f32 {
        s.chars().fold(0.0, |a, c| a + self.canvas.char_width(c))
    }

}
<|endoftext|>


<commit_before>use std::slice;

use ruby_sys::string;

use types::Value;
use util;

pub fn new(string: &str) -> Value {
    let str = util::str_to_cstring(string);

    unsafe { string::rb_str_new_cstr(str.as_ptr()) }
}

pub fn from_value(value: Value) -> String {
    let str = unsafe { string::rb_string_value_cstr(&value) };

    util::cstr_as_string(str)
}

pub fn from_value_unchecked(value: Value) -> String {
    unsafe {
        let str = string::rb_string_value_ptr(&value) as *const u8;
        let len = string::rb_str_len(value) as usize;

        let vec = slice::from_raw_parts(str, len).to_vec();

        String::from_utf8_unchecked(vec)
    }
}

pub fn bytesize(value: Value) -> i64 {
    unsafe { string::rb_str_len(value) as i64 }
}
<commit_msg>Change binding::string::new()<commit_after>use std::slice;

use ruby_sys::string;

use types::{c_char, c_long, Value};
use util;

pub fn new(string: &str) -> Value {
    let str = string.as_ptr() as *const c_char;
    let len = string.len() as c_long;

    unsafe { string::rb_str_new(str, len) }
}

pub fn from_value(value: Value) -> String {
    let str = unsafe { string::rb_string_value_cstr(&value) };

    util::cstr_as_string(str)
}

pub fn from_value_unchecked(value: Value) -> String {
    unsafe {
        let str = string::rb_string_value_ptr(&value) as *const u8;
        let len = string::rb_str_len(value) as usize;

        let vec = slice::from_raw_parts(str, len).to_vec();

        String::from_utf8_unchecked(vec)
    }
}

pub fn bytesize(value: Value) -> i64 {
    unsafe { string::rb_str_len(value) as i64 }
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)

#![cfg(not(test))]
#![deny(warnings)]

extern crate cargo_metadata;
extern crate getopts;
extern crate serde_json as json;

use std::collections::HashSet;
use std::env;
use std::fs;
use std::hash::{Hash, Hasher};
use std::io::{self, Write};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus};
use std::str;

use getopts::{Matches, Options};

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

const SUCCESS: i32 = 0;
const FAILURE: i32 = 1;

fn execute() -> i32 {
    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("q", "quiet", "no output printed to stdout");
    opts.optflag("v", "verbose", "use verbose output");
    opts.optmulti(
        "p",
        "package",
        "specify package to format (only usable in workspaces)",
        "<package>",
    );
    opts.optflag("", "version", "print rustfmt version and exit");
    opts.optflag("", "all", "format all packages (only usable in workspaces)");

    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
    let mut is_package_arg = false;
    for arg in env::args().skip(2).take_while(|a| a != "--") {
        if arg.starts_with('-') {
            is_package_arg = arg.starts_with("--package");
        } else if !is_package_arg {
            print_usage_to_stderr(&opts, &format!("Invalid argument: `{}`.", arg));
            return FAILURE;
        } else {
            is_package_arg = false;
        }
    }

    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
        Ok(m) => m,
        Err(e) => {
            print_usage_to_stderr(&opts, &e.to_string());
            return FAILURE;
        }
    };

    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage_to_stderr(&opts, "quiet mode and verbose mode are not compatible");
            return FAILURE;
        }
    };

    if matches.opt_present("h") {
        print_usage_to_stdout(&opts, "");
        return SUCCESS;
    }

    if matches.opt_present("version") {
        return handle_command_status(get_version(verbosity), &opts);
    }

    let strategy = CargoFmtStrategy::from_matches(&matches);
    handle_command_status(format_crate(verbosity, &strategy), &opts)
}

macro_rules! print_usage {
    ($print: ident, $opts: ident, $reason: expr) => {{
        let msg = format!("{}\nusage: cargo fmt [options]", $reason);
        $print!(
            "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
             Arguments after `--` are passed to rustfmt.",
            $opts.usage(&msg)
        );
    }};
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    print_usage!(println, opts, reason);
}

fn print_usage_to_stderr(opts: &Options, reason: &str) {
    print_usage!(eprintln, opts, reason);
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn handle_command_status(status: Result<ExitStatus, io::Error>, opts: &getopts::Options) -> i32 {
    match status {
        Err(e) => {
            print_usage_to_stderr(opts, &e.to_string());
            FAILURE
        }
        Ok(status) => {
            if status.success() {
                SUCCESS
            } else {
                status.code().unwrap_or(FAILURE)
            }
        }
    }
}

fn get_version(verbosity: Verbosity) -> Result<ExitStatus, io::Error> {
    run_rustfmt(&[], &[String::from("--version")], verbosity)
}

fn format_crate(
    verbosity: Verbosity,
    strategy: &CargoFmtStrategy,
) -> Result<ExitStatus, io::Error> {
    let rustfmt_args = get_fmt_args();
    let targets = if rustfmt_args.iter().any(|s| s == "--dump-default-config") {
        HashSet::new()
    } else {
        get_targets(strategy)?
    };

    // Currently only bin and lib files get formatted
    let files: Vec<_> = targets
        .into_iter()
        .inspect(|t| {
            if verbosity == Verbosity::Verbose {
                println!("[{}] {:?}", t.kind, t.path)
            }
        })
        .map(|t| t.path)
        .collect();

    run_rustfmt(&files, &rustfmt_args, verbosity)
}

fn get_fmt_args() -> Vec<String> {
    // All arguments after -- are passed to rustfmt
    env::args().skip_while(|a| a != "--").skip(1).collect()
}

/// Target uses a `path` field for equality and hashing.
#[derive(Debug)]
pub struct Target {
    /// A path to the main source file of the target.
    path: PathBuf,
    /// A kind of target (e.g. lib, bin, example, ...).
    kind: String,
}

impl Target {
    pub fn from_target(target: &cargo_metadata::Target) -> Self {
        let path = PathBuf::from(&target.src_path);
        let canonicalized = fs::canonicalize(&path).unwrap_or(path);

        Target {
            path: canonicalized,
            kind: target.kind[0].clone(),
        }
    }
}

impl PartialEq for Target {
    fn eq(&self, other: &Target) -> bool {
        self.path == other.path
    }
}

impl Eq for Target {}

impl Hash for Target {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.path.hash(state);
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum CargoFmtStrategy {
    /// Format every packages and dependencies.
    All,
    /// Format pacakges that are specified by the command line argument.
    Some(Vec<String>),
    /// Format the root packages only.
    Root,
}

impl CargoFmtStrategy {
    pub fn from_matches(matches: &Matches) -> CargoFmtStrategy {
        match (matches.opt_present("all"), matches.opt_present("p")) {
            (false, false) => CargoFmtStrategy::Root,
            (true, _) => CargoFmtStrategy::All,
            (false, true) => CargoFmtStrategy::Some(matches.opt_strs("p")),
        }
    }
}

/// Based on the specified `CargoFmtStrategy`, returns a set of main source files.
fn get_targets(strategy: &CargoFmtStrategy) -> Result<HashSet<Target>, io::Error> {
    let mut targets = HashSet::new();

    match *strategy {
        CargoFmtStrategy::Root => get_targets_root_only(&mut targets)?,
        CargoFmtStrategy::All => get_targets_recursive(None, &mut targets, &mut HashSet::new())?,
        CargoFmtStrategy::Some(ref hitlist) => get_targets_with_hitlist(hitlist, &mut targets)?,
    }

    if targets.is_empty() {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Failed to find targets".to_owned(),
        ))
    } else {
        Ok(targets)
    }
}

fn get_targets_root_only(targets: &mut HashSet<Target>) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;

    for package in metadata.packages {
        for target in package.targets {
            targets.insert(Target::from_target(&target));
        }
    }

    Ok(())
}

fn get_targets_recursive(
    manifest_path: Option<&Path>,
    mut targets: &mut HashSet<Target>,
    visited: &mut HashSet<String>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(manifest_path)?;

    for package in metadata.packages {
        add_targets(&package.targets, &mut targets);

        // Look for local dependencies.
        for dependency in package.dependencies {
            if dependency.source.is_some() || visited.contains(&dependency.name) {
                continue;
            }

            let mut manifest_path = PathBuf::from(&package.manifest_path);

            manifest_path.pop();
            manifest_path.push(&dependency.name);
            manifest_path.push("Cargo.toml");

            if manifest_path.exists() {
                visited.insert(dependency.name);
                get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
            }
        }
    }

    Ok(())
}

fn get_targets_with_hitlist(
    hitlist: &[String],
    targets: &mut HashSet<Target>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;

    let mut workspace_hitlist: HashSet<&String> = HashSet::from_iter(hitlist);

    for package in metadata.packages {
        if workspace_hitlist.remove(&package.name) {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    if workspace_hitlist.is_empty() {
        Ok(())
    } else {
        let package = workspace_hitlist.iter().next().unwrap();
        Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("package `{}` is not a member of the workspace", package),
        ))
    }
}

fn add_targets(target_paths: &[cargo_metadata::Target], targets: &mut HashSet<Target>) {
    for target in target_paths {
        targets.insert(Target::from_target(target));
    }
}

fn run_rustfmt(
    files: &[PathBuf],
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<ExitStatus, io::Error> {
    let stdout = if verbosity == Verbosity::Quiet {
        std::process::Stdio::null()
    } else {
        std::process::Stdio::inherit()
    };

    if verbosity == Verbosity::Verbose {
        print!("rustfmt");
        for a in fmt_args {
            print!(" {}", a);
        }
        for f in files {
            print!(" {}", f.display());
        }
        println!();
    }

    let mut command = Command::new("rustfmt")
        .stdout(stdout)
        .args(files)
        .args(fmt_args)
        .spawn()
        .map_err(|e| match e.kind() {
            io::ErrorKind::NotFound => io::Error::new(
                io::ErrorKind::Other,
                "Could not run rustfmt, please make sure it is in your PATH.",
            ),
            _ => e,
        })?;

    command.wait()
}

fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
    match cargo_metadata::metadata(manifest_path) {
        Ok(metadata) => Ok(metadata),
        Err(..) => Err(io::Error::new(
            io::ErrorKind::Other,
            "`cargo manifest` failed.",
        )),
    }
}
<commit_msg>Restore cargo fmt behavior in workspaces<commit_after>// Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)

#![cfg(not(test))]
#![deny(warnings)]

extern crate cargo_metadata;
extern crate getopts;
extern crate serde_json as json;

use std::collections::HashSet;
use std::env;
use std::fs;
use std::hash::{Hash, Hasher};
use std::io::{self, Write};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus};
use std::str;

use getopts::{Matches, Options};

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

const SUCCESS: i32 = 0;
const FAILURE: i32 = 1;

fn execute() -> i32 {
    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("q", "quiet", "no output printed to stdout");
    opts.optflag("v", "verbose", "use verbose output");
    opts.optmulti(
        "p",
        "package",
        "specify package to format (only usable in workspaces)",
        "<package>",
    );
    opts.optflag("", "version", "print rustfmt version and exit");
    opts.optflag("", "all", "format all packages (only usable in workspaces)");

    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
    let mut is_package_arg = false;
    for arg in env::args().skip(2).take_while(|a| a != "--") {
        if arg.starts_with('-') {
            is_package_arg = arg.starts_with("--package");
        } else if !is_package_arg {
            print_usage_to_stderr(&opts, &format!("Invalid argument: `{}`.", arg));
            return FAILURE;
        } else {
            is_package_arg = false;
        }
    }

    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
        Ok(m) => m,
        Err(e) => {
            print_usage_to_stderr(&opts, &e.to_string());
            return FAILURE;
        }
    };

    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage_to_stderr(&opts, "quiet mode and verbose mode are not compatible");
            return FAILURE;
        }
    };

    if matches.opt_present("h") {
        print_usage_to_stdout(&opts, "");
        return SUCCESS;
    }

    if matches.opt_present("version") {
        return handle_command_status(get_version(verbosity), &opts);
    }

    let strategy = CargoFmtStrategy::from_matches(&matches);
    handle_command_status(format_crate(verbosity, &strategy), &opts)
}

macro_rules! print_usage {
    ($print: ident, $opts: ident, $reason: expr) => {{
        let msg = format!("{}\nusage: cargo fmt [options]", $reason);
        $print!(
            "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
             Arguments after `--` are passed to rustfmt.",
            $opts.usage(&msg)
        );
    }};
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    print_usage!(println, opts, reason);
}

fn print_usage_to_stderr(opts: &Options, reason: &str) {
    print_usage!(eprintln, opts, reason);
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn handle_command_status(status: Result<ExitStatus, io::Error>, opts: &getopts::Options) -> i32 {
    match status {
        Err(e) => {
            print_usage_to_stderr(opts, &e.to_string());
            FAILURE
        }
        Ok(status) => {
            if status.success() {
                SUCCESS
            } else {
                status.code().unwrap_or(FAILURE)
            }
        }
    }
}

fn get_version(verbosity: Verbosity) -> Result<ExitStatus, io::Error> {
    run_rustfmt(&[], &[String::from("--version")], verbosity)
}

fn format_crate(
    verbosity: Verbosity,
    strategy: &CargoFmtStrategy,
) -> Result<ExitStatus, io::Error> {
    let rustfmt_args = get_fmt_args();
    let targets = if rustfmt_args.iter().any(|s| s == "--dump-default-config") {
        HashSet::new()
    } else {
        get_targets(strategy)?
    };

    // Currently only bin and lib files get formatted
    let files: Vec<_> = targets
        .into_iter()
        .inspect(|t| {
            if verbosity == Verbosity::Verbose {
                println!("[{}] {:?}", t.kind, t.path)
            }
        })
        .map(|t| t.path)
        .collect();

    run_rustfmt(&files, &rustfmt_args, verbosity)
}

fn get_fmt_args() -> Vec<String> {
    // All arguments after -- are passed to rustfmt
    env::args().skip_while(|a| a != "--").skip(1).collect()
}

/// Target uses a `path` field for equality and hashing.
#[derive(Debug)]
pub struct Target {
    /// A path to the main source file of the target.
    path: PathBuf,
    /// A kind of target (e.g. lib, bin, example, ...).
    kind: String,
}

impl Target {
    pub fn from_target(target: &cargo_metadata::Target) -> Self {
        let path = PathBuf::from(&target.src_path);
        let canonicalized = fs::canonicalize(&path).unwrap_or(path);

        Target {
            path: canonicalized,
            kind: target.kind[0].clone(),
        }
    }
}

impl PartialEq for Target {
    fn eq(&self, other: &Target) -> bool {
        self.path == other.path
    }
}

impl Eq for Target {}

impl Hash for Target {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.path.hash(state);
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum CargoFmtStrategy {
    /// Format every packages and dependencies.
    All,
    /// Format pacakges that are specified by the command line argument.
    Some(Vec<String>),
    /// Format the root packages only.
    Root,
}

impl CargoFmtStrategy {
    pub fn from_matches(matches: &Matches) -> CargoFmtStrategy {
        match (matches.opt_present("all"), matches.opt_present("p")) {
            (false, false) => CargoFmtStrategy::Root,
            (true, _) => CargoFmtStrategy::All,
            (false, true) => CargoFmtStrategy::Some(matches.opt_strs("p")),
        }
    }
}

/// Based on the specified `CargoFmtStrategy`, returns a set of main source files.
fn get_targets(strategy: &CargoFmtStrategy) -> Result<HashSet<Target>, io::Error> {
    let mut targets = HashSet::new();

    match *strategy {
        CargoFmtStrategy::Root => get_targets_root_only(&mut targets)?,
        CargoFmtStrategy::All => get_targets_recursive(None, &mut targets, &mut HashSet::new())?,
        CargoFmtStrategy::Some(ref hitlist) => get_targets_with_hitlist(hitlist, &mut targets)?,
    }

    if targets.is_empty() {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Failed to find targets".to_owned(),
        ))
    } else {
        Ok(targets)
    }
}

fn get_targets_root_only(targets: &mut HashSet<Target>) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;
    let current_dir = env::current_dir()?;
    let current_dir_manifest = current_dir.join("Cargo.toml");
    let workspace_root_path = PathBuf::from(&metadata.workspace_root);
    let in_workspace_root = workspace_root_path == current_dir;

    for package in metadata.packages {
        if in_workspace_root || PathBuf::from(&package.manifest_path) == current_dir_manifest {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    Ok(())
}

fn get_targets_recursive(
    manifest_path: Option<&Path>,
    mut targets: &mut HashSet<Target>,
    visited: &mut HashSet<String>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(manifest_path)?;

    for package in metadata.packages {
        add_targets(&package.targets, &mut targets);

        // Look for local dependencies.
        for dependency in package.dependencies {
            if dependency.source.is_some() || visited.contains(&dependency.name) {
                continue;
            }

            let mut manifest_path = PathBuf::from(&package.manifest_path);

            manifest_path.pop();
            manifest_path.push(&dependency.name);
            manifest_path.push("Cargo.toml");

            if manifest_path.exists() {
                visited.insert(dependency.name);
                get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
            }
        }
    }

    Ok(())
}

fn get_targets_with_hitlist(
    hitlist: &[String],
    targets: &mut HashSet<Target>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;

    let mut workspace_hitlist: HashSet<&String> = HashSet::from_iter(hitlist);

    for package in metadata.packages {
        if workspace_hitlist.remove(&package.name) {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    if workspace_hitlist.is_empty() {
        Ok(())
    } else {
        let package = workspace_hitlist.iter().next().unwrap();
        Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("package `{}` is not a member of the workspace", package),
        ))
    }
}

fn add_targets(target_paths: &[cargo_metadata::Target], targets: &mut HashSet<Target>) {
    for target in target_paths {
        targets.insert(Target::from_target(target));
    }
}

fn run_rustfmt(
    files: &[PathBuf],
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<ExitStatus, io::Error> {
    let stdout = if verbosity == Verbosity::Quiet {
        std::process::Stdio::null()
    } else {
        std::process::Stdio::inherit()
    };

    if verbosity == Verbosity::Verbose {
        print!("rustfmt");
        for a in fmt_args {
            print!(" {}", a);
        }
        for f in files {
            print!(" {}", f.display());
        }
        println!();
    }

    let mut command = Command::new("rustfmt")
        .stdout(stdout)
        .args(files)
        .args(fmt_args)
        .spawn()
        .map_err(|e| match e.kind() {
            io::ErrorKind::NotFound => io::Error::new(
                io::ErrorKind::Other,
                "Could not run rustfmt, please make sure it is in your PATH.",
            ),
            _ => e,
        })?;

    command.wait()
}

fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
    match cargo_metadata::metadata(manifest_path) {
        Ok(metadata) => Ok(metadata),
        Err(..) => Err(io::Error::new(
            io::ErrorKind::Other,
            "`cargo manifest` failed.",
        )),
    }
}
<|endoftext|>


<commit_before>use std::process::{Command, Stdio};
use std::path::{Path, PathBuf};
use std::io::{BufRead, BufReader};
use std::ffi::OsString;
use std::env;
use std::thread;

use cargo_metadata;
use serde_json;

mod cargo_output;
mod rustc_diagnostic;
mod diagnostic_formatter;

use self::cargo_output::CargoOutput;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum BuildType {
    Debug,
    Release
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Profile {
    Main,
    Test,
    Bench
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum TargetKind {
    Lib,
    Bin,
    Example,
    Test,
    Bench
}

#[derive(Clone, Debug)]
pub struct CargoProject {
    pub packages: Vec< CargoPackage >
}

#[derive(Clone, Debug)]
pub struct CargoPackage {
    pub name: String,
    pub manifest_path: PathBuf,
    pub crate_root: PathBuf,
    pub targets: Vec< CargoTarget >
}

#[derive(Clone, Debug)]
pub struct CargoTarget {
    pub name: String,
    pub kind: TargetKind,
    pub source_directory: PathBuf
}

impl CargoProject {
    pub fn new( manifest_path: Option< &str > ) -> CargoProject {
        let metadata = cargo_metadata::metadata( manifest_path.map( |path| Path::new( path ) ) ).unwrap();
        CargoProject {
            packages: metadata.packages.into_iter().map( |package| {
                let manifest_path: PathBuf = package.manifest_path.into();
                CargoPackage {
                    name: package.name,
                    crate_root: manifest_path.parent().unwrap().into(),
                    manifest_path: manifest_path,
                    targets: package.targets.into_iter().filter_map( |target| {
                        Some( CargoTarget {
                            name: target.name,
                            kind: match target.kind[ 0 ].as_str() {
                                "lib" => TargetKind::Lib,
                                "bin" => TargetKind::Bin,
                                "example" => TargetKind::Example,
                                "test" => TargetKind::Test,
                                "bench" => TargetKind::Bench,
                                "custom-build" => return None,
                                _ => panic!( "Unknown target kind: '{}'", target.kind[ 0 ] )
                            },
                            source_directory: Into::< PathBuf >::into( target.src_path ).parent().unwrap().into()
                        })
                    }).collect()
                }
            }).collect()
        }
    }

    pub fn default_package( &self ) -> &CargoPackage {
        &self.packages[ 0 ]
    }
}

#[derive(Clone, Debug)]
pub enum BuildTarget {
    Lib( String, Profile ),
    Bin( String, Profile ),
    ExampleBin( String ),
    IntegrationTest( String ),
    IntegrationBench( String )
}

#[derive(Clone, Debug)]
pub struct BuildConfig {
    pub build_target: BuildTarget,
    pub build_type: BuildType,
    pub triplet: Option< String >,
    pub package: Option< String >,
    pub features: Vec< String >,
    pub no_default_features: bool,
    pub enable_all_features: bool,
    pub extra_paths: Vec< PathBuf >,
    pub extra_rustflags: Vec< String >,
    pub extra_environment: Vec< (String, String) >
}

fn profile_to_arg( profile: Profile ) -> &'static str {
    match profile {
        Profile::Main => "dev",
        Profile::Test => "test",
        Profile::Bench => "bench"
    }
}

pub fn target_to_build_target( target: &CargoTarget, profile: Profile ) -> BuildTarget {
    match target.kind {
        TargetKind::Lib => BuildTarget::Lib( target.name.clone(), profile ),
        TargetKind::Bin => BuildTarget::Bin( target.name.clone(), profile ),
        TargetKind::Example => BuildTarget::ExampleBin( target.name.clone() ),
        TargetKind::Test => BuildTarget::IntegrationTest( target.name.clone() ),
        TargetKind::Bench => BuildTarget::IntegrationBench( target.name.clone() )
    }
}

impl BuildConfig {
    fn as_command( &self ) -> Command {
        let mut command = Command::new( "cargo" );
        command.arg( "rustc" );
        command.arg( "--message-format" );
        command.arg( "json" );
        command.arg( "--color" );
        command.arg( "always" );

        if let Some( ref triplet ) = self.triplet {
            command.arg( "--target" ).arg( triplet.as_str() );
        }

        if let Some( ref package ) = self.package {
            command.arg( "--package" ).arg( package.as_str() );
        }

        match self.build_type {
            BuildType::Debug => {},
            BuildType::Release => {
                command.arg( "--release" );
            }
        }

        match self.build_target {
            BuildTarget::Lib( _, profile ) => {
                command
                    .arg( "--profile" ).arg( profile_to_arg( profile ) )
                    .arg( "--lib" );
            },
            BuildTarget::Bin( ref name, profile ) => {
                command
                    .arg( "--profile" ).arg( profile_to_arg( profile ) )
                    .arg( "--bin" ).arg( name.as_str() );
            },
            BuildTarget::ExampleBin( ref name ) => {
                command.arg( "--example" ).arg( name.as_str() );
            },
            BuildTarget::IntegrationTest( ref name ) => {
                command.arg( "--test" ).arg( name.as_str() );
            },
            BuildTarget::IntegrationBench( ref name ) => {
                command.arg( "--bench" ).arg( name.as_str() );
            }
        }

        if self.no_default_features {
            command.arg( "--no-default-features" );
        }

        if self.enable_all_features {
            command.arg( "--all-features" );
        }

        if !self.features.is_empty() {
            command.arg( "--features" );
            command.arg( &self.features.join( " " ) );
        }

        command
    }

    pub fn build( &self ) -> CargoResult {
        let mut result = self.build_internal();
        if result.is_ok() == false {
            return result;
        }

        // HACK: For some reason when you install emscripten for the first time
        // the first build is always a dud (it produces no artifacts), so we retry once.
        let is_emscripten = self.triplet.as_ref().map( |triplet| {
            triplet == "wasm32-unknown-emscripten" || triplet == "asmjs-unknown-emscripten"
        }).unwrap_or( false );

        if is_emscripten {
            let no_js_generated = result
                .artifacts()
                .iter()
                .find( |artifact| artifact.extension().map( |ext| ext == "js" ).unwrap_or( false ) )
                .is_none();

            if no_js_generated {
                debug!( "No artifacts were generated yet build succeeded; retrying..." );
                result = self.build_internal();
            }
        }

        return result;
    }

    fn build_internal( &self ) -> CargoResult {
        let mut command = self.as_command();

        let mut paths = env::var_os( "PATH" )
            .map( |paths| env::split_paths( &paths ).collect() )
            .unwrap_or( Vec::new() );

        for path in &self.extra_paths {
            paths.push( path.into() );
        }

        let new_paths = env::join_paths( paths ).unwrap();
        command.env( "PATH", new_paths );

        let mut rustflags = env::var_os( "RUSTFLAGS" ).unwrap_or( OsString::new() );
        for flag in &self.extra_rustflags {
            if !rustflags.is_empty() {
                rustflags.push( " " );
            }
            rustflags.push( flag );
        }
        command.env( "RUSTFLAGS", rustflags );

        for &(ref key, ref value) in &self.extra_environment {
            command.env( key, value );
        }

        command.stdout( Stdio::piped() );
        command.stderr( Stdio::piped() );

        debug!( "Launching cargo: {:?}", command );
        let mut child = match command.spawn() {
            Ok( child ) => child,
            Err( _ ) => {
                return CargoResult {
                    status: None,
                    artifacts: Vec::new()
                };
            }
        };

        let stderr = BufReader::new( child.stderr.take().unwrap() );
        let stdout = BufReader::new( child.stdout.take().unwrap() );

        thread::spawn( move || {
            let mut skip = 0;
            for line in stderr.lines() {
                let line = match line {
                    Ok( line ) => line,
                    Err( _ ) => break
                };

                if skip > 0 {
                    skip -= 1;
                    continue;
                }

                // This is really ugly, so let's skip it.
                if line.trim() == "Caused by:" {
                    skip += 1;
                    continue;
                }

                eprintln!( "{}", line );
            }
        });

        let mut artifacts: Vec< PathBuf > = Vec::new();
        for line in stdout.lines() {
            let line = match line {
                Ok( line ) => line,
                Err( _ ) => break
            };

            let line = line.trim();
            if line.is_empty() {
                continue;
            }

            let json: serde_json::Value = serde_json::from_str( &line ).expect( "failed to parse cargo output" );
            let line = serde_json::to_string_pretty( &json ).unwrap();
            if let Some( output ) = CargoOutput::parse( &line ) {
                match output {
                    CargoOutput::Message( message ) => {
                        diagnostic_formatter::print( &message );
                    },
                    CargoOutput::Artifact( artifact ) => {
                        for filename in artifact.filenames {
                            debug!( "Built artifact: {}", filename );
                            // NOTE: Since we extract the paths from the JSON
                            //       we get a list of artifacts as `String`s instead of `PathBuf`s.
                            artifacts.push( filename.into() );
                        }
                    },
                    _ => {}
                }
            }
        }

        let result = child.wait();
        let status = result.unwrap().code().expect( "failed to grab cargo status code" );
        debug!( "Cargo finished with status: {}", status );

        // For some reason when building tests cargo doesn't treat
        // the `.wasm` file as an artifact.
        if status == 0 && self.triplet.as_ref().map( |triplet| triplet == "wasm32-unknown-emscripten" ).unwrap_or( false ) {
            match self.build_target {
                BuildTarget::Bin( _, Profile::Test ) | BuildTarget::Lib( _, Profile::Test ) => {
                    let wasm_path = {
                        let main_artifact = artifacts.iter()
                            .find( |artifact| artifact.extension().map( |ext| ext == "js" ).unwrap_or( false ) );

                        if let Some( main_artifact ) = main_artifact {
                            let filename = main_artifact.file_name().unwrap();
                            let wasm_path = main_artifact.parent().unwrap().join( "deps" ).join( filename ).with_extension( "wasm" );
                            assert!( wasm_path.exists(), "internal error: wasm doesn't exist where I expected it to be" );

                            Some( wasm_path )
                        } else {
                            None
                        }
                    };

                    if let Some( wasm_path ) = wasm_path {
                        artifacts.push( wasm_path );
                    }
                },
                _ => {}
            }
        }

        CargoResult {
            status: Some( status ),
            artifacts
        }
    }
}

pub struct CargoResult {
    status: Option< i32 >,
    artifacts: Vec< PathBuf >
}

impl CargoResult {
    pub fn is_ok( &self ) -> bool {
        self.status == Some( 0 )
    }

    pub fn artifacts( &self ) -> &[PathBuf] {
        &self.artifacts
    }

    pub fn add_artifact< P: AsRef< Path > >( &mut self, artifact: P ) {
        self.artifacts.push( artifact.as_ref().to_owned() );
    }
}
<commit_msg>Add extra debug logs<commit_after>use std::process::{Command, Stdio};
use std::path::{Path, PathBuf};
use std::io::{BufRead, BufReader};
use std::ffi::OsString;
use std::env;
use std::thread;

use cargo_metadata;
use serde_json;

mod cargo_output;
mod rustc_diagnostic;
mod diagnostic_formatter;

use self::cargo_output::CargoOutput;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum BuildType {
    Debug,
    Release
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Profile {
    Main,
    Test,
    Bench
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum TargetKind {
    Lib,
    Bin,
    Example,
    Test,
    Bench
}

#[derive(Clone, Debug)]
pub struct CargoProject {
    pub packages: Vec< CargoPackage >
}

#[derive(Clone, Debug)]
pub struct CargoPackage {
    pub name: String,
    pub manifest_path: PathBuf,
    pub crate_root: PathBuf,
    pub targets: Vec< CargoTarget >
}

#[derive(Clone, Debug)]
pub struct CargoTarget {
    pub name: String,
    pub kind: TargetKind,
    pub source_directory: PathBuf
}

impl CargoProject {
    pub fn new( manifest_path: Option< &str > ) -> CargoProject {
        let metadata = cargo_metadata::metadata( manifest_path.map( |path| Path::new( path ) ) ).unwrap();
        CargoProject {
            packages: metadata.packages.into_iter().map( |package| {
                let manifest_path: PathBuf = package.manifest_path.into();
                CargoPackage {
                    name: package.name,
                    crate_root: manifest_path.parent().unwrap().into(),
                    manifest_path: manifest_path,
                    targets: package.targets.into_iter().filter_map( |target| {
                        Some( CargoTarget {
                            name: target.name,
                            kind: match target.kind[ 0 ].as_str() {
                                "lib" => TargetKind::Lib,
                                "bin" => TargetKind::Bin,
                                "example" => TargetKind::Example,
                                "test" => TargetKind::Test,
                                "bench" => TargetKind::Bench,
                                "custom-build" => return None,
                                _ => panic!( "Unknown target kind: '{}'", target.kind[ 0 ] )
                            },
                            source_directory: Into::< PathBuf >::into( target.src_path ).parent().unwrap().into()
                        })
                    }).collect()
                }
            }).collect()
        }
    }

    pub fn default_package( &self ) -> &CargoPackage {
        &self.packages[ 0 ]
    }
}

#[derive(Clone, Debug)]
pub enum BuildTarget {
    Lib( String, Profile ),
    Bin( String, Profile ),
    ExampleBin( String ),
    IntegrationTest( String ),
    IntegrationBench( String )
}

#[derive(Clone, Debug)]
pub struct BuildConfig {
    pub build_target: BuildTarget,
    pub build_type: BuildType,
    pub triplet: Option< String >,
    pub package: Option< String >,
    pub features: Vec< String >,
    pub no_default_features: bool,
    pub enable_all_features: bool,
    pub extra_paths: Vec< PathBuf >,
    pub extra_rustflags: Vec< String >,
    pub extra_environment: Vec< (String, String) >
}

fn profile_to_arg( profile: Profile ) -> &'static str {
    match profile {
        Profile::Main => "dev",
        Profile::Test => "test",
        Profile::Bench => "bench"
    }
}

pub fn target_to_build_target( target: &CargoTarget, profile: Profile ) -> BuildTarget {
    match target.kind {
        TargetKind::Lib => BuildTarget::Lib( target.name.clone(), profile ),
        TargetKind::Bin => BuildTarget::Bin( target.name.clone(), profile ),
        TargetKind::Example => BuildTarget::ExampleBin( target.name.clone() ),
        TargetKind::Test => BuildTarget::IntegrationTest( target.name.clone() ),
        TargetKind::Bench => BuildTarget::IntegrationBench( target.name.clone() )
    }
}

impl BuildConfig {
    fn as_command( &self ) -> Command {
        let mut command = Command::new( "cargo" );
        command.arg( "rustc" );
        command.arg( "--message-format" );
        command.arg( "json" );
        command.arg( "--color" );
        command.arg( "always" );

        if let Some( ref triplet ) = self.triplet {
            command.arg( "--target" ).arg( triplet.as_str() );
        }

        if let Some( ref package ) = self.package {
            command.arg( "--package" ).arg( package.as_str() );
        }

        match self.build_type {
            BuildType::Debug => {},
            BuildType::Release => {
                command.arg( "--release" );
            }
        }

        match self.build_target {
            BuildTarget::Lib( _, profile ) => {
                command
                    .arg( "--profile" ).arg( profile_to_arg( profile ) )
                    .arg( "--lib" );
            },
            BuildTarget::Bin( ref name, profile ) => {
                command
                    .arg( "--profile" ).arg( profile_to_arg( profile ) )
                    .arg( "--bin" ).arg( name.as_str() );
            },
            BuildTarget::ExampleBin( ref name ) => {
                command.arg( "--example" ).arg( name.as_str() );
            },
            BuildTarget::IntegrationTest( ref name ) => {
                command.arg( "--test" ).arg( name.as_str() );
            },
            BuildTarget::IntegrationBench( ref name ) => {
                command.arg( "--bench" ).arg( name.as_str() );
            }
        }

        if self.no_default_features {
            command.arg( "--no-default-features" );
        }

        if self.enable_all_features {
            command.arg( "--all-features" );
        }

        if !self.features.is_empty() {
            command.arg( "--features" );
            command.arg( &self.features.join( " " ) );
        }

        command
    }

    pub fn build( &self ) -> CargoResult {
        let mut result = self.build_internal();
        if result.is_ok() == false {
            return result;
        }

        // HACK: For some reason when you install emscripten for the first time
        // the first build is always a dud (it produces no artifacts), so we retry once.
        let is_emscripten = self.triplet.as_ref().map( |triplet| {
            triplet == "wasm32-unknown-emscripten" || triplet == "asmjs-unknown-emscripten"
        }).unwrap_or( false );

        if is_emscripten {
            let no_js_generated = result
                .artifacts()
                .iter()
                .find( |artifact| artifact.extension().map( |ext| ext == "js" ).unwrap_or( false ) )
                .is_none();

            if no_js_generated {
                debug!( "No artifacts were generated yet build succeeded; retrying..." );
                result = self.build_internal();
            }
        }

        return result;
    }

    fn build_internal( &self ) -> CargoResult {
        let mut command = self.as_command();

        let mut paths = env::var_os( "PATH" )
            .map( |paths| env::split_paths( &paths ).collect() )
            .unwrap_or( Vec::new() );

        for path in &self.extra_paths {
            paths.push( path.into() );
        }

        let new_paths = env::join_paths( paths ).unwrap();
        debug!( "Will launch cargo with PATH: {:?}", new_paths );
        command.env( "PATH", new_paths );

        let mut rustflags = env::var_os( "RUSTFLAGS" ).unwrap_or( OsString::new() );
        for flag in &self.extra_rustflags {
            if !rustflags.is_empty() {
                rustflags.push( " " );
            }
            rustflags.push( flag );
        }
        debug!( "Will launch cargo with RUSTFLAGS: {:?}", rustflags );
        command.env( "RUSTFLAGS", rustflags );

        for &(ref key, ref value) in &self.extra_environment {
            debug!( "Will launch cargo with variable \"{}\" set to \"{}\"", key, value );
            command.env( key, value );
        }

        command.stdout( Stdio::piped() );
        command.stderr( Stdio::piped() );

        debug!( "Launching cargo: {:?}", command );
        let mut child = match command.spawn() {
            Ok( child ) => child,
            Err( _ ) => {
                return CargoResult {
                    status: None,
                    artifacts: Vec::new()
                };
            }
        };

        let stderr = BufReader::new( child.stderr.take().unwrap() );
        let stdout = BufReader::new( child.stdout.take().unwrap() );

        thread::spawn( move || {
            let mut skip = 0;
            for line in stderr.lines() {
                let line = match line {
                    Ok( line ) => line,
                    Err( _ ) => break
                };

                if skip > 0 {
                    skip -= 1;
                    continue;
                }

                // This is really ugly, so let's skip it.
                if line.trim() == "Caused by:" {
                    skip += 1;
                    continue;
                }

                eprintln!( "{}", line );
            }
        });

        let mut artifacts: Vec< PathBuf > = Vec::new();
        for line in stdout.lines() {
            let line = match line {
                Ok( line ) => line,
                Err( _ ) => break
            };

            let line = line.trim();
            if line.is_empty() {
                continue;
            }

            let json: serde_json::Value = serde_json::from_str( &line ).expect( "failed to parse cargo output" );
            let line = serde_json::to_string_pretty( &json ).unwrap();
            if let Some( output ) = CargoOutput::parse( &line ) {
                match output {
                    CargoOutput::Message( message ) => {
                        diagnostic_formatter::print( &message );
                    },
                    CargoOutput::Artifact( artifact ) => {
                        for filename in artifact.filenames {
                            debug!( "Built artifact: {}", filename );
                            // NOTE: Since we extract the paths from the JSON
                            //       we get a list of artifacts as `String`s instead of `PathBuf`s.
                            artifacts.push( filename.into() );
                        }
                    },
                    _ => {}
                }
            }
        }

        let result = child.wait();
        let status = result.unwrap().code().expect( "failed to grab cargo status code" );
        debug!( "Cargo finished with status: {}", status );

        // For some reason when building tests cargo doesn't treat
        // the `.wasm` file as an artifact.
        if status == 0 && self.triplet.as_ref().map( |triplet| triplet == "wasm32-unknown-emscripten" ).unwrap_or( false ) {
            match self.build_target {
                BuildTarget::Bin( _, Profile::Test ) | BuildTarget::Lib( _, Profile::Test ) => {
                    let wasm_path = {
                        let main_artifact = artifacts.iter()
                            .find( |artifact| artifact.extension().map( |ext| ext == "js" ).unwrap_or( false ) );

                        if let Some( main_artifact ) = main_artifact {
                            let filename = main_artifact.file_name().unwrap();
                            let wasm_path = main_artifact.parent().unwrap().join( "deps" ).join( filename ).with_extension( "wasm" );
                            assert!( wasm_path.exists(), "internal error: wasm doesn't exist where I expected it to be" );

                            Some( wasm_path )
                        } else {
                            None
                        }
                    };

                    if let Some( wasm_path ) = wasm_path {
                        artifacts.push( wasm_path );
                    }
                },
                _ => {}
            }
        }

        CargoResult {
            status: Some( status ),
            artifacts
        }
    }
}

pub struct CargoResult {
    status: Option< i32 >,
    artifacts: Vec< PathBuf >
}

impl CargoResult {
    pub fn is_ok( &self ) -> bool {
        self.status == Some( 0 )
    }

    pub fn artifacts( &self ) -> &[PathBuf] {
        &self.artifacts
    }

    pub fn add_artifact< P: AsRef< Path > >( &mut self, artifact: P ) {
        self.artifacts.push( artifact.as_ref().to_owned() );
    }
}
<|endoftext|>


<commit_before>use tempdir;

use std::env;
use std::fs;
use std::io;
use std::io::Write;
use std::path;
use std::process;

struct Project {
    root: tempdir::TempDir,
    files: Vec<(path::PathBuf, Vec<u8>)>,
}

impl Project {
    fn new() -> Project {
        Project {
            root: tempdir::TempDir::new("built_integration").unwrap(),
            files: Vec::new(),
        }
    }

    fn add_file<N: Into<path::PathBuf>, C: Into<Vec<u8>>>(&mut self, name: N, content: C) {
        self.files.push((name.into(), content.into()))
    }

    /// Hold on to the tempdir, it will be removed when dropped!
    fn create(self) -> io::Result<tempdir::TempDir> {
        fs::DirBuilder::new()
            .create(&self.root.path().join("src"))
            .unwrap();
        for (name, content) in self.files {
            let fname = self.root.path().join(name);
            let mut file = fs::File::create(&fname)?;
            file.write_all(&content)?;
        }
        Ok(self.root)
    }

    #[cfg(feature = "git2")]
    fn init_git(&self) -> git2::Repository {
        git2::Repository::init(&self.root).expect("git-init failed")
    }
}

/// Tries to find built's Cargo.toml, panics if it ends up in /
fn get_built_root() -> path::PathBuf {
    env::current_exe()
        .map(|path| {
            let mut path = path;
            loop {
                if path.join("Cargo.toml").exists() {
                    break;
                }
                path = path::PathBuf::from(path.parent().unwrap());
            }
            path
        })
        .unwrap()
}

#[test]
fn new_testbox() {
    let mut p = Project::new();

    let built_root = get_built_root();

    p.add_file("Cargo.toml",
               format!("
[package]
name = \"testbox\"
version = \"1.2.3-rc1\"
authors = [\"Joe\", \"Bob\", \"Harry:Potter\"]
build = \"build.rs\"
description = \"xobtset\"
homepage = \"localhost\"

[dependencies]
chrono = \"0.4\"
semver = \"0.9\"
built = {{ path = {:?}, features=[\"git2\", \"chrono\", \"semver\"] }}

[build-dependencies]
built = {{ path = {:?}, features=[\"git2\", \"chrono\", \"semver\"] }}

[features]
default = [\"SuperAwesome\", \"MegaAwesome\"]
SuperAwesome = []
MegaAwesome = []", &built_root, &built_root));

    p.add_file(
        "build.rs",
        r#"
use std::env;
use std::path;
extern crate built;

fn main() {
    // Teleport to a CI-platform, should get detected
    env::set_var("CONTINUOUS_INTEGRATION", "1");

    let mut options = built::Options::default();
    options.set_dependencies(true);
    let src = env::var("CARGO_MANIFEST_DIR").unwrap();
    let dst = path::Path::new(&env::var("OUT_DIR").unwrap()).join("built.rs");
    built::write_built_file_with_opts(&options, &src, &dst).unwrap();
}"#,
    );

    p.add_file(
        "src/main.rs",
        r#"
//! The testbox.
#![deny(warnings, bad_style, future_incompatible, unused, missing_docs, unused_comparisons)]

extern crate built;
extern crate semver;
extern crate chrono;

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

fn main() {
    assert_eq!(built_info::GIT_VERSION, None);
    assert!(built_info::CI_PLATFORM.is_some());
    assert_eq!(built_info::PKG_VERSION, "1.2.3-rc1");
    assert_eq!(built_info::PKG_VERSION_MAJOR, "1");
    assert_eq!(built_info::PKG_VERSION_MINOR, "2");
    assert_eq!(built_info::PKG_VERSION_PATCH, "3");
    assert_eq!(built_info::PKG_VERSION_PRE, "rc1");
    assert_eq!(built_info::PKG_AUTHORS, "Joe:Bob:Harry:Potter");
    assert_eq!(built_info::PKG_NAME, "testbox");
    assert_eq!(built_info::PKG_DESCRIPTION, "xobtset");
    assert_eq!(built_info::PKG_HOMEPAGE, "localhost");
    assert!(built_info::NUM_JOBS > 0);
    assert!(built_info::OPT_LEVEL == "0");
    assert!(built_info::DEBUG);
    assert_eq!(built_info::PROFILE, "debug");
    assert_eq!(built_info::FEATURES,
               ["DEFAULT", "MEGAAWESOME", "SUPERAWESOME"]);
    assert_eq!(built_info::FEATURES_STR,
               "DEFAULT, MEGAAWESOME, SUPERAWESOME");
    assert_ne!(built_info::RUSTC_VERSION, "");
    assert_ne!(built_info::RUSTDOC_VERSION, "");
    assert_ne!(built_info::DEPENDENCIES_STR, "");
    assert_ne!(built_info::HOST, "");
    assert_ne!(built_info::TARGET, "");
    assert_ne!(built_info::RUSTC, "");
    assert_ne!(built_info::RUSTDOC, "");
    assert_ne!(built_info::CFG_TARGET_ARCH, "");
    assert_ne!(built_info::CFG_ENDIAN, "");
    assert_ne!(built_info::CFG_ENV, "");
    assert_ne!(built_info::CFG_FAMILY, "");
    assert_ne!(built_info::CFG_OS, "");
    assert_ne!(built_info::CFG_POINTER_WIDTH, "");

    assert!(built::util::parse_versions(built_info::DEPENDENCIES.iter())
        .any(|(name, ver)| name == "toml" && ver >= semver::Version::parse("0.1.0").unwrap()));

    assert!((chrono::offset::Utc::now() - built::util::strptime(built_info::BUILT_TIME_UTC)).num_days() <= 1);
}"#,
    );

    let root = p.create().expect("Creating the project failed");
    let cargo_result = process::Command::new("cargo")
        .current_dir(&root)
        .arg("run")
        .arg("-q")
        .output()
        .expect("cargo failed");
    if !cargo_result.status.success() {
        panic!(
            "cargo failed with {}",
            String::from_utf8_lossy(&cargo_result.stderr)
        );
    }
}

#[test]
#[cfg(feature = "git2")]
fn empty_git() {
    // Issue #7, git can be there and still fail
    let mut p = Project::new();
    let built_root = get_built_root();
    p.add_file(
        "Cargo.toml",
        format!(
            r#"
[package]
name = "testbox"
version = "0.0.1"
build = "build.rs"

[build-dependencies]
built = {{ path = {:?} }}"#,
            &built_root
        ),
    );
    p.add_file(
        "build.rs",
        r#"
extern crate built;
fn main() {
    built::write_built_file().expect("writing failed");
}"#,
    );
    p.add_file("src/main.rs", "fn main() {}");
    p.init_git();
    let root = p.create().expect("Creating the project failed");
    let cargo_result = process::Command::new("cargo")
        .current_dir(&root)
        .arg("run")
        .output()
        .expect("cargo failed");
    if !cargo_result.status.success() {
        panic!(
            "cargo failed with {}",
            String::from_utf8_lossy(&cargo_result.stderr)
        );
    }
}
<commit_msg>Rustfmt<commit_after>use tempdir;

use std::env;
use std::fs;
use std::io;
use std::io::Write;
use std::path;
use std::process;

struct Project {
    root: tempdir::TempDir,
    files: Vec<(path::PathBuf, Vec<u8>)>,
}

impl Project {
    fn new() -> Project {
        Project {
            root: tempdir::TempDir::new("built_integration").unwrap(),
            files: Vec::new(),
        }
    }

    fn add_file<N: Into<path::PathBuf>, C: Into<Vec<u8>>>(&mut self, name: N, content: C) {
        self.files.push((name.into(), content.into()))
    }

    /// Hold on to the tempdir, it will be removed when dropped!
    fn create(self) -> io::Result<tempdir::TempDir> {
        fs::DirBuilder::new()
            .create(&self.root.path().join("src"))
            .unwrap();
        for (name, content) in self.files {
            let fname = self.root.path().join(name);
            let mut file = fs::File::create(&fname)?;
            file.write_all(&content)?;
        }
        Ok(self.root)
    }

    #[cfg(feature = "git2")]
    fn init_git(&self) -> git2::Repository {
        git2::Repository::init(&self.root).expect("git-init failed")
    }
}

/// Tries to find built's Cargo.toml, panics if it ends up in /
fn get_built_root() -> path::PathBuf {
    env::current_exe()
        .map(|path| {
            let mut path = path;
            loop {
                if path.join("Cargo.toml").exists() {
                    break;
                }
                path = path::PathBuf::from(path.parent().unwrap());
            }
            path
        })
        .unwrap()
}

#[test]
fn new_testbox() {
    let mut p = Project::new();

    let built_root = get_built_root();

    p.add_file(
        "Cargo.toml",
        format!(
            "
[package]
name = \"testbox\"
version = \"1.2.3-rc1\"
authors = [\"Joe\", \"Bob\", \"Harry:Potter\"]
build = \"build.rs\"
description = \"xobtset\"
homepage = \"localhost\"

[dependencies]
chrono = \"0.4\"
semver = \"0.9\"
built = {{ path = {:?}, features=[\"git2\", \"chrono\", \"semver\"] }}

[build-dependencies]
built = {{ path = {:?}, features=[\"git2\", \"chrono\", \"semver\"] }}

[features]
default = [\"SuperAwesome\", \"MegaAwesome\"]
SuperAwesome = []
MegaAwesome = []",
            &built_root, &built_root
        ),
    );

    p.add_file(
        "build.rs",
        r#"
use std::env;
use std::path;
extern crate built;

fn main() {
    // Teleport to a CI-platform, should get detected
    env::set_var("CONTINUOUS_INTEGRATION", "1");

    let mut options = built::Options::default();
    options.set_dependencies(true);
    let src = env::var("CARGO_MANIFEST_DIR").unwrap();
    let dst = path::Path::new(&env::var("OUT_DIR").unwrap()).join("built.rs");
    built::write_built_file_with_opts(&options, &src, &dst).unwrap();
}"#,
    );

    p.add_file(
        "src/main.rs",
        r#"
//! The testbox.
#![deny(warnings, bad_style, future_incompatible, unused, missing_docs, unused_comparisons)]

extern crate built;
extern crate semver;
extern crate chrono;

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

fn main() {
    assert_eq!(built_info::GIT_VERSION, None);
    assert!(built_info::CI_PLATFORM.is_some());
    assert_eq!(built_info::PKG_VERSION, "1.2.3-rc1");
    assert_eq!(built_info::PKG_VERSION_MAJOR, "1");
    assert_eq!(built_info::PKG_VERSION_MINOR, "2");
    assert_eq!(built_info::PKG_VERSION_PATCH, "3");
    assert_eq!(built_info::PKG_VERSION_PRE, "rc1");
    assert_eq!(built_info::PKG_AUTHORS, "Joe:Bob:Harry:Potter");
    assert_eq!(built_info::PKG_NAME, "testbox");
    assert_eq!(built_info::PKG_DESCRIPTION, "xobtset");
    assert_eq!(built_info::PKG_HOMEPAGE, "localhost");
    assert!(built_info::NUM_JOBS > 0);
    assert!(built_info::OPT_LEVEL == "0");
    assert!(built_info::DEBUG);
    assert_eq!(built_info::PROFILE, "debug");
    assert_eq!(built_info::FEATURES,
               ["DEFAULT", "MEGAAWESOME", "SUPERAWESOME"]);
    assert_eq!(built_info::FEATURES_STR,
               "DEFAULT, MEGAAWESOME, SUPERAWESOME");
    assert_ne!(built_info::RUSTC_VERSION, "");
    assert_ne!(built_info::RUSTDOC_VERSION, "");
    assert_ne!(built_info::DEPENDENCIES_STR, "");
    assert_ne!(built_info::HOST, "");
    assert_ne!(built_info::TARGET, "");
    assert_ne!(built_info::RUSTC, "");
    assert_ne!(built_info::RUSTDOC, "");
    assert_ne!(built_info::CFG_TARGET_ARCH, "");
    assert_ne!(built_info::CFG_ENDIAN, "");
    assert_ne!(built_info::CFG_ENV, "");
    assert_ne!(built_info::CFG_FAMILY, "");
    assert_ne!(built_info::CFG_OS, "");
    assert_ne!(built_info::CFG_POINTER_WIDTH, "");

    assert!(built::util::parse_versions(built_info::DEPENDENCIES.iter())
        .any(|(name, ver)| name == "toml" && ver >= semver::Version::parse("0.1.0").unwrap()));

    assert!((chrono::offset::Utc::now() - built::util::strptime(built_info::BUILT_TIME_UTC)).num_days() <= 1);
}"#,
    );

    let root = p.create().expect("Creating the project failed");
    let cargo_result = process::Command::new("cargo")
        .current_dir(&root)
        .arg("run")
        .arg("-q")
        .output()
        .expect("cargo failed");
    if !cargo_result.status.success() {
        panic!(
            "cargo failed with {}",
            String::from_utf8_lossy(&cargo_result.stderr)
        );
    }
}

#[test]
#[cfg(feature = "git2")]
fn empty_git() {
    // Issue #7, git can be there and still fail
    let mut p = Project::new();
    let built_root = get_built_root();
    p.add_file(
        "Cargo.toml",
        format!(
            r#"
[package]
name = "testbox"
version = "0.0.1"
build = "build.rs"

[build-dependencies]
built = {{ path = {:?} }}"#,
            &built_root
        ),
    );
    p.add_file(
        "build.rs",
        r#"
extern crate built;
fn main() {
    built::write_built_file().expect("writing failed");
}"#,
    );
    p.add_file("src/main.rs", "fn main() {}");
    p.init_git();
    let root = p.create().expect("Creating the project failed");
    let cargo_result = process::Command::new("cargo")
        .current_dir(&root)
        .arg("run")
        .output()
        .expect("cargo failed");
    if !cargo_result.status.success() {
        panic!(
            "cargo failed with {}",
            String::from_utf8_lossy(&cargo_result.stderr)
        );
    }
}
<|endoftext|>


<commit_before>//! Codec for chunk type 14 = FLI_ICOLORS.

use std::cmp::min;

use ::RasterMut;

/// Magic for a FLI_ICOLORS chunk.
///
/// This is likely to be used by very old development FLICs only.
pub const FLI_ICOLORS: u16 = 14;

/// Animator initial colour map.
const INIT_CMAP: [u8; 3 * 256] = [
    /* 32 level grey scale */
     0, 0, 0,    2, 2, 2,    4, 4, 4,    6, 6, 6,
     8, 8, 8,   10,10,10,   12,12,12,   14,14,14,
    16,16,16,   18,18,18,   20,20,20,   22,22,22,
    24,24,24,   26,26,26,   28,28,28,   30,30,30,
    33,33,33,   35,35,35,   37,37,37,   39,39,39,
    41,41,41,   43,43,43,   45,45,45,   47,47,47,
    49,49,49,   51,51,51,   53,53,53,   55,55,55,
    57,57,57,   59,59,59,   61,61,61,   63,63,63,
    /* A hand threaded 6x6x6 rgb cube */
    63,51,51,   63,63,51,   51,63,51,   51,63,63,
    51,51,63,   63,51,63,   63,39,39,   63,51,39,
    63,63,39,   51,63,39,   39,63,39,   39,63,51,
    39,63,63,   39,51,63,   39,39,63,   51,39,63,
    63,39,63,   63,39,51,   63,27,27,   63,39,27,
    63,51,27,   63,63,27,   51,63,27,   39,63,27,
    27,63,27,   27,63,39,   27,63,51,   27,63,63,
    27,51,63,   27,39,63,   27,27,63,   39,27,63,
    51,27,63,   63,27,63,   63,27,51,   63,27,39,
    63,15,15,   63,27,15,   63,39,15,   63,51,15,
    63,63,15,   51,63,15,   39,63,15,   27,63,15,
    15,63,15,   15,63,27,   15,63,39,   15,63,51,
    15,63,63,   15,51,63,   15,39,63,   15,27,63,
    15,15,63,   27,15,63,   39,15,63,   51,15,63,
    63,15,63,   63,15,51,   63,15,39,   63,15,27,
    63, 3,15,   63, 3, 3,   63,15, 3,   63,27, 3,
    63,39, 3,   63,51, 3,   63,63, 3,   51,63, 3,
    39,63, 3,   27,63, 3,   15,63, 3,    3,63, 3,
     3,63,15,    3,63,27,    3,63,39,    3,63,51,
     3,63,63,    3,51,63,    3,39,63,    3,27,63,
     3,15,63,    3, 3,63,   15, 3,63,   27, 3,63,
    39, 3,63,   51, 3,63,   63, 3,63,   63, 3,51,
    63, 3,39,   63, 3,27,   51, 3,15,   51, 3, 3,
    51,15, 3,   51,27, 3,   51,39, 3,   51,51, 3,
    39,51, 3,   27,51, 3,   15,51, 3,    3,51, 3,
     3,51,15,    3,51,27,    3,51,39,    3,51,51,
     3,39,51,    3,27,51,    3,15,51,    3, 3,51,
    15, 3,51,   27, 3,51,   39, 3,51,   51, 3,51,
    51, 3,39,   51, 3,27,   39, 3,15,   39, 3, 3,
    39,15, 3,   39,27, 3,   39,39, 3,   27,39, 3,
    15,39, 3,    3,39, 3,    3,39,15,    3,39,27,
     3,39,39,    3,27,39,    3,15,39,    3, 3,39,
    15, 3,39,   27, 3,39,   39, 3,39,   39, 3,27,
    27, 3,15,   27, 3, 3,   27,15, 3,   27,27, 3,
    15,27, 3,    3,27, 3,    3,27,15,    3,27,27,
     3,15,27,    3, 3,27,   15, 3,27,   27, 3,27,
    15, 3, 3,   15,15, 3,    3,15, 3,    3,15,15,
     3, 3,15,   15, 3,15,   27,15,15,   27,27,15,
    15,27,15,   15,27,27,   15,15,27,   27,15,27,
    39,15,15,   39,27,15,   39,39,15,   27,39,15,
    15,39,15,   15,39,27,   15,39,39,   15,27,39,
    15,15,39,   27,15,39,   39,15,39,   39,15,27,
    51,15,15,   51,27,15,   51,39,15,   51,51,15,
    39,51,15,   27,51,15,   15,51,15,   15,51,27,
    15,51,39,   15,51,51,   15,39,51,   15,27,51,
    15,15,51,   27,15,51,   39,15,51,   51,15,51,
    51,15,39,   51,15,27,   51,27,27,   51,39,27,
    51,51,27,   39,51,27,   27,51,27,   27,51,39,
    27,51,51,   27,39,51,   27,27,51,   39,27,51,
    51,27,51,   51,27,39,   51,39,39,   51,51,39,
    39,51,39,   39,51,51,   39,39,51,   51,39,51,
    39,27,27,   39,39,27,   27,39,27,   27,39,39,
    27,27,39,   39,27,39,    3, 3, 3,   15,15,15,
    27,27,27,   39,39,39,   51,51,51,   63,63,63,
    /* 3 empty slots */
    63,22, 3,   39, 7, 5,   36,36,63,
    /* Colours the system would like to use for interface */
     0, 0, 0, /* menu black */
    22,22,22, /* menu grey */
    38,38,38, /* menu light */
    52,52,52, /* menu bright */
    63, 0, 0, /* menu red */
];

/// Decode a FLI_ICOLORS chunk.
pub fn decode_fli_icolors(dst: &mut RasterMut) {
    let start = 0;
    let end = min(dst.pal.len(), INIT_CMAP.len());

    dst.pal[start..end].copy_from_slice(&INIT_CMAP[start..end]);
}
<commit_msg>Scale up FLI_ICOLORS chunk colour components.<commit_after>//! Codec for chunk type 14 = FLI_ICOLORS.

use std::cmp::min;

use ::RasterMut;

/// Magic for a FLI_ICOLORS chunk.
///
/// This is likely to be used by very old development FLICs only.
pub const FLI_ICOLORS: u16 = 14;

/// Animator initial colour map.
const INIT_CMAP: [u8; 3 * 256] = [
    /* 32 level grey scale */
      0,  0,  0,      8,  8,  8,     16, 16, 16,     24, 24, 24,
     32, 32, 32,     40, 40, 40,     48, 48, 48,     56, 56, 56,
     64, 64, 64,     72, 72, 72,     80, 80, 80,     88, 88, 88,
     96, 96, 96,    104,104,104,    112,112,112,    120,120,120,
    132,132,132,    140,140,140,    148,148,148,    156,156,156,
    164,164,164,    172,172,172,    180,180,180,    188,188,188,
    196,196,196,    204,204,204,    212,212,212,    220,220,220,
    228,228,228,    236,236,236,    244,244,244,    252,252,252,
    /* A hand threaded 6x6x6 rgb cube */
    252,204,204,    252,252,204,    204,252,204,    204,252,252,
    204,204,252,    252,204,252,    252,156,156,    252,204,156,
    252,252,156,    204,252,156,    156,252,156,    156,252,204,
    156,252,252,    156,204,252,    156,156,252,    204,156,252,
    252,156,252,    252,156,204,    252,108,108,    252,156,108,
    252,204,108,    252,252,108,    204,252,108,    156,252,108,
    108,252,108,    108,252,156,    108,252,204,    108,252,252,
    108,204,252,    108,156,252,    108,108,252,    156,108,252,
    204,108,252,    252,108,252,    252,108,204,    252,108,156,
    252, 60, 60,    252,108, 60,    252,156, 60,    252,204, 60,
    252,252, 60,    204,252, 60,    156,252, 60,    108,252, 60,
     60,252, 60,     60,252,108,     60,252,156,     60,252,204,
     60,252,252,     60,204,252,     60,156,252,     60,108,252,
     60, 60,252,    108, 60,252,    156, 60,252,    204, 60,252,
    252, 60,252,    252, 60,204,    252, 60,156,    252, 60,108,
    252, 12, 60,    252, 12, 12,    252, 60, 12,    252,108, 12,
    252,156, 12,    252,204, 12,    252,252, 12,    204,252, 12,
    156,252, 12,    108,252, 12,     60,252, 12,     12,252, 12,
     12,252, 60,     12,252,108,     12,252,156,     12,252,204,
     12,252,252,     12,204,252,     12,156,252,     12,108,252,
     12, 60,252,     12, 12,252,     60, 12,252,    108, 12,252,
    156, 12,252,    204, 12,252,    252, 12,252,    252, 12,204,
    252, 12,156,    252, 12,108,    204, 12, 60,    204, 12, 12,
    204, 60, 12,    204,108, 12,    204,156, 12,    204,204, 12,
    156,204, 12,    108,204, 12,     60,204, 12,     12,204, 12,
     12,204, 60,     12,204,108,     12,204,156,     12,204,204,
     12,156,204,     12,108,204,     12, 60,204,     12, 12,204,
     60, 12,204,    108, 12,204,    156, 12,204,    204, 12,204,
    204, 12,156,    204, 12,108,    156, 12, 60,    156, 12, 12,
    156, 60, 12,    156,108, 12,    156,156, 12,    108,156, 12,
     60,156, 12,     12,156, 12,     12,156, 60,     12,156,108,
     12,156,156,     12,108,156,     12, 60,156,     12, 12,156,
     60, 12,156,    108, 12,156,    156, 12,156,    156, 12,108,
    108, 12, 60,    108, 12, 12,    108, 60, 12,    108,108, 12,
     60,108, 12,     12,108, 12,     12,108, 60,     12,108,108,
     12, 60,108,     12, 12,108,     60, 12,108,    108, 12,108,
     60, 12, 12,     60, 60, 12,     12, 60, 12,     12, 60, 60,
     12, 12, 60,     60, 12, 60,    108, 60, 60,    108,108, 60,
     60,108, 60,     60,108,108,     60, 60,108,    108, 60,108,
    156, 60, 60,    156,108, 60,    156,156, 60,    108,156, 60,
     60,156, 60,     60,156,108,     60,156,156,     60,108,156,
     60, 60,156,    108, 60,156,    156, 60,156,    156, 60,108,
    204, 60, 60,    204,108, 60,    204,156, 60,    204,204, 60,
    156,204, 60,    108,204, 60,     60,204, 60,     60,204,108,
     60,204,156,     60,204,204,     60,156,204,     60,108,204,
     60, 60,204,    108, 60,204,    156, 60,204,    204, 60,204,
    204, 60,156,    204, 60,108,    204,108,108,    204,156,108,
    204,204,108,    156,204,108,    108,204,108,    108,204,156,
    108,204,204,    108,156,204,    108,108,204,    156,108,204,
    204,108,204,    204,108,156,    204,156,156,    204,204,156,
    156,204,156,    156,204,204,    156,156,204,    204,156,204,
    156,108,108,    156,156,108,    108,156,108,    108,156,156,
    108,108,156,    156,108,156,     12, 12, 12,     60, 60, 60,
    108,108,108,    156,156,156,    204,204,204,    252,252,252,
    /* 3 empty slots */
    252, 88, 12,    156, 28, 20,    144,144,252,
    /* Colours the system would like to use for interface */
      0,  0,  0, /* menu black */
     88, 88, 88, /* menu grey */
    152,152,152, /* menu light */
    208,208,208, /* menu bright */
    252,  0,  0, /* menu red */
];

/// Decode a FLI_ICOLORS chunk.
pub fn decode_fli_icolors(dst: &mut RasterMut) {
    let start = 0;
    let end = min(dst.pal.len(), INIT_CMAP.len());

    dst.pal[start..end].copy_from_slice(&INIT_CMAP[start..end]);
}
<|endoftext|>