<commit_before>// Kevin Cantu
// additional string functions I've wanted in Rust

/* so far including:
   splitfn
   lines
   words
*/

#[link(name = "str2", author = "kcantu", vers = "0.0")];
use std;

// a better slice, unicode safe
// since strings are null terminated, cannot copy in place
//
// start is the character position to begin copying
// end is the character position which should not be copied
//
// Does not make internal conversion to char (which is UTF-32/UCS-4),
// but is UTF-8 aware.
//
fn byte_position (&&ss: str, char_position: uint) -> uint
{
   let cursor_char = 0u;
   let cursor_byte = 0u;

   while cursor_char < char_position {
      cursor_byte += str::utf8_char_width(ss[cursor_byte]);
      cursor_char += 1u;
   }
   ret cursor_char;
}

fn slice_chars(ss: str, start: uint, end: uint) -> str unsafe
{
   // FIXME: should we make some assertions here?

   // find the start and end
   let byte_start = byte_position(ss, start);
   let byte_end = byte_position(ss, end);

   // copy the bytes
   let new_vector = [];
   let ii = byte_start;

   while ii < byte_end {
      vec::push(new_vector, ss[ii]);
   }
   vec::push(new_vector, 0u8);

   // return as a string
   let new_string: str = unsafe::reinterpret_cast(new_vector);
   unsafe::leak(new_vector);
   ret new_string;
}

// a more general split, unicode safe
// using a function, e.g., char::is_whitespace instead of single u8
fn splitfn(ss: str, sepf: fn&(cc: char)->bool) -> [str]
{
   let vv: [str] = [];
   let accum: str = "";
   let ends_with_sep: bool = false;

   str::iter_chars(ss, {|cc|
      if sepf(cc) {
         vv += [accum];
         accum = "";
         ends_with_sep = true;
      } else {
         str::push_char(accum, cc);
         ends_with_sep = false;
      }
   });
   if str::char_len(accum) != 0u || ends_with_sep {
      vv += [accum];
   }
   ret vv;
}

#[test]
fn test_splitfn_a ()
{
   let data = "ประเทศไทย中华Việt Nam";
   assert ["ประเทศไทย中",
           "Việt Nam"]
      == splitfn (data, {|cc| cc == '华'});
}

fn lines (ss: str) -> [str]
{
   ret splitfn(ss, {|cc| cc == '\n'});
}

#[test]
fn test_lines_splitfn ()
{
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["", "Mary had a little lamb", "Little lamb", "Little lamb", ""]
      == lines(data);
}

fn words (ss: str) -> [str]
{
   ret vec::filter( splitfn(ss, {|cc| char::is_whitespace(cc)}),
                    {|w| 0u < str::char_len(w)});
}

#[test]
fn test_words_splitfn ()
{
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["Mary","had","a","little","lamb","Little","lamb","Little","lamb"]
      == words(data);
}

#[test]
fn test_example ()
{
   let s = "ประเทศไทย中华Việt Nam";
   let i = 0u;
   while i < str::byte_len(s)
   {
      let {ch:c, next:j} = str::char_range_at(s, i);
      std::io::println(#fmt("%u: %c",i,c));
      //std::io::println(#fmt("%u: %c (%c)",i,c,s[i] as char)); // note that s[i] is str[uint] -> u8
      i = j;
   }

   /* Output:
      0: ป
      3: ร
      6: ะ
      9: เ
      12: ท
      15: ศ
      18: ไ
      21: ท
      24: ย
      27: 中
      30: 华
      33: V
      34: i
      35: ệ
      38: t
      39:
      40: N
      41: a
      42: m
   */
}

<commit_msg>slice_chars now compiles...<commit_after>// Kevin Cantu
// additional string functions I've wanted in Rust

/* so far including:
   splitfn
   lines
   words
*/

#[link(name = "str2", author = "kcantu", vers = "0.0")];
use std;

// a better slice, unicode safe
// since strings are null terminated, cannot copy in place
//
// start is the character position to begin copying
// end is the character position which should not be copied
//
// Does not make internal conversion to char (which is UTF-32/UCS-4),
// but is UTF-8 aware.
//

// helper: note, slice_chars could be faster (by not starting byte_position from zero the second time)
// if this was a named block internal to slice_chars
fn byte_position (&&ss: str, char_position: uint) -> uint
{
   let cursor_char = 0u;
   let cursor_byte = 0u;

   while cursor_char < char_position {
      let sz = str::utf8_char_width(ss[cursor_byte]);
      assert (sz > 0u);
      cursor_byte += sz;
      cursor_char += 1u;
   }
   assert cursor_byte == str::byte_len(ss);
   ret cursor_char;
}

fn slice_chars(ss: str, start: uint, end: uint) -> str unsafe
{
   // FIXME: should we make some assertions here?

   // find the start and end
   let byte_start = byte_position(ss, start);
   let byte_end = byte_position(ss, end);

   // copy the bytes
   let new_vector = [];
   let ii = byte_start;

   while ii < byte_end {
      vec::push(new_vector, ss[ii]);
   }
   vec::push(new_vector, 0u8);

   // return as a string
   let new_string: str = unsafe::reinterpret_cast(new_vector);
   unsafe::leak(new_vector);
   ret new_string;
}

// a more general split, unicode safe
// using a function, e.g., char::is_whitespace instead of single u8
fn splitfn(ss: str, sepf: fn&(cc: char)->bool) -> [str]
{
   let vv: [str] = [];
   let accum: str = "";
   let ends_with_sep: bool = false;

   str::iter_chars(ss, {|cc|
      if sepf(cc) {
         vv += [accum];
         accum = "";
         ends_with_sep = true;
      } else {
         str::push_char(accum, cc);
         ends_with_sep = false;
      }
   });
   if str::char_len(accum) != 0u || ends_with_sep {
      vv += [accum];
   }
   ret vv;
}

#[test]
fn test_splitfn_a ()
{
   let data = "ประเทศไทย中华Việt Nam";
   assert ["ประเทศไทย中",
           "Việt Nam"]
      == splitfn (data, {|cc| cc == '华'});
}

fn lines (ss: str) -> [str]
{
   ret splitfn(ss, {|cc| cc == '\n'});
}

#[test]
fn test_lines_splitfn ()
{
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["", "Mary had a little lamb", "Little lamb", "Little lamb", ""]
      == lines(data);
}

fn words (ss: str) -> [str]
{
   ret vec::filter( splitfn(ss, {|cc| char::is_whitespace(cc)}),
                    {|w| 0u < str::char_len(w)});
}

#[test]
fn test_words_splitfn ()
{
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["Mary","had","a","little","lamb","Little","lamb","Little","lamb"]
      == words(data);
}

#[test]
fn test_example ()
{
   let s = "ประเทศไทย中华Việt Nam";
   let i = 0u;
   while i < str::byte_len(s)
   {
      let {ch:c, next:j} = str::char_range_at(s, i);
      std::io::println(#fmt("%u: %c",i,c));
      //std::io::println(#fmt("%u: %c (%c)",i,c,s[i] as char)); // note that s[i] is str[uint] -> u8
      i = j;
   }

   /* Output:
      0: ป
      3: ร
      6: ะ
      9: เ
      12: ท
      15: ศ
      18: ไ
      21: ท
      24: ย
      27: 中
      30: 华
      33: V
      34: i
      35: ệ
      38: t
      39:
      40: N
      41: a
      42: m
   */
}

<|endoftext|>


<commit_before>#![feature(core_intrinsics, patchpoint_call_intrinsic, stackmap_call_intrinsic)]
#![feature(question_mark)]
#![feature(type_ascription)]
#![allow(unused_features)]

use std::intrinsics;

#[allow(dead_code)]
mod byteorder;
#[allow(dead_code, unused_imports, unused_variables, unused_mut)]
mod elf;

mod llvm_stackmaps;

fn subcall(data: *mut u8) {
    println!("Enter `subcall`");
    let mut i = 0;
    let mut saw_one = false;
    print!("[");
    let mut datum = unsafe { *data.offset(i) as char };
    while datum != '\0' {
        if saw_one {
            print!(", ");
        }
        print!("{}", datum);
        saw_one = true;
        i += 1;
        datum = unsafe { *data.offset(i) as char };
    }
    println!("]");
    println!("Finis `subcall`");
}

fn main() {
    demo().unwrap();
}

#[derive(Debug)]
enum DemoError {
    ParseError(elf::ParseError),
    MissingSection(String),
}

impl std::convert::From<elf::ParseError> for DemoError {
    fn from(x: elf::ParseError) -> Self { DemoError::ParseError(x) }
}

fn demo() -> Result<(), DemoError> {
    use std::path::Path;
    use self::llvm_stackmaps::StackMap;
    use self::byteorder::LittleEndian;

    // FIXME: this is not a reliable way to extract the executable file path.
    // (look into alternatives)
    let binary = std::env::args().next().unwrap();

    println!("Hello World from {}", binary);

    let path = Path::new(&binary);
    let file = elf::File::open_path(&path)?;

    let stackmap_section = {
        let name = ".llvm_stackmaps".to_string();
        file.get_section(name.clone())
            .ok_or_else(|| DemoError::MissingSection(name))?
    };

    println!("stackmap_section: {:?}", stackmap_section);

    let stack_map = StackMap::read_from::<LittleEndian>(&mut &stackmap_section.data[..]);
    println!("stack_map: {:?}", stack_map);

    let data = &mut [b'h', b'e', b'l', b'l', b'o', 0];
    unsafe {
        intrinsics::stackmap_call(0, 13, subcall, data.as_mut_ptr());
    }

    println!("Goodbye World");

    Ok(())
}
<commit_msg>REMOVEME added code to emit the dataflow results to aid me in debugging.<commit_after>#![feature(core_intrinsics, patchpoint_call_intrinsic, stackmap_call_intrinsic)]
#![feature(question_mark)]
#![feature(type_ascription)]
#![feature(rustc_attrs)]
#![allow(unused_features)]

use std::intrinsics;

#[allow(dead_code)]
mod byteorder;
#[allow(dead_code, unused_imports, unused_variables, unused_mut)]
mod elf;

mod llvm_stackmaps;

fn subcall(data: *mut u8) {
    println!("Enter `subcall`");
    let mut i = 0;
    let mut saw_one = false;
    print!("[");
    let mut datum = unsafe { *data.offset(i) as char };
    while datum != '\0' {
        if saw_one {
            print!(", ");
        }
        print!("{}", datum);
        saw_one = true;
        i += 1;
        datum = unsafe { *data.offset(i) as char };
    }
    println!("]");
    println!("Finis `subcall`");
}

fn main() {
    demo().unwrap();
}

#[derive(Debug)]
enum DemoError {
    ParseError(elf::ParseError),
    MissingSection(String),
}

impl std::convert::From<elf::ParseError> for DemoError {
    fn from(x: elf::ParseError) -> Self { DemoError::ParseError(x) }
}

#[rustc_mir(borrowck_graphviz_postflow="/tmp/foo.dot")]
fn demo() -> Result<(), DemoError> {
    use std::path::Path;
    use self::llvm_stackmaps::StackMap;
    use self::byteorder::LittleEndian;

    // FIXME: this is not a reliable way to extract the executable file path.
    // (look into alternatives)
    let binary = std::env::args().next().unwrap();

    println!("Hello World from {}", binary);

    let path = Path::new(&binary);
    let file = elf::File::open_path(&path)?;

    let stackmap_section = {
        let name = ".llvm_stackmaps".to_string();
        file.get_section(name.clone())
            .ok_or_else(|| DemoError::MissingSection(name))?
    };

    println!("stackmap_section: {:?}", stackmap_section);

    let stack_map = StackMap::read_from::<LittleEndian>(&mut &stackmap_section.data[..]);
    println!("stack_map: {:?}", stack_map);

    let mut data = vec![b'h', b'e', b'l', b'l', b'o', 0];
    println!("path addr: {:?}", &path as *const _);
    println!("file addr: {:?}", &file as *const _);
    println!("data addr: {:?}", &data as *const _);
    unsafe {
        intrinsics::stackmap_call(0, 13, subcall, data.as_mut_ptr());
    }

    println!("Goodbye World");

    Ok(())
}
<|endoftext|>


<commit_before>//! ZWave basic functionality - top layer
//!
//! This is the top layer which handles the whole ZWave interface
//! and allows to easy access all nodes and their functionality.
//!
//! It's proposed to use this module from the crate.

//! The `Controller` provides the functionality to connected
//! to a Z-Wave network, to send  messages and to receive them.

use driver::Driver;

use std::rc::Rc;
use std::cell::RefCell;
use cc::CmdClass;

use error::Error;

/************************** Controller Area *********************/

/// The private representation of a controller
struct _Controller<D> where D: Driver {
    driver: D,
    nodes: Vec<Node<D>>,
}

// reference type for the controller
type ControllerRef<D> = Rc<RefCell<_Controller<D>>>;

// The public representation of a controller, with some syntactic sugar.
pub struct Controller<D>(ControllerRef<D>) where D: Driver;

// The actual controller implementation
impl<D> Controller<D> where D: Driver {
    /// Creates a new controller
    pub fn new(driver: D) -> Result<Controller<D>, Error> {
        let controller = Controller(Rc::new(RefCell::new(_Controller {
            driver: driver,
            nodes: vec!()
        })));

        // discover nodes automaically
        let nd = controller.discover_nodes();
        if nd.is_some() {
            return Err(nd.unwrap());
        }

        Ok(controller)
    }

    /// Refresh the complete node list
    pub fn discover_nodes(&self) -> Option<Error> {
        // clear the existing nodes
        /*self.0.borrow_mut().nodes.clear();

        // write out the descovery node command and receive the answer
        let res = self.0.borrow().driver.write_and_read(Message::new(Type::Request, Function::DiscoveryNodes, vec!()));

        // when a error occoured return it
        let res = unwrap_or_return!(res.clone().ok(), res.err());

        // grab the data
        let data = res.data;

        // check if the data is long enough and if the right bit is set
        if data.len() != 34 || data[2] != 0x1D {
            return Some(Error::new(ErrorKind::UnknownZWave, "The ZWave message has a wrong format"));
        }

        // loop over each bitmask byte
        for i in 3..31 {
            // loop over each bit of the byte
            for j in 0..7 {
                // check if the bit is set
                if Controller::get_bit_at(data[i], j) {
                    // calc the number out of the bitmask
                    let n = ((i-3) * 8) + (j as usize+1);
                    // create the node for the given id
                    let n = Node::new(self.clone(), n as u8);
                    // add it !!! need 2 steps to prevent collition with borrow
                    self.0.borrow_mut().nodes.push(n);
                }
            }
        }*/

        // when everything went well, return no error
        None
    }

    /// Returns a vector of all available nodes
    pub fn get_nodes(&self) -> Vec<Node<D>> {
        self.0.borrow().nodes.clone()
    }

    /// Returns the Node with the given ZWave network id, when available.
    pub fn get_node(&self, index: usize) -> Option<Node<D>> {
        let this = self.0.borrow();

        // loop over all nodes and check if the id exist
        for n in &this.nodes {
            if index == n.get_id() as usize {
                // return the node with the id
                return Some(n.clone());
            }
        }

        // when no id was found return nothing
        None
    }

    /*** private functions below this line ***/

    /// Checks if the bit at the requested position is set
    fn get_bit_at(input: u8, n: u8) -> bool {
        if n < 8 {
            input & (1 << n) != 0
        } else {
            false
        }
    }
}

impl<D> Clone for Controller<D> where D: Driver {
    fn clone(&self) -> Controller<D> {
        Controller(self.0.clone())
    }
}

/************************** Node Area *********************/

// The private representation of a node
struct _Node<D> where D: Driver {
    id: u8,
    controller: Controller<D>,
    generic_type: GenericType,
    class_basic: Option<CmdClass>
}

// reference type for the node
type NodeRef<D> = Rc<RefCell<_Node<D>>>;

// The public representation of a node, with some syntactic sugar.
pub struct Node<D>(NodeRef<D>) where D: Driver;

// The actual node implementation
impl<D> Node<D> where D: Driver {
    /// Creates a new node with no edges.
    pub fn new(contr: Controller<D>, id: u8) -> Node<D> {
        let node = Node(Rc::new(RefCell::new(_Node {
            id: id,
            controller: contr,
            generic_type: GenericType::Unknown,
            class_basic: None
        })));

        node.discover_type();
        node.discover_classes();

        node
    }

    /// Sets the available type for this node
    pub fn discover_type(&self) {
        /*let mut this = &mut self.0.borrow_mut();

        // create a new message
        let msg = Message::new(Type::Request, Function::GetNodeProtocolInfo, vec!(this.id));

        // send the message to the ZWave driver
        let msg = unwrap_or_return!(this.controller.get_driver().write_and_read(msg).ok(), ());

        //check if the answer has the right length && is no error
        if msg.data.len() != 6 {
            this.generic_type = GenericType::Unknown;
            return;
        }

        // extract the delivered type
        this.generic_type = GenericType::from_u8(msg.data[4]).unwrap_or(GenericType::Unknown);*/
    }

    /// Sets the available function classes for this node
    pub fn discover_classes(&self) {
        //let mut this = &mut self.0.borrow_mut();

        // todo get the information from the device

        // basic is always available
        //this.class_basic = Some(Basic::new(self.clone()));
    }

    /// returns the basic command class to interact with
    pub fn get_basic(&self) -> Option<CmdClass> {
        self.0.borrow_mut().class_basic.clone()
    }

    /// returns the id of the node in the zwave network
    pub fn get_id(&self) -> u8 {
        self.0.borrow().id.clone()
    }

    // returns the generic type of the node
    pub fn get_generic_type(&self) -> GenericType {
        self.0.borrow().generic_type.clone()
    }
}

impl<D> Clone for Node<D> where D: Driver {
    fn clone(&self) -> Node<D> {
        Node(self.0.clone())
    }
}

/// List of different Node types
enum_from_primitive! {
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum GenericType {
    Unknown = 0x00,
    RemoteController = 0x01,
    StaticController = 0x02,
    AvControlPoint = 0x03,
    RoutingSlave = 0x04,
    Display = 0x06,
    GarageDoor = 0x07,
    WindowCovering = 0x09,
    Thermostat = 0x08,
    RepeaterSlave = 0x0F,
    BinarySwitch = 0x10,
    MultiLevelSwitch = 0x11,
    RemoteSwitch = 0x12,
    ToggleSwitch = 0x13,
    ZIpGateway = 0x14,
    ZIpNode = 0x15,
    Ventilation = 0x16,
    GenericSecurityPanel = 0x17,
    RemoteSwitch2 = 0x18,
    BinarySensor = 0x20,
    MultilevelSensor = 0x21,
    WaterControl = 0x22,
    PulseMeter = 0x30,
    Meter = 0x31,
    EntryControl = 0x40,
    SemiInteroperable = 0x50,
    AlarmSensor = 0xa1,
    NonInteroperable = 0xFF,
}
}
<commit_msg>Added the controller and node class<commit_after>//! ZWave basic functionality - top layer
//!
//! This is the top layer which handles the whole ZWave interface
//! and allows to easy access all nodes and their functionality.
//!
//! It's proposed to use this module from the crate.

//! The `Controller` provides the functionality to connected
//! to a Z-Wave network, to send  messages and to receive them.

use driver::{Driver, GenericType};

use std::rc::Rc;
use std::cell::RefCell;
use cc::CmdClass;

use error::Error;

/************************** Controller Area *********************/

/// The private representation of a controller
struct _Controller<D> where D: Driver+Clone {
    driver: D,
    nodes: Vec<Node<D>>,
}

// reference type for the controller
type ControllerRef<D> = Rc<RefCell<_Controller<D>>>;

// The public representation of a controller, with some syntactic sugar.
pub struct Controller<D>(ControllerRef<D>) where D: Driver+Clone;

// The actual controller implementation
impl<D> Controller<D> where D: Driver+Clone {
    /// Creates a new controller
    pub fn new(driver: D) -> Result<Controller<D>, Error> {
        let controller = Controller(Rc::new(RefCell::new(_Controller {
            driver: driver,
            nodes: vec!()
        })));

        // discover nodes automaically
        controller.discover_nodes()?;

        Ok(controller)
    }

    /// Refresh the complete node list
    pub fn discover_nodes(&self) -> Result<(), Error> {
        // clear the existing nodes
        self.0.borrow_mut().nodes.clear();

        // write out the descovery node command and receive the answer
        let res = self.0.borrow_mut().driver.get_node_ids()?;

        // create a node object for each id
        for i in res {
            // create the node for the given id
            let n = Node::new(self.clone(), i as u8);
            // add it !!! need 2 steps to prevent collition with borrow
            self.0.borrow_mut().nodes.push(n);
        }

        // when everything went well, return no error
        Ok(())
    }

    /// Returns a vector of all available nodes
    pub fn get_nodes(&self) -> Vec<Node<D>> {
        self.0.borrow().nodes.clone()
    }

    /// Returns the Node with the given ZWave network id, when available.
    pub fn get_node(&self, index: usize) -> Option<Node<D>> {
        let this = self.0.borrow();

        // loop over all nodes and check if the id exist
        for n in &this.nodes {
            if index == n.get_id() as usize {
                // return the node with the id
                return Some(n.clone());
            }
        }

        // when no id was found return nothing
        None
    }

    /// returns the driver for this controller
    pub fn get_driver(&self) -> D {
        self.0.borrow().driver.clone()
    }
}

/// The clone function need to be written manually
/// beacause of a 'bug' in rust.
impl<D> Clone for Controller<D> where D: Driver+Clone {
    fn clone(&self) -> Controller<D> {
        Controller(self.0.clone())
    }
}

/************************** Node Area *********************/

// The private representation of a node
struct _Node<D> where D: Driver+Clone {
    id: u8,
    controller: Controller<D>,
    generic_type: GenericType,
    class_basic: Option<CmdClass>
}

// reference type for the node
type NodeRef<D> = Rc<RefCell<_Node<D>>>;

// The public representation of a node, with some syntactic sugar.
pub struct Node<D>(NodeRef<D>) where D: Driver+Clone;

// The actual node implementation
impl<D> Node<D> where D: Driver+Clone {
    /// Creates a new node with no edges.
    pub fn new(contr: Controller<D>, id: u8) -> Node<D> {
        let node = Node(Rc::new(RefCell::new(_Node {
            id: id,
            controller: contr,
            generic_type: GenericType::Unknown,
            class_basic: None
        })));

        // we need to handle to spress the warning,
        // wiich can't be deactivated until today
        if node.discover_type().is_err() {
            node.0.borrow_mut().generic_type = GenericType::Unknown;
        }
        node.discover_classes();

        node
    }

    /// Sets the available type for this node
    pub fn discover_type(&self) -> Result<(), Error> {
        let mut this = &mut self.0.borrow_mut();

        this.generic_type = this.controller.get_driver().get_node_generic_class(&this.id)?;

        Ok(())
    }

    /// Sets the available function classes for this node
    pub fn discover_classes(&self) {
        //let mut this = &mut self.0.borrow_mut();

        // todo get the information from the device

        // basic is always available
        //this.class_basic = Some(Basic::new(self.clone()));
    }

    /// returns the basic command class to interact with
    pub fn get_basic(&self) -> Option<CmdClass> {
        self.0.borrow_mut().class_basic.clone()
    }

    /// returns the id of the node in the zwave network
    pub fn get_id(&self) -> u8 {
        self.0.borrow().id.clone()
    }

    // returns the generic type of the node
    pub fn get_generic_type(&self) -> GenericType {
        self.0.borrow().generic_type.clone()
    }
}

impl<D> Clone for Node<D> where D: Driver+Clone {
    fn clone(&self) -> Node<D> {
        Node(self.0.clone())
    }
}
<|endoftext|>


<commit_before>extern crate serde_json;

use sha2::{Digest, Sha256};
use std::cell::RefCell;
use std::collections::HashMap;
use std::error::Error;
use std::fs::{self, DirEntry, File};
use std::io::Read;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;

#[derive(Serialize, Deserialize, PartialEq)]
pub enum JobStatus {
    Pending,
    Done,
    Error,
}

#[derive(Serialize, Deserialize)]
pub struct Job {
    source_path: String,
    source_sha256sum: String,
    destination_path: String,
    destination_sha256sum: String,

    status: JobStatus,
}

#[derive(Serialize, Deserialize)]
pub struct BatchJob {
    source_dir: String,
    destination_dir: String,
    rules: HashMap<String, String>,
    jobs: Vec<RefCell<Job>>,
}

impl BatchJob {
    pub fn new(source_dir: String, destination_dir: String) -> BatchJob {
        let mut bj = BatchJob {
            source_dir: source_dir,
            destination_dir: destination_dir,
            rules: HashMap::new(),
            jobs: vec![],
        };

        bj.rules.insert(
            String::from("avi"),
            String::from("ffmpeg -i $file_path -c:v libx264 -preset slow $file_path_out"),
        );

        bj
    }

    pub fn init(&mut self) -> Result<(), Box<Error>> {
        let mut lst = vec![];

        // flatten
        {
            let mut add_it = |x: &DirEntry| {
                lst.push(x.path());
            };

            self.visit_dirs(Path::new(&self.source_dir.trim()), &mut add_it)?;
        }

        println!("scanned {} files", lst.len());

        for file in lst.iter() {
            let source_path = file.to_str().unwrap();
            println!("processing {}", source_path);
            let mut file = File::open(source_path).expect("Unable to create config file");
            let hash = Sha256::digest_reader(&mut file)?;

            let job = Job {
                source_path: String::from(source_path),
                source_sha256sum: String::from(format!("{:x}", hash)),
                destination_path: String::new(),
                destination_sha256sum: String::new(),
                status: JobStatus::Pending,
            };

            self.jobs.push(RefCell::new(job));
        }

        Ok(())
    }

    pub fn load_from_file(dir: &str) -> Result<BatchJob, Box<Error>> {
        let filepath = format!("{}/dbfc.config", dir);
        let mut file = File::open(filepath)?;
        let mut buffer = String::new();
        file.read_to_string(&mut buffer)?;
        let bj: BatchJob = serde_json::from_str(&buffer)?;

        Ok(bj)
    }

    pub fn save_to_file(&self) -> Result<(), Box<Error>> {
        let json_result = serde_json::to_string_pretty(&self)?;

        let config_filepath = format!("{}/dbfc.config", self.source_dir);
        let mut file = File::create(config_filepath).expect("Unable to create config file");
        file.write_all(json_result.as_bytes())
            .expect("Unable to write to config file");

        Ok(())
    }

    pub fn run(&mut self) {
        let pending_jobs = self.jobs
            .iter()
            .filter(|j| j.borrow().status == JobStatus::Pending)
            .collect::<Vec<&RefCell<Job>>>();

        println!("{} pending jobs", pending_jobs.len());

        for job_ref in pending_jobs {
            let mut job = job_ref.borrow_mut();

            match self.run_job(&job, self.source_dir.as_str()) {
                Ok(_) => {
                    job.status = JobStatus::Done;
                }
                Err(why) => {
                    job.status = JobStatus::Error;
                    println!("   {}", why);
                }
            }
        }

        if let Err(why) = self.save_to_file() {
            println!("Failed to save batch job state: {}", why);
        }
    }

    fn run_job(&self, job: &Job, source_dir: &str) -> Result<(), String> {
        let path = Path::new(job.source_path.as_str());
        let sub_path = match path.strip_prefix(source_dir) {
            Ok(sp) => sp,
            Err(e) => {
                return Err(format!("   Could not get sub-path: {}", e));
            }
        };

        println!("Processing: {:?}", sub_path);

        if !path.exists() {
            return Err(format!("   Path does not exist"));
        } else if !path.is_file() {
            return Err(format!("   Path is not a file"));
        }

        let extension = match path.extension() {
            Some(e) => match e.to_str() {
                Some(es) => es,
                None => {
                    return Err(format!("   Error converting to string"));
                }
            },
            None => {
                return Err(format!("   No extension"));
            }
        };

        let rule = match self.rules.get(extension) {
            Some(r) => r,
            None => {
                return Err(format!("   No rule defined for extension '{}'", extension));
            }
        };

        let out_path = Path::new(self.destination_dir.as_str()).join(sub_path);
        println!("   Writting to {:?}", out_path);

        // get args and replace any variables
        let raw_args: Vec<&str> = rule.split_whitespace().collect();
        let mut args = Vec::with_capacity(raw_args.len());
        for arg in raw_args.iter() {
            args.push(String::from(match *arg {
                "$file_path" => path.to_str().unwrap(),
                "$file_path_out" => out_path.to_str().unwrap(),
                _ => arg,
            }));
        }
        println!("   {:?}", args);

        // create the output path
        if let Err(why) = fs::create_dir_all(out_path.parent().unwrap()) {
            return Err(format!("   Unable to create out file directory: {}", why));
        }

        let command_name = String::from(args[0].as_str());
        let command_args = &args[1..args.len()];
        let command = Command::new(&command_name)
            .args(command_args)
            .output()
            .expect(format!("Failed to execute command").as_str());

        println!("stdout: {}", String::from_utf8_lossy(&command.stdout));
        println!("stderr: {}", String::from_utf8_lossy(&command.stderr));

        if !command.status.success() {
            return Err(format!(
                "    Command '{}' failed with exit code {:?}",
                &command_name,
                command.status.code()
            ));
        }

        Ok(())
    }

    fn visit_dirs(&self, dir: &Path, cb: &mut FnMut(&DirEntry)) -> Result<(), Box<Error>> {
        if dir.is_dir() {
            for entry in fs::read_dir(dir)? {
                let entry = entry?;
                let path = entry.path();
                if path.is_dir() {
                    self.visit_dirs(&path, cb)?;
                } else {
                    cb(&entry);
                }
            }
        }

        Ok(())
    }

    fn convert_video(&self, source_filepath: &Path, output_dir: &str) {
        let mut out_file = PathBuf::new();
        out_file.push(output_dir);
        out_file.push(source_filepath.file_stem().unwrap());
        out_file.set_extension("mp4");

        let mut output = Command::new("ffmpeg")
            .arg("-loglevel")
            .arg("warning")
            .arg("-i")
            .arg(source_filepath)
            .arg("-y")
            .arg("-c:v")
            .arg("libx264")
            .arg("-preset")
            .arg("ultrafast")
            .arg("-framerate")
            .arg("30")
            .arg("-vsync")
            .arg("1")
            .arg("-crf")
            .arg("20")
            .arg(out_file.as_path())
            .spawn()
            .unwrap_or_else(|e| panic!("failed to execute process: {}", e));

        output.wait().unwrap();
    }
}
<commit_msg>Write destination file to dbfc.config after processing<commit_after>extern crate serde_json;

use sha2::{Digest, Sha256};
use std::cell::RefCell;
use std::collections::HashMap;
use std::error::Error;
use std::fs::{self, DirEntry, File};
use std::io::Read;
use std::io::Write;
use std::path::Path;
use std::process::Command;

#[derive(Serialize, Deserialize, PartialEq)]
pub enum JobStatus {
    Pending,
    Done,
    Error,
}

#[derive(Serialize, Deserialize)]
pub struct Job {
    source_path: String,
    source_sha256sum: String,
    destination_path: String,
    destination_sha256sum: String,

    status: JobStatus,
}

#[derive(Serialize, Deserialize)]
pub struct BatchJob {
    source_dir: String,
    destination_dir: String,
    rules: HashMap<String, String>,
    jobs: Vec<RefCell<Job>>,
}

impl BatchJob {
    pub fn new(source_dir: String, destination_dir: String) -> BatchJob {
        let mut bj = BatchJob {
            source_dir: source_dir,
            destination_dir: destination_dir,
            rules: HashMap::new(),
            jobs: vec![],
        };

        bj.rules.insert(
            String::from("avi"),
            String::from("ffmpeg -i $file_path -c:v libx264 -preset slow $file_path_out"),
        );

        bj
    }

    pub fn init(&mut self) -> Result<(), Box<Error>> {
        let mut lst = vec![];

        // flatten
        {
            let mut add_it = |x: &DirEntry| {
                lst.push(x.path());
            };

            self.visit_dirs(Path::new(&self.source_dir.trim()), &mut add_it)?;
        }

        println!("scanned {} files", lst.len());

        for file in lst.iter() {
            let source_path = file.to_str().unwrap();
            println!("processing {}", source_path);
            let mut file = File::open(source_path).expect("Unable to create config file");
            let hash = Sha256::digest_reader(&mut file)?;

            let job = Job {
                source_path: String::from(source_path),
                source_sha256sum: String::from(format!("{:x}", hash)),
                destination_path: String::new(),
                destination_sha256sum: String::new(),
                status: JobStatus::Pending,
            };

            self.jobs.push(RefCell::new(job));
        }

        Ok(())
    }

    pub fn load_from_file(dir: &str) -> Result<BatchJob, Box<Error>> {
        let filepath = format!("{}/dbfc.config", dir);
        let mut file = File::open(filepath)?;
        let mut buffer = String::new();
        file.read_to_string(&mut buffer)?;
        let bj: BatchJob = serde_json::from_str(&buffer)?;

        Ok(bj)
    }

    pub fn save_to_file(&self) -> Result<(), Box<Error>> {
        let json_result = serde_json::to_string_pretty(&self)?;

        let config_filepath = format!("{}/dbfc.config", self.source_dir);
        let mut file = File::create(config_filepath).expect("Unable to create config file");
        file.write_all(json_result.as_bytes())
            .expect("Unable to write to config file");

        Ok(())
    }

    pub fn run(&mut self) {
        let pending_jobs = self.jobs
            .iter()
            .filter(|j| j.borrow().status == JobStatus::Pending)
            .collect::<Vec<&RefCell<Job>>>();

        println!("{} pending jobs", pending_jobs.len());

        for job_ref in pending_jobs {
            let mut job = job_ref.borrow_mut();

            match self.run_job(&mut job, self.source_dir.as_str()) {
                Ok(_) => {
                    job.status = JobStatus::Done;
                }
                Err(why) => {
                    job.status = JobStatus::Error;
                    println!("   {}", why);
                }
            }
        }

        if let Err(why) = self.save_to_file() {
            println!("Failed to save batch job state: {}", why);
        }
    }

    fn run_job(&self, job: &mut Job, source_dir: &str) -> Result<(), String> {
        let path = Path::new(job.source_path.as_str());
        let sub_path = match path.strip_prefix(source_dir) {
            Ok(sp) => sp,
            Err(e) => {
                return Err(format!("   Could not get sub-path: {}", e));
            }
        };

        println!("Processing: {:?}", sub_path);

        if !path.exists() {
            return Err(format!("   Path does not exist"));
        } else if !path.is_file() {
            return Err(format!("   Path is not a file"));
        }

        let extension = match path.extension() {
            Some(e) => match e.to_str() {
                Some(es) => es,
                None => {
                    return Err(format!("   Error converting to string"));
                }
            },
            None => {
                return Err(format!("   No extension"));
            }
        };

        let rule = match self.rules.get(extension) {
            Some(r) => r,
            None => {
                return Err(format!("   No rule defined for extension '{}'", extension));
            }
        };

        let out_path = Path::new(self.destination_dir.as_str()).join(sub_path);
        println!("   Writting to {:?}", out_path);

        // get args and replace any variables
        let raw_args: Vec<&str> = rule.split_whitespace().collect();
        let mut args = Vec::with_capacity(raw_args.len());
        for arg in raw_args.iter() {
            args.push(String::from(match *arg {
                "$file_path" => path.to_str().unwrap(),
                "$file_path_out" => out_path.to_str().unwrap(),
                _ => arg,
            }));
        }
        println!("   {:?}", args);

        // create the output path
        if let Err(why) = fs::create_dir_all(out_path.parent().unwrap()) {
            return Err(format!("   Unable to create out file directory: {}", why));
        }

        let command_name = String::from(args[0].as_str());
        let command_args = &args[1..args.len()];
        let command = Command::new(&command_name)
            .args(command_args)
            .output()
            .expect(format!("Failed to execute command").as_str());

        println!("stdout: {}", String::from_utf8_lossy(&command.stdout));
        println!("stderr: {}", String::from_utf8_lossy(&command.stderr));

        if !command.status.success() {
            return Err(format!(
                "    Command '{}' failed with exit code {:?}",
                &command_name,
                command.status.code()
            ));
        }

        job.destination_path = String::from(out_path.to_str().unwrap());

        Ok(())
    }

    fn visit_dirs(&self, dir: &Path, cb: &mut FnMut(&DirEntry)) -> Result<(), Box<Error>> {
        if dir.is_dir() {
            for entry in fs::read_dir(dir)? {
                let entry = entry?;
                let path = entry.path();
                if path.is_dir() {
                    self.visit_dirs(&path, cb)?;
                } else {
                    cb(&entry);
                }
            }
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(unix, feature(fs_ext))]

extern crate cargo;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::io;
use std::path::{PathBuf, Path};
use std::process::Command;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult, lev_distance, Config};

#[derive(RustcDecodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help       Display this message
    -V, --version    Print version info and exit
    --list           List installed commands
    -v, --verbose    Use verbose output

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{ ($mac:ident) => ({
    $mac!(bench);
    $mac!(build);
    $mac!(clean);
    $mac!(doc);
    $mac!(fetch);
    $mac!(generate_lockfile);
    $mac!(git_checkout);
    $mac!(help);
    $mac!(locate_project);
    $mac!(login);
    $mac!(new);
    $mac!(owner);
    $mac!(package);
    $mac!(pkgid);
    $mac!(publish);
    $mac!(read_manifest);
    $mac!(run);
    $mac!(search);
    $mac!(test);
    $mac!(update);
    $mac!(verify_project);
    $mac!(version);
    $mac!(yank);
}) }

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    config.shell().set_verbose(flags.flag_verbose);

    init_git_transports(config);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbose(true);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => {
            vec!["cargo".to_string(), flags.arg_args[0].clone(),
                 "-h".to_string()]
        }

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => env::args().collect(),
    };

    macro_rules! cmd{ ($name:ident) => (
        if args[1] == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }
    ) }
    each_subcommand!(cmd);

    execute_subcommand(&args[1], &args, &mut config.shell());
    Ok(None)
}

fn find_closest(cmd: &str) -> Option<String> {
    let cmds = list_commands();
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));

    if filtered.len() == 0 {
        None
    } else {
        Some(filtered[0].1.to_string())
    }
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => {
            let msg = match find_closest(cmd) {
                Some(closest) => format!("No such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "No such subcommand".to_string()
            };
            return handle_error(CliError::new(&msg, 127), shell)
        }
    };
    match Command::new(&command).args(&args[1..]).status() {
        Ok(ref status) if status.success() => {}
        Ok(ref status) => {
            match status.code() {
                Some(code) => handle_error(CliError::new("", code), shell),
                None => {
                    let msg = format!("subcommand failed with: {}", status);
                    handle_error(CliError::new(&msg, 101), shell)
                }
            }
        }
        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
            handle_error(CliError::new("No such subcommand", 127), shell)
        }
        Err(err) => {
            let msg = format!("Subcommand failed to run: {}", err);
            handle_error(CliError::new(&msg, 127), shell)
        }
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> BTreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = BTreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries {
            let entry = match entry { Ok(e) => e, Err(..) => continue };
            let entry = entry.path();
            let filename = match entry.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
               filename.ends_with(env::consts::EXE_SUFFIX) &&
               is_executable(&entry) {
                let command = &filename[
                    command_prefix.len()..
                    filename.len() - env::consts::EXE_SUFFIX.len()];
                commands.insert(command.to_string());
            }
        }
    }

    macro_rules! add_cmd{ ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable(path: &Path) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path).map(|m| {
        m.permissions().mode() & 0o001 == 0o001
    }).unwrap_or(false)
}
#[cfg(windows)]
fn is_executable(path: &Path) -> bool {
    fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<PathBuf> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(&command_exe));
    command_paths.find(|path| fs::metadata(&path).is_ok())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<PathBuf> {
    let mut dirs = vec![];
    if let Ok(mut path) = env::current_exe() {
        path.pop();
        dirs.push(path.join("../lib/cargo"));
        dirs.push(path);
    }
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>Auto merge of #1576 - takkanm:add_search_to_help, r=alexcrichton<commit_after>#![cfg_attr(unix, feature(fs_ext))]

extern crate cargo;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::io;
use std::path::{PathBuf, Path};
use std::process::Command;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult, lev_distance, Config};

#[derive(RustcDecodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help       Display this message
    -V, --version    Print version info and exit
    --list           List installed commands
    -v, --verbose    Use verbose output

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{ ($mac:ident) => ({
    $mac!(bench);
    $mac!(build);
    $mac!(clean);
    $mac!(doc);
    $mac!(fetch);
    $mac!(generate_lockfile);
    $mac!(git_checkout);
    $mac!(help);
    $mac!(locate_project);
    $mac!(login);
    $mac!(new);
    $mac!(owner);
    $mac!(package);
    $mac!(pkgid);
    $mac!(publish);
    $mac!(read_manifest);
    $mac!(run);
    $mac!(search);
    $mac!(test);
    $mac!(update);
    $mac!(verify_project);
    $mac!(version);
    $mac!(yank);
}) }

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    config.shell().set_verbose(flags.flag_verbose);

    init_git_transports(config);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbose(true);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => {
            vec!["cargo".to_string(), flags.arg_args[0].clone(),
                 "-h".to_string()]
        }

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => env::args().collect(),
    };

    macro_rules! cmd{ ($name:ident) => (
        if args[1] == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }
    ) }
    each_subcommand!(cmd);

    execute_subcommand(&args[1], &args, &mut config.shell());
    Ok(None)
}

fn find_closest(cmd: &str) -> Option<String> {
    let cmds = list_commands();
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));

    if filtered.len() == 0 {
        None
    } else {
        Some(filtered[0].1.to_string())
    }
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => {
            let msg = match find_closest(cmd) {
                Some(closest) => format!("No such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "No such subcommand".to_string()
            };
            return handle_error(CliError::new(&msg, 127), shell)
        }
    };
    match Command::new(&command).args(&args[1..]).status() {
        Ok(ref status) if status.success() => {}
        Ok(ref status) => {
            match status.code() {
                Some(code) => handle_error(CliError::new("", code), shell),
                None => {
                    let msg = format!("subcommand failed with: {}", status);
                    handle_error(CliError::new(&msg, 101), shell)
                }
            }
        }
        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
            handle_error(CliError::new("No such subcommand", 127), shell)
        }
        Err(err) => {
            let msg = format!("Subcommand failed to run: {}", err);
            handle_error(CliError::new(&msg, 127), shell)
        }
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> BTreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = BTreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries {
            let entry = match entry { Ok(e) => e, Err(..) => continue };
            let entry = entry.path();
            let filename = match entry.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
               filename.ends_with(env::consts::EXE_SUFFIX) &&
               is_executable(&entry) {
                let command = &filename[
                    command_prefix.len()..
                    filename.len() - env::consts::EXE_SUFFIX.len()];
                commands.insert(command.to_string());
            }
        }
    }

    macro_rules! add_cmd{ ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable(path: &Path) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path).map(|m| {
        m.permissions().mode() & 0o001 == 0o001
    }).unwrap_or(false)
}
#[cfg(windows)]
fn is_executable(path: &Path) -> bool {
    fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<PathBuf> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(&command_exe));
    command_paths.find(|path| fs::metadata(&path).is_ok())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<PathBuf> {
    let mut dirs = vec![];
    if let Ok(mut path) = env::current_exe() {
        path.pop();
        dirs.push(path.join("../lib/cargo"));
        dirs.push(path);
    }
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<|endoftext|>


<commit_before>// put actual stuff here

pub use self::cachedefs::{AccessType, CacheStats, CacheBlock, Cache, VictimCache};

pub mod cachedefs;

#[derive(Debug)]
pub struct CacheSystem {
    pub stats: CacheStats,
    pub l1: Cache,
    pub vc: VictimCache,
    pub l2: Cache,
}

impl CacheSystem {
    pub fn new(c1: u64, b1: u64, s1: u64, v: u64, c2: u64, b2: u64, s2: u64) -> Self {
        CacheSystem {
            stats: CacheStats::new(),
            l1: Cache::new(c1, b1, s1),
            vc: VictimCache::new(b1, v),
            l2: Cache::new(c2, b2, s2),
        }
    }

    pub fn cache_access(&mut self, mode: AccessType, address: u64) {
        //println!("Trying to {:?} at address {:#X}", mode, address);
        let in_l1 = self.search_l1(mode, address);
        if !in_l1 {
            print!("M1");
            let in_vc = self.search_and_modify_vc(address);
            if !in_vc {
                if self.vc.v > 0 {
                    print!("MV");
                }
                //let in_l2 = self.search_l2(mode, address);
            } else {
                println!("HV**");
            }
            self.move_to_l1(mode, address);
        } else {
            if self.vc.v > 0 {
                println!("H1****");
            } else {
                println!("H1**");
            }
        }
    }

    pub fn complete_cache(&mut self) {
        println!("Completing the cache!");
    }

    pub fn print_statistics(&self) {
        println!("Cache Statistics");
        println!("Accesses: {}", self.stats.accesses);
        println!("Accesses to L2: {}", self.stats.accesses_l2);
        println!("Accesses to VC: {}", self.stats.accesses_vc);
        println!("Reads: {}", self.stats.reads);
        println!("Read misses to L1: {}", self.stats.read_misses_l1);
        println!("Read misses to L2: {}", self.stats.read_misses_l2);
        println!("Writes: {}", self.stats.writes);
        println!("Write misses to L1: {}", self.stats.write_misses_l1);
        println!("Write misses to L2: {}", self.stats.write_misses_l2);
        println!("Write backs from L1: {}", self.stats.write_back_l1);
        println!("Write backs from L2: {}", self.stats.write_back_l2);
        println!("L1 victims hit in victim hits: {}", self.stats.victim_hits);
        println!("Average access time: {}", self.stats.avg_access_time_l1);
    }

    fn search_l1(&mut self, mode: AccessType, address: u64) -> bool {
        let ref mut stats = self.stats;
        let ref mut cache = self.l1;
        stats.accesses += 1;

        let mut found = false;
        let mut hot_block_index = -1i64;
        let index = (address >> cache.b) & ((1u64 << cache.indexbits) - 1);
        let tag = address >> (cache.b + cache.indexbits);

        let selected_set = cache.sets.get_mut(index as usize);
        if let Some(set) = selected_set {
            for (count, block) in set.into_iter().enumerate() {
                if tag == block.tag {
                    hot_block_index = count as i64;
                    found = true;
                    break;
                }
            }
            if found {
                let mut hot_block = set.remove(hot_block_index as usize).unwrap();
                if let AccessType::Write = mode {
                    hot_block.dirty = true;
                }
                set.push_back(hot_block);
            }
        } else {
            panic!("Address index out of bounds in L1! Panic!")
        }

        if let AccessType::Read = mode {
            stats.reads += 1;
            if !found {
                stats.read_misses_l1 += 1;
            }
        } else {
            stats.writes += 1;
            if !found {
                stats.write_misses_l1 += 1;
            }
        }

        found
    }

    fn move_to_l1(&mut self, mode: AccessType, address: u64) {
        let ref mut stats = self.stats;
        let ref mut cache = self.l1;
        let ref mut vc = self.vc;

        let index = (address >> cache.b) & ((1u64 << cache.indexbits) - 1);
        let tag = address >> (cache.b + cache.indexbits);
        let block_in = CacheBlock {
            address: address,
            tag: tag,
            dirty: match mode {
                AccessType::Read => { false },
                AccessType::Write => { true },
            },
        };

        let selected_set = cache.sets.get_mut(index as usize);
        if let Some(set) = selected_set {
            if set.len() >= cache.max_blocks_per_set as usize {
                let mut evicted_block = set.pop_front().unwrap();
                if evicted_block.dirty {
                    stats.write_back_l1 += 1;
                    /*let in_l2 = self.search_l2(AccessType::Write, evicted_block.address);
                    if !in_l2 {
                        self.move_to_l2(AccessType::Write, evicted_block.address);
                    }*/
                }
                evicted_block.dirty = false;

                if vc.v > 0 {
                    if vc.set.len() == vc.v as usize {
                        vc.set.pop_front();
                    }
                    evicted_block.tag = evicted_block.address >> vc.b;
                    vc.set.push_back(evicted_block);
                }
            }
            set.push_back(block_in);
        } else {
            panic!("Address index out of bounds in L1! Panic!")
        }
    }

    fn search_and_modify_vc(&mut self, address: u64) -> bool {
        let ref mut stats = self.stats;
        let ref mut vc = self.vc;
        if vc.v == 0 {
            return false;
        }

        stats.accesses_vc += 1;

        let mut found = false;
        let mut hot_block_index = -1i64;
        let tag = address >> vc.b;
        let ref mut set = vc.set;

        for (count, block) in set.into_iter().enumerate() {
            if block.tag == tag {
                found = true;
                hot_block_index = count as i64;
                break;
            }
        }

        if found {
            set.remove(hot_block_index as usize).unwrap();
            stats.victim_hits += 1;
        }

        found
    }

    fn search_l2(&mut self, mode: AccessType, address: u64) -> bool {
        let ref mut stats = self.stats;
        let ref mut cache = self.l2;
        stats.accesses_l2 += 1;

        let mut found = false;
        let mut hot_block_index = -1i64;
        let index = (address >> cache.b) & ((1u64 << cache.indexbits) - 1);
        let tag = address >> (cache.b + cache.indexbits);

        let selected_set = cache.sets.get_mut(index as usize);
        if let Some(set) = selected_set {
            for (count, block) in set.into_iter().enumerate() {
                if tag == block.tag {
                    hot_block_index = count as i64;
                    found = true;
                    break;
                }
            }
            if found {
                let mut hot_block = set.remove(hot_block_index as usize).unwrap();
                if let AccessType::Write = mode {
                    hot_block.dirty = true;
                }
                set.push_back(hot_block);
            }
        } else {
            panic!("Address index out of bounds in L2! Panic!");
        }

        if !found {
            if let AccessType::Read = mode {
                stats.read_misses_l2 += 1;
            } else {
                stats.write_misses_l2 += 1;
            }
        }

        found
    }

    fn move_to_l2(&mut self, mode: AccessType, address: u64) {
        // Todo tomorrow morning :3
    }
}
<commit_msg>Getting rid of a lot of stuff I might not need<commit_after>// put actual stuff here

pub use self::cachedefs::{AccessType, CacheStats, CacheBlock, Cache, VictimCache};

pub mod cachedefs;

#[derive(Debug)]
pub struct CacheSystem {
    pub stats: CacheStats,
    pub l1: Cache,
    pub vc: VictimCache,
    pub l2: Cache,
}

impl CacheSystem {
    pub fn new(c1: u64, b1: u64, s1: u64, v: u64, c2: u64, b2: u64, s2: u64) -> Self {
        CacheSystem {
            stats: CacheStats::new(),
            l1: Cache::new(c1, b1, s1),
            vc: VictimCache::new(b1, v),
            l2: Cache::new(c2, b2, s2),
        }
    }

    pub fn cache_access(&mut self, mode: AccessType, address: u64) {
        //println!("Trying to {:?} at address {:#X}", mode, address);
        let in_l1 = self.search_l1(mode, address);
        if !in_l1 {
            print!("M1");
            let in_vc = self.search_and_modify_vc(address);
            if !in_vc {
                if self.vc.v > 0 {
                    print!("MV");
                }
                let in_l2 = self.search_l2(mode, address);
            } else {
                println!("HV**");
            }
            self.move_to_l1(mode, address);
        } else {
            if self.vc.v > 0 {
                println!("H1****");
            } else {
                println!("H1**");
            }
        }
    }

    pub fn complete_cache(&mut self) {
        println!("Completing the cache!");
    }

    pub fn print_statistics(&self) {
        println!("Cache Statistics");
        println!("Accesses: {}", self.stats.accesses);
        println!("Accesses to L2: {}", self.stats.accesses_l2);
        println!("Accesses to VC: {}", self.stats.accesses_vc);
        println!("Reads: {}", self.stats.reads);
        println!("Read misses to L1: {}", self.stats.read_misses_l1);
        println!("Read misses to L2: {}", self.stats.read_misses_l2);
        println!("Writes: {}", self.stats.writes);
        println!("Write misses to L1: {}", self.stats.write_misses_l1);
        println!("Write misses to L2: {}", self.stats.write_misses_l2);
        println!("Write backs from L1: {}", self.stats.write_back_l1);
        println!("Write backs from L2: {}", self.stats.write_back_l2);
        println!("L1 victims hit in victim hits: {}", self.stats.victim_hits);
        println!("Average access time: {}", self.stats.avg_access_time_l1);
    }

    fn search_l1(&mut self, mode: AccessType, address: u64) -> bool {
        self.stats.accesses += 1;

        let mut found = false;
        let mut hot_block_index = -1i64;
        let index = (address >> self.l1.b) & ((1u64 << self.l1.indexbits) - 1);
        let tag = address >> (self.l1.b + self.l1.indexbits);

        let selected_set = self.l1.sets.get_mut(index as usize);
        if let Some(set) = selected_set {
            for (count, block) in set.into_iter().enumerate() {
                if tag == block.tag {
                    hot_block_index = count as i64;
                    found = true;
                    break;
                }
            }
            if found {
                let mut hot_block = set.remove(hot_block_index as usize).unwrap();
                if let AccessType::Write = mode {
                    hot_block.dirty = true;
                }
                set.push_back(hot_block);
            }
        } else {
            panic!("Address index out of bounds in L1! Panic!")
        }

        if let AccessType::Read = mode {
            self.stats.reads += 1;
            if !found {
                self.stats.read_misses_l1 += 1;
            }
        } else {
            self.stats.writes += 1;
            if !found {
                self.stats.write_misses_l1 += 1;
            }
        }

        found
    }

    fn move_to_l1(&mut self, mode: AccessType, address: u64) {
        let index = (address >> self.l1.b) & ((1u64 << self.l1.indexbits) - 1);
        let tag = address >> (self.l1.b + self.l1.indexbits);
        let block_in = CacheBlock {
            address: address,
            tag: tag,
            dirty: match mode {
                AccessType::Read => { false },
                AccessType::Write => { true },
            },
        };

        let selected_set = self.l1.sets.get_mut(index as usize);
        if let Some(set) = selected_set {
            if set.len() >= self.l1.max_blocks_per_set as usize {
                let mut evicted_block = set.pop_front().unwrap();
                if evicted_block.dirty {
                    self.stats.write_back_l1 += 1;
                    /*let in_l2 = self.search_l2(AccessType::Write, evicted_block.address);
                    if !in_l2 {
                        self.move_to_l2(AccessType::Write, evicted_block.address);
                    }*/
                }
                evicted_block.dirty = false;

                if self.vc.v > 0 {
                    if self.vc.set.len() == self.vc.v as usize {
                        self.vc.set.pop_front();
                    }
                    evicted_block.tag = evicted_block.address >> self.vc.b;
                    self.vc.set.push_back(evicted_block);
                }
            }
            set.push_back(block_in);
        } else {
            panic!("Address index out of bounds in L1! Panic!")
        }
    }

    fn search_and_modify_vc(&mut self, address: u64) -> bool {
        if self.vc.v == 0 {
            return false;
        }

        self.stats.accesses_vc += 1;

        let mut found = false;
        let mut hot_block_index = -1i64;
        let tag = address >> self.vc.b;
        let ref mut set = self.vc.set;

        for (count, block) in set.into_iter().enumerate() {
            if block.tag == tag {
                found = true;
                hot_block_index = count as i64;
                break;
            }
        }

        if found {
            set.remove(hot_block_index as usize).unwrap();
            self.stats.victim_hits += 1;
        }

        found
    }

    fn search_l2(&mut self, mode: AccessType, address: u64) -> bool {
        self.stats.accesses_l2 += 1;

        let mut found = false;
        let mut hot_block_index = -1i64;
        let index = (address >> self.l2.b) & ((1u64 << self.l2.indexbits) - 1);
        let tag = address >> (self.l2.b + self.l2.indexbits);

        let selected_set = self.l2.sets.get_mut(index as usize);
        if let Some(set) = selected_set {
            for (count, block) in set.into_iter().enumerate() {
                if tag == block.tag {
                    hot_block_index = count as i64;
                    found = true;
                    break;
                }
            }
            if found {
                let mut hot_block = set.remove(hot_block_index as usize).unwrap();
                if let AccessType::Write = mode {
                    hot_block.dirty = true;
                }
                set.push_back(hot_block);
            }
        } else {
            panic!("Address index out of bounds in L2! Panic!");
        }

        if !found {
            if let AccessType::Read = mode {
                self.stats.read_misses_l2 += 1;
            } else {
                self.stats.write_misses_l2 += 1;
            }
        }

        found
    }

    fn move_to_l2(&mut self, mode: AccessType, address: u64) {
        // Todo tomorrow morning :3
    }
}
<|endoftext|>


<commit_before>#![deny(unused)]
#![cfg_attr(test, deny(warnings))]

#[cfg(test)] extern crate hamcrest;
#[macro_use] extern crate log;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate serde_json;
extern crate crates_io as registry;
extern crate crossbeam;
extern crate curl;
extern crate docopt;
extern crate filetime;
extern crate flate2;
extern crate fs2;
extern crate git2;
extern crate glob;
extern crate handlebars;
extern crate libc;
extern crate libgit2_sys;
extern crate num_cpus;
extern crate rustc_serialize;
extern crate semver;
extern crate serde;
extern crate serde_ignored;
extern crate shell_escape;
extern crate tar;
extern crate tempdir;
extern crate term;
extern crate time;
extern crate toml;
extern crate url;

use std::io;
use std::fmt;
use rustc_serialize::Decodable;
use serde::ser;
use docopt::Docopt;

use core::{Shell, MultiShell, ShellConfig, Verbosity, ColorConfig};
use core::shell::Verbosity::{Verbose};
use term::color::{BLACK};

pub use util::{CargoError, CargoResult, CliError, CliResult, human, Config, ChainError};

pub const CARGO_ENV: &'static str = "CARGO";

macro_rules! bail {
    ($($fmt:tt)*) => (
        return Err(::util::human(&format_args!($($fmt)*)))
    )
}

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub struct CommitInfo {
    pub short_commit_hash: String,
    pub commit_hash: String,
    pub commit_date: String,
}

pub struct CfgInfo {
    // Information about the git repository we may have been built from.
    pub commit_info: Option<CommitInfo>,
    // The date that the build was performed.
    pub build_date: String,
    // The release channel we were built for.
    pub release_channel: String,
}

pub struct VersionInfo {
    pub major: String,
    pub minor: String,
    pub patch: String,
    pub pre_release: Option<String>,
    // Information that's only available when we were built with
    // configure/make, rather than cargo itself.
    pub cfg_info: Option<CfgInfo>,
}

impl fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "cargo {}.{}.{}",
               self.major, self.minor, self.patch)?;
        if let Some(channel) = self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
            if channel != "stable" {
                write!(f, "-{}", channel)?;
                let empty = String::from("");
                write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
            }
        };

        if let Some(ref cfg) = self.cfg_info {
            match cfg.commit_info {
                Some(ref ci) => {
                    write!(f, " ({} {})",
                           ci.short_commit_hash, ci.commit_date)?;
                },
                None => {
                    write!(f, " (built {})",
                           cfg.build_date)?;
                }
            }
        };
        Ok(())
    }
}

pub fn call_main_without_stdin<Flags: Decodable>(
            exec: fn(Flags, &Config) -> CliResult,
            config: &Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult
{
    let docopt = Docopt::new(usage).unwrap()
        .options_first(options_first)
        .argv(args.iter().map(|s| &s[..]))
        .help(true);

    let flags = docopt.decode().map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::new(human(e.to_string()), code)
    })?;

    exec(flags, config)
}

pub fn print_json<T: ser::Serialize>(obj: &T) {
    let encoded = serde_json::to_string(&obj).unwrap();
    println!("{}", encoded);
}

pub fn shell(verbosity: Verbosity, color_config: ColorConfig) -> MultiShell {
    enum Output {
        Stdout,
        Stderr,
    }

    let tty = isatty(Output::Stderr);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let err = Shell::create(|| Box::new(io::stderr()), config);

    let tty = isatty(Output::Stdout);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let out = Shell::create(|| Box::new(io::stdout()), config);

    return MultiShell::new(out, err, verbosity);

    #[cfg(unix)]
    fn isatty(output: Output) -> bool {
        let fd = match output {
            Output::Stdout => libc::STDOUT_FILENO,
            Output::Stderr => libc::STDERR_FILENO,
        };

        unsafe { libc::isatty(fd) != 0 }
    }
    #[cfg(windows)]
    fn isatty(output: Output) -> bool {
        extern crate kernel32;
        extern crate winapi;

        let handle = match output {
            Output::Stdout => winapi::winbase::STD_OUTPUT_HANDLE,
            Output::Stderr => winapi::winbase::STD_ERROR_HANDLE,
        };

        unsafe {
            let handle = kernel32::GetStdHandle(handle);
            let mut out = 0;
            kernel32::GetConsoleMode(handle, &mut out) != 0
        }
    }
}

pub fn exit_with_error(err: CliError, shell: &mut MultiShell) -> ! {
    debug!("exit_with_error; err={:?}", err);

    let CliError { error, exit_code, unknown } = err;
    // exit_code == 0 is non-fatal error, e.g. docopt version info
    let fatal = exit_code != 0;

    let hide = unknown && shell.get_verbose() != Verbose;

    if let Some(error) = error {
        let _ignored_result = if hide {
            shell.error("An unknown error occurred")
        } else if fatal {
            shell.error(&error)
        } else {
            shell.say(&error, BLACK)
        };

        if !handle_cause(&error, shell) || hide {
            let _ = shell.err().say("\nTo learn more, run the command again \
                                     with --verbose.".to_string(), BLACK);
        }
    }

    std::process::exit(exit_code)
}

pub fn handle_error(err: &CargoError, shell: &mut MultiShell) {
    debug!("handle_error; err={:?}", err);

    let _ignored_result = shell.error(err);
    handle_cause(err, shell);
}

fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool {
    let verbose = shell.get_verbose();
    let mut err;
    loop {
        cargo_err = match cargo_err.cargo_cause() {
            Some(cause) => cause,
            None => { err = cargo_err.cause(); break }
        };
        if verbose != Verbose && !cargo_err.is_human() { return false }
        print(cargo_err.to_string(), shell);
    }
    loop {
        let cause = match err { Some(err) => err, None => return true };
        if verbose != Verbose { return false }
        print(cause.to_string(), shell);
        err = cause.cause();
    }

    fn print(error: String, shell: &mut MultiShell) {
        let _ = shell.err().say("\nCaused by:", BLACK);
        let _ = shell.err().say(format!("  {}", error), BLACK);
    }
}

pub fn version() -> VersionInfo {
    macro_rules! env_str {
        ($name:expr) => { env!($name).to_string() }
    }
    macro_rules! option_env_str {
        ($name:expr) => { option_env!($name).map(|s| s.to_string()) }
    }
    match option_env!("CFG_RELEASE_CHANNEL") {
        // We have environment variables set up from configure/make.
        Some(_) => {
            let commit_info =
                option_env!("CFG_COMMIT_HASH").map(|s| {
                    CommitInfo {
                        commit_hash: s.to_string(),
                        short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
                        commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
                    }
                });
            VersionInfo {
                major: env_str!("CARGO_PKG_VERSION_MAJOR"),
                minor: env_str!("CARGO_PKG_VERSION_MINOR"),
                patch: env_str!("CARGO_PKG_VERSION_PATCH"),
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: Some(CfgInfo {
                    build_date: option_env_str!("CFG_BUILD_DATE").unwrap(),
                    release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
                    commit_info: commit_info,
                }),
            }
        },
        // We are being compiled by Cargo itself.
        None => {
            VersionInfo {
                major: env_str!("CARGO_PKG_VERSION_MAJOR"),
                minor: env_str!("CARGO_PKG_VERSION_MINOR"),
                patch: env_str!("CARGO_PKG_VERSION_PATCH"),
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: None,
            }
        }
    }
}
<commit_msg>Remove build date from version<commit_after>#![deny(unused)]
#![cfg_attr(test, deny(warnings))]

#[cfg(test)] extern crate hamcrest;
#[macro_use] extern crate log;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate serde_json;
extern crate crates_io as registry;
extern crate crossbeam;
extern crate curl;
extern crate docopt;
extern crate filetime;
extern crate flate2;
extern crate fs2;
extern crate git2;
extern crate glob;
extern crate handlebars;
extern crate libc;
extern crate libgit2_sys;
extern crate num_cpus;
extern crate rustc_serialize;
extern crate semver;
extern crate serde;
extern crate serde_ignored;
extern crate shell_escape;
extern crate tar;
extern crate tempdir;
extern crate term;
extern crate time;
extern crate toml;
extern crate url;

use std::io;
use std::fmt;
use rustc_serialize::Decodable;
use serde::ser;
use docopt::Docopt;

use core::{Shell, MultiShell, ShellConfig, Verbosity, ColorConfig};
use core::shell::Verbosity::{Verbose};
use term::color::{BLACK};

pub use util::{CargoError, CargoResult, CliError, CliResult, human, Config, ChainError};

pub const CARGO_ENV: &'static str = "CARGO";

macro_rules! bail {
    ($($fmt:tt)*) => (
        return Err(::util::human(&format_args!($($fmt)*)))
    )
}

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub struct CommitInfo {
    pub short_commit_hash: String,
    pub commit_hash: String,
    pub commit_date: String,
}

pub struct CfgInfo {
    // Information about the git repository we may have been built from.
    pub commit_info: Option<CommitInfo>,
    // The release channel we were built for.
    pub release_channel: String,
}

pub struct VersionInfo {
    pub major: String,
    pub minor: String,
    pub patch: String,
    pub pre_release: Option<String>,
    // Information that's only available when we were built with
    // configure/make, rather than cargo itself.
    pub cfg_info: Option<CfgInfo>,
}

impl fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "cargo {}.{}.{}",
               self.major, self.minor, self.patch)?;
        if let Some(channel) = self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
            if channel != "stable" {
                write!(f, "-{}", channel)?;
                let empty = String::from("");
                write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
            }
        };

        if let Some(ref cfg) = self.cfg_info {
            if let Some(ref ci) = cfg.commit_info {
                write!(f, " ({} {})",
                       ci.short_commit_hash, ci.commit_date)?;
            }
        };
        Ok(())
    }
}

pub fn call_main_without_stdin<Flags: Decodable>(
            exec: fn(Flags, &Config) -> CliResult,
            config: &Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult
{
    let docopt = Docopt::new(usage).unwrap()
        .options_first(options_first)
        .argv(args.iter().map(|s| &s[..]))
        .help(true);

    let flags = docopt.decode().map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::new(human(e.to_string()), code)
    })?;

    exec(flags, config)
}

pub fn print_json<T: ser::Serialize>(obj: &T) {
    let encoded = serde_json::to_string(&obj).unwrap();
    println!("{}", encoded);
}

pub fn shell(verbosity: Verbosity, color_config: ColorConfig) -> MultiShell {
    enum Output {
        Stdout,
        Stderr,
    }

    let tty = isatty(Output::Stderr);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let err = Shell::create(|| Box::new(io::stderr()), config);

    let tty = isatty(Output::Stdout);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let out = Shell::create(|| Box::new(io::stdout()), config);

    return MultiShell::new(out, err, verbosity);

    #[cfg(unix)]
    fn isatty(output: Output) -> bool {
        let fd = match output {
            Output::Stdout => libc::STDOUT_FILENO,
            Output::Stderr => libc::STDERR_FILENO,
        };

        unsafe { libc::isatty(fd) != 0 }
    }
    #[cfg(windows)]
    fn isatty(output: Output) -> bool {
        extern crate kernel32;
        extern crate winapi;

        let handle = match output {
            Output::Stdout => winapi::winbase::STD_OUTPUT_HANDLE,
            Output::Stderr => winapi::winbase::STD_ERROR_HANDLE,
        };

        unsafe {
            let handle = kernel32::GetStdHandle(handle);
            let mut out = 0;
            kernel32::GetConsoleMode(handle, &mut out) != 0
        }
    }
}

pub fn exit_with_error(err: CliError, shell: &mut MultiShell) -> ! {
    debug!("exit_with_error; err={:?}", err);

    let CliError { error, exit_code, unknown } = err;
    // exit_code == 0 is non-fatal error, e.g. docopt version info
    let fatal = exit_code != 0;

    let hide = unknown && shell.get_verbose() != Verbose;

    if let Some(error) = error {
        let _ignored_result = if hide {
            shell.error("An unknown error occurred")
        } else if fatal {
            shell.error(&error)
        } else {
            shell.say(&error, BLACK)
        };

        if !handle_cause(&error, shell) || hide {
            let _ = shell.err().say("\nTo learn more, run the command again \
                                     with --verbose.".to_string(), BLACK);
        }
    }

    std::process::exit(exit_code)
}

pub fn handle_error(err: &CargoError, shell: &mut MultiShell) {
    debug!("handle_error; err={:?}", err);

    let _ignored_result = shell.error(err);
    handle_cause(err, shell);
}

fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool {
    let verbose = shell.get_verbose();
    let mut err;
    loop {
        cargo_err = match cargo_err.cargo_cause() {
            Some(cause) => cause,
            None => { err = cargo_err.cause(); break }
        };
        if verbose != Verbose && !cargo_err.is_human() { return false }
        print(cargo_err.to_string(), shell);
    }
    loop {
        let cause = match err { Some(err) => err, None => return true };
        if verbose != Verbose { return false }
        print(cause.to_string(), shell);
        err = cause.cause();
    }

    fn print(error: String, shell: &mut MultiShell) {
        let _ = shell.err().say("\nCaused by:", BLACK);
        let _ = shell.err().say(format!("  {}", error), BLACK);
    }
}

pub fn version() -> VersionInfo {
    macro_rules! env_str {
        ($name:expr) => { env!($name).to_string() }
    }
    macro_rules! option_env_str {
        ($name:expr) => { option_env!($name).map(|s| s.to_string()) }
    }
    match option_env!("CFG_RELEASE_CHANNEL") {
        // We have environment variables set up from configure/make.
        Some(_) => {
            let commit_info =
                option_env!("CFG_COMMIT_HASH").map(|s| {
                    CommitInfo {
                        commit_hash: s.to_string(),
                        short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
                        commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
                    }
                });
            VersionInfo {
                major: env_str!("CARGO_PKG_VERSION_MAJOR"),
                minor: env_str!("CARGO_PKG_VERSION_MINOR"),
                patch: env_str!("CARGO_PKG_VERSION_PATCH"),
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: Some(CfgInfo {
                    release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
                    commit_info: commit_info,
                }),
            }
        },
        // We are being compiled by Cargo itself.
        None => {
            VersionInfo {
                major: env_str!("CARGO_PKG_VERSION_MAJOR"),
                minor: env_str!("CARGO_PKG_VERSION_MINOR"),
                patch: env_str!("CARGO_PKG_VERSION_PATCH"),
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: None,
            }
        }
    }
}
<|endoftext|>