<commit_before>#![feature(convert)]
#![feature(buf_stream)]
#[macro_use] extern crate log;
extern crate env_logger;
extern crate yak_client;
extern crate capnp;

use std::net::{TcpListener, TcpStream, Ipv4Addr};
use std::thread;
use std::io::{self,Read,Write,BufStream,BufRead};
use std::str::FromStr;
use std::fmt;
use std::collections::HashMap;

use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, MallocMessageBuilder, ReaderOptions};

use yak_client::yak_capnp::*;

type Key = Vec<u8>;
type Values = Vec<Vec<u8>>;
struct MemStore (HashMap<Key, Values>);

impl MemStore {
  fn new() -> MemStore {
    MemStore(HashMap::new())
  }

  fn truncate(&mut self) {
    let MemStore(ref mut map) = *self;
    map.clear();
  }

  fn read(&self, key: &[u8]) -> Values {
    let MemStore(ref map) = *self;
    map.get(key).map(|x| x.clone()).unwrap_or(vec![])
  }
  fn write(&mut self, key: &[u8], val: &[u8]) {
    let MemStore(ref mut map) = *self;
    let entry = map.entry(key.into()).or_insert(vec![]);
    entry.push(val.into())
  }
}

#[derive(Debug)]
enum ServerError {
  CapnpError(capnp::Error),
  CapnpNotInSchema(capnp::NotInSchema),
  IoError(std::io::Error)
}

pub fn main() {
  env_logger::init().unwrap();

  let mut a = std::env::args().skip(1);
  let local : String = a.next().unwrap();
  let next : Option<String> = a.next();

  let listener = TcpListener::bind(local.as_str()).unwrap();
  info!("listening started on {}, ready to accept", local);
  for stream in listener.incoming() {
    let next = next.clone();
    thread::spawn(move || {
	let mut sock = &stream.unwrap();
	let peer = sock.peer_addr().unwrap();
	info!("Accept stream from {:?}", peer);
        let mut strm = BufStream::new(sock);
        process_requests(peer, strm).unwrap()
      });
  }
}

fn process_requests<Id: fmt::Display, S: Read + Write>(id: Id, mut strm: BufStream<S>) -> Result<(), ServerError> {
  let mut store = MemStore::new();
  loop {
    debug!("{}: Waiting for message", id);
    let len = try!(strm.fill_buf()).len();
    if len == 0 {
        debug!("{}: End of client stream", id);
        return Ok(())
    }
    let message_reader = try!(serialize_packed::read_message(&mut strm, ReaderOptions::new()));
    let msg = try!(message_reader.get_root::<client_request::Reader>());
    debug!("{}: Read message", id);

    let mut message = MallocMessageBuilder::new_default();
    {
      let mut response = message.init_root::<client_response::Builder>();
      match try!(msg.which()) {
        client_request::Truncate(v) => truncate(&id, &mut store, try!(v), response),
          client_request::Read(v) => read(&id, &mut store, try!(v), response),
          client_request::Write(v) => write(&id, &mut store, try!(v), response),
      };
    }

    try!(serialize_packed::write_message(&mut strm, &mut message));
    try!(strm.flush())
  }
}

fn truncate<Id: fmt::Display>(id: &Id, store: &mut MemStore, req: truncate_request::Reader, mut response: client_response::Builder) -> Result<(), ServerError> {
  let space = try!(req.get_space());
  info!("{}/{:?}: truncate", id, space);
  store.truncate();
  response.set_ok(());
  Ok(())
}

fn read<Id: fmt::Display>(id: &Id, store: &mut MemStore, req: read_request::Reader, mut response: client_response::Builder) -> Result<(), ServerError> {
  let space = try!(req.get_space());
  let key = try!(req.get_key()).into();
  let val = store.read(key);
  info!("{}/{:?}: read:{:?}: -> {:?}", id, space, key, val);

  let mut data = response.init_ok_data(val.len() as u32);
  for i in 0..val.len() {
    let mut datum = data.borrow().get(i as u32);
    datum.set_value(&val[i])
  }
  Ok(())
}

fn write<Id: fmt::Display>(id: &Id, store: &mut MemStore, v: write_request::Reader, mut response: client_response::Builder) -> Result<(), ServerError> {
  let space = try!(v.get_space());
  let key = try!(v.get_key()).into();
  let val = try!(v.get_value()).into();
  info!("{}/{:?}: write:{:?} -> {:?}", id, space, key, val);

  store.write(key, val);
  response.set_ok(());
  Ok(())
}

impl From<capnp::Error> for ServerError {
  fn from(err: capnp::Error) -> ServerError {
    ServerError::CapnpError(err)
  }
}

impl From<capnp::NotInSchema> for ServerError {
  fn from(err: capnp::NotInSchema) -> ServerError {
    ServerError::CapnpNotInSchema(err)
  }
}

impl From<io::Error> for ServerError {
  fn from(err: io::Error) -> ServerError {
    ServerError::IoError(err)
  }
}
<commit_msg>Move main store methods into a trait.<commit_after>#![feature(convert)]
#![feature(buf_stream)]
#[macro_use] extern crate log;
extern crate env_logger;
extern crate yak_client;
extern crate capnp;

use std::net::{TcpListener, TcpStream, Ipv4Addr};
use std::thread;
use std::io::{self,Read,Write,BufStream,BufRead};
use std::str::FromStr;
use std::fmt;
use std::collections::HashMap;

use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, MallocMessageBuilder, ReaderOptions};

use yak_client::yak_capnp::*;

type Key = Vec<u8>;
type Values = Vec<Vec<u8>>;
struct MemStore (HashMap<Key, Values>);

trait Store {
  fn truncate(&mut self);
  fn read(&self, key: &[u8]) -> Values;
  fn write(&mut self, key: &[u8], val: &[u8]);
}

impl MemStore {
  fn new() -> MemStore {
    MemStore(HashMap::new())
  }
}

impl Store for MemStore {
  fn truncate(&mut self) {
    let MemStore(ref mut map) = *self;
    map.clear();
  }

  fn read(&self, key: &[u8]) -> Values {
    let MemStore(ref map) = *self;
    map.get(key).map(|x| x.clone()).unwrap_or(vec![])
  }
  fn write(&mut self, key: &[u8], val: &[u8]) {
    let MemStore(ref mut map) = *self;
    let entry = map.entry(key.into()).or_insert(vec![]);
    entry.push(val.into())
  }
}

#[derive(Debug)]
enum ServerError {
  CapnpError(capnp::Error),
  CapnpNotInSchema(capnp::NotInSchema),
  IoError(std::io::Error)
}

pub fn main() {
  env_logger::init().unwrap();

  let mut a = std::env::args().skip(1);
  let local : String = a.next().unwrap();
  let next : Option<String> = a.next();

  let listener = TcpListener::bind(local.as_str()).unwrap();
  info!("listening started on {}, ready to accept", local);
  for stream in listener.incoming() {
    let next = next.clone();
    thread::spawn(move || {
	let mut sock = &stream.unwrap();
	let peer = sock.peer_addr().unwrap();
	info!("Accept stream from {:?}", peer);
        let mut strm = BufStream::new(sock);
        process_requests(peer, strm).unwrap()
      });
  }
}

fn process_requests<Id: fmt::Display, S: Read + Write>(id: Id, mut strm: BufStream<S>) -> Result<(), ServerError> {
  let mut store = MemStore::new();
  loop {
    debug!("{}: Waiting for message", id);
    let len = try!(strm.fill_buf()).len();
    if len == 0 {
        debug!("{}: End of client stream", id);
        return Ok(())
    }
    let message_reader = try!(serialize_packed::read_message(&mut strm, ReaderOptions::new()));
    let msg = try!(message_reader.get_root::<client_request::Reader>());
    debug!("{}: Read message", id);

    let mut message = MallocMessageBuilder::new_default();
    {
      let mut response = message.init_root::<client_response::Builder>();
      match try!(msg.which()) {
        client_request::Truncate(v) => truncate(&id, &mut store, try!(v), response),
          client_request::Read(v) => read(&id, &mut store, try!(v), response),
          client_request::Write(v) => write(&id, &mut store, try!(v), response),
      };
    }

    try!(serialize_packed::write_message(&mut strm, &mut message));
    try!(strm.flush())
  }
}

fn truncate<Id: fmt::Display, S: Store>(id: &Id, store: &mut S, req: truncate_request::Reader, mut response: client_response::Builder) -> Result<(), ServerError> {
  let space = try!(req.get_space());
  info!("{}/{:?}: truncate", id, space);
  store.truncate();
  response.set_ok(());
  Ok(())
}

fn read<Id: fmt::Display, S: Store>(id: &Id, store: &mut S, req: read_request::Reader, mut response: client_response::Builder) -> Result<(), ServerError> {
  let space = try!(req.get_space());
  let key = try!(req.get_key()).into();
  let val = store.read(key);
  info!("{}/{:?}: read:{:?}: -> {:?}", id, space, key, val);

  let mut data = response.init_ok_data(val.len() as u32);
  for i in 0..val.len() {
    let mut datum = data.borrow().get(i as u32);
    datum.set_value(&val[i])
  }
  Ok(())
}

fn write<Id: fmt::Display, S: Store>(id: &Id, store: &mut S, v: write_request::Reader, mut response: client_response::Builder) -> Result<(), ServerError> {
  let space = try!(v.get_space());
  let key = try!(v.get_key()).into();
  let val = try!(v.get_value()).into();
  info!("{}/{:?}: write:{:?} -> {:?}", id, space, key, val);

  store.write(key, val);
  response.set_ok(());
  Ok(())
}

impl From<capnp::Error> for ServerError {
  fn from(err: capnp::Error) -> ServerError {
    ServerError::CapnpError(err)
  }
}

impl From<capnp::NotInSchema> for ServerError {
  fn from(err: capnp::NotInSchema) -> ServerError {
    ServerError::CapnpNotInSchema(err)
  }
}

impl From<io::Error> for ServerError {
  fn from(err: io::Error) -> ServerError {
    ServerError::IoError(err)
  }
}
<|endoftext|>


<commit_before>use super::*;

#[test]
fn run_empty_task() {
    run("bad.toml", "empty", "error");
}

#[test]
fn run_file_and_task() {
    run("./examples/dependencies.toml", "A", "error");
}

#[test]
#[should_panic]
fn run_cli_panic() {
    run_cli();
}

#[test]
#[should_panic]
fn run_for_args_bad_subcommand() {
    let app = create_cli();

    let matches = app.get_matches_from(vec!["bad"]);

    run_for_args(matches);
}

#[test]
fn run_for_args_valid() {
    let app = create_cli();

    let matches = app.get_matches_from(vec!["cargo", "make", "-b", "./examples/dependencies.toml", "-t", "A", "-l", "error"]);

    run_for_args(matches);
}
<commit_msg>more tests<commit_after>use super::*;

#[test]
fn run_empty_task() {
    run("bad.toml", "empty", "error");
}

#[test]
fn run_file_and_task() {
    run("./examples/dependencies.toml", "A", "error");
}

#[test]
#[should_panic]
fn run_cli_panic() {
    run_cli();
}

#[test]
#[should_panic]
fn run_for_args_bad_subcommand() {
    let app = create_cli();

    let matches = app.get_matches_from(vec!["bad"]);

    run_for_args(matches);
}

#[test]
fn run_for_args_valid() {
    let app = create_cli();

    let matches = app.get_matches_from(vec!["cargo", "make", "-b", "./examples/dependencies.toml", "-t", "A", "-l", "error"]);

    run_for_args(matches);
}

#[test]
fn run_for_args_log_level_override() {
    let app = create_cli();

    let matches = app.get_matches_from(vec!["cargo", "make", "-b", "./examples/dependencies.toml", "-t", "A", "-l", "error", "-v"]);

    run_for_args(matches);
}
<|endoftext|>


<commit_before>// "Tifflin" Kernel - ISO9660 Filesystem Driver
// - By John Hodge (thePowersGang)
//
// Modules/fs_iso9660/lib.rs
#![feature(no_std,core,linkage)]
#![no_std]
#[macro_use] extern crate core;
#[macro_use] extern crate kernel;
use kernel::prelude::*;

use kernel::vfs::{self, mount, node};
use kernel::metadevs::storage::{self,VolumeHandle,SizePrinter};
use kernel::lib::mem::aref::{ArefInner,ArefBorrow};

module_define!{FS_ISO9660, [VFS], init}

struct Driver;
static S_DRIVER: Driver = Driver;

struct Instance(ArefInner<InstanceInner>);
impl ::core::ops::Deref for Instance {
	type Target = InstanceInner;
	fn deref(&self) -> &InstanceInner { &self.0 }
}

struct InstanceInner
{
	pv: VolumeHandle,
}

fn init()
{
	let h = mount::DriverRegistration::new("iso9660", &S_DRIVER);
	// TODO: Remember the registration for unloading
	::core::mem::forget(h);
}

impl mount::Driver for Driver
{
	fn detect(&self, vol: &VolumeHandle) -> vfs::Result<usize> {
		let bs = vol.block_size() as u64;
		let blk = {
			let mut block: Vec<_> = (0 .. bs).map(|_|0).collect();
			try!(vol.read_blocks(32*1024 / bs, &mut block));
			block
			};
		if &blk[1..6] == b"CD001" {
			Ok(1)
		}
		else {
			Ok(0)
		}
	}
	fn mount(&self, vol: VolumeHandle) -> vfs::Result<Box<mount::Filesystem>> {
		todo!("mount");
	}
}

<commit_msg>Kernel/ISO9660 - Implement mount<commit_after>// "Tifflin" Kernel - ISO9660 Filesystem Driver
// - By John Hodge (thePowersGang)
//
// Modules/fs_iso9660/lib.rs
#![feature(no_std,core,linkage)]
#![no_std]
#[macro_use] extern crate core;
#[macro_use] extern crate kernel;
use kernel::prelude::*;

use kernel::vfs::{self, mount, node};
use kernel::metadevs::storage::{self,VolumeHandle,SizePrinter};
use kernel::lib::mem::aref::{ArefInner,ArefBorrow};
use kernel::lib::byteorder::{ByteOrder,LittleEndian};

module_define!{FS_ISO9660, [VFS], init}

//mod ondisk;

struct Driver;
static S_DRIVER: Driver = Driver;

struct Instance(ArefInner<InstanceInner>);
impl ::core::ops::Deref for Instance {
	type Target = InstanceInner;
	fn deref(&self) -> &InstanceInner { &self.0 }
}

struct InstanceInner
{
	pv: VolumeHandle,
	lb_size: usize,
	root_lba: u32,
	root_size: u32,
}

fn init()
{
	let h = mount::DriverRegistration::new("iso9660", &S_DRIVER);
	// TODO: Remember the registration for unloading
	::core::mem::forget(h);
}

impl mount::Driver for Driver
{
	fn detect(&self, vol: &VolumeHandle) -> vfs::Result<usize> {
		let bs = vol.block_size() as u64;
		let blk = {
			let mut block: Vec<_> = (0 .. bs).map(|_|0).collect();
			try!(vol.read_blocks(32*1024 / bs, &mut block));
			block
			};
		if &blk[1..6] == b"CD001" {
			Ok(1)
		}
		else {
			Ok(0)
		}
	}
	fn mount(&self, vol: VolumeHandle) -> vfs::Result<Box<mount::Filesystem>> {
		if 2048 % vol.block_size() != 0 {
			return Err( vfs::Error::Unknown("Can't mount ISO9660 with sector size not a factor of 2048"/*, vol.block_size()*/) );
		}
		let scale = 2048 / vol.block_size();

		let mut block: Vec<u8> = (0 .. 2048).map(|_|0).collect();
		for sector in (16 .. )
		{
			try!(vol.read_blocks((sector*scale) as u64, &mut block));
			if &block[1..6] != b"CD001" {
				return Err( vfs::Error::Unknown("Invalid volume descriptor present") );
			}
			else if block[0] == 255 {
				return Err( vfs::Error::Unknown("Can't find ISO9660 primary volume descriptor") );
			}
			else if block[0] == 0x01 {
				// Found it!
				break ;
			}
			else {
				// Try the next one
			}
		}
		::kernel::logging::hex_dump("ISO966 PVD", &block);

		// Obtain the logical block size (different from medium sector size)
		let lb_size = LittleEndian::read_u16(&block[128..]);
		// Extract the root directory entry
		// - We want the LBA and byte length
		let root_lba  = LittleEndian::read_u32(&block[156+ 2..]);
		let root_size = LittleEndian::read_u32(&block[156+10..]);

		Ok( Box::new( Instance(
			unsafe { ArefInner::new( InstanceInner {
				pv: vol,
				lb_size: lb_size as usize,
				root_lba: root_lba,
				root_size: root_size,
				} ) }
			) ) )
	}
}

impl mount::Filesystem for Instance
{
	fn root_inode(&self) -> node::InodeId {
		todo!("Instance::root_inode");
	}
	fn get_node_by_inode(&self, id: node::InodeId) -> Option<node::Node> {
		todo!("Instance::get_node_by_inode");
	}

}

<|endoftext|>


<commit_before>
extern crate libc;
mod mruby
{

    use libc::{c_char};

#[repr(C)]
    struct mrb_state;
#[repr(C)]
    struct mrb_value;
#[repr(C)]
    struct RClass;

#[link(name="m")]
#[link(name="mruby")]
    extern "C" {
        fn mrb_open() -> *mut mrb_state;
        fn mrb_load_string(state:*mut mrb_state,s:*const c_char) -> mrb_value;
        fn mrb_close(state:*mut mrb_state);
        fn mrb_class_get(state:*mut mrb_state,name:*const c_char) -> *mut RClass;
        fn mrb_define_class(state:*mut mrb_state,name:*const c_char,class:*mut RClass) -> *mut RClass;
    }

    enum MvalType {
        TypeFalse ,
        TypeFree,
        TypeTrue,
        TypeFixnum,
        TypeSymbol,
        TypeUndef,
        TypeFloat,
        TypeCptr,
        TypeObject,
        TypeClass,
        TypeModule,
        TypeIClass,
        TypeSClass,
        TypeProc,
        TypeArray,
        TypeHash,
        TypeString,
        TypeRange,
        TypeException,
        TypeFile,
        TypeEnv,
        TypeData,
        TypeFiber,
        TypeMaxDefine
    }

    pub struct Mrb{
        state:*mut mrb_state
    }

    pub struct Value {
        val :*mut mrb_value
    }

    pub struct Class {
        mrb : &'r Mrb,
        class :*mut RClass
    }

    pub fn open() -> Mrb {
        let s = unsafe { mrb_open() } ;
        Mrb{state:s}
    }

    impl Mrb {
        pub fn load_str(&self,s:&str) {
            let cs = s.to_c_str();
            unsafe {
                mrb_load_string(self.state,cs.as_ptr());
            }
        }

        pub fn close(&self) {
            unsafe {
                mrb_close(self.state);
            }
        }

        pub fn define_class(&self,name:&str,clz:&Class) -> Class {
            let cs = name.to_c_str();
            let c = unsafe { mrb_define_class(self.state,cs.as_ptr(),clz.class) } ;
            Class{mrb:self,class:c}
        }

        pub fn obj_class(&self) -> Class {
            let s = "Object";
            let c = unsafe { mrb_class_get(self.state,s.to_c_str().as_ptr()) } ;
            Class{mrb:self,class:c}
        }
    }

}

fn main() {
    let m = mruby::open();
    let exec = "[1,2,3].each do |i| puts i+1 end";
    m.load_str(exec);

    let o = &m.obj_class();
    let c = m.define_class("Hello",o);
    m.close();
}

<commit_msg>add lifetime 'a<commit_after>
extern crate libc;
mod mruby
{

    use libc::{c_char};

#[repr(C)]
    struct mrb_state;
#[repr(C)]
    struct mrb_value;
#[repr(C)]
    struct RClass;

#[link(name="m")]
#[link(name="mruby")]
    extern "C" {
        fn mrb_open() -> *mut mrb_state;
        fn mrb_load_string(state:*mut mrb_state,s:*const c_char) -> mrb_value;
        fn mrb_close(state:*mut mrb_state);
        fn mrb_class_get(state:*mut mrb_state,name:*const c_char) -> *mut RClass;
        fn mrb_define_class(state:*mut mrb_state,name:*const c_char,class:*mut RClass) -> *mut RClass;
    }

    enum MvalType {
        TypeFalse ,
        TypeFree,
        TypeTrue,
        TypeFixnum,
        TypeSymbol,
        TypeUndef,
        TypeFloat,
        TypeCptr,
        TypeObject,
        TypeClass,
        TypeModule,
        TypeIClass,
        TypeSClass,
        TypeProc,
        TypeArray,
        TypeHash,
        TypeString,
        TypeRange,
        TypeException,
        TypeFile,
        TypeEnv,
        TypeData,
        TypeFiber,
        TypeMaxDefine
    }

    pub struct Mrb{
        state:*mut mrb_state
    }

    pub struct Value {
        val :*mut mrb_value
    }

    pub struct Class<'a>{
        mrb : &'a Mrb,
        class :*mut RClass
    }

    pub fn open() -> Mrb {
        let s = unsafe { mrb_open() } ;
        Mrb{state:s}
    }

    impl Mrb {
        pub fn load_str(&self,s:&str) {
            let cs = s.to_c_str();
            unsafe {
                mrb_load_string(self.state,cs.as_ptr());
            }
        }

        pub fn close(&self) {
            unsafe {
                mrb_close(self.state);
            }
        }

        pub fn define_class(&self,name:&str,clz:&Class) -> Class {
            let cs = name.to_c_str();
            let c = unsafe { mrb_define_class(self.state,cs.as_ptr(),clz.class) } ;
            Class{mrb:self,class:c}
        }

        pub fn obj_class(&self) -> Class {
            let s = "Object";
            let c = unsafe { mrb_class_get(self.state,s.to_c_str().as_ptr()) } ;
            Class{mrb:self,class:c}
        }
    }

}

fn main() {
    let m = mruby::open();
    let exec = "[1,2,3].each do |i| puts i+1 end";
    m.load_str(exec);

    let o = &m.obj_class();
    let c = m.define_class("Hello",o);
    m.close();
}

<|endoftext|>


<commit_before>use std::io;
use std::fs;
use std::fs::DirBuilder;
use std::path::Path;
use super::generation::PageGenerator;

pub fn new_project(parent_dir: &str) -> Result<(), io::Error> {
    try!(DirBuilder::new().recursive(true).create(parent_dir));

    try!(DirBuilder::new().recursive(false).create(format!("{}/pages", parent_dir)));

    Ok(())
}

pub fn build_project() -> Result<(), io::Error> {
    let pages_path = "pages";
    let output_dir = "_site";
    let mut page_generator = PageGenerator::new();

    let directory_iterator = try!(Path::new(pages_path).read_dir());

    try!(DirBuilder::new().create(output_dir));

    for entry in directory_iterator {
        let file = try!(entry);
        let file_type = file.file_type().unwrap();
        let source_file = format!("{}/{}", pages_path, file.file_name().to_str().unwrap());
        let file_stem = String::from(file.path().file_stem().unwrap().to_str().unwrap());
        let destination_file = format!("{}/{}.html", output_dir, file_stem);

        if file_type.is_file() && file.file_name().to_str().unwrap().contains(".md") {
            try!(page_generator.set_input_file(source_file.as_ref())
                                .set_output_file(destination_file.as_ref())
                                .set_wrap(true)
                                .generate());
        }
    }

    Ok(())
}

pub fn clean_project() -> Result<(), io::Error> {
    try!(fs::remove_dir_all("_site"));

    Ok(())
}

#[cfg(test)]
mod test {
    use super::*;
    use std::fs::remove_dir_all;
    use std::env;
    use std::path;
    use std::error::Error;
    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn it_creates_default_directory_structure() {
        // Setup
        let temp_dir = env::temp_dir();
        let proj_dir = String::from(temp_dir.to_str().unwrap()) + "/test-project0";
        let page_dir = proj_dir.clone() + "/pages";

        new_project(proj_dir.as_ref());

        // Assert directories exists
        assert!(path::Path::new(&proj_dir).exists());
        assert!(path::Path::new(&page_dir).exists());

        // Teardown
        match remove_dir_all(proj_dir) {
            Ok(_) => {},
            Err(what) => panic!("{}", Error::description(&what))
        }
    }

    #[test]
    fn it_parses_md_files_to_html_in_the_project() {
        // Setup
        let temp_dir = env::temp_dir();
        let proj_dir = String::from(temp_dir.to_str().unwrap()) + "/test-project1";
        let page_dir = proj_dir.clone() + "/pages";
        let site_dir = proj_dir.clone() + "/_site";
        let test_file_name = page_dir.clone() + "/test.md";
        let test_file_compiled_name = "_site/test.html";

        new_project(&proj_dir);

        // Add markdown file
        let mut test_file = match File::create(&test_file_name) {
            Ok(file) => file,
            Err(what) => panic!("{}", Error::description(&what))
        };

        test_file.write_all(b"# This is a test");

        env::set_current_dir(&proj_dir);
        build_project();

        let mut test_output_file = match File::open(&test_file_compiled_name) {
            Ok(file) => file,
            Err(what) => panic!("{}", Error::description(&what))
        };

        let mut compiled_contents = String::new();

        test_output_file.read_to_string(&mut compiled_contents);

        let expected = "<!DOCTYPE html>\n\
                        \n\
                        \n\
                        <title>Aluminum Page</title>\n\
                        \n\
                        \n\

This is a test
\n\
                        \n\
                        ";

        assert!(path::Path::new(&test_file_compiled_name).exists());
        assert_eq!(expected, compiled_contents.trim());

        // Teardown
        match remove_dir_all(proj_dir) {
            Ok(_) => {},
            Err(what) => panic!("{}", Error::description(&what))
        }
    }

    #[test]
    fn it_deletes_the_site_directory_when_the_project_gets_cleaned() {
        let temp_dir = env::temp_dir();
        let proj_dir = String::from(temp_dir.to_str().unwrap()) + "/test-project2";
        let site_dir = proj_dir.clone() + "/_site";

        new_project(&proj_dir);

        env::set_current_dir(&proj_dir);
        build_project();

        assert!(path::Path::new(&site_dir).exists());

        clean_project();

        assert!(!path::Path::new(&site_dir).exists());

        match remove_dir_all(proj_dir) {
            Ok(_) => {},
            Err(what) => panic!("{}", Error::description(&what))
        }
    }
}
<commit_msg>feat: new project creates _config.yml file<commit_after>use std::io;
use std::fs;
use std::fs::{DirBuilder, File};
use std::path::Path;
use super::generation::PageGenerator;

pub fn new_project(parent_dir: &str) -> Result<(), io::Error> {
    try!(DirBuilder::new().recursive(true).create(parent_dir));

    try!(DirBuilder::new().recursive(false).create(format!("{}/pages", parent_dir)));

    try!(File::create(format!("{}/_config.yml", parent_dir)));

    Ok(())
}

pub fn build_project() -> Result<(), io::Error> {
    let pages_path = "pages";
    let output_dir = "_site";
    let mut page_generator = PageGenerator::new();

    let directory_iterator = try!(Path::new(pages_path).read_dir());

    try!(DirBuilder::new().create(output_dir));

    for entry in directory_iterator {
        let file = try!(entry);
        let file_type = file.file_type().unwrap();
        let source_file = format!("{}/{}", pages_path, file.file_name().to_str().unwrap());
        let file_stem = String::from(file.path().file_stem().unwrap().to_str().unwrap());
        let destination_file = format!("{}/{}.html", output_dir, file_stem);

        if file_type.is_file() && file.file_name().to_str().unwrap().contains(".md") {
            try!(page_generator.set_input_file(source_file.as_ref())
                                .set_output_file(destination_file.as_ref())
                                .set_wrap(true)
                                .generate());
        }
    }

    Ok(())
}

pub fn clean_project() -> Result<(), io::Error> {
    try!(fs::remove_dir_all("_site"));

    Ok(())
}

#[cfg(test)]
mod test {
    use super::*;
    use std::fs::remove_dir_all;
    use std::env;
    use std::path;
    use std::error::Error;
    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn it_creates_default_directory_structure() {
        // Setup
        let temp_dir = env::temp_dir();
        let proj_dir = String::from(temp_dir.to_str().unwrap()) + "/test-project0";
        let page_dir = proj_dir.clone() + "/pages";
        let site_config = proj_dir.clone() + "/_config.yml";

        new_project(proj_dir.as_ref());

        // Assert directories exists
        assert!(path::Path::new(&proj_dir).exists());
        assert!(path::Path::new(&page_dir).exists());
        assert!(path::Path::new(&site_config).exists());

        // Teardown
        match remove_dir_all(proj_dir) {
            Ok(_) => {},
            Err(what) => panic!("{}", Error::description(&what))
        }
    }

    #[test]
    fn it_parses_md_files_to_html_in_the_project() {
        // Setup
        let temp_dir = env::temp_dir();
        let proj_dir = String::from(temp_dir.to_str().unwrap()) + "/test-project1";
        let page_dir = proj_dir.clone() + "/pages";
        let site_dir = proj_dir.clone() + "/_site";
        let test_file_name = page_dir.clone() + "/test.md";
        let test_file_compiled_name = "_site/test.html";

        new_project(&proj_dir);

        // Add markdown file
        let mut test_file = match File::create(&test_file_name) {
            Ok(file) => file,
            Err(what) => panic!("{}", Error::description(&what))
        };

        test_file.write_all(b"# This is a test");

        env::set_current_dir(&proj_dir);
        build_project();

        let mut test_output_file = match File::open(&test_file_compiled_name) {
            Ok(file) => file,
            Err(what) => panic!("{}", Error::description(&what))
        };

        let mut compiled_contents = String::new();

        test_output_file.read_to_string(&mut compiled_contents);

        let expected = "<!DOCTYPE html>\n\
                        \n\
                        \n\
                        <title>Aluminum Page</title>\n\
                        \n\
                        \n\

This is a test
\n\
                        \n\
                        ";

        assert!(path::Path::new(&test_file_compiled_name).exists());
        assert_eq!(expected, compiled_contents.trim());

        // Teardown
        match remove_dir_all(proj_dir) {
            Ok(_) => {},
            Err(what) => panic!("{}", Error::description(&what))
        }
    }

    #[test]
    fn it_deletes_the_site_directory_when_the_project_gets_cleaned() {
        let temp_dir = env::temp_dir();
        let proj_dir = String::from(temp_dir.to_str().unwrap()) + "/test-project2";
        let site_dir = proj_dir.clone() + "/_site";

        new_project(&proj_dir);

        env::set_current_dir(&proj_dir);
        build_project();

        assert!(path::Path::new(&site_dir).exists());

        clean_project();

        assert!(!path::Path::new(&site_dir).exists());

        match remove_dir_all(proj_dir) {
            Ok(_) => {},
            Err(what) => panic!("{}", Error::description(&what))
        }
    }
}
<|endoftext|>


<commit_before>use byteorder::{LittleEndian, WriteBytesExt};

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Label(usize);

#[derive(Debug)]
struct ByteBuffer {
    data: Vec<u8>,
}

impl ByteBuffer {
    fn new() -> ByteBuffer {
        ByteBuffer {
            data: Vec::new()
        }
    }

    pub fn data(self) -> Vec<u8> {
        self.data
    }

    pub fn pos(&mut self) -> usize {
        self.data.len()
    }

    pub fn emit_u8(&mut self, value: u8) {
        self.data.write_u8(value).unwrap();
    }

    pub fn emit_u16(&mut self, value: u16) {
        self.data.write_u16::<LittleEndian>(value).unwrap();
    }

    pub fn emit_u32(&mut self, value: u32) {
        self.data.write_u32::<LittleEndian>(value).unwrap();
    }

    pub fn emit_u32_at(&mut self, value: u32, pos: usize) {
        let mut slice = &mut self.data[pos..];
        slice.write_u32::<LittleEndian>(value).unwrap();
    }

    pub fn emit_u64(&mut self, value: u64) {
        self.data.write_u64::<LittleEndian>(value).unwrap();
    }
}

#[derive(Debug)]
pub struct Buffer {
    buf: ByteBuffer,
    labels: Vec<Option<usize>>,
    jumps: Vec<ForwardJump>,
}

impl Buffer {
    pub fn new() -> Buffer {
        Buffer {
            buf: ByteBuffer::new(),
            labels: Vec::new(),
            jumps: Vec::new(),
        }
    }

    pub fn pos(&mut self) -> usize {
        self.buf.pos()
    }

    pub fn finish(mut self) -> Vec<u8> {
        self.fix_forward_jumps();

        self.buf.data()
    }

    fn fix_forward_jumps(&mut self) {
        for jmp in &self.jumps {
            let target = self.labels[jmp.to.0].expect("label not defined");
            let diff = (target - jmp.at - 4) as i32;

            self.buf.emit_u32_at(diff as u32, jmp.at);
        }
    }

    pub fn create_label(&mut self) -> Label {
        let idx = self.labels.len();
        self.labels.push(None);

        Label(idx)
    }

    pub fn define_label(&mut self, lbl: Label) {
        assert!(self.labels[lbl.0].is_none());
        self.labels[lbl.0] = Some(self.buf.pos());
    }

    pub fn emit_label(&mut self, lbl: Label) {
        let value = self.labels[lbl.0];

        match value {
            // backward jumps already know their target
            Some(idx) => {
                let current = self.buf.pos() + 4;
                let target = idx;

                let diff = -((current - target) as i32);
                self.emit_u32(diff as u32);
            }

            // forward jumps do not know their target yet
            // we need to do this later...
            None => {
                let pos = self.buf.pos();
                self.emit_u32(0);
                self.jumps.push(ForwardJump {
                    at: pos,
                    to: lbl
                });
            }
        }
    }

    pub fn emit_u8(&mut self, value: u8) {
        self.buf.emit_u8(value);
    }

    pub fn emit_u32(&mut self, value: u32) {
        self.buf.emit_u32(value);
    }
}

#[derive(Debug)]
struct ForwardJump {
    at: usize,
    to: Label
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_label() {
        let mut buf = Buffer::new();

        assert_eq!(Label(0), buf.create_label());
        assert_eq!(Label(1), buf.create_label());
    }

    #[test]
    fn test_backward_with_gap() {
        let mut buf = Buffer::new();
        let lbl = buf.create_label();
        buf.define_label(lbl);
        buf.emit_u8(0x33);
        buf.emit_label(lbl);

        assert_eq!(vec![0x33, 0xfb, 0xff, 0xff, 0xff], buf.finish());
    }

    #[test]
    fn test_backward() {
        let mut buf = Buffer::new();
        let lbl = buf.create_label();
        buf.define_label(lbl);
        buf.emit_label(lbl);

        assert_eq!(vec![0xfc, 0xff, 0xff, 0xff], buf.finish());
    }

    #[test]
    fn test_forward_with_gap() {
        let mut buf = Buffer::new();
        let lbl = buf.create_label();
        buf.emit_label(lbl);
        buf.emit_u8(0x11);
        buf.define_label(lbl);

        assert_eq!(vec![1, 0, 0, 0, 0x11], buf.finish());
    }

    #[test]
    fn test_forward() {
        let mut buf = Buffer::new();
        let lbl = buf.create_label();
        buf.emit_label(lbl);
        buf.define_label(lbl);

        assert_eq!(vec![0, 0, 0, 0], buf.finish());
    }

    #[test]
    #[should_panic]
    fn test_define_label_twice() {
        let mut buf = Buffer::new();
        let lbl = buf.create_label();

        buf.define_label(lbl);
        buf.define_label(lbl);
    }

    #[test]
    #[should_panic]
    fn test_label_undefined() {
        let mut buf = Buffer::new();
        let lbl = buf.create_label();

        buf.emit_label(lbl);
        buf.finish();
    }
}
<commit_msg>codegen: removed ByteBuffer<commit_after>use byteorder::{LittleEndian, WriteBytesExt};

#[derive(Debug)]
pub struct Buffer {
    data: Vec<u8>,
    labels: Vec<Option<usize>>,
    jumps: Vec<ForwardJump>,
}

impl Buffer {
    pub fn new() -> Buffer {
        Buffer {
            data: Vec::new(),
            labels: Vec::new(),
            jumps: Vec::new(),
        }
    }

    pub fn pos(&self) -> usize {
        self.data.len()
    }

    pub fn finish(mut self) -> Vec<u8> {
        self.fix_forward_jumps();

        self.data
    }

    fn fix_forward_jumps(&mut self) {
        for jmp in &self.jumps {
            let target = self.labels[jmp.to.0].expect("label not defined");
            let diff = (target - jmp.at - 4) as i32;

            let mut slice = &mut self.data[jmp.at..];
            slice.write_u32::<LittleEndian>(diff as u32).unwrap();
        }
    }

    pub fn create_label(&mut self) -> Label {
        let idx = self.labels.len();
        self.labels.push(None);

        Label(idx)
    }

    pub fn define_label(&mut self, lbl: Label) {
        let lbl_idx = lbl.index();

        assert!(self.labels[lbl_idx].is_none());
        self.labels[lbl_idx] = Some(self.pos());
    }

    pub fn emit_label(&mut self, lbl: Label) {
        let value = self.labels[lbl.index()];

        match value {
            // backward jumps already know their target
            Some(idx) => {
                let current = self.pos() + 4;
                let target = idx;

                let diff = -((current - target) as i32);
                self.emit_u32(diff as u32);
            }

            // forward jumps do not know their target yet
            // we need to do this later...
            None => {
                let pos = self.pos();
                self.emit_u32(0);
                self.jumps.push(ForwardJump {
                    at: pos,
                    to: lbl
                });
            }
        }
    }

    pub fn emit_u8(&mut self, value: u8) {
        self.data.write_u8(value).unwrap();
    }

    pub fn emit_u32(&mut self, value: u32) {
        self.data.write_u32::<LittleEndian>(value).unwrap();
    }
}

#[derive(Debug)]
struct ForwardJump {
    at: usize,
    to: Label
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Label(usize);

impl Label {
    pub fn index(&self) -> usize {
        self.0
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_label() {
        let mut buf = Buffer::new();

        assert_eq!(Label(0), buf.create_label());
        assert_eq!(Label(1), buf.create_label());
    }

    #[test]
    fn test_backward_with_gap() {
        let mut buf = Buffer::new();
        let lbl = buf.create_label();
        buf.define_label(lbl);
        buf.emit_u8(0x33);
        buf.emit_label(lbl);

        assert_eq!(vec![0x33, 0xfb, 0xff, 0xff, 0xff], buf.finish());
    }

    #[test]
    fn test_backward() {
        let mut buf = Buffer::new();
        let lbl = buf.create_label();
        buf.define_label(lbl);
        buf.emit_label(lbl);

        assert_eq!(vec![0xfc, 0xff, 0xff, 0xff], buf.finish());
    }

    #[test]
    fn test_forward_with_gap() {
        let mut buf = Buffer::new();
        let lbl = buf.create_label();
        buf.emit_label(lbl);
        buf.emit_u8(0x11);
        buf.define_label(lbl);

        assert_eq!(vec![1, 0, 0, 0, 0x11], buf.finish());
    }

    #[test]
    fn test_forward() {
        let mut buf = Buffer::new();
        let lbl = buf.create_label();
        buf.emit_label(lbl);
        buf.define_label(lbl);

        assert_eq!(vec![0, 0, 0, 0], buf.finish());
    }

    #[test]
    #[should_panic]
    fn test_define_label_twice() {
        let mut buf = Buffer::new();
        let lbl = buf.create_label();

        buf.define_label(lbl);
        buf.define_label(lbl);
    }

    #[test]
    #[should_panic]
    fn test_label_undefined() {
        let mut buf = Buffer::new();
        let lbl = buf.create_label();

        buf.emit_label(lbl);
        buf.finish();
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use stb_image::bindgen::*;

use std::any::Any;
use libc;
use libc::{c_void, c_int};
use std::slice::raw::from_buf_raw;

pub struct Image<T> {
    pub width   : uint,
    pub height  : uint,
    pub depth   : uint,
    pub data    : ~[T],
}

pub fn new_image<T>(width: uint, height: uint, depth: uint, data: ~[T]) -> Image<T> {
    Image::<T> {
        width   : width,
        height  : height,
        depth   : depth,
        data    : data,
    }
}

pub enum LoadResult {
    Error(~str),
    ImageU8(Image<u8>),
    ImageF32(Image<f32>),
}

impl LoadResult {
    pub fn from_result(res: Result<LoadResult,~Any>)-> LoadResult {
        match res {
            Ok(res) => res,
            Err(e)  => Error(e.to_str()),
        }
    }
}

pub fn load(path: ~str) -> LoadResult {
    let force_depth = 0;
    load_with_depth(path, force_depth, false)
}

fn load_internal<T>(buf : *T, w : c_int, h : c_int, d : c_int) -> Image<T> {
    unsafe {
        // FIXME: Shouldn't copy; instead we should use a sendable resource. They
        // aren't particularly safe yet though.
        let data = from_buf_raw(buf, (w * h * d) as uint);
        libc::free(buf as *mut c_void);
        Image::<T>{
            width   : w as uint,
            height  : h as uint,
            depth   : d as uint,
            data    : data}
    }
}

pub fn load_with_depth(path: ~str, force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        path.to_c_str().with_ref(|bytes| {
            if !convert_hdr && stbi_is_hdr(bytes)!=0   {
                let buffer = stbi_loadf(bytes,
                                        &mut width,
                                        &mut height,
                                        &mut depth,
                                        force_depth as c_int);
                if buffer.is_null() {
                    Error(~"stbi_loadf failed")
                } else {
                    ImageF32(load_internal(buffer, width, height, depth))
                }
            } else {
                let buffer = stbi_load(bytes,
                                       &mut width,
                                       &mut height,
                                       &mut depth,
                                       force_depth as c_int);
                if buffer.is_null() {
                    Error(~"stbi_load failed")
                } else {
                    ImageU8(load_internal(buffer, width, height, depth))
                }
            }
        })
    }
}

pub fn load_from_memory(buffer: &[u8]) -> LoadResult {
    let force_depth = 0;
    load_from_memory_with_depth(buffer, force_depth, false)
}

pub fn load_from_memory_with_depth(buffer: &[u8], force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        if !convert_hdr && stbi_is_hdr_from_memory(buffer.as_ptr(), buffer.len() as c_int) != 0 {
            let buffer = stbi_loadf_from_memory(buffer.as_ptr(),
                                                buffer.len() as c_int,
                                                &mut width,
                                                &mut height,
                                                &mut depth,
                                                force_depth as c_int);
            if buffer.is_null() {
                Error(~"stbi_loadf_from_memory failed")
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageF32(load_internal(buffer, width, height, actual_depth))
            }
        } else {
            let buffer = stbi_load_from_memory(buffer.as_ptr(),
                                               buffer.len() as c_int,
                                               &mut width,
                                               &mut height,
                                               &mut depth,
                                               force_depth as c_int);
            if buffer.is_null() {
                Error(~"stbi_load_from_memory failed")
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageU8(load_internal(buffer, width, height, actual_depth))
            }
        }
    }
}
<commit_msg>Update ~[T] -> Vec<T><commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use stb_image::bindgen::*;

use std::any::Any;
use libc;
use libc::{c_void, c_int};
use std::slice::raw::buf_as_slice;

pub struct Image<T> {
    pub width   : uint,
    pub height  : uint,
    pub depth   : uint,
    pub data    : Vec<T>,
}

pub fn new_image<T>(width: uint, height: uint, depth: uint, data: Vec<T>) -> Image<T> {
    Image::<T> {
        width   : width,
        height  : height,
        depth   : depth,
        data    : data,
    }
}

pub enum LoadResult {
    Error(~str),
    ImageU8(Image<u8>),
    ImageF32(Image<f32>),
}

impl LoadResult {
    pub fn from_result(res: Result<LoadResult,~Any>)-> LoadResult {
        match res {
            Ok(res) => res,
            Err(e)  => Error(e.to_str()),
        }
    }
}

pub fn load(path: ~str) -> LoadResult {
    let force_depth = 0;
    load_with_depth(path, force_depth, false)
}

fn load_internal<T: Clone>(buf : *T, w : c_int, h : c_int, d : c_int) -> Image<T> {
    unsafe {
        // FIXME: Shouldn't copy; instead we should use a sendable resource. They
        // aren't particularly safe yet though.
        let data = buf_as_slice(buf, (w * h * d) as uint, |s| { Vec::from_slice(s) });
        libc::free(buf as *mut c_void);
        Image::<T>{
            width   : w as uint,
            height  : h as uint,
            depth   : d as uint,
            data    : data}
    }
}

pub fn load_with_depth(path: ~str, force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        path.to_c_str().with_ref(|bytes| {
            if !convert_hdr && stbi_is_hdr(bytes)!=0   {
                let buffer = stbi_loadf(bytes,
                                        &mut width,
                                        &mut height,
                                        &mut depth,
                                        force_depth as c_int);
                if buffer.is_null() {
                    Error(~"stbi_loadf failed")
                } else {
                    ImageF32(load_internal(buffer, width, height, depth))
                }
            } else {
                let buffer = stbi_load(bytes,
                                       &mut width,
                                       &mut height,
                                       &mut depth,
                                       force_depth as c_int);
                if buffer.is_null() {
                    Error(~"stbi_load failed")
                } else {
                    ImageU8(load_internal(buffer, width, height, depth))
                }
            }
        })
    }
}

pub fn load_from_memory(buffer: &[u8]) -> LoadResult {
    let force_depth = 0;
    load_from_memory_with_depth(buffer, force_depth, false)
}

pub fn load_from_memory_with_depth(buffer: &[u8], force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        if !convert_hdr && stbi_is_hdr_from_memory(buffer.as_ptr(), buffer.len() as c_int) != 0 {
            let buffer = stbi_loadf_from_memory(buffer.as_ptr(),
                                                buffer.len() as c_int,
                                                &mut width,
                                                &mut height,
                                                &mut depth,
                                                force_depth as c_int);
            if buffer.is_null() {
                Error(~"stbi_loadf_from_memory failed")
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageF32(load_internal(buffer, width, height, actual_depth))
            }
        } else {
            let buffer = stbi_load_from_memory(buffer.as_ptr(),
                                               buffer.len() as c_int,
                                               &mut width,
                                               &mut height,
                                               &mut depth,
                                               force_depth as c_int);
            if buffer.is_null() {
                Error(~"stbi_load_from_memory failed")
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageU8(load_internal(buffer, width, height, actual_depth))
            }
        }
    }
}
<|endoftext|>


<commit_before>//!
//! [`RawDevice`](RawDevice) and [`RawSurface`](RawSurface)
//! implementations using the legacy mode-setting infrastructure.
//!
//! Usually this implementation will be wrapped into a [`GbmDevice`](::backend::drm::gbm::GbmDevice).
//! Take a look at `anvil`s source code for an example of this.
//!
//! For an example how to use this standalone, take a look at the `raw_legacy_drm` example.
//!

use super::{common::Error, DevPath, Device, DeviceHandler, RawDevice};

use drm::control::{
    connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Event, ResourceHandles,
};
use drm::{Device as BasicDevice, SystemError as DrmError};
use nix::libc::dev_t;
use nix::sys::stat::fstat;

use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::os::unix::io::{AsRawFd, RawFd};
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock};

use failure::{Fail, ResultExt};

mod surface;
pub use self::surface::LegacyDrmSurface;
use self::surface::{LegacyDrmSurfaceInternal, State};

#[cfg(feature = "backend_session")]
pub mod session;

/// Open raw drm device utilizing legacy mode-setting
pub struct LegacyDrmDevice<A: AsRawFd + 'static> {
    dev: Rc<Dev<A>>,
    dev_id: dev_t,
    active: Arc<AtomicBool>,
    backends: Rc<RefCell<HashMap<crtc::Handle, Weak<LegacyDrmSurfaceInternal<A>>>>>,
    handler: Option<RefCell<Box<dyn DeviceHandler<Device = LegacyDrmDevice<A>>>>>,
    logger: ::slog::Logger,
}

pub(in crate::backend::drm) struct Dev<A: AsRawFd + 'static> {
    fd: A,
    privileged: bool,
    active: Arc<AtomicBool>,
    old_state: HashMap<crtc::Handle, (crtc::Info, Vec<connector::Handle>)>,
    logger: ::slog::Logger,
}
impl<A: AsRawFd + 'static> AsRawFd for Dev<A> {
    fn as_raw_fd(&self) -> RawFd {
        self.fd.as_raw_fd()
    }
}
impl<A: AsRawFd + 'static> BasicDevice for Dev<A> {}
impl<A: AsRawFd + 'static> ControlDevice for Dev<A> {}
impl<A: AsRawFd + 'static> Drop for Dev<A> {
    fn drop(&mut self) {
        info!(self.logger, "Dropping device: {:?}", self.dev_path());
        if self.active.load(Ordering::SeqCst) {
            // Here we restore the tty to it's previous state.
            // In case e.g. getty was running on the tty sets the correct framebuffer again,
            // so that getty will be visible.
            let old_state = self.old_state.clone();
            for (handle, (info, connectors)) in old_state {
                if let Err(err) = self.set_crtc(
                    handle,
                    info.framebuffer(),
                    info.position(),
                    &connectors,
                    info.mode(),
                ) {
                    error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err);
                }
            }
        }
        if self.privileged {
            if let Err(err) = self.release_master_lock() {
                error!(self.logger, "Failed to drop drm master state. Error: {}", err);
            }
        }
    }
}

impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
    /// Create a new [`LegacyDrmDevice`] from an open drm node
    ///
    /// Returns an error if the file is no valid drm node or context creation was not
    /// successful.
    pub fn new<L>(dev: A, logger: L) -> Result<Self, Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_drm"));
        info!(log, "LegacyDrmDevice initializing");

        let dev_id = fstat(dev.as_raw_fd())
            .map_err(Error::UnableToGetDeviceId)?
            .st_rdev;

        let active = Arc::new(AtomicBool::new(true));
        let mut dev = Dev {
            fd: dev,
            privileged: true,
            old_state: HashMap::new(),
            active: active.clone(),
            logger: log.clone(),
        };

        // we want to modeset, so we better be the master, if we run via a tty session
        if dev.acquire_master_lock().is_err() {
            warn!(log, "Unable to become drm master, assuming unprivileged mode");
            dev.privileged = false;
        };

        // enumerate (and save) the current device state
        let res_handles = ControlDevice::resource_handles(&dev)
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error loading drm resources",
                dev: dev.dev_path(),
                source,
            })?;
        for &con in res_handles.connectors() {
            let con_info = dev.get_connector(con).compat().map_err(|source| Error::Access {
                errmsg: "Error loading connector info",
                dev: dev.dev_path(),
                source,
            })?;
            if let Some(enc) = con_info.current_encoder() {
                let enc_info = dev.get_encoder(enc).compat().map_err(|source| Error::Access {
                    errmsg: "Error loading encoder info",
                    dev: dev.dev_path(),
                    source,
                })?;
                if let Some(crtc) = enc_info.crtc() {
                    let info = dev.get_crtc(crtc).compat().map_err(|source| Error::Access {
                        errmsg: "Error loading crtc info",
                        dev: dev.dev_path(),
                        source,
                    })?;
                    dev.old_state
                        .entry(crtc)
                        .or_insert((info, Vec::new()))
                        .1
                        .push(con);
                }
            }
        }

        Ok(LegacyDrmDevice {
            dev: Rc::new(dev),
            dev_id,
            active,
            backends: Rc::new(RefCell::new(HashMap::new())),
            handler: None,
            logger: log.clone(),
        })
    }
}

impl<A: AsRawFd + 'static> AsRawFd for LegacyDrmDevice<A> {
    fn as_raw_fd(&self) -> RawFd {
        self.dev.as_raw_fd()
    }
}

impl<A: AsRawFd + 'static> BasicDevice for LegacyDrmDevice<A> {}
impl<A: AsRawFd + 'static> ControlDevice for LegacyDrmDevice<A> {}

impl<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
    type Surface = LegacyDrmSurface<A>;

    fn device_id(&self) -> dev_t {
        self.dev_id
    }

    fn set_handler(&mut self, handler: impl DeviceHandler<Device = Self> + 'static) {
        self.handler = Some(RefCell::new(Box::new(handler)));
    }

    fn clear_handler(&mut self) {
        let _ = self.handler.take();
    }

    fn create_surface(&mut self, crtc: crtc::Handle) -> Result<LegacyDrmSurface<A>, Error> {
        if self.backends.borrow().contains_key(&crtc) {
            return Err(Error::CrtcAlreadyInUse(crtc));
        }

        if !self.active.load(Ordering::SeqCst) {
            return Err(Error::DeviceInactive);
        }

        // Try to enumarate the current state to set the initial state variable correctly

        let crtc_info = self.get_crtc(crtc).compat().map_err(|source| Error::Access {
            errmsg: "Error loading crtc info",
            dev: self.dev_path(),
            source,
        })?;

        let mode = crtc_info.mode();

        let mut connectors = HashSet::new();
        let res_handles = ControlDevice::resource_handles(self)
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error loading drm resources",
                dev: self.dev_path(),
                source,
            })?;
        for &con in res_handles.connectors() {
            let con_info = self.get_connector(con).compat().map_err(|source| Error::Access {
                errmsg: "Error loading connector info",
                dev: self.dev_path(),
                source,
            })?;
            if let Some(enc) = con_info.current_encoder() {
                let enc_info = self.get_encoder(enc).compat().map_err(|source| Error::Access {
                    errmsg: "Error loading encoder info",
                    dev: self.dev_path(),
                    source,
                })?;
                if let Some(current_crtc) = enc_info.crtc() {
                    if crtc == current_crtc {
                        connectors.insert(con);
                    }
                }
            }
        }

        // Now try to do the least possible amount of changes to set this to the state the users requested
        // TODO!

        let state = State { mode, connectors };
        let backend = Rc::new(LegacyDrmSurfaceInternal {
            dev: self.dev.clone(),
            crtc,
            state: RwLock::new(state.clone()),
            pending: RwLock::new(state),
            logger: self.logger.new(o!("crtc" => format!("{:?}", crtc))),
        });

        self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend));
        Ok(LegacyDrmSurface(backend))
    }

    fn process_events(&mut self) {
        match self.receive_events() {
            Ok(events) => {
                for event in events {
                    if let Event::PageFlip(event) = event {
                        if self.active.load(Ordering::SeqCst) {
                            if self
                                .backends
                                .borrow()
                                .get(&event.crtc)
                                .iter()
                                .flat_map(|x| x.upgrade())
                                .next()
                                .is_some()
                            {
                                trace!(self.logger, "Handling event for backend {:?}", event.crtc);
                                if let Some(handler) = self.handler.as_ref() {
                                    handler.borrow_mut().vblank(event.crtc);
                                }
                            } else {
                                self.backends.borrow_mut().remove(&event.crtc);
                            }
                        } else {
                            debug!(self.logger, "Device not active. Ignoring PageFlip");
                        }
                    } else {
                        trace!(self.logger, "Unrelated event");
                    }
                }
            }
            Err(source) => {
                if let Some(handler) = self.handler.as_ref() {
                    handler.borrow_mut().error(Error::Access {
                        errmsg: "Error processing drm events",
                        dev: self.dev_path(),
                        source: source.compat(),
                    });
                }
            }
        }
    }

    fn resource_handles(&self) -> Result<ResourceHandles, Error> {
        ControlDevice::resource_handles(self)
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error loading resource info",
                dev: self.dev_path(),
                source,
            })
    }

    fn get_connector_info(&self, conn: connector::Handle) -> Result<connector::Info, DrmError> {
        self.get_connector(conn)
    }
    fn get_crtc_info(&self, crtc: crtc::Handle) -> Result<crtc::Info, DrmError> {
        self.get_crtc(crtc)
    }
    fn get_encoder_info(&self, enc: encoder::Handle) -> Result<encoder::Info, DrmError> {
        self.get_encoder(enc)
    }
    fn get_framebuffer_info(&self, fb: framebuffer::Handle) -> Result<framebuffer::Info, DrmError> {
        self.get_framebuffer(fb)
    }
    fn get_plane_info(&self, plane: plane::Handle) -> Result<plane::Info, DrmError> {
        self.get_plane(plane)
    }
}

impl<A: AsRawFd + 'static> RawDevice for LegacyDrmDevice<A> {
    type Surface = LegacyDrmSurface<A>;
}

impl<A: AsRawFd + 'static> Drop for LegacyDrmDevice<A> {
    fn drop(&mut self) {
        self.clear_handler();
    }
}
<commit_msg>legacy: remove outdated comment<commit_after>//!
//! [`RawDevice`](RawDevice) and [`RawSurface`](RawSurface)
//! implementations using the legacy mode-setting infrastructure.
//!
//! Usually this implementation will be wrapped into a [`GbmDevice`](::backend::drm::gbm::GbmDevice).
//! Take a look at `anvil`s source code for an example of this.
//!
//! For an example how to use this standalone, take a look at the `raw_legacy_drm` example.
//!

use super::{common::Error, DevPath, Device, DeviceHandler, RawDevice};

use drm::control::{
    connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Event, ResourceHandles,
};
use drm::{Device as BasicDevice, SystemError as DrmError};
use nix::libc::dev_t;
use nix::sys::stat::fstat;

use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::os::unix::io::{AsRawFd, RawFd};
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock};

use failure::{Fail, ResultExt};

mod surface;
pub use self::surface::LegacyDrmSurface;
use self::surface::{LegacyDrmSurfaceInternal, State};

#[cfg(feature = "backend_session")]
pub mod session;

/// Open raw drm device utilizing legacy mode-setting
pub struct LegacyDrmDevice<A: AsRawFd + 'static> {
    dev: Rc<Dev<A>>,
    dev_id: dev_t,
    active: Arc<AtomicBool>,
    backends: Rc<RefCell<HashMap<crtc::Handle, Weak<LegacyDrmSurfaceInternal<A>>>>>,
    handler: Option<RefCell<Box<dyn DeviceHandler<Device = LegacyDrmDevice<A>>>>>,
    logger: ::slog::Logger,
}

pub(in crate::backend::drm) struct Dev<A: AsRawFd + 'static> {
    fd: A,
    privileged: bool,
    active: Arc<AtomicBool>,
    old_state: HashMap<crtc::Handle, (crtc::Info, Vec<connector::Handle>)>,
    logger: ::slog::Logger,
}
impl<A: AsRawFd + 'static> AsRawFd for Dev<A> {
    fn as_raw_fd(&self) -> RawFd {
        self.fd.as_raw_fd()
    }
}
impl<A: AsRawFd + 'static> BasicDevice for Dev<A> {}
impl<A: AsRawFd + 'static> ControlDevice for Dev<A> {}
impl<A: AsRawFd + 'static> Drop for Dev<A> {
    fn drop(&mut self) {
        info!(self.logger, "Dropping device: {:?}", self.dev_path());
        if self.active.load(Ordering::SeqCst) {
            // Here we restore the tty to it's previous state.
            // In case e.g. getty was running on the tty sets the correct framebuffer again,
            // so that getty will be visible.
            let old_state = self.old_state.clone();
            for (handle, (info, connectors)) in old_state {
                if let Err(err) = self.set_crtc(
                    handle,
                    info.framebuffer(),
                    info.position(),
                    &connectors,
                    info.mode(),
                ) {
                    error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err);
                }
            }
        }
        if self.privileged {
            if let Err(err) = self.release_master_lock() {
                error!(self.logger, "Failed to drop drm master state. Error: {}", err);
            }
        }
    }
}

impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
    /// Create a new [`LegacyDrmDevice`] from an open drm node
    ///
    /// Returns an error if the file is no valid drm node or context creation was not
    /// successful.
    pub fn new<L>(dev: A, logger: L) -> Result<Self, Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_drm"));
        info!(log, "LegacyDrmDevice initializing");

        let dev_id = fstat(dev.as_raw_fd())
            .map_err(Error::UnableToGetDeviceId)?
            .st_rdev;

        let active = Arc::new(AtomicBool::new(true));
        let mut dev = Dev {
            fd: dev,
            privileged: true,
            old_state: HashMap::new(),
            active: active.clone(),
            logger: log.clone(),
        };

        // we want to modeset, so we better be the master, if we run via a tty session
        if dev.acquire_master_lock().is_err() {
            warn!(log, "Unable to become drm master, assuming unprivileged mode");
            dev.privileged = false;
        };

        // enumerate (and save) the current device state
        let res_handles = ControlDevice::resource_handles(&dev)
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error loading drm resources",
                dev: dev.dev_path(),
                source,
            })?;
        for &con in res_handles.connectors() {
            let con_info = dev.get_connector(con).compat().map_err(|source| Error::Access {
                errmsg: "Error loading connector info",
                dev: dev.dev_path(),
                source,
            })?;
            if let Some(enc) = con_info.current_encoder() {
                let enc_info = dev.get_encoder(enc).compat().map_err(|source| Error::Access {
                    errmsg: "Error loading encoder info",
                    dev: dev.dev_path(),
                    source,
                })?;
                if let Some(crtc) = enc_info.crtc() {
                    let info = dev.get_crtc(crtc).compat().map_err(|source| Error::Access {
                        errmsg: "Error loading crtc info",
                        dev: dev.dev_path(),
                        source,
                    })?;
                    dev.old_state
                        .entry(crtc)
                        .or_insert((info, Vec::new()))
                        .1
                        .push(con);
                }
            }
        }

        Ok(LegacyDrmDevice {
            dev: Rc::new(dev),
            dev_id,
            active,
            backends: Rc::new(RefCell::new(HashMap::new())),
            handler: None,
            logger: log.clone(),
        })
    }
}

impl<A: AsRawFd + 'static> AsRawFd for LegacyDrmDevice<A> {
    fn as_raw_fd(&self) -> RawFd {
        self.dev.as_raw_fd()
    }
}

impl<A: AsRawFd + 'static> BasicDevice for LegacyDrmDevice<A> {}
impl<A: AsRawFd + 'static> ControlDevice for LegacyDrmDevice<A> {}

impl<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
    type Surface = LegacyDrmSurface<A>;

    fn device_id(&self) -> dev_t {
        self.dev_id
    }

    fn set_handler(&mut self, handler: impl DeviceHandler<Device = Self> + 'static) {
        self.handler = Some(RefCell::new(Box::new(handler)));
    }

    fn clear_handler(&mut self) {
        let _ = self.handler.take();
    }

    fn create_surface(&mut self, crtc: crtc::Handle) -> Result<LegacyDrmSurface<A>, Error> {
        if self.backends.borrow().contains_key(&crtc) {
            return Err(Error::CrtcAlreadyInUse(crtc));
        }

        if !self.active.load(Ordering::SeqCst) {
            return Err(Error::DeviceInactive);
        }

        // Try to enumarate the current state to set the initial state variable correctly

        let crtc_info = self.get_crtc(crtc).compat().map_err(|source| Error::Access {
            errmsg: "Error loading crtc info",
            dev: self.dev_path(),
            source,
        })?;

        let mode = crtc_info.mode();

        let mut connectors = HashSet::new();
        let res_handles = ControlDevice::resource_handles(self)
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error loading drm resources",
                dev: self.dev_path(),
                source,
            })?;
        for &con in res_handles.connectors() {
            let con_info = self.get_connector(con).compat().map_err(|source| Error::Access {
                errmsg: "Error loading connector info",
                dev: self.dev_path(),
                source,
            })?;
            if let Some(enc) = con_info.current_encoder() {
                let enc_info = self.get_encoder(enc).compat().map_err(|source| Error::Access {
                    errmsg: "Error loading encoder info",
                    dev: self.dev_path(),
                    source,
                })?;
                if let Some(current_crtc) = enc_info.crtc() {
                    if crtc == current_crtc {
                        connectors.insert(con);
                    }
                }
            }
        }

        let state = State { mode, connectors };
        let backend = Rc::new(LegacyDrmSurfaceInternal {
            dev: self.dev.clone(),
            crtc,
            state: RwLock::new(state.clone()),
            pending: RwLock::new(state),
            logger: self.logger.new(o!("crtc" => format!("{:?}", crtc))),
        });

        self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend));
        Ok(LegacyDrmSurface(backend))
    }

    fn process_events(&mut self) {
        match self.receive_events() {
            Ok(events) => {
                for event in events {
                    if let Event::PageFlip(event) = event {
                        if self.active.load(Ordering::SeqCst) {
                            if self
                                .backends
                                .borrow()
                                .get(&event.crtc)
                                .iter()
                                .flat_map(|x| x.upgrade())
                                .next()
                                .is_some()
                            {
                                trace!(self.logger, "Handling event for backend {:?}", event.crtc);
                                if let Some(handler) = self.handler.as_ref() {
                                    handler.borrow_mut().vblank(event.crtc);
                                }
                            } else {
                                self.backends.borrow_mut().remove(&event.crtc);
                            }
                        } else {
                            debug!(self.logger, "Device not active. Ignoring PageFlip");
                        }
                    } else {
                        trace!(self.logger, "Unrelated event");
                    }
                }
            }
            Err(source) => {
                if let Some(handler) = self.handler.as_ref() {
                    handler.borrow_mut().error(Error::Access {
                        errmsg: "Error processing drm events",
                        dev: self.dev_path(),
                        source: source.compat(),
                    });
                }
            }
        }
    }

    fn resource_handles(&self) -> Result<ResourceHandles, Error> {
        ControlDevice::resource_handles(self)
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error loading resource info",
                dev: self.dev_path(),
                source,
            })
    }

    fn get_connector_info(&self, conn: connector::Handle) -> Result<connector::Info, DrmError> {
        self.get_connector(conn)
    }
    fn get_crtc_info(&self, crtc: crtc::Handle) -> Result<crtc::Info, DrmError> {
        self.get_crtc(crtc)
    }
    fn get_encoder_info(&self, enc: encoder::Handle) -> Result<encoder::Info, DrmError> {
        self.get_encoder(enc)
    }
    fn get_framebuffer_info(&self, fb: framebuffer::Handle) -> Result<framebuffer::Info, DrmError> {
        self.get_framebuffer(fb)
    }
    fn get_plane_info(&self, plane: plane::Handle) -> Result<plane::Info, DrmError> {
        self.get_plane(plane)
    }
}

impl<A: AsRawFd + 'static> RawDevice for LegacyDrmDevice<A> {
    type Surface = LegacyDrmSurface<A>;
}

impl<A: AsRawFd + 'static> Drop for LegacyDrmDevice<A> {
    fn drop(&mut self) {
        self.clear_handler();
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

//! Compilation of native dependencies like LLVM.
//!
//! Native projects like LLVM unfortunately aren't suited just yet for
//! compilation in build scripts that Cargo has. This is because thie
//! compilation takes a *very* long time but also because we don't want to
//! compile LLVM 3 times as part of a normal bootstrap (we want it cached).
//!
//! LLVM and compiler-rt are essentially just wired up to everything else to
//! ensure that they're always in place if needed.

use std::env;
use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::Path;
use std::process::Command;

use build_helper::output;
use cmake;
use gcc;

use Build;
use util;
use build_helper::up_to_date;

/// Compile LLVM for `target`.
pub fn llvm(build: &Build, target: &str) {
    // If we're using a custom LLVM bail out here, but we can only use a
    // custom LLVM for the build triple.
    if let Some(config) = build.config.target_config.get(target) {
        if let Some(ref s) = config.llvm_config {
            return check_llvm_version(build, s);
        }
    }

    let rebuild_trigger = build.src.join("src/rustllvm/llvm-rebuild-trigger");
    let mut rebuild_trigger_contents = String::new();
    t!(t!(File::open(&rebuild_trigger)).read_to_string(&mut rebuild_trigger_contents));

    let out_dir = build.llvm_out(target);
    let done_stamp = out_dir.join("llvm-finished-building");
    if done_stamp.exists() {
        let mut done_contents = String::new();
        t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents));

        // If LLVM was already built previously and contents of the rebuild-trigger file
        // didn't change from the previous build, then no action is required.
        if done_contents == rebuild_trigger_contents {
            return
        }
    }
    if build.config.llvm_clean_rebuild {
        drop(fs::remove_dir_all(&out_dir));
    }

    println!("Building LLVM for {}", target);
    let _time = util::timeit();
    t!(fs::create_dir_all(&out_dir));

    // http://llvm.org/docs/CMake.html
    let mut cfg = cmake::Config::new(build.src.join("src/llvm"));
    if build.config.ninja {
        cfg.generator("Ninja");
    }

    let profile = match (build.config.llvm_optimize, build.config.llvm_release_debuginfo) {
        (false, _) => "Debug",
        (true, false) => "Release",
        (true, true) => "RelWithDebInfo",
    };

    // NOTE: remember to also update `config.toml.example` when changing the defaults!
    let llvm_targets = match build.config.llvm_targets {
        Some(ref s) => s,
        None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX",
    };

    let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"};

    cfg.target(target)
       .host(&build.config.build)
       .out_dir(&out_dir)
       .profile(profile)
       .define("LLVM_ENABLE_ASSERTIONS", assertions)
       .define("LLVM_TARGETS_TO_BUILD", llvm_targets)
       .define("LLVM_INCLUDE_EXAMPLES", "OFF")
       .define("LLVM_INCLUDE_TESTS", "OFF")
       .define("LLVM_INCLUDE_DOCS", "OFF")
       .define("LLVM_ENABLE_ZLIB", "OFF")
       .define("WITH_POLLY", "OFF")
       .define("LLVM_ENABLE_TERMINFO", "OFF")
       .define("LLVM_ENABLE_LIBEDIT", "OFF")
       .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string())
       .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
       .define("LLVM_DEFAULT_TARGET_TRIPLE", target);

    if target.contains("msvc") {
        cfg.define("LLVM_USE_CRT_DEBUG", "MT");
        cfg.define("LLVM_USE_CRT_RELEASE", "MT");
        cfg.define("LLVM_USE_CRT_RELWITHDEBINFO", "MT");
    }

    if target.starts_with("i686") {
        cfg.define("LLVM_BUILD_32_BITS", "ON");
    }

    if let Some(num_linkers) = build.config.llvm_link_jobs {
        if num_linkers > 0 {
            cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
        }
    }

    // http://llvm.org/docs/HowToCrossCompileLLVM.html
    if target != build.config.build {
        // FIXME: if the llvm root for the build triple is overridden then we
        //        should use llvm-tblgen from there, also should verify that it
        //        actually exists most of the time in normal installs of LLVM.
        let host = build.llvm_out(&build.config.build).join("bin/llvm-tblgen");
        cfg.define("CMAKE_CROSSCOMPILING", "True")
           .define("LLVM_TABLEGEN", &host);
    }

    // MSVC handles compiler business itself
    if !target.contains("msvc") {
        if let Some(ref ccache) = build.config.ccache {
           cfg.define("CMAKE_C_COMPILER", ccache)
              .define("CMAKE_C_COMPILER_ARG1", build.cc(target))
              .define("CMAKE_CXX_COMPILER", ccache)
              .define("CMAKE_CXX_COMPILER_ARG1", build.cxx(target));
        } else {
           cfg.define("CMAKE_C_COMPILER", build.cc(target))
              .define("CMAKE_CXX_COMPILER", build.cxx(target));
        }
        cfg.build_arg("-j").build_arg(build.jobs().to_string());

        cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" "));
        cfg.define("CMAKE_CXX_FLAGS", build.cflags(target).join(" "));
    }

    if env::var_os("SCCACHE_ERROR_LOG").is_some() {
        cfg.env("RUST_LOG", "sccache=info");
    }

    // FIXME: we don't actually need to build all LLVM tools and all LLVM
    //        libraries here, e.g. we just want a few components and a few
    //        tools. Figure out how to filter them down and only build the right
    //        tools and libs on all platforms.
    cfg.build();

    t!(t!(File::create(&done_stamp)).write_all(rebuild_trigger_contents.as_bytes()));
}

fn check_llvm_version(build: &Build, llvm_config: &Path) {
    if !build.config.llvm_version_check {
        return
    }

    let mut cmd = Command::new(llvm_config);
    let version = output(cmd.arg("--version"));
    if version.starts_with("3.5") || version.starts_with("3.6") ||
       version.starts_with("3.7") {
        return
    }
    panic!("\n\nbad LLVM version: {}, need >=3.5\n\n", version)
}

/// Compiles the `rust_test_helpers.c` library which we used in various
/// `run-pass` test suites for ABI testing.
pub fn test_helpers(build: &Build, target: &str) {
    let dst = build.test_helpers_out(target);
    let src = build.src.join("src/rt/rust_test_helpers.c");
    if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
        return
    }

    println!("Building test helpers");
    t!(fs::create_dir_all(&dst));
    let mut cfg = gcc::Config::new();

    // We may have found various cross-compilers a little differently due to our
    // extra configuration, so inform gcc of these compilers. Note, though, that
    // on MSVC we still need gcc's detection of env vars (ugh).
    if !target.contains("msvc") {
        if let Some(ar) = build.ar(target) {
            cfg.archiver(ar);
        }
        cfg.compiler(build.cc(target));
    }

    cfg.cargo_metadata(false)
       .out_dir(&dst)
       .target(target)
       .host(&build.config.build)
       .opt_level(0)
       .debug(false)
       .file(build.src.join("src/rt/rust_test_helpers.c"))
       .compile("librust_test_helpers.a");
}
const OPENSSL_VERS: &'static str = "1.0.2k";
const OPENSSL_SHA256: &'static str =
    "6b3977c61f2aedf0f96367dcfb5c6e578cf37e7b8d913b4ecb6643c3cb88d8c0";

pub fn openssl(build: &Build, target: &str) {
    let out = match build.openssl_dir(target) {
        Some(dir) => dir,
        None => return,
    };

    let stamp = out.join(".stamp");
    let mut contents = String::new();
    drop(File::open(&stamp).and_then(|mut f| f.read_to_string(&mut contents)));
    if contents == OPENSSL_VERS {
        return
    }
    t!(fs::create_dir_all(&out));

    let name = format!("openssl-{}.tar.gz", OPENSSL_VERS);
    let tarball = out.join(&name);
    if !tarball.exists() {
        let tmp = tarball.with_extension("tmp");
        // originally from https://www.openssl.org/source/...
        let url = format!("https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/{}",
                          name);
        let mut ok = false;
        for _ in 0..3 {
            let status = Command::new("curl")
                            .arg("-o").arg(&tmp)
                            .arg(&url)
                            .status()
                            .expect("failed to spawn curl");
            if status.success() {
                ok = true;
                break
            }
        }
        if !ok {
            panic!("failed to download openssl source")
        }
        let mut shasum = if target.contains("apple") {
            let mut cmd = Command::new("shasum");
            cmd.arg("-a").arg("256");
            cmd
        } else {
            Command::new("sha256sum")
        };
        let output = output(&mut shasum.arg(&tmp));
        let found = output.split_whitespace().next().unwrap();
        if found != OPENSSL_SHA256 {
            panic!("downloaded openssl sha256 different\n\
                    expected: {}\n\
                    found:    {}\n", OPENSSL_SHA256, found);
        }
        t!(fs::rename(&tmp, &tarball));
    }
    let obj = out.join(format!("openssl-{}", OPENSSL_VERS));
    let dst = build.openssl_install_dir(target).unwrap();
    drop(fs::remove_dir_all(&obj));
    drop(fs::remove_dir_all(&dst));
    build.run(Command::new("tar").arg("xf").arg(&tarball).current_dir(&out));

    let mut configure = Command::new(obj.join("Configure"));
    configure.arg(format!("--prefix={}", dst.display()));
    configure.arg("no-dso");
    configure.arg("no-ssl2");
    configure.arg("no-ssl3");

    let os = match target {
        "aarch64-unknown-linux-gnu" => "linux-aarch64",
        "arm-unknown-linux-gnueabi" => "linux-armv4",
        "arm-unknown-linux-gnueabihf" => "linux-armv4",
        "armv7-unknown-linux-gnueabihf" => "linux-armv4",
        "i686-apple-darwin" => "darwin-i386-cc",
        "i686-unknown-freebsd" => "BSD-x86-elf",
        "i686-unknown-linux-gnu" => "linux-elf",
        "i686-unknown-linux-musl" => "linux-elf",
        "mips-unknown-linux-gnu" => "linux-mips32",
        "mips64-unknown-linux-gnuabi64" => "linux64-mips64",
        "mips64el-unknown-linux-gnuabi64" => "linux64-mips64",
        "mipsel-unknown-linux-gnu" => "linux-mips32",
        "powerpc-unknown-linux-gnu" => "linux-ppc",
        "powerpc64-unknown-linux-gnu" => "linux-ppc64",
        "powerpc64le-unknown-linux-gnu" => "linux-ppc64le",
        "s390x-unknown-linux-gnu" => "linux64-s390x",
        "x86_64-apple-darwin" => "darwin64-x86_64-cc",
        "x86_64-unknown-freebsd" => "BSD-x86_64",
        "x86_64-unknown-linux-gnu" => "linux-x86_64",
        "x86_64-unknown-linux-musl" => "linux-x86_64",
        "x86_64-unknown-netbsd" => "BSD-x86_64",
        _ => panic!("don't know how to configure OpenSSL for {}", target),
    };
    configure.arg(os);
    configure.env("CC", build.cc(target));
    for flag in build.cflags(target) {
        configure.arg(flag);
    }
    configure.current_dir(&obj);
    println!("Configuring openssl for {}", target);
    build.run_quiet(&mut configure);
    println!("Building openssl for {}", target);
    build.run_quiet(Command::new("make").current_dir(&obj));
    println!("Installing openssl for {}", target);
    build.run_quiet(Command::new("make").arg("install").current_dir(&obj));

    let mut f = t!(File::create(&stamp));
    t!(f.write_all(OPENSSL_VERS.as_bytes()));
}
<commit_msg>Make sure openssl compiles with only one core<commit_after>// Copyright 2015 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.

//! Compilation of native dependencies like LLVM.
//!
//! Native projects like LLVM unfortunately aren't suited just yet for
//! compilation in build scripts that Cargo has. This is because thie
//! compilation takes a *very* long time but also because we don't want to
//! compile LLVM 3 times as part of a normal bootstrap (we want it cached).
//!
//! LLVM and compiler-rt are essentially just wired up to everything else to
//! ensure that they're always in place if needed.

use std::env;
use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::Path;
use std::process::Command;

use build_helper::output;
use cmake;
use gcc;

use Build;
use util;
use build_helper::up_to_date;

/// Compile LLVM for `target`.
pub fn llvm(build: &Build, target: &str) {
    // If we're using a custom LLVM bail out here, but we can only use a
    // custom LLVM for the build triple.
    if let Some(config) = build.config.target_config.get(target) {
        if let Some(ref s) = config.llvm_config {
            return check_llvm_version(build, s);
        }
    }

    let rebuild_trigger = build.src.join("src/rustllvm/llvm-rebuild-trigger");
    let mut rebuild_trigger_contents = String::new();
    t!(t!(File::open(&rebuild_trigger)).read_to_string(&mut rebuild_trigger_contents));

    let out_dir = build.llvm_out(target);
    let done_stamp = out_dir.join("llvm-finished-building");
    if done_stamp.exists() {
        let mut done_contents = String::new();
        t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents));

        // If LLVM was already built previously and contents of the rebuild-trigger file
        // didn't change from the previous build, then no action is required.
        if done_contents == rebuild_trigger_contents {
            return
        }
    }
    if build.config.llvm_clean_rebuild {
        drop(fs::remove_dir_all(&out_dir));
    }

    println!("Building LLVM for {}", target);
    let _time = util::timeit();
    t!(fs::create_dir_all(&out_dir));

    // http://llvm.org/docs/CMake.html
    let mut cfg = cmake::Config::new(build.src.join("src/llvm"));
    if build.config.ninja {
        cfg.generator("Ninja");
    }

    let profile = match (build.config.llvm_optimize, build.config.llvm_release_debuginfo) {
        (false, _) => "Debug",
        (true, false) => "Release",
        (true, true) => "RelWithDebInfo",
    };

    // NOTE: remember to also update `config.toml.example` when changing the defaults!
    let llvm_targets = match build.config.llvm_targets {
        Some(ref s) => s,
        None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX",
    };

    let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"};

    cfg.target(target)
       .host(&build.config.build)
       .out_dir(&out_dir)
       .profile(profile)
       .define("LLVM_ENABLE_ASSERTIONS", assertions)
       .define("LLVM_TARGETS_TO_BUILD", llvm_targets)
       .define("LLVM_INCLUDE_EXAMPLES", "OFF")
       .define("LLVM_INCLUDE_TESTS", "OFF")
       .define("LLVM_INCLUDE_DOCS", "OFF")
       .define("LLVM_ENABLE_ZLIB", "OFF")
       .define("WITH_POLLY", "OFF")
       .define("LLVM_ENABLE_TERMINFO", "OFF")
       .define("LLVM_ENABLE_LIBEDIT", "OFF")
       .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string())
       .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
       .define("LLVM_DEFAULT_TARGET_TRIPLE", target);

    if target.contains("msvc") {
        cfg.define("LLVM_USE_CRT_DEBUG", "MT");
        cfg.define("LLVM_USE_CRT_RELEASE", "MT");
        cfg.define("LLVM_USE_CRT_RELWITHDEBINFO", "MT");
    }

    if target.starts_with("i686") {
        cfg.define("LLVM_BUILD_32_BITS", "ON");
    }

    if let Some(num_linkers) = build.config.llvm_link_jobs {
        if num_linkers > 0 {
            cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
        }
    }

    // http://llvm.org/docs/HowToCrossCompileLLVM.html
    if target != build.config.build {
        // FIXME: if the llvm root for the build triple is overridden then we
        //        should use llvm-tblgen from there, also should verify that it
        //        actually exists most of the time in normal installs of LLVM.
        let host = build.llvm_out(&build.config.build).join("bin/llvm-tblgen");
        cfg.define("CMAKE_CROSSCOMPILING", "True")
           .define("LLVM_TABLEGEN", &host);
    }

    // MSVC handles compiler business itself
    if !target.contains("msvc") {
        if let Some(ref ccache) = build.config.ccache {
           cfg.define("CMAKE_C_COMPILER", ccache)
              .define("CMAKE_C_COMPILER_ARG1", build.cc(target))
              .define("CMAKE_CXX_COMPILER", ccache)
              .define("CMAKE_CXX_COMPILER_ARG1", build.cxx(target));
        } else {
           cfg.define("CMAKE_C_COMPILER", build.cc(target))
              .define("CMAKE_CXX_COMPILER", build.cxx(target));
        }
        cfg.build_arg("-j").build_arg(build.jobs().to_string());

        cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" "));
        cfg.define("CMAKE_CXX_FLAGS", build.cflags(target).join(" "));
    }

    if env::var_os("SCCACHE_ERROR_LOG").is_some() {
        cfg.env("RUST_LOG", "sccache=info");
    }

    // FIXME: we don't actually need to build all LLVM tools and all LLVM
    //        libraries here, e.g. we just want a few components and a few
    //        tools. Figure out how to filter them down and only build the right
    //        tools and libs on all platforms.
    cfg.build();

    t!(t!(File::create(&done_stamp)).write_all(rebuild_trigger_contents.as_bytes()));
}

fn check_llvm_version(build: &Build, llvm_config: &Path) {
    if !build.config.llvm_version_check {
        return
    }

    let mut cmd = Command::new(llvm_config);
    let version = output(cmd.arg("--version"));
    if version.starts_with("3.5") || version.starts_with("3.6") ||
       version.starts_with("3.7") {
        return
    }
    panic!("\n\nbad LLVM version: {}, need >=3.5\n\n", version)
}

/// Compiles the `rust_test_helpers.c` library which we used in various
/// `run-pass` test suites for ABI testing.
pub fn test_helpers(build: &Build, target: &str) {
    let dst = build.test_helpers_out(target);
    let src = build.src.join("src/rt/rust_test_helpers.c");
    if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
        return
    }

    println!("Building test helpers");
    t!(fs::create_dir_all(&dst));
    let mut cfg = gcc::Config::new();

    // We may have found various cross-compilers a little differently due to our
    // extra configuration, so inform gcc of these compilers. Note, though, that
    // on MSVC we still need gcc's detection of env vars (ugh).
    if !target.contains("msvc") {
        if let Some(ar) = build.ar(target) {
            cfg.archiver(ar);
        }
        cfg.compiler(build.cc(target));
    }

    cfg.cargo_metadata(false)
       .out_dir(&dst)
       .target(target)
       .host(&build.config.build)
       .opt_level(0)
       .debug(false)
       .file(build.src.join("src/rt/rust_test_helpers.c"))
       .compile("librust_test_helpers.a");
}
const OPENSSL_VERS: &'static str = "1.0.2k";
const OPENSSL_SHA256: &'static str =
    "6b3977c61f2aedf0f96367dcfb5c6e578cf37e7b8d913b4ecb6643c3cb88d8c0";

pub fn openssl(build: &Build, target: &str) {
    let out = match build.openssl_dir(target) {
        Some(dir) => dir,
        None => return,
    };

    let stamp = out.join(".stamp");
    let mut contents = String::new();
    drop(File::open(&stamp).and_then(|mut f| f.read_to_string(&mut contents)));
    if contents == OPENSSL_VERS {
        return
    }
    t!(fs::create_dir_all(&out));

    let name = format!("openssl-{}.tar.gz", OPENSSL_VERS);
    let tarball = out.join(&name);
    if !tarball.exists() {
        let tmp = tarball.with_extension("tmp");
        // originally from https://www.openssl.org/source/...
        let url = format!("https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/{}",
                          name);
        let mut ok = false;
        for _ in 0..3 {
            let status = Command::new("curl")
                            .arg("-o").arg(&tmp)
                            .arg(&url)
                            .status()
                            .expect("failed to spawn curl");
            if status.success() {
                ok = true;
                break
            }
        }
        if !ok {
            panic!("failed to download openssl source")
        }
        let mut shasum = if target.contains("apple") {
            let mut cmd = Command::new("shasum");
            cmd.arg("-a").arg("256");
            cmd
        } else {
            Command::new("sha256sum")
        };
        let output = output(&mut shasum.arg(&tmp));
        let found = output.split_whitespace().next().unwrap();
        if found != OPENSSL_SHA256 {
            panic!("downloaded openssl sha256 different\n\
                    expected: {}\n\
                    found:    {}\n", OPENSSL_SHA256, found);
        }
        t!(fs::rename(&tmp, &tarball));
    }
    let obj = out.join(format!("openssl-{}", OPENSSL_VERS));
    let dst = build.openssl_install_dir(target).unwrap();
    drop(fs::remove_dir_all(&obj));
    drop(fs::remove_dir_all(&dst));
    build.run(Command::new("tar").arg("xf").arg(&tarball).current_dir(&out));

    let mut configure = Command::new(obj.join("Configure"));
    configure.arg(format!("--prefix={}", dst.display()));
    configure.arg("no-dso");
    configure.arg("no-ssl2");
    configure.arg("no-ssl3");

    let os = match target {
        "aarch64-unknown-linux-gnu" => "linux-aarch64",
        "arm-unknown-linux-gnueabi" => "linux-armv4",
        "arm-unknown-linux-gnueabihf" => "linux-armv4",
        "armv7-unknown-linux-gnueabihf" => "linux-armv4",
        "i686-apple-darwin" => "darwin-i386-cc",
        "i686-unknown-freebsd" => "BSD-x86-elf",
        "i686-unknown-linux-gnu" => "linux-elf",
        "i686-unknown-linux-musl" => "linux-elf",
        "mips-unknown-linux-gnu" => "linux-mips32",
        "mips64-unknown-linux-gnuabi64" => "linux64-mips64",
        "mips64el-unknown-linux-gnuabi64" => "linux64-mips64",
        "mipsel-unknown-linux-gnu" => "linux-mips32",
        "powerpc-unknown-linux-gnu" => "linux-ppc",
        "powerpc64-unknown-linux-gnu" => "linux-ppc64",
        "powerpc64le-unknown-linux-gnu" => "linux-ppc64le",
        "s390x-unknown-linux-gnu" => "linux64-s390x",
        "x86_64-apple-darwin" => "darwin64-x86_64-cc",
        "x86_64-unknown-freebsd" => "BSD-x86_64",
        "x86_64-unknown-linux-gnu" => "linux-x86_64",
        "x86_64-unknown-linux-musl" => "linux-x86_64",
        "x86_64-unknown-netbsd" => "BSD-x86_64",
        _ => panic!("don't know how to configure OpenSSL for {}", target),
    };
    configure.arg(os);
    configure.env("CC", build.cc(target));
    for flag in build.cflags(target) {
        configure.arg(flag);
    }
    configure.current_dir(&obj);
    println!("Configuring openssl for {}", target);
    build.run_quiet(&mut configure);
    println!("Building openssl for {}", target);
    build.run_quiet(Command::new("make").arg("-j1").current_dir(&obj));
    println!("Installing openssl for {}", target);
    build.run_quiet(Command::new("make").arg("install").current_dir(&obj));

    let mut f = t!(File::create(&stamp));
    t!(f.write_all(OPENSSL_VERS.as_bytes()));
}
<|endoftext|>