<commit_before>use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use rustc_serialize::Encodable;
use rustc_serialize::Encoder;
use rustc_serialize::json;

use openssl;
use openssl::ssl;
use openssl::ssl::SslStream;
use openssl::ssl::error::SslError;

use std::ops::{Range, Index};
use std::net::TcpStream;
use std::io::{Cursor, Read, Write};
use std::path::Path;
use std::vec::Vec;
use std::collections::HashMap;

use num::pow;
use rand::{self, Rng};
use time;

#[derive(Debug)]
pub struct Payload<'a> {
    pub aps: PayloadAPS<'a>,
    pub info: Option<HashMap<&'a str, &'a str>>
}

#[derive(Debug)]
pub struct PayloadAPS<'a> {
    pub alert: PayloadAPSAlert<'a>,
    pub badge: Option<i32>,
    pub sound: Option<&'a str>,
    pub content_available: Option<i32>
}

#[derive(Debug)]
pub enum PayloadAPSAlert<'a> {
    Plain(&'a str),
    Localized(&'a str, Vec<&'a str>)
}

impl<'a> Encodable for Payload<'a> {
    fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
		match *self {
		    Payload{ref aps, ref info} => {
				if let Some(ref map) = *info {
					encoder.emit_struct("Payload", 1 + map.len(), |encoder| {
					try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
					let mut index = 1usize;
					for (key, val) in map.iter() {
					    try!(encoder.emit_struct_field(key, index, |encoder| val.encode(encoder)));
					    index = index + 1;
					}
					Ok(())
					})
				}
				else {
					encoder.emit_struct("Payload", 1, |encoder| {
					try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
					Ok(())
					})
				}
		    }
		}
    }
}

impl<'a> Encodable for PayloadAPS<'a> {
    fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
        match *self {
			PayloadAPS{ref alert, ref badge, ref sound, ref content_available} => {
				let mut count = 1;
		        if badge.is_some() { count = count + 1; }
		        if sound.is_some() { count = count + 1; }
		        if content_available.is_some() { count = count + 1; }

		        let mut index = 0usize;
				encoder.emit_struct("PayloadAPS", count, |encoder| {
					try!(encoder.emit_struct_field( "alert", index, |encoder| alert.encode(encoder)));
					index = index + 1;
					if badge.is_some() {
						try!(encoder.emit_struct_field( "badge", index, |encoder| badge.unwrap().encode(encoder)));
						index = index + 1;
		            }
		            if sound.is_some() {
						try!(encoder.emit_struct_field( "sound", index, |encoder| sound.unwrap().encode(encoder)));
						index = index + 1;
		            }
		            if content_available.is_some() {
						try!(encoder.emit_struct_field( "content-available", index, |encoder| content_available.unwrap().encode(encoder)));
						index = index + 1;
		            }
					Ok(())
				})
			}
		}
    }
}

impl<'a> Encodable for PayloadAPSAlert<'a> {
    fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
		match *self {
		    PayloadAPSAlert::Plain(ref str) => {
				encoder.emit_str(str)
		    },
		    PayloadAPSAlert::Localized(ref key, ref args) => {
				encoder.emit_struct("PayloadAPSAlert", 2, |encoder| {
					try!(encoder.emit_struct_field( "loc-key", 0usize, |encoder| key.encode(encoder)));
					try!(encoder.emit_struct_field( "loc-args", 1usize, |encoder| args.encode(encoder)));
					Ok(())
					})
			}
		}
	}
}

#[allow(dead_code)]
fn hex_to_int(hex: &str) -> u32 {
    let mut total = 0u32;
    let mut n = hex.to_string().len();

    for c in hex.chars() {
        n = n - 1;
		match c {
		    '0'...'9' => {
				total += pow(16, n) * ((c as u32) - ('0' as u32));
		    },
		    'a'...'f' => {
				total += pow(16, n) * ((c as u32) - ('a' as u32) + 10);
		    },
		    _ => {

		    }
		}
    }

    return total;
}

#[allow(dead_code)]
fn convert_to_binary(device_token: &str) -> Vec<u8> {
    let mut device_token_bytes: Vec<u8> = Vec::new();
    for i in 0..8 {
		let string = device_token.to_string();
		let range = Range{start:i*8, end:i*8+8};
		let sub_str = string.index(range);

		let sub_str_num = hex_to_int(sub_str);
		let mut sub_str_bytes = vec![];
		let _ = sub_str_bytes.write_u32::<BigEndian>(sub_str_num);

        for s in sub_str_bytes.iter() {
            device_token_bytes.push(*s);
        }
    }

    return device_token_bytes;
}

#[allow(dead_code)]
pub fn convert_to_token(binary: &[u8]) -> String {
    let mut token = "".to_string();
    for i in 0..8 {
		let range = Range{start:i*4, end:i*4+4};
		let sub_slice = binary.index(range);

		let mut rdr = Cursor::new(sub_slice.to_vec());
		let num = rdr.read_u32::<BigEndian>().unwrap();

		token = format!("{}{:x}", token, num);
    }
    return token;
}

#[allow(dead_code)]
pub fn convert_to_timestamp(binary: &[u8]) -> u32 {
    let mut rdr = Cursor::new(binary.to_vec());
    let num = rdr.read_u32::<BigEndian>().unwrap();

    return num;
}

pub struct APNS<'a> {
    pub sandbox: bool,
    pub certificate: &'a Path,
    pub private_key: &'a Path,
    pub ca_certificate: &'a Path,
}

impl<'a> APNS<'a> {
    pub fn new(sandbox: bool, cert_file: &'a Path, private_key_file: &'a Path, ca_file: &'a Path) -> APNS<'a> {
		APNS{sandbox: sandbox, certificate: cert_file, private_key: private_key_file, ca_certificate: ca_file}
    }

    #[allow(dead_code)]
    pub fn get_feedback(&self) -> Result<Vec<(u32, String)>, SslError> {
		let apns_feedback_production = "feedback.push.apple.com:2196";
		let apns_feedback_development = "feedback.sandbox.push.apple.com:2196";

		let apns_feedback_url = if self.sandbox { apns_feedback_development } else { apns_feedback_production };
		let mut stream = try!(get_ssl_stream(apns_feedback_url, self.certificate, self.private_key, self.ca_certificate));

		let mut tokens: Vec<(u32, String)> = Vec::new();
        let mut read_buffer = [0u8; 38];
        loop {
            match stream.read(&mut read_buffer) {
                Ok(size) => {
                    if size != 38 {
                        break;
                    }
                },
                Err(..) => {
                    /*				return Result::Err(SslError::StreamError(error));*/
                    break;
                }
            }
		    let time_range = Range{start:0, end:4};
		    let time_slice = read_buffer.index(time_range);
		    let time = convert_to_timestamp(time_slice);

		    let token_range = Range{start:6, end:38};
		    let token_slice = read_buffer.index(token_range);

            let token = convert_to_token(token_slice);
			tokens.push((time, token));
        }

        return Result::Ok(tokens);
    }

    #[allow(dead_code)]
    pub fn send_payload(&self, payload: Payload, device_token: &str) {
        let notification_bytes = get_notification_bytes(payload, device_token);

        let apns_url_production = "gateway.push.apple.com:2195";
        let apns_url_development = "gateway.sandbox.push.apple.com:2195";

        let apns_url = if self.sandbox { apns_url_development } else { apns_url_production };

        let ssl_result = get_ssl_stream(apns_url, self.certificate, self.private_key, self.ca_certificate);
        match ssl_result {
            Ok(mut ssls) => {
                if let Err(error) = ssls.write_all(&notification_bytes) {
                    println!("ssl_stream write error {:?}", error);
                }

				let _ = ssls.flush();

				// Read possible error code response
				if ssls.pending() == 6 {
                    let mut read_buffer = [0u8; 6];
                    match ssls.read(&mut read_buffer) {
                        Ok(size) => {
                            for c in read_buffer.iter() {
                                print!("{}", c);
                            }
                            println!("ssl_stream read size {:?}", size);
                        }
                        Err(error) => {
                            println!("ssl_stream read error {:?}", error);
                        }
                    }
                }
            },
            Err(error) => {
                println!("failed to get_ssl_stream error {:?}", error);
            }
        };
    }
}

fn get_notification_bytes(payload: Payload, device_token: &str) -> Vec<u8> {
    let payload_str = match json::encode(&payload) {
        Ok(json_str) => { json_str.to_string() }
        Err(error) => {
            println!("json encode error {:?}", error);
            return vec![];
        }
    };

    let payload_bytes = payload_str.into_bytes();
    let device_token_bytes: Vec<u8> = convert_to_binary(device_token);

    let mut notification_buffer: Vec<u8> = vec![];
    let mut message_buffer: Vec<u8> = vec![];

    // Device token
    let mut device_token_length = vec![];
    let _ = device_token_length.write_u16::<BigEndian>(device_token_bytes.len() as u16);

    message_buffer.push(1u8);
    for s in device_token_length.iter() {
        message_buffer.push(*s);
    }
    for s in device_token_bytes.iter() {
        message_buffer.push(*s);
    }

    // Payload
    let mut payload_length = vec![];
    let _ = payload_length.write_u16::<BigEndian>(payload_bytes.len() as u16);

    message_buffer.push(2u8);
    for s in payload_length.iter() {
        message_buffer.push(*s);
    }
    for s in payload_bytes.iter() {
        message_buffer.push(*s);
    }

    // Notification identifier
    let payload_id = rand::thread_rng().gen();
    let mut payload_id_be = vec![];
    let _ = payload_id_be.write_u32::<BigEndian>(payload_id);

    let mut payload_id_length = vec![];
    let _ = payload_id_length.write_u16::<BigEndian>(payload_id_be.len() as u16);

    message_buffer.push(3u8);
    for s in payload_id_length.iter() {
        message_buffer.push(*s);
    }
    for s in payload_id_be.iter() {
        message_buffer.push(*s);
    }

    //	Expiration date
    let time = time::now().to_timespec().sec + 86400;	// expired after one day
    let mut exp_date_be = vec![];
    let _ = exp_date_be.write_u32::<BigEndian>(time as u32);

    let mut exp_date_length = vec![];
    let _ = exp_date_length.write_u16::<BigEndian>(exp_date_be.len() as u16);

    message_buffer.push(4u8);
    for s in exp_date_length.iter() {
        message_buffer.push(*s);
    }
    for s in exp_date_be.iter() {
        message_buffer.push(*s);
    }

    // Priority
    let mut priority_length = vec![];
    let _ = priority_length.write_u16::<BigEndian>(1u16);

    message_buffer.push(5u8);
    for s in priority_length.iter() {
        message_buffer.push(*s);
    }
    message_buffer.push(10u8);

    let mut message_buffer_length = vec![];
    let _ = message_buffer_length.write_u32::<BigEndian>(message_buffer.len() as u32);

    let command = 2u8;
    notification_buffer.push(command);
    for s in message_buffer_length.iter() {
        notification_buffer.push(*s);
    }
    for s in message_buffer.iter() {
        notification_buffer.push(*s);
    }

    return notification_buffer;
}

fn get_ssl_stream(url: &str, cert_file: &Path, private_key_file: &Path, ca_file: &Path) -> Result<SslStream<TcpStream>, SslError> {
    let mut context = try!(ssl::SslContext::new(ssl::SslMethod::Sslv23));

    if let Err(error) = context.set_CA_file(ca_file) {
		println!("set_CA_file error {:?}", error);
    }
    if let Err(error) = context.set_certificate_file(cert_file, openssl::x509::X509FileType::PEM) {
		println!("set_certificate_file error {:?}", error);
    }
    if let Err(error) = context.set_private_key_file(private_key_file, openssl::x509::X509FileType::PEM) {
		println!("set_private_key_file error {:?}", error);
    }

    let tcp_conn = match TcpStream::connect(url) {
		Ok(conn) => { conn },
		Err(error) => {
			println!("tcp_stream connect error {:?}", error);
			return Result::Err(SslError::StreamError(error));
		}
	};

    return SslStream::new(&context, tcp_conn);
}
<commit_msg>compatible with the latest openssl crates<commit_after>use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use rustc_serialize::Encodable;
use rustc_serialize::Encoder;
use rustc_serialize::json;

use openssl;
use openssl::ssl;
use openssl::ssl::SslStream;
use openssl::ssl::error::SslError;

use std::ops::{Range, Index};
use std::net::TcpStream;
use std::io::{Cursor, Read, Write};
use std::path::Path;
use std::vec::Vec;
use std::collections::HashMap;

use num::pow;
use rand::{self, Rng};
use time;

#[derive(Debug)]
pub struct Payload<'a> {
    pub aps: PayloadAPS<'a>,
    pub info: Option<HashMap<&'a str, &'a str>>
}

#[derive(Debug)]
pub struct PayloadAPS<'a> {
    pub alert: PayloadAPSAlert<'a>,
    pub badge: Option<i32>,
    pub sound: Option<&'a str>,
    pub content_available: Option<i32>
}

#[derive(Debug)]
pub enum PayloadAPSAlert<'a> {
    Plain(&'a str),
    Localized(&'a str, Vec<&'a str>)
}

impl<'a> Encodable for Payload<'a> {
    fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
		match *self {
		    Payload{ref aps, ref info} => {
				if let Some(ref map) = *info {
					encoder.emit_struct("Payload", 1 + map.len(), |encoder| {
					try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
					let mut index = 1usize;
					for (key, val) in map.iter() {
					    try!(encoder.emit_struct_field(key, index, |encoder| val.encode(encoder)));
					    index = index + 1;
					}
					Ok(())
					})
				}
				else {
					encoder.emit_struct("Payload", 1, |encoder| {
					try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
					Ok(())
					})
				}
		    }
		}
    }
}

impl<'a> Encodable for PayloadAPS<'a> {
    fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
        match *self {
			PayloadAPS{ref alert, ref badge, ref sound, ref content_available} => {
				let mut count = 1;
		        if badge.is_some() { count = count + 1; }
		        if sound.is_some() { count = count + 1; }
		        if content_available.is_some() { count = count + 1; }

		        let mut index = 0usize;
				encoder.emit_struct("PayloadAPS", count, |encoder| {
					try!(encoder.emit_struct_field( "alert", index, |encoder| alert.encode(encoder)));
					index = index + 1;
					if badge.is_some() {
						try!(encoder.emit_struct_field( "badge", index, |encoder| badge.unwrap().encode(encoder)));
						index = index + 1;
		            }
		            if sound.is_some() {
						try!(encoder.emit_struct_field( "sound", index, |encoder| sound.unwrap().encode(encoder)));
						index = index + 1;
		            }
		            if content_available.is_some() {
						try!(encoder.emit_struct_field( "content-available", index, |encoder| content_available.unwrap().encode(encoder)));
						index = index + 1;
		            }
					Ok(())
				})
			}
		}
    }
}

impl<'a> Encodable for PayloadAPSAlert<'a> {
    fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
		match *self {
		    PayloadAPSAlert::Plain(ref str) => {
				encoder.emit_str(str)
		    },
		    PayloadAPSAlert::Localized(ref key, ref args) => {
				encoder.emit_struct("PayloadAPSAlert", 2, |encoder| {
					try!(encoder.emit_struct_field( "loc-key", 0usize, |encoder| key.encode(encoder)));
					try!(encoder.emit_struct_field( "loc-args", 1usize, |encoder| args.encode(encoder)));
					Ok(())
					})
			}
		}
	}
}

#[allow(dead_code)]
fn hex_to_int(hex: &str) -> u32 {
    let mut total = 0u32;
    let mut n = hex.to_string().len();

    for c in hex.chars() {
        n = n - 1;
		match c {
		    '0'...'9' => {
				total += pow(16, n) * ((c as u32) - ('0' as u32));
		    },
		    'a'...'f' => {
				total += pow(16, n) * ((c as u32) - ('a' as u32) + 10);
		    },
		    _ => {

		    }
		}
    }

    return total;
}

#[allow(dead_code)]
fn convert_to_binary(device_token: &str) -> Vec<u8> {
    let mut device_token_bytes: Vec<u8> = Vec::new();
    for i in 0..8 {
		let string = device_token.to_string();
		let range = Range{start:i*8, end:i*8+8};
		let sub_str = string.index(range);

		let sub_str_num = hex_to_int(sub_str);
		let mut sub_str_bytes = vec![];
		let _ = sub_str_bytes.write_u32::<BigEndian>(sub_str_num);

        for s in sub_str_bytes.iter() {
            device_token_bytes.push(*s);
        }
    }

    return device_token_bytes;
}

#[allow(dead_code)]
pub fn convert_to_token(binary: &[u8]) -> String {
    let mut token = "".to_string();
    for i in 0..8 {
		let range = Range{start:i*4, end:i*4+4};
		let sub_slice = binary.index(range);

		let mut rdr = Cursor::new(sub_slice.to_vec());
		let num = rdr.read_u32::<BigEndian>().unwrap();

		token = format!("{}{:x}", token, num);
    }
    return token;
}

#[allow(dead_code)]
pub fn convert_to_timestamp(binary: &[u8]) -> u32 {
    let mut rdr = Cursor::new(binary.to_vec());
    let num = rdr.read_u32::<BigEndian>().unwrap();

    return num;
}

pub struct APNS<'a> {
    pub sandbox: bool,
    pub certificate: &'a Path,
    pub private_key: &'a Path,
    pub ca_certificate: &'a Path,
}

impl<'a> APNS<'a> {
    pub fn new(sandbox: bool, cert_file: &'a Path, private_key_file: &'a Path, ca_file: &'a Path) -> APNS<'a> {
		APNS{sandbox: sandbox, certificate: cert_file, private_key: private_key_file, ca_certificate: ca_file}
    }

    #[allow(dead_code)]
    pub fn get_feedback(&self) -> Result<Vec<(u32, String)>, SslError> {
		let apns_feedback_production = "feedback.push.apple.com:2196";
		let apns_feedback_development = "feedback.sandbox.push.apple.com:2196";

		let apns_feedback_url = if self.sandbox { apns_feedback_development } else { apns_feedback_production };
		let mut stream = try!(get_ssl_stream(apns_feedback_url, self.certificate, self.private_key, self.ca_certificate));

		let mut tokens: Vec<(u32, String)> = Vec::new();
        let mut read_buffer = [0u8; 38];
        loop {
            match stream.ssl_read(&mut read_buffer) {
                Ok(size) => {
                    if size != 38 {
                        break;
                    }
                },
                Err(..) => {
                    /*				return Result::Err(SslError::StreamError(error));*/
                    break;
                }
            }
		    let time_range = Range{start:0, end:4};
		    let time_slice = read_buffer.index(time_range);
		    let time = convert_to_timestamp(time_slice);

		    let token_range = Range{start:6, end:38};
		    let token_slice = read_buffer.index(token_range);

            let token = convert_to_token(token_slice);
			tokens.push((time, token));
        }

        return Result::Ok(tokens);
    }

    #[allow(dead_code)]
    pub fn send_payload(&self, payload: Payload, device_token: &str) {
        let notification_bytes = get_notification_bytes(payload, device_token);

        let apns_url_production = "gateway.push.apple.com:2195";
        let apns_url_development = "gateway.sandbox.push.apple.com:2195";

        let apns_url = if self.sandbox { apns_url_development } else { apns_url_production };

        let ssl_result = get_ssl_stream(apns_url, self.certificate, self.private_key, self.ca_certificate);
        match ssl_result {
            Ok(mut ssls) => {
                if let Err(error) = ssls.ssl_write(&notification_bytes) {
                    println!("ssl_stream write error {:?}", error);
                }

				// Read possible error code response
				if ssls.ssl().pending() == 6 {
                    let mut read_buffer = [0u8; 6];
                    match ssls.ssl_read(&mut read_buffer) {
                        Ok(size) => {
                            for c in read_buffer.iter() {
                                print!("{}", c);
                            }
                            println!("ssl_stream read size {:?}", size);
                        }
                        Err(error) => {
                            println!("ssl_stream read error {:?}", error);
                        }
                    }
                }
            },
            Err(error) => {
                println!("failed to get_ssl_stream error {:?}", error);
            }
        };
    }
}

fn get_notification_bytes(payload: Payload, device_token: &str) -> Vec<u8> {
    let payload_str = match json::encode(&payload) {
        Ok(json_str) => { json_str.to_string() }
        Err(error) => {
            println!("json encode error {:?}", error);
            return vec![];
        }
    };

    let payload_bytes = payload_str.into_bytes();
    let device_token_bytes: Vec<u8> = convert_to_binary(device_token);

    let mut notification_buffer: Vec<u8> = vec![];
    let mut message_buffer: Vec<u8> = vec![];

    // Device token
    let mut device_token_length = vec![];
    let _ = device_token_length.write_u16::<BigEndian>(device_token_bytes.len() as u16);

    message_buffer.push(1u8);
    for s in device_token_length.iter() {
        message_buffer.push(*s);
    }
    for s in device_token_bytes.iter() {
        message_buffer.push(*s);
    }

    // Payload
    let mut payload_length = vec![];
    let _ = payload_length.write_u16::<BigEndian>(payload_bytes.len() as u16);

    message_buffer.push(2u8);
    for s in payload_length.iter() {
        message_buffer.push(*s);
    }
    for s in payload_bytes.iter() {
        message_buffer.push(*s);
    }

    // Notification identifier
    let payload_id = rand::thread_rng().gen();
    let mut payload_id_be = vec![];
    let _ = payload_id_be.write_u32::<BigEndian>(payload_id);

    let mut payload_id_length = vec![];
    let _ = payload_id_length.write_u16::<BigEndian>(payload_id_be.len() as u16);

    message_buffer.push(3u8);
    for s in payload_id_length.iter() {
        message_buffer.push(*s);
    }
    for s in payload_id_be.iter() {
        message_buffer.push(*s);
    }

    //	Expiration date
    let time = time::now().to_timespec().sec + 86400;	// expired after one day
    let mut exp_date_be = vec![];
    let _ = exp_date_be.write_u32::<BigEndian>(time as u32);

    let mut exp_date_length = vec![];
    let _ = exp_date_length.write_u16::<BigEndian>(exp_date_be.len() as u16);

    message_buffer.push(4u8);
    for s in exp_date_length.iter() {
        message_buffer.push(*s);
    }
    for s in exp_date_be.iter() {
        message_buffer.push(*s);
    }

    // Priority
    let mut priority_length = vec![];
    let _ = priority_length.write_u16::<BigEndian>(1u16);

    message_buffer.push(5u8);
    for s in priority_length.iter() {
        message_buffer.push(*s);
    }
    message_buffer.push(10u8);

    let mut message_buffer_length = vec![];
    let _ = message_buffer_length.write_u32::<BigEndian>(message_buffer.len() as u32);

    let command = 2u8;
    notification_buffer.push(command);
    for s in message_buffer_length.iter() {
        notification_buffer.push(*s);
    }
    for s in message_buffer.iter() {
        notification_buffer.push(*s);
    }

    return notification_buffer;
}

fn get_ssl_stream(url: &str, cert_file: &Path, private_key_file: &Path, ca_file: &Path) -> Result<SslStream<TcpStream>, SslError> {
    let mut context = try!(ssl::SslContext::new(ssl::SslMethod::Sslv23));
	let ssl = try!(ssl::Ssl::new(&context));

    if let Err(error) = context.set_CA_file(ca_file) {
		println!("set_CA_file error {:?}", error);
    }
    if let Err(error) = context.set_certificate_file(cert_file, openssl::x509::X509FileType::PEM) {
		println!("set_certificate_file error {:?}", error);
    }
    if let Err(error) = context.set_private_key_file(private_key_file, openssl::x509::X509FileType::PEM) {
		println!("set_private_key_file error {:?}", error);
    }

    let tcp_conn = match TcpStream::connect(url) {
		Ok(conn) => { conn },
		Err(error) => {
			println!("tcp_stream connect error {:?}", error);
			return Result::Err(SslError::StreamError(error));
		}
	};

	return SslStream::connect(ssl, tcp_conn);
}
<|endoftext|>


<commit_before>#![feature(use_extern_macros)]

extern crate clap;
extern crate jump;

use clap::{Arg, App, AppSettings};
use jump::Config;
use std::process;

macro_rules! exit_if_err {
    // TODO: print to stderr
    ($x:expr, $msg:expr) => (match $x {
        Ok(val) => val,
        Err(err) => {
            println!($msg, err);
            process::exit(1)
        }
    });
}

fn main() {
    let args = App::new("Jump Configure")
        .version(clap::crate_version!())
        .author(clap::crate_authors!())
        .about("Allows you to easily jump around your filesystem")
        .setting(AppSettings::UnifiedHelpMessage)
        .arg(Arg::with_name("marker")
             .help("The name of the marker")
             .index(1)
             .required(true))
        .get_matches();

    let config = exit_if_err!(Config::load(), "echo \"Failed to load config: {}\"");
    // We can unwrap this because it is marked as required
    let name = args.value_of("marker").unwrap();
    let marker_path = config.get_marker(name);
    match marker_path {
        None       => println!("echo \"Can't jump to {}\"", name),
        Some(path) => println!("cd \"{}\"", path),
    }

}
<commit_msg>Fixing output<commit_after>#![feature(use_extern_macros)]

extern crate clap;
extern crate jump;

use clap::{Arg, App, AppSettings};
use jump::Config;
use std::process;

macro_rules! exit_if_err {
    // TODO: print to stderr
    ($x:expr, $msg:expr) => (match $x {
        Ok(val) => val,
        Err(err) => {
            println!($msg, err);
            process::exit(1)
        }
    });
}

fn main() {
    let args = App::new("Jump Configure")
        .version(clap::crate_version!())
        .author(clap::crate_authors!())
        .about("Allows you to easily jump around your filesystem")
        .setting(AppSettings::UnifiedHelpMessage)
        .arg(Arg::with_name("marker")
             .help("The name of the marker")
             .index(1)
             .required(true))
        .get_matches();

    let config = exit_if_err!(Config::load(), "echo \"Failed to load config: {}\"");
    // We can unwrap this because it is marked as required
    let name = args.value_of("marker").unwrap();
    let marker_path = config.get_marker(name);
    match marker_path {
        None       => println!("echo \"Can't jump to {}\"", name),
        Some(path) => println!("cd {:?}", path),
    }

}
<|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.

#![cfg(not(test))]

extern crate env_logger;
extern crate getopts;
extern crate rustfmt_nightly as rustfmt;

use std::fs::File;
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::{env, error};

use getopts::{Matches, Options};

use rustfmt::config::file_lines::FileLines;
use rustfmt::config::{get_toml_path, Color, Config, WriteMode};
use rustfmt::{run, FileName, Input, Summary};

type FmtError = Box<error::Error + Send + Sync>;
type FmtResult<T> = std::result::Result<T, FmtError>;

/// Rustfmt operations.
enum Operation {
    /// Format files and their child modules.
    Format {
        files: Vec<PathBuf>,
        config_path: Option<PathBuf>,
        minimal_config_path: Option<String>,
    },
    /// Print the help message.
    Help,
    // Print version information
    Version,
    /// Print detailed configuration help.
    ConfigHelp,
    /// Output default config to a file, or stdout if None
    ConfigOutputDefault {
        path: Option<String>,
    },
    /// No file specified, read from stdin
    Stdin {
        input: String,
        config_path: Option<PathBuf>,
    },
}

/// Parsed command line options.
#[derive(Clone, Debug, Default)]
struct CliOptions {
    skip_children: bool,
    verbose: bool,
    write_mode: Option<WriteMode>,
    color: Option<Color>,
    file_lines: FileLines, // Default is all lines in all files.
    unstable_features: bool,
    error_on_unformatted: bool,
}

impl CliOptions {
    fn from_matches(matches: &Matches) -> FmtResult<CliOptions> {
        let mut options = CliOptions::default();
        options.skip_children = matches.opt_present("skip-children");
        options.verbose = matches.opt_present("verbose");
        let unstable_features = matches.opt_present("unstable-features");
        let rust_nightly = option_env!("CFG_RELEASE_CHANNEL")
            .map(|c| c == "nightly")
            .unwrap_or(false);
        if unstable_features && !rust_nightly {
            return Err(FmtError::from(
                "Unstable features are only available on Nightly channel",
            ));
        } else {
            options.unstable_features = unstable_features;
        }

        if let Some(ref write_mode) = matches.opt_str("write-mode") {
            if let Ok(write_mode) = WriteMode::from_str(write_mode) {
                options.write_mode = Some(write_mode);
            } else {
                return Err(FmtError::from(format!(
                    "Invalid write-mode: {}",
                    write_mode
                )));
            }
        }

        if let Some(ref color) = matches.opt_str("color") {
            match Color::from_str(color) {
                Ok(color) => options.color = Some(color),
                _ => return Err(FmtError::from(format!("Invalid color: {}", color))),
            }
        }

        if let Some(ref file_lines) = matches.opt_str("file-lines") {
            options.file_lines = file_lines.parse()?;
        }

        if matches.opt_present("error-on-unformatted") {
            options.error_on_unformatted = true;
        }

        Ok(options)
    }

    fn apply_to(self, config: &mut Config) {
        config.set().skip_children(self.skip_children);
        config.set().verbose(self.verbose);
        config.set().file_lines(self.file_lines);
        config.set().unstable_features(self.unstable_features);
        config.set().error_on_unformatted(self.error_on_unformatted);
        if let Some(write_mode) = self.write_mode {
            config.set().write_mode(write_mode);
        }
        if let Some(color) = self.color {
            config.set().color(color);
        }
    }
}

/// read the given config file path recursively if present else read the project file path
fn match_cli_path_or_file(
    config_path: Option<PathBuf>,
    input_file: &Path,
) -> FmtResult<(Config, Option<PathBuf>)> {
    if let Some(config_file) = config_path {
        let toml = Config::from_toml_path(config_file.as_ref())?;
        return Ok((toml, Some(config_file)));
    }
    Config::from_resolved_toml_path(input_file).map_err(FmtError::from)
}

fn make_opts() -> Options {
    let mut opts = Options::new();

    // Sorted in alphabetical order.
    opts.optopt(
        "",
        "color",
        "Use colored output (if supported)",
        "[always|never|auto]",
    );
    opts.optflag(
        "",
        "config-help",
        "Show details of rustfmt configuration options",
    );
    opts.optopt(
        "",
        "config-path",
        "Recursively searches the given path for the rustfmt.toml config file. If not \
         found reverts to the input file path",
        "[Path for the configuration file]",
    );
    opts.optopt(
        "",
        "dump-default-config",
        "Dumps default configuration to PATH. PATH defaults to stdout, if omitted.",
        "PATH",
    );
    opts.optopt(
        "",
        "dump-minimal-config",
        "Dumps configuration options that were checked during formatting to a file.",
        "PATH",
    );
    opts.optflag(
        "",
        "error-on-unformatted",
        "Error if unable to get comments or string literals within max_width, \
         or they are left with trailing whitespaces",
    );
    opts.optopt(
        "",
        "file-lines",
        "Format specified line ranges. See README for more detail on the JSON format.",
        "JSON",
    );
    opts.optflag("h", "help", "Show this message");
    opts.optflag("", "skip-children", "Don't reformat child modules");
    opts.optflag(
        "",
        "unstable-features",
        "Enables unstable features. Only available on nightly channel",
    );
    opts.optflag("v", "verbose", "Print verbose output");
    opts.optflag("V", "version", "Show version information");
    opts.optopt(
        "",
        "write-mode",
        "How to write output (not usable when piping from stdin)",
        "[replace|overwrite|display|plain|diff|coverage|checkstyle]",
    );

    opts
}

fn execute(opts: &Options) -> FmtResult<Summary> {
    let matches = opts.parse(env::args().skip(1))?;

    match determine_operation(&matches)? {
        Operation::Help => {
            print_usage_to_stdout(opts, "");
            Summary::print_exit_codes();
            Ok(Summary::default())
        }
        Operation::Version => {
            print_version();
            Ok(Summary::default())
        }
        Operation::ConfigHelp => {
            Config::print_docs();
            Ok(Summary::default())
        }
        Operation::ConfigOutputDefault { path } => {
            let toml = Config::default().all_options().to_toml()?;
            if let Some(path) = path {
                let mut file = File::create(path)?;
                file.write_all(toml.as_bytes())?;
            } else {
                io::stdout().write_all(toml.as_bytes())?;
            }
            Ok(Summary::default())
        }
        Operation::Stdin { input, config_path } => {
            // try to read config from local directory
            let (mut config, _) =
                match_cli_path_or_file(config_path, &env::current_dir().unwrap())?;

            // write_mode is always Plain for Stdin.
            config.set().write_mode(WriteMode::Plain);

            // parse file_lines
            if let Some(ref file_lines) = matches.opt_str("file-lines") {
                config.set().file_lines(file_lines.parse()?);
                for f in config.file_lines().files() {
                    match *f {
                        FileName::Custom(ref f) if f == "stdin" => {}
                        _ => eprintln!("Warning: Extra file listed in file_lines option '{}'", f),
                    }
                }
            }

            let mut error_summary = Summary::default();
            if config.version_meets_requirement(&mut error_summary) {
                error_summary.add(run(Input::Text(input), &config));
            }

            Ok(error_summary)
        }
        Operation::Format {
            files,
            config_path,
            minimal_config_path,
        } => {
            let options = CliOptions::from_matches(&matches)?;

            for f in options.file_lines.files() {
                match *f {
                    FileName::Real(ref f) if files.contains(f) => {}
                    FileName::Real(_) => {
                        eprintln!("Warning: Extra file listed in file_lines option '{}'", f)
                    }
                    _ => eprintln!("Warning: Not a file '{}'", f),
                }
            }

            let mut config = Config::default();
            // Load the config path file if provided
            if let Some(config_file) = config_path.as_ref() {
                config = Config::from_toml_path(config_file.as_ref())?;
            };

            if options.verbose {
                if let Some(path) = config_path.as_ref() {
                    println!("Using rustfmt config file {}", path.display());
                }
            }

            let mut error_summary = Summary::default();
            for file in files {
                if !file.exists() {
                    eprintln!("Error: file `{}` does not exist", file.to_str().unwrap());
                    error_summary.add_operational_error();
                } else if file.is_dir() {
                    eprintln!("Error: `{}` is a directory", file.to_str().unwrap());
                    error_summary.add_operational_error();
                } else {
                    // Check the file directory if the config-path could not be read or not provided
                    if config_path.is_none() {
                        let (config_tmp, path_tmp) =
                            Config::from_resolved_toml_path(file.parent().unwrap())?;
                        if options.verbose {
                            if let Some(path) = path_tmp.as_ref() {
                                println!(
                                    "Using rustfmt config file {} for {}",
                                    path.display(),
                                    file.display()
                                );
                            }
                        }
                        config = config_tmp;
                    }

                    if !config.version_meets_requirement(&mut error_summary) {
                        break;
                    }

                    options.clone().apply_to(&mut config);
                    error_summary.add(run(Input::File(file), &config));
                }
            }

            // If we were given a path via dump-minimal-config, output any options
            // that were used during formatting as TOML.
            if let Some(path) = minimal_config_path {
                let mut file = File::create(path)?;
                let toml = config.used_options().to_toml()?;
                file.write_all(toml.as_bytes())?;
            }

            Ok(error_summary)
        }
    }
}

fn main() {
    env_logger::init();

    let opts = make_opts();

    let exit_code = match execute(&opts) {
        Ok(summary) => {
            if summary.has_operational_errors() {
                1
            } else if summary.has_parsing_errors() {
                2
            } else if summary.has_formatting_errors() {
                3
            } else if summary.has_diff {
                // should only happen in diff mode
                4
            } else {
                assert!(summary.has_no_errors());
                0
            }
        }
        Err(e) => {
            eprintln!("{}", e.to_string());
            1
        }
    };
    // Make sure standard output is flushed before we exit.
    std::io::stdout().flush().unwrap();

    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    let sep = if reason.is_empty() {
        String::new()
    } else {
        format!("{}\n\n", reason)
    };
    let msg = format!(
        "{}Format Rust code\n\nusage: {} [options] <file>...",
        sep,
        env::args_os().next().unwrap().to_string_lossy()
    );
    println!("{}", opts.usage(&msg));
}

fn print_version() {
    let version_info = format!(
        "{}-{}",
        option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
        include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))
    );

    println!("rustfmt {}", version_info);
}

fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
    if matches.opt_present("h") {
        return Ok(Operation::Help);
    }

    if matches.opt_present("config-help") {
        return Ok(Operation::ConfigHelp);
    }

    if matches.opt_present("dump-default-config") {
        // NOTE for some reason when configured with HasArg::Maybe + Occur::Optional opt_default
        // doesn't recognize `--foo bar` as a long flag with an argument but as a long flag with no
        // argument *plus* a free argument. Thus we check for that case in this branch -- this is
        // required for backward compatibility.
        if let Some(path) = matches.free.get(0) {
            return Ok(Operation::ConfigOutputDefault {
                path: Some(path.clone()),
            });
        } else {
            return Ok(Operation::ConfigOutputDefault {
                path: matches.opt_str("dump-default-config"),
            });
        }
    }

    if matches.opt_present("version") {
        return Ok(Operation::Version);
    }

    let config_path_not_found = |path: &str| -> FmtResult<Operation> {
        Err(FmtError::from(format!(
            "Error: unable to find a config file for the given path: `{}`",
            path
        )))
    };

    // Read the config_path and convert to parent dir if a file is provided.
    // If a config file cannot be found from the given path, return error.
    let config_path: Option<PathBuf> = match matches.opt_str("config-path").map(PathBuf::from) {
        Some(ref path) if !path.exists() => return config_path_not_found(path.to_str().unwrap()),
        Some(ref path) if path.is_dir() => {
            let config_file_path = get_toml_path(path)?;
            if config_file_path.is_some() {
                config_file_path
            } else {
                return config_path_not_found(path.to_str().unwrap());
            }
        }
        path => path,
    };

    // If no path is given, we won't output a minimal config.
    let minimal_config_path = matches.opt_str("dump-minimal-config");

    // if no file argument is supplied, read from stdin
    if matches.free.is_empty() {
        let mut buffer = String::new();
        io::stdin().read_to_string(&mut buffer)?;

        return Ok(Operation::Stdin {
            input: buffer,
            config_path,
        });
    }

    let files: Vec<_> = matches
        .free
        .iter()
        .map(|s| {
            let p = PathBuf::from(s);
            // we will do comparison later, so here tries to canonicalize first
            // to get the expected behavior.
            p.canonicalize().unwrap_or(p)
        })
        .collect();

    Ok(Operation::Format {
        files,
        config_path,
        minimal_config_path,
    })
}
<commit_msg>Let --dump-default-config default to stdout #2579 (#2586)<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.

#![cfg(not(test))]

extern crate env_logger;
extern crate getopts;
extern crate rustfmt_nightly as rustfmt;

use std::fs::File;
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::{env, error};

use getopts::{Matches, Options};

use rustfmt::config::file_lines::FileLines;
use rustfmt::config::{get_toml_path, Color, Config, WriteMode};
use rustfmt::{run, FileName, Input, Summary};

type FmtError = Box<error::Error + Send + Sync>;
type FmtResult<T> = std::result::Result<T, FmtError>;

/// Rustfmt operations.
enum Operation {
    /// Format files and their child modules.
    Format {
        files: Vec<PathBuf>,
        config_path: Option<PathBuf>,
        minimal_config_path: Option<String>,
    },
    /// Print the help message.
    Help,
    // Print version information
    Version,
    /// Print detailed configuration help.
    ConfigHelp,
    /// Output default config to a file, or stdout if None
    ConfigOutputDefault {
        path: Option<String>,
    },
    /// No file specified, read from stdin
    Stdin {
        input: String,
        config_path: Option<PathBuf>,
    },
}

/// Parsed command line options.
#[derive(Clone, Debug, Default)]
struct CliOptions {
    skip_children: bool,
    verbose: bool,
    write_mode: Option<WriteMode>,
    color: Option<Color>,
    file_lines: FileLines, // Default is all lines in all files.
    unstable_features: bool,
    error_on_unformatted: bool,
}

impl CliOptions {
    fn from_matches(matches: &Matches) -> FmtResult<CliOptions> {
        let mut options = CliOptions::default();
        options.skip_children = matches.opt_present("skip-children");
        options.verbose = matches.opt_present("verbose");
        let unstable_features = matches.opt_present("unstable-features");
        let rust_nightly = option_env!("CFG_RELEASE_CHANNEL")
            .map(|c| c == "nightly")
            .unwrap_or(false);
        if unstable_features && !rust_nightly {
            return Err(FmtError::from(
                "Unstable features are only available on Nightly channel",
            ));
        } else {
            options.unstable_features = unstable_features;
        }

        if let Some(ref write_mode) = matches.opt_str("write-mode") {
            if let Ok(write_mode) = WriteMode::from_str(write_mode) {
                options.write_mode = Some(write_mode);
            } else {
                return Err(FmtError::from(format!(
                    "Invalid write-mode: {}",
                    write_mode
                )));
            }
        }

        if let Some(ref color) = matches.opt_str("color") {
            match Color::from_str(color) {
                Ok(color) => options.color = Some(color),
                _ => return Err(FmtError::from(format!("Invalid color: {}", color))),
            }
        }

        if let Some(ref file_lines) = matches.opt_str("file-lines") {
            options.file_lines = file_lines.parse()?;
        }

        if matches.opt_present("error-on-unformatted") {
            options.error_on_unformatted = true;
        }

        Ok(options)
    }

    fn apply_to(self, config: &mut Config) {
        config.set().skip_children(self.skip_children);
        config.set().verbose(self.verbose);
        config.set().file_lines(self.file_lines);
        config.set().unstable_features(self.unstable_features);
        config.set().error_on_unformatted(self.error_on_unformatted);
        if let Some(write_mode) = self.write_mode {
            config.set().write_mode(write_mode);
        }
        if let Some(color) = self.color {
            config.set().color(color);
        }
    }
}

/// read the given config file path recursively if present else read the project file path
fn match_cli_path_or_file(
    config_path: Option<PathBuf>,
    input_file: &Path,
) -> FmtResult<(Config, Option<PathBuf>)> {
    if let Some(config_file) = config_path {
        let toml = Config::from_toml_path(config_file.as_ref())?;
        return Ok((toml, Some(config_file)));
    }
    Config::from_resolved_toml_path(input_file).map_err(FmtError::from)
}

fn make_opts() -> Options {
    let mut opts = Options::new();

    // Sorted in alphabetical order.
    opts.optopt(
        "",
        "color",
        "Use colored output (if supported)",
        "[always|never|auto]",
    );
    opts.optflag(
        "",
        "config-help",
        "Show details of rustfmt configuration options",
    );
    opts.optopt(
        "",
        "config-path",
        "Recursively searches the given path for the rustfmt.toml config file. If not \
         found reverts to the input file path",
        "[Path for the configuration file]",
    );
    opts.opt(
        "",
        "dump-default-config",
        "Dumps default configuration to PATH. PATH defaults to stdout, if omitted.",
        "PATH",
        getopts::HasArg::Maybe,
        getopts::Occur::Optional,
    );
    opts.optopt(
        "",
        "dump-minimal-config",
        "Dumps configuration options that were checked during formatting to a file.",
        "PATH",
    );
    opts.optflag(
        "",
        "error-on-unformatted",
        "Error if unable to get comments or string literals within max_width, \
         or they are left with trailing whitespaces",
    );
    opts.optopt(
        "",
        "file-lines",
        "Format specified line ranges. See README for more detail on the JSON format.",
        "JSON",
    );
    opts.optflag("h", "help", "Show this message");
    opts.optflag("", "skip-children", "Don't reformat child modules");
    opts.optflag(
        "",
        "unstable-features",
        "Enables unstable features. Only available on nightly channel",
    );
    opts.optflag("v", "verbose", "Print verbose output");
    opts.optflag("V", "version", "Show version information");
    opts.optopt(
        "",
        "write-mode",
        "How to write output (not usable when piping from stdin)",
        "[replace|overwrite|display|plain|diff|coverage|checkstyle]",
    );

    opts
}

fn execute(opts: &Options) -> FmtResult<Summary> {
    let matches = opts.parse(env::args().skip(1))?;

    match determine_operation(&matches)? {
        Operation::Help => {
            print_usage_to_stdout(opts, "");
            Summary::print_exit_codes();
            Ok(Summary::default())
        }
        Operation::Version => {
            print_version();
            Ok(Summary::default())
        }
        Operation::ConfigHelp => {
            Config::print_docs();
            Ok(Summary::default())
        }
        Operation::ConfigOutputDefault { path } => {
            let toml = Config::default().all_options().to_toml()?;
            if let Some(path) = path {
                let mut file = File::create(path)?;
                file.write_all(toml.as_bytes())?;
            } else {
                io::stdout().write_all(toml.as_bytes())?;
            }
            Ok(Summary::default())
        }
        Operation::Stdin { input, config_path } => {
            // try to read config from local directory
            let (mut config, _) =
                match_cli_path_or_file(config_path, &env::current_dir().unwrap())?;

            // write_mode is always Plain for Stdin.
            config.set().write_mode(WriteMode::Plain);

            // parse file_lines
            if let Some(ref file_lines) = matches.opt_str("file-lines") {
                config.set().file_lines(file_lines.parse()?);
                for f in config.file_lines().files() {
                    match *f {
                        FileName::Custom(ref f) if f == "stdin" => {}
                        _ => eprintln!("Warning: Extra file listed in file_lines option '{}'", f),
                    }
                }
            }

            let mut error_summary = Summary::default();
            if config.version_meets_requirement(&mut error_summary) {
                error_summary.add(run(Input::Text(input), &config));
            }

            Ok(error_summary)
        }
        Operation::Format {
            files,
            config_path,
            minimal_config_path,
        } => {
            let options = CliOptions::from_matches(&matches)?;

            for f in options.file_lines.files() {
                match *f {
                    FileName::Real(ref f) if files.contains(f) => {}
                    FileName::Real(_) => {
                        eprintln!("Warning: Extra file listed in file_lines option '{}'", f)
                    }
                    _ => eprintln!("Warning: Not a file '{}'", f),
                }
            }

            let mut config = Config::default();
            // Load the config path file if provided
            if let Some(config_file) = config_path.as_ref() {
                config = Config::from_toml_path(config_file.as_ref())?;
            };

            if options.verbose {
                if let Some(path) = config_path.as_ref() {
                    println!("Using rustfmt config file {}", path.display());
                }
            }

            let mut error_summary = Summary::default();
            for file in files {
                if !file.exists() {
                    eprintln!("Error: file `{}` does not exist", file.to_str().unwrap());
                    error_summary.add_operational_error();
                } else if file.is_dir() {
                    eprintln!("Error: `{}` is a directory", file.to_str().unwrap());
                    error_summary.add_operational_error();
                } else {
                    // Check the file directory if the config-path could not be read or not provided
                    if config_path.is_none() {
                        let (config_tmp, path_tmp) =
                            Config::from_resolved_toml_path(file.parent().unwrap())?;
                        if options.verbose {
                            if let Some(path) = path_tmp.as_ref() {
                                println!(
                                    "Using rustfmt config file {} for {}",
                                    path.display(),
                                    file.display()
                                );
                            }
                        }
                        config = config_tmp;
                    }

                    if !config.version_meets_requirement(&mut error_summary) {
                        break;
                    }

                    options.clone().apply_to(&mut config);
                    error_summary.add(run(Input::File(file), &config));
                }
            }

            // If we were given a path via dump-minimal-config, output any options
            // that were used during formatting as TOML.
            if let Some(path) = minimal_config_path {
                let mut file = File::create(path)?;
                let toml = config.used_options().to_toml()?;
                file.write_all(toml.as_bytes())?;
            }

            Ok(error_summary)
        }
    }
}

fn main() {
    env_logger::init();

    let opts = make_opts();

    let exit_code = match execute(&opts) {
        Ok(summary) => {
            if summary.has_operational_errors() {
                1
            } else if summary.has_parsing_errors() {
                2
            } else if summary.has_formatting_errors() {
                3
            } else if summary.has_diff {
                // should only happen in diff mode
                4
            } else {
                assert!(summary.has_no_errors());
                0
            }
        }
        Err(e) => {
            eprintln!("{}", e.to_string());
            1
        }
    };
    // Make sure standard output is flushed before we exit.
    std::io::stdout().flush().unwrap();

    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    let sep = if reason.is_empty() {
        String::new()
    } else {
        format!("{}\n\n", reason)
    };
    let msg = format!(
        "{}Format Rust code\n\nusage: {} [options] <file>...",
        sep,
        env::args_os().next().unwrap().to_string_lossy()
    );
    println!("{}", opts.usage(&msg));
}

fn print_version() {
    let version_info = format!(
        "{}-{}",
        option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
        include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))
    );

    println!("rustfmt {}", version_info);
}

fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
    if matches.opt_present("h") {
        return Ok(Operation::Help);
    }

    if matches.opt_present("config-help") {
        return Ok(Operation::ConfigHelp);
    }

    if matches.opt_present("dump-default-config") {
        // NOTE for some reason when configured with HasArg::Maybe + Occur::Optional opt_default
        // doesn't recognize `--foo bar` as a long flag with an argument but as a long flag with no
        // argument *plus* a free argument. Thus we check for that case in this branch -- this is
        // required for backward compatibility.
        if let Some(path) = matches.free.get(0) {
            return Ok(Operation::ConfigOutputDefault {
                path: Some(path.clone()),
            });
        } else {
            return Ok(Operation::ConfigOutputDefault {
                path: matches.opt_str("dump-default-config"),
            });
        }
    }

    if matches.opt_present("version") {
        return Ok(Operation::Version);
    }

    let config_path_not_found = |path: &str| -> FmtResult<Operation> {
        Err(FmtError::from(format!(
            "Error: unable to find a config file for the given path: `{}`",
            path
        )))
    };

    // Read the config_path and convert to parent dir if a file is provided.
    // If a config file cannot be found from the given path, return error.
    let config_path: Option<PathBuf> = match matches.opt_str("config-path").map(PathBuf::from) {
        Some(ref path) if !path.exists() => return config_path_not_found(path.to_str().unwrap()),
        Some(ref path) if path.is_dir() => {
            let config_file_path = get_toml_path(path)?;
            if config_file_path.is_some() {
                config_file_path
            } else {
                return config_path_not_found(path.to_str().unwrap());
            }
        }
        path => path,
    };

    // If no path is given, we won't output a minimal config.
    let minimal_config_path = matches.opt_str("dump-minimal-config");

    // if no file argument is supplied, read from stdin
    if matches.free.is_empty() {
        let mut buffer = String::new();
        io::stdin().read_to_string(&mut buffer)?;

        return Ok(Operation::Stdin {
            input: buffer,
            config_path,
        });
    }

    let files: Vec<_> = matches
        .free
        .iter()
        .map(|s| {
            let p = PathBuf::from(s);
            // we will do comparison later, so here tries to canonicalize first
            // to get the expected behavior.
            p.canonicalize().unwrap_or(p)
        })
        .collect();

    Ok(Operation::Format {
        files,
        config_path,
        minimal_config_path,
    })
}
<|endoftext|>


<commit_before>//! [Problem 74](https://projecteuler.net/problem=74) solver.

#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#[macro_use(problem)] extern crate common;

use std::collections::HashMap;
use std::iter;

#[derive(Clone)]
enum Length { Loop(usize), Chain(usize), Unknown }

fn fact_sum(mut n: u32, fs: &[u32; 10]) -> u32 {
    if n == 0 { return 1; }

    let mut sum = 0;
    while n > 0 {
        sum += fs[(n % 10) as usize];
        n /= 10;
    }
    sum
}

fn get_chain_len(n: u32, map: &mut[Length], fs: &[u32; 10]) -> usize {
    let mut chain_map = HashMap::new();
    let mut idx = n;
    let mut chain_len = 0;
    let mut loop_len  = 0;

    loop {
        match map[idx as usize] {
            Length::Loop(c)  => { loop_len += c;  break; }
            Length::Chain(c) => { chain_len += c; break; }
            Length::Unknown  => {
                match chain_map.get(&idx) {
                    Some(&chain_idx) => {
                        loop_len  = chain_len - chain_idx;
                        chain_len = chain_idx;
                        break;
                    }
                    None => {
                        let _ = chain_map.insert(idx, chain_len);
                        idx = fact_sum(idx, fs);
                        chain_len += 1;
                    }
                }
            }
        }
    }

    for (&key, &idx) in chain_map.iter() {
        if idx >= chain_len {
            map[key as usize] = Length::Loop(loop_len);
        } else {
            map[key as usize] = Length::Chain(loop_len + chain_len - idx);
        }
    }

    chain_len + loop_len
}

fn solve() -> String {
    let limit = 1000000;
    let factorial = {
        let mut val = [1; 10];
        for i in (1 .. 10) {
            val[i] = val[i - 1] * (i as u32);
        }
        val
    };

    let mut map = iter::repeat(Length::Unknown).take((factorial[9] * 6 + 1) as usize).collect::<Vec<_>>();
    let mut cnt = 0;
    for n in (1 .. limit + 1) {
        let len = get_chain_len(n, map.as_mut_slice(), &factorial);
        if len == 60 { cnt += 1; }
    }

    cnt.to_string()
}

problem!("402", solve);

#[cfg(test)]
mod tests {
    use std::iter;

    #[test]
    fn len() {
        let factorial = {
            let mut val = [1; 10];
            for i in (1 .. 10) {
                val[i] = val[i - 1] * i;
            }
            val
        };
        let mut map = iter::repeat(super::Length::Unknown).take(factorial[9] * 6 + 1).collect::<Vec<_>>();

        assert_eq!(3, super::get_chain_len(169, map.as_mut_slice(), &factorial));
        assert_eq!(2, super::get_chain_len(871, map.as_mut_slice(), &factorial));
        assert_eq!(2, super::get_chain_len(872, map.as_mut_slice(), &factorial));
        assert_eq!(5, super::get_chain_len(69, map.as_mut_slice(), &factorial));
        assert_eq!(4, super::get_chain_len(78, map.as_mut_slice(), &factorial));
        assert_eq!(2, super::get_chain_len(540, map.as_mut_slice(), &factorial));
    }

}
<commit_msg>p074: fix test<commit_after>//! [Problem 74](https://projecteuler.net/problem=74) solver.

#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#[macro_use(problem)] extern crate common;

use std::collections::HashMap;
use std::iter;

#[derive(Clone)]
enum Length { Loop(usize), Chain(usize), Unknown }

fn fact_sum(mut n: u32, fs: &[u32; 10]) -> u32 {
    if n == 0 { return 1; }

    let mut sum = 0;
    while n > 0 {
        sum += fs[(n % 10) as usize];
        n /= 10;
    }
    sum
}

fn get_chain_len(n: u32, map: &mut[Length], fs: &[u32; 10]) -> usize {
    let mut chain_map = HashMap::new();
    let mut idx = n;
    let mut chain_len = 0;
    let mut loop_len  = 0;

    loop {
        match map[idx as usize] {
            Length::Loop(c)  => { loop_len += c;  break; }
            Length::Chain(c) => { chain_len += c; break; }
            Length::Unknown  => {
                match chain_map.get(&idx) {
                    Some(&chain_idx) => {
                        loop_len  = chain_len - chain_idx;
                        chain_len = chain_idx;
                        break;
                    }
                    None => {
                        let _ = chain_map.insert(idx, chain_len);
                        idx = fact_sum(idx, fs);
                        chain_len += 1;
                    }
                }
            }
        }
    }

    for (&key, &idx) in chain_map.iter() {
        if idx >= chain_len {
            map[key as usize] = Length::Loop(loop_len);
        } else {
            map[key as usize] = Length::Chain(loop_len + chain_len - idx);
        }
    }

    chain_len + loop_len
}

fn solve() -> String {
    let limit = 1000000;
    let factorial = {
        let mut val = [1; 10];
        for i in (1 .. 10) {
            val[i] = val[i - 1] * (i as u32);
        }
        val
    };

    let mut map = iter::repeat(Length::Unknown).take((factorial[9] * 6 + 1) as usize).collect::<Vec<_>>();
    let mut cnt = 0;
    for n in (1 .. limit + 1) {
        let len = get_chain_len(n, map.as_mut_slice(), &factorial);
        if len == 60 { cnt += 1; }
    }

    cnt.to_string()
}

problem!("402", solve);

#[cfg(test)]
mod tests {
    use std::iter;

    #[test]
    fn len() {
        let factorial = {
            let mut val = [1; 10];
            for i in (1 .. 10) {
                val[i] = val[i - 1] * (i as u32);
            }
            val
        };
        let mut map = iter::repeat(super::Length::Unknown).take((factorial[9] * 6 + 1) as usize).collect::<Vec<_>>();

        assert_eq!(3, super::get_chain_len(169, map.as_mut_slice(), &factorial));
        assert_eq!(2, super::get_chain_len(871, map.as_mut_slice(), &factorial));
        assert_eq!(2, super::get_chain_len(872, map.as_mut_slice(), &factorial));
        assert_eq!(5, super::get_chain_len(69, map.as_mut_slice(), &factorial));
        assert_eq!(4, super::get_chain_len(78, map.as_mut_slice(), &factorial));
        assert_eq!(2, super::get_chain_len(540, map.as_mut_slice(), &factorial));
    }

}
<|endoftext|>


<commit_before>use cargo::core::Workspace;
use cargo::ops::{self, MessageFormat, Packages};
use cargo::util::{CliResult, CliError, Human, human, Config};
use cargo::util::important_paths::find_root_manifest_for_wd;

#[derive(RustcDecodable)]
pub struct Options {
    arg_args: Vec<String>,
    flag_features: Vec<String>,
    flag_all_features: bool,
    flag_jobs: Option<u32>,
    flag_manifest_path: Option<String>,
    flag_no_default_features: bool,
    flag_no_run: bool,
    flag_package: Vec<String>,
    flag_target: Option<String>,
    flag_lib: bool,
    flag_doc: bool,
    flag_bin: Vec<String>,
    flag_bins: bool,
    flag_example: Vec<String>,
    flag_examples: bool,
    flag_test: Vec<String>,
    flag_tests: bool,
    flag_bench: Vec<String>,
    flag_benches: bool,
    flag_verbose: u32,
    flag_quiet: Option<bool>,
    flag_color: Option<String>,
    flag_message_format: MessageFormat,
    flag_release: bool,
    flag_no_fail_fast: bool,
    flag_frozen: bool,
    flag_locked: bool,
    flag_all: bool,
}

pub const USAGE: &'static str = "
Execute all unit and integration tests of a local package

Usage:
    cargo test [options] [--] [<args>...]

Options:
    -h, --help                   Print this message
    --lib                        Test only this package's library
    --doc                        Test only this library's documentation
    --bin NAME ...               Test only the specified binary
    --bins                       Test all binaries
    --example NAME ...           Check that the specified examples compile
    --examples                   Check that all examples compile
    --test NAME ...              Test only the specified test target
    --tests                      Test all tests
    --bench NAME ...             Test only the specified bench target
    --benches                    Test all benches
    --no-run                     Compile, but don't run tests
    -p SPEC, --package SPEC ...  Package to run tests for
    --all                        Test all packages in the workspace
    -j N, --jobs N               Number of parallel jobs, defaults to # of CPUs
    --release                    Build artifacts in release mode, with optimizations
    --features FEATURES          Space-separated list of features to also build
    --all-features               Build all available features
    --no-default-features        Do not build the `default` feature
    --target TRIPLE              Build for the target triple
    --manifest-path PATH         Path to the manifest to build tests for
    -v, --verbose ...            Use verbose output (-vv very verbose/build.rs output)
    -q, --quiet                  No output printed to stdout
    --color WHEN                 Coloring: auto, always, never
    --message-format FMT         Error format: human, json [default: human]
    --no-fail-fast               Run all tests regardless of failure
    --frozen                     Require Cargo.lock and cache are up to date
    --locked                     Require Cargo.lock is up to date

All of the trailing arguments are passed to the test binaries generated for
filtering tests and generally providing options configuring how they run. For
example, this will run all tests with the name `foo` in their name:

    cargo test foo

If the --package argument is given, then SPEC is a package id specification
which indicates which package should be tested. If it is not given, then the
current package is tested. For more information on SPEC and its format, see the
`cargo help pkgid` command.

All packages in the workspace are tested if the `--all` flag is supplied. The
`--all` flag may be supplied in the presence of a virtual manifest.

The --jobs argument affects the building of the test executable but does
not affect how many jobs are used when running the tests.

Compilation can be configured via the `test` profile in the manifest.

By default the rust test harness hides output from test execution to
keep results readable. Test output can be recovered (e.g. for debugging)
by passing `--nocapture` to the test binaries:

  cargo test -- --nocapture

To get the list of all options available for the test binaries use this:

  cargo test -- --help
";

pub fn execute(options: Options, config: &Config) -> CliResult {
    config.configure(options.flag_verbose,
                     options.flag_quiet,
                     &options.flag_color,
                     options.flag_frozen,
                     options.flag_locked)?;

    let root = find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())?;

    let empty = Vec::new();
    let (mode, filter);
    if options.flag_doc {
        mode = ops::CompileMode::Doctest;
        filter = ops::CompileFilter::new(true, &empty, false, &empty, false,
                                               &empty, false, &empty, false);
    } else {
        mode = ops::CompileMode::Test;
        filter = ops::CompileFilter::new(options.flag_lib,
                                         &options.flag_bin, options.flag_bins,
                                         &options.flag_test, options.flag_tests,
                                         &options.flag_example, options.flag_examples,
                                         &options.flag_bench, options.flag_benches);
    }

    let spec = if options.flag_all {
        Packages::All
    } else {
        Packages::Packages(&options.flag_package)
    };

    let ops = ops::TestOptions {
        no_run: options.flag_no_run,
        no_fail_fast: options.flag_no_fail_fast,
        only_doc: options.flag_doc,
        compile_opts: ops::CompileOptions {
            config: config,
            jobs: options.flag_jobs,
            target: options.flag_target.as_ref().map(|s| &s[..]),
            features: &options.flag_features,
            all_features: options.flag_all_features,
            no_default_features: options.flag_no_default_features,
            spec: spec,
            release: options.flag_release,
            mode: mode,
            filter: filter,
            message_format: options.flag_message_format,
            target_rustdoc_args: None,
            target_rustc_args: None,
        },
    };

    let ws = Workspace::new(&root, config)?;
    let err = ops::run_tests(&ws, &ops, &options.arg_args)?;
    match err {
        None => Ok(()),
        Some(err) => {
            Err(match err.exit.as_ref().and_then(|e| e.code()) {
                Some(i) => CliError::new(human(err.hint()), i),
                None => CliError::new(Box::new(Human(err)), 101),
            })
        }
    }
}
<commit_msg>Reword the `cargo test --help` text about the --jobs argument<commit_after>use cargo::core::Workspace;
use cargo::ops::{self, MessageFormat, Packages};
use cargo::util::{CliResult, CliError, Human, human, Config};
use cargo::util::important_paths::find_root_manifest_for_wd;

#[derive(RustcDecodable)]
pub struct Options {
    arg_args: Vec<String>,
    flag_features: Vec<String>,
    flag_all_features: bool,
    flag_jobs: Option<u32>,
    flag_manifest_path: Option<String>,
    flag_no_default_features: bool,
    flag_no_run: bool,
    flag_package: Vec<String>,
    flag_target: Option<String>,
    flag_lib: bool,
    flag_doc: bool,
    flag_bin: Vec<String>,
    flag_bins: bool,
    flag_example: Vec<String>,
    flag_examples: bool,
    flag_test: Vec<String>,
    flag_tests: bool,
    flag_bench: Vec<String>,
    flag_benches: bool,
    flag_verbose: u32,
    flag_quiet: Option<bool>,
    flag_color: Option<String>,
    flag_message_format: MessageFormat,
    flag_release: bool,
    flag_no_fail_fast: bool,
    flag_frozen: bool,
    flag_locked: bool,
    flag_all: bool,
}

pub const USAGE: &'static str = "
Execute all unit and integration tests of a local package

Usage:
    cargo test [options] [--] [<args>...]

Options:
    -h, --help                   Print this message
    --lib                        Test only this package's library
    --doc                        Test only this library's documentation
    --bin NAME ...               Test only the specified binary
    --bins                       Test all binaries
    --example NAME ...           Check that the specified examples compile
    --examples                   Check that all examples compile
    --test NAME ...              Test only the specified test target
    --tests                      Test all tests
    --bench NAME ...             Test only the specified bench target
    --benches                    Test all benches
    --no-run                     Compile, but don't run tests
    -p SPEC, --package SPEC ...  Package to run tests for
    --all                        Test all packages in the workspace
    -j N, --jobs N               Number of parallel builds, see below for details
    --release                    Build artifacts in release mode, with optimizations
    --features FEATURES          Space-separated list of features to also build
    --all-features               Build all available features
    --no-default-features        Do not build the `default` feature
    --target TRIPLE              Build for the target triple
    --manifest-path PATH         Path to the manifest to build tests for
    -v, --verbose ...            Use verbose output (-vv very verbose/build.rs output)
    -q, --quiet                  No output printed to stdout
    --color WHEN                 Coloring: auto, always, never
    --message-format FMT         Error format: human, json [default: human]
    --no-fail-fast               Run all tests regardless of failure
    --frozen                     Require Cargo.lock and cache are up to date
    --locked                     Require Cargo.lock is up to date

All of the trailing arguments are passed to the test binaries generated for
filtering tests and generally providing options configuring how they run. For
example, this will run all tests with the name `foo` in their name:

    cargo test foo

If the --package argument is given, then SPEC is a package id specification
which indicates which package should be tested. If it is not given, then the
current package is tested. For more information on SPEC and its format, see the
`cargo help pkgid` command.

All packages in the workspace are tested if the `--all` flag is supplied. The
`--all` flag may be supplied in the presence of a virtual manifest.

The --jobs argument affects the building of the test executable but does
not affect how many jobs are used when running the tests. The default value
for the --jobs argument is the number of CPUs. If you want to control the
number of simultaneous running test cases, pass the `--test-threads` option
to the test binaries:

  cargo test -- --test-threads=1

Compilation can be configured via the `test` profile in the manifest.

By default the rust test harness hides output from test execution to
keep results readable. Test output can be recovered (e.g. for debugging)
by passing `--nocapture` to the test binaries:

  cargo test -- --nocapture

To get the list of all options available for the test binaries use this:

  cargo test -- --help
";

pub fn execute(options: Options, config: &Config) -> CliResult {
    config.configure(options.flag_verbose,
                     options.flag_quiet,
                     &options.flag_color,
                     options.flag_frozen,
                     options.flag_locked)?;

    let root = find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())?;

    let empty = Vec::new();
    let (mode, filter);
    if options.flag_doc {
        mode = ops::CompileMode::Doctest;
        filter = ops::CompileFilter::new(true, &empty, false, &empty, false,
                                               &empty, false, &empty, false);
    } else {
        mode = ops::CompileMode::Test;
        filter = ops::CompileFilter::new(options.flag_lib,
                                         &options.flag_bin, options.flag_bins,
                                         &options.flag_test, options.flag_tests,
                                         &options.flag_example, options.flag_examples,
                                         &options.flag_bench, options.flag_benches);
    }

    let spec = if options.flag_all {
        Packages::All
    } else {
        Packages::Packages(&options.flag_package)
    };

    let ops = ops::TestOptions {
        no_run: options.flag_no_run,
        no_fail_fast: options.flag_no_fail_fast,
        only_doc: options.flag_doc,
        compile_opts: ops::CompileOptions {
            config: config,
            jobs: options.flag_jobs,
            target: options.flag_target.as_ref().map(|s| &s[..]),
            features: &options.flag_features,
            all_features: options.flag_all_features,
            no_default_features: options.flag_no_default_features,
            spec: spec,
            release: options.flag_release,
            mode: mode,
            filter: filter,
            message_format: options.flag_message_format,
            target_rustdoc_args: None,
            target_rustc_args: None,
        },
    };

    let ws = Workspace::new(&root, config)?;
    let err = ops::run_tests(&ws, &ops, &options.arg_args)?;
    match err {
        None => Ok(()),
        Some(err) => {
            Err(match err.exit.as_ref().and_then(|e| e.code()) {
                Some(i) => CliError::new(human(err.hint()), i),
                None => CliError::new(Box::new(Human(err)), 101),
            })
        }
    }
}
<|endoftext|>