<commit_before>extern crate num;
extern crate portaudio;
extern crate rtlsdr;

use portaudio as pa;
use rtlsdr::{RTLSDRDevice, RTLSDRError};
use num::{Num, Zero};
use num::complex::Complex;
use std::env;
use std::f32::consts::PI;
use std::error::Error;
use pa::error::Error as PAError;
use std::thread;
use std::sync::mpsc::channel;

// Make sure that the buffer size is radix-2, otherwise the read_sync function
// will fail with an error code of -8. I want the buffer sizes between the SDR
// and the audio sizes to match, but since we get two samples per read the
// buffer size needs to be double.
const SDR_BUF_SIZE: usize = 262144;

// The buffer size for the audio sink.
const AUDIO_BUF_SIZE: usize = 524288;

// Most other sample rates fail, but this one works for my particular device.
// I will investigate exactly what's happening here and generate a list of
// possible sample rates (if there are others besides this one).
const SDR_SAMPLE_RATE: u32 = 2400000;

// Here is the sample rate of the output waveform we'll try to use.
const AUDIO_SAMPLE_RATE: f32 = 48000.0;

// The number of channels being used for audio.
const CHANNELS: i32 = 2;

// We set the gain manually right now since it seems to be a better option
// than using the AGC (the SDR gets blazing hot with the AGC on).
const SDR_GAIN: i32 = 496;

fn main() {
    match run() {
        Ok(()) => (),
        Err(e) => println!("ERROR: {}", e),
    }
}

struct RTLSDR {
    rtlsdr: RTLSDRDevice,
}

unsafe impl Send for RTLSDR {}

fn run() -> Result<(), Box<Error>> {
    let sdr_index: i32 = env::args()
        .nth(1)
        .expect("Please specify the SDR index.")
        .parse::<i32>()?;
    let fm_freq_mhz: f32 = env::args()
        .nth(2)
        .expect("Please specify a center frequency in MHz.")
        .parse::<f32>()?;
    let bandwidth: u32 = env::args()
        .nth(3)
        .expect("Please specify the bandwidth.")
        .parse::<u32>()?;

    // Set up the threading channels for communication between our two threads.
    let (dongle_tx, dongle_rx) = channel();
    let (demod_tx, demod_rx) = channel();

    // This thread only collects data off of the SDR as quickly as possible and
    // sends it out.
    thread::spawn(move || {
        // Initialize the SDR based on the user's input parameters.
        let fm_freq: u32 = (fm_freq_mhz * 1e6) as u32;
        let mut sdr =
            RTLSDR { rtlsdr: init_sdr(sdr_index, fm_freq, bandwidth).unwrap() };

        loop {
            let bytes = sdr.rtlsdr.read_sync(SDR_BUF_SIZE).unwrap();
            let iq_vec = samps_to_cmplx(bytes).unwrap();
            dongle_tx.send(iq_vec).unwrap();
        }
    });

    // This thread does all of the signal processing required to demodulate
    // the signal and get it to a nice audio stream.
    thread::spawn(move || {
        // Decimating down to 100k samples seems to work the best. I don't
        // really quite get why that is, so I'll need to do more research.
        let dec_rate_filt = 6;
        let dec_rate_audio = 4;

        let taps_filt = windowed_sinc(
            bandwidth as f32,
            SDR_SAMPLE_RATE as f32,
            128,
            &hamming,
        );
        let taps_audio = windowed_sinc(
            bandwidth as f32 / dec_rate_filt as f32,
            SDR_SAMPLE_RATE as f32 / dec_rate_filt as f32,
            128,
            &hamming,
        );

        let mut prev = Complex::zero();
        loop {
            // First, low_pass and decimate the raw IQ signal.
            let mut iq_vec = dongle_rx.recv().unwrap();
            iq_vec = filter(&iq_vec, &taps_filt);
            iq_vec = decimate(iq_vec, dec_rate_filt);

            // Next, demodulate the signal and filter the signal again. The
            // second filter seems to help with the noise after demodulation.
            let res = demod_fm(iq_vec, prev);
            let mut demod_iq = filter_real(&res.0, &taps_audio);
            demod_iq = decimate(demod_iq, dec_rate_audio);
            prev = res.1;
            demod_tx.send(demod_iq).unwrap();
        }
    });

    // Initialize the PortAudio class. We use a blocking stream since we're
    // doing processing on the signal and can't keep up with non-blocking
    // timing requirements.
    let audio = try!(pa::PortAudio::new());
    let settings = try!(audio.default_output_stream_settings(
        CHANNELS,
        AUDIO_SAMPLE_RATE as f64,
        AUDIO_BUF_SIZE as u32,
    ));
    let mut stream = try!(audio.open_blocking_stream(settings));
    try!(stream.start());

    loop {
        let demod_iq = demod_rx.recv().unwrap();
        let buffer_frames = (demod_iq.len() / CHANNELS as usize) as u32;
        let mut out_frames = 0;

        while out_frames < buffer_frames {
            out_frames = match stream.write_available() {
                Ok(available) => {
                    match available {
                        pa::StreamAvailable::Frames(frames) => frames as u32,
                        pa::StreamAvailable::InputOverflowed => {
                            return Err(Box::new(PAError::InputOverflowed))
                        }
                        pa::StreamAvailable::OutputUnderflowed => {
                            return Err(Box::new(PAError::OutputUnderflowed))
                        }
                    }
                }
                Err(e) => return Err(Box::new(e)),
            };
        }

        let n_write_samples = buffer_frames as usize * CHANNELS as usize;

        stream.write(
            buffer_frames,
            |output| for ix in 0..n_write_samples {
                output[ix] = demod_iq[ix];
            },
        )?;
    }
}

fn init_sdr(
    sdr_index: i32,
    fm_freq: u32,
    bandwidth: u32,
) -> Result<RTLSDRDevice, RTLSDRError> {
    let mut sdr = try!(rtlsdr::open(sdr_index));
    try!(sdr.set_center_freq(fm_freq));
    try!(sdr.set_sample_rate(SDR_SAMPLE_RATE));
    try!(sdr.set_tuner_bandwidth(bandwidth));
    try!(sdr.set_tuner_gain(SDR_GAIN));
    try!(sdr.set_agc_mode(false));
    try!(sdr.reset_buffer());
    Ok(sdr)
}

/// Decimates a signal by an integer factor.
///
/// # Arguments
///
/// * `signal` - The signal to decimate
/// * `dec_rate` - The decimation factor
///
fn decimate<T: Copy>(signal: Vec<T>, dec_rate: usize) -> Vec<T> {
    let mut ix = 0;
    let new_size = (signal.len() / dec_rate + 1) as usize;
    let mut signal_dec = Vec::<T>::with_capacity(new_size);
    while ix < signal.len() {
        signal_dec.push(signal[ix]);
        ix += dec_rate;
    }
    signal_dec
}

/// Converts samples from the SDR into complex IQ pairs.
///
/// # Arguments
///
/// * `bytes` - The unsigned bytes from the SDR.
///
fn samps_to_cmplx(bytes: Vec<u8>) -> Option<Vec<Complex<f32>>> {
    // First, check that we've been given an even number of bytes. Not sure
    // what to do if we don't get I and Q.
    let bytes_len = bytes.len();
    if bytes_len % 2 != 0 {
        println!("Received an odd number of samples.");
        return None;

    }

    // Write the values to the complex value and normalize from [0, 255] to
    // [-1, 1].
    let mut iq_vec: Vec<Complex<f32>> = Vec::with_capacity(bytes_len / 2);
    for iq in bytes.chunks(2) {
        let iq_cmplx = Complex::new(
            (iq[0] as f32 - 127.0) / 127.0,
            (iq[1] as f32 - 127.0) / 127.0,
        );
        iq_vec.push(iq_cmplx);
    }
    Some(iq_vec)
}

/// Performs FM demodulation on a complex signal.
///
/// # Arguments
///
/// * `iq` - The IQ samples to demodulate
/// * `prev` - The previous sample from the previous demodulation.
///
fn demod_fm(
    iq: Vec<Complex<f32>>,
    prev: Complex<f32>,
) -> (Vec<f32>, Complex<f32>) {

    let mut p = prev.clone();
    let mut demod_queue: Vec<f32> = Vec::with_capacity(iq.len());

    let gain = SDR_SAMPLE_RATE as f32 / (2.0 * PI * 75e3);

    for samp in iq.iter() {
        let conj = p.conj() * samp;
        demod_queue.push(conj.arg() * gain);
        p = *samp;
    }
    (demod_queue, p)
}

/// Filters a Complex vector and returns a new vector.
///
/// # Arguments
///
/// * `samples` - The complex samples to filter
/// * `taps` - The taps of the filter
///
fn filter<T: Copy + Num + Zero>(
    samples: &Vec<Complex<T>>,
    taps: &Vec<T>,
) -> Vec<Complex<T>> {
    // We'll lose taps.len() - 1 samples from the filtering.
    let mut filt_samps: Vec<Complex<T>> =
        Vec::with_capacity(samples.len() - taps.len() + 1);

    for window in samples.windows(taps.len()) {
        let iter = window.iter().zip(taps.iter());
        let filt_samp = iter.fold(Complex::zero(), |acc, (x, y)| acc + *x * *y);
        filt_samps.push(filt_samp);
    }
    filt_samps
}

/// Filters a real vector and returns a new vector.
///
/// # Arguments
///
/// * `samples` - The real samples to filter
/// * `taps` - The taps of the filter
///
fn filter_real<T: Copy + Num + Zero>(
    samples: &Vec<T>,
    taps: &Vec<T>,
) -> Vec<T> {
    // We'll lose taps.len() - 1 samples from the filtering.
    let mut filt_samps: Vec<T> =
        Vec::with_capacity(samples.len() - taps.len() + 1);
    for window in samples.windows(taps.len()) {
        let iter = window.iter().zip(taps.iter());
        let filt_samp = iter.fold(T::zero(), |acc, (x, y)| acc + *x * *y);
        filt_samps.push(filt_samp);
    }
    filt_samps
}

/// Generates a vector containing the taps for a Hamming window.
///
/// # Arguments
///
/// * `ntaps` - The number of taps to generate for the filter
///
fn hamming(ntaps: usize) -> Vec<f32> {
    let m: f32 = ntaps as f32 - 1.0;
    let mut taps: Vec<f32> = Vec::with_capacity(ntaps);
    for ix in 0..ntaps {
        taps.push(0.54 - 0.46 * (2.0 * PI * ix as f32 / m).cos());
    }
    taps
}

/// Generates filter taps for a sinc filter with a windowing function.
///
/// # Arguments
///
/// * `cutoff_freq` - The cutoff frequency in Hertz
/// * `sample_rate` - The sample frequency in Hertz
/// * `ntaps` - The number of taps to generate for the window
/// * `window` - THe windowing function used to generate the taps for the window
///
fn windowed_sinc(
    cutoff_freq: f32,
    sample_rate: f32,
    ntaps: usize,
    window: &Fn(usize) -> Vec<f32>,
) -> Vec<f32> {
    // Convert the frequency to radians and make it a ratio of the sample rate.
    let wc: f32 = 2.0 * PI * cutoff_freq / sample_rate;

    let win_taps: Vec<f32> = window(ntaps);
    let mut taps: Vec<f32> = Vec::with_capacity(ntaps);

    let ntaps_i: i32 = ntaps as i32;
    let m: i32 = (ntaps_i - 1) / 2;

    for ix in -m..m + 1 {
        let ix_f: f32 = ix as f32;

        // The windowed sinc function is undefined at zero, so set it to
        // something sensible here.
        if ix == 0 {
            let hi = wc / PI * win_taps[(ix + m) as usize];
            taps.push(hi);
        } else {
            let hi = (ix_f * wc).sin() / (ix_f * PI) *
                win_taps[(ix + m) as usize];
            taps.push(hi);
        }
    }
    taps
}
<commit_msg>Making clippy suggestion updates<commit_after>extern crate num;
extern crate portaudio;
extern crate rtlsdr;

use portaudio as pa;
use rtlsdr::{RTLSDRDevice, RTLSDRError};
use num::{Num, Zero};
use num::complex::Complex;
use std::env;
use std::f32::consts::PI;
use std::error::Error;
use pa::error::Error as PAError;
use std::thread;
use std::sync::mpsc::channel;

// Make sure that the buffer size is radix-2, otherwise the read_sync function
// will fail with an error code of -8. I want the buffer sizes between the SDR
// and the audio sizes to match, but since we get two samples per read the
// buffer size needs to be double.
const SDR_BUF_SIZE: usize = 262_144;

// The buffer size for the audio sink.
const AUDIO_BUF_SIZE: usize = 524_288;

// Most other sample rates fail, but this one works for my particular device.
// I will investigate exactly what's happening here and generate a list of
// possible sample rates (if there are others besides this one).
const SDR_SAMPLE_RATE: u32 = 2_400_000;

// Here is the sample rate of the output waveform we'll try to use.
const AUDIO_SAMPLE_RATE: f32 = 48000.0;

// The number of channels being used for audio.
const CHANNELS: i32 = 2;

// We set the gain manually right now since it seems to be a better option
// than using the AGC (the SDR gets blazing hot with the AGC on).
const SDR_GAIN: i32 = 496;

fn main() {
    match run() {
        Ok(()) => (),
        Err(e) => println!("ERROR: {}", e),
    }
}

struct RTLSDR {
    rtlsdr: RTLSDRDevice,
}

unsafe impl Send for RTLSDR {}

fn run() -> Result<(), Box<Error>> {
    let sdr_index: i32 = env::args()
        .nth(1)
        .expect("Please specify the SDR index.")
        .parse::<i32>()?;
    let fm_freq_mhz: f32 = env::args()
        .nth(2)
        .expect("Please specify a center frequency in MHz.")
        .parse::<f32>()?;
    let bandwidth: u32 = env::args()
        .nth(3)
        .expect("Please specify the bandwidth.")
        .parse::<u32>()?;

    // Set up the threading channels for communication between our two threads.
    let (dongle_tx, dongle_rx) = channel();
    let (demod_tx, demod_rx) = channel();

    // This thread only collects data off of the SDR as quickly as possible and
    // sends it out.
    thread::spawn(move || {
        // Initialize the SDR based on the user's input parameters.
        let fm_freq: u32 = (fm_freq_mhz * 1e6) as u32;
        let mut sdr =
            RTLSDR { rtlsdr: init_sdr(sdr_index, fm_freq, bandwidth).unwrap() };

        loop {
            let bytes = sdr.rtlsdr.read_sync(SDR_BUF_SIZE).unwrap();
            let iq_vec = samps_to_cmplx(bytes.as_slice()).unwrap();
            dongle_tx.send(iq_vec).unwrap();
        }
    });

    // This thread does all of the signal processing required to demodulate
    // the signal and get it to a nice audio stream.
    thread::spawn(move || {
        // Decimating down to 100k samples seems to work the best. I don't
        // really quite get why that is, so I'll need to do more research.
        let dec_rate_filt = 6;
        let dec_rate_audio = 4;

        let taps_filt = windowed_sinc(
            bandwidth as f32,
            SDR_SAMPLE_RATE as f32,
            128,
            &hamming,
        );
        let taps_audio = windowed_sinc(
            bandwidth as f32 / dec_rate_filt as f32,
            SDR_SAMPLE_RATE as f32 / dec_rate_filt as f32,
            128,
            &hamming,
        );

        let mut prev = Complex::zero();
        loop {
            // First, low_pass and decimate the raw IQ signal.
            let mut iq_vec = dongle_rx.recv().unwrap();
            iq_vec = filter(&iq_vec, &taps_filt);
            iq_vec = decimate(&iq_vec, dec_rate_filt);

            // Next, demodulate the signal and filter the signal again. The
            // second filter seems to help with the noise after demodulation.
            let res = demod_fm(&iq_vec, prev);
            let mut demod_iq = filter_real(&res.0, &taps_audio);
            demod_iq = decimate(&demod_iq, dec_rate_audio);
            prev = res.1;
            demod_tx.send(demod_iq).unwrap();
        }
    });

    // Initialize the PortAudio class. We use a blocking stream since we're
    // doing processing on the signal and can't keep up with non-blocking
    // timing requirements.
    let audio = try!(pa::PortAudio::new());
    let settings = try!(audio.default_output_stream_settings(
        CHANNELS,
        AUDIO_SAMPLE_RATE as f64,
        AUDIO_BUF_SIZE as u32,
    ));
    let mut stream = try!(audio.open_blocking_stream(settings));
    try!(stream.start());

    loop {
        let demod_iq = demod_rx.recv().unwrap();
        let buffer_frames = (demod_iq.len() / CHANNELS as usize) as u32;
        let mut out_frames = 0;

        while out_frames < buffer_frames {
            out_frames = match stream.write_available() {
                Ok(available) => {
                    match available {
                        pa::StreamAvailable::Frames(frames) => frames as u32,
                        pa::StreamAvailable::InputOverflowed => {
                            return Err(Box::new(PAError::InputOverflowed))
                        }
                        pa::StreamAvailable::OutputUnderflowed => {
                            return Err(Box::new(PAError::OutputUnderflowed))
                        }
                    }
                }
                Err(e) => return Err(Box::new(e)),
            };
        }

        let n_write_samples = buffer_frames as usize * CHANNELS as usize;

        stream.write(
            buffer_frames,
            |output| for ix in 0..n_write_samples {
                output[ix] = demod_iq[ix];
            },
        )?;
    }
}

fn init_sdr(
    sdr_index: i32,
    fm_freq: u32,
    bandwidth: u32,
) -> Result<RTLSDRDevice, RTLSDRError> {
    let mut sdr = try!(rtlsdr::open(sdr_index));
    try!(sdr.set_center_freq(fm_freq));
    try!(sdr.set_sample_rate(SDR_SAMPLE_RATE));
    try!(sdr.set_tuner_bandwidth(bandwidth));
    try!(sdr.set_tuner_gain(SDR_GAIN));
    try!(sdr.set_agc_mode(false));
    try!(sdr.reset_buffer());
    Ok(sdr)
}

/// Decimates a signal by an integer factor.
///
/// # Arguments
///
/// * `signal` - The signal to decimate
/// * `dec_rate` - The decimation factor
///
fn decimate<T: Copy>(signal: &[T], dec_rate: usize) -> Vec<T> {
    let mut ix = 0;
    let new_size = (signal.len() / dec_rate + 1) as usize;
    let mut signal_dec = Vec::<T>::with_capacity(new_size);
    while ix < signal.len() {
        signal_dec.push(signal[ix]);
        ix += dec_rate;
    }
    signal_dec
}

/// Converts samples from the SDR into complex IQ pairs.
///
/// # Arguments
///
/// * `bytes` - The unsigned bytes from the SDR.
///
fn samps_to_cmplx(bytes: &[u8]) -> Option<Vec<Complex<f32>>> {
    // First, check that we've been given an even number of bytes. Not sure
    // what to do if we don't get I and Q.
    let bytes_len = bytes.len();
    if bytes_len % 2 != 0 {
        println!("Received an odd number of samples.");
        return None;

    }

    // Write the values to the complex value and normalize from [0, 255] to
    // [-1, 1].
    let mut iq_vec: Vec<Complex<f32>> = Vec::with_capacity(bytes_len / 2);
    for iq in bytes.chunks(2) {
        let iq_cmplx = Complex::new(
            (iq[0] as f32 - 127.0) / 127.0,
            (iq[1] as f32 - 127.0) / 127.0,
        );
        iq_vec.push(iq_cmplx);
    }
    Some(iq_vec)
}

/// Performs FM demodulation on a complex signal.
///
/// # Arguments
///
/// * `iq` - The IQ samples to demodulate
/// * `prev` - The previous sample from the previous demodulation.
///
fn demod_fm(
    iq: &[Complex<f32>],
    prev: Complex<f32>,
) -> (Vec<f32>, Complex<f32>) {

    let mut p = prev;
    let mut demod_queue: Vec<f32> = Vec::with_capacity(iq.len());

    let gain = SDR_SAMPLE_RATE as f32 / (2.0 * PI * 75e3);

    for samp in iq.iter() {
        let conj = p.conj() * samp;
        demod_queue.push(conj.arg() * gain);
        p = *samp;
    }
    (demod_queue, p)
}

/// Filters a Complex vector and returns a new vector.
///
/// # Arguments
///
/// * `samples` - The complex samples to filter
/// * `taps` - The taps of the filter
///
fn filter<T: Copy + Num + Zero>(
    samples: &[Complex<T>],
    taps: &[T],
) -> Vec<Complex<T>> {
    // We'll lose taps.len() - 1 samples from the filtering.
    let mut filt_samps: Vec<Complex<T>> =
        Vec::with_capacity(samples.len() - taps.len() + 1);

    for window in samples.windows(taps.len()) {
        let iter = window.iter().zip(taps.iter());
        let filt_samp = iter.fold(Complex::zero(), |acc, (x, y)| acc + *x * *y);
        filt_samps.push(filt_samp);
    }
    filt_samps
}

/// Filters a real vector and returns a new vector.
///
/// # Arguments
///
/// * `samples` - The real samples to filter
/// * `taps` - The taps of the filter
///
fn filter_real<T: Copy + Num + Zero>(
    samples: &[T],
    taps: &[T],
) -> Vec<T> {
    // We'll lose taps.len() - 1 samples from the filtering.
    let mut filt_samps: Vec<T> =
        Vec::with_capacity(samples.len() - taps.len() + 1);
    for window in samples.windows(taps.len()) {
        let iter = window.iter().zip(taps.iter());
        let filt_samp = iter.fold(T::zero(), |acc, (x, y)| acc + *x * *y);
        filt_samps.push(filt_samp);
    }
    filt_samps
}

/// Generates a vector containing the taps for a Hamming window.
///
/// # Arguments
///
/// * `ntaps` - The number of taps to generate for the filter
///
fn hamming(ntaps: usize) -> Vec<f32> {
    let m: f32 = ntaps as f32 - 1.0;
    let mut taps: Vec<f32> = Vec::with_capacity(ntaps);
    for ix in 0..ntaps {
        taps.push(0.54 - 0.46 * (2.0 * PI * ix as f32 / m).cos());
    }
    taps
}

/// Generates filter taps for a sinc filter with a windowing function.
///
/// # Arguments
///
/// * `cutoff_freq` - The cutoff frequency in Hertz
/// * `sample_rate` - The sample frequency in Hertz
/// * `ntaps` - The number of taps to generate for the window
/// * `window` - The windowing function used to generate the taps for the window
///
fn windowed_sinc(
    cutoff_freq: f32,
    sample_rate: f32,
    ntaps: usize,
    window: &Fn(usize) -> Vec<f32>,
) -> Vec<f32> {
    // Convert the frequency to radians and make it a ratio of the sample rate.
    let wc: f32 = 2.0 * PI * cutoff_freq / sample_rate;

    let win_taps: Vec<f32> = window(ntaps);
    let mut taps: Vec<f32> = Vec::with_capacity(ntaps);

    let ntaps_i: i32 = ntaps as i32;
    let m: i32 = (ntaps_i - 1) / 2;

    for ix in -m..m + 1 {
        let ix_f: f32 = ix as f32;

        // The windowed sinc function is undefined at zero, so set it to
        // something sensible here.
        if ix == 0 {
            let hi = wc / PI * win_taps[(ix + m) as usize];
            taps.push(hi);
        } else {
            let hi = (ix_f * wc).sin() / (ix_f * PI) *
                win_taps[(ix + m) as usize];
            taps.push(hi);
        }
    }
    taps
}
<|endoftext|>


<commit_before>use std::cell::Cell;

struct Coordinates {
    x: Cell<i32>,
    y: Cell<i32>,
}

fn main() {
    let origin = Coordinates { x: Cell::new(0), y: Cell::new(0) };

    println!("X is {:?} and Y is {:?}", origin.x, origin.y);

    move_up(&origin.y); // borrowing the value
    move_up(&origin.y); // so that I can change it

    println!("X is {:?} and Y is {:?}", origin.x, origin.y);
}

fn move_up(y_cord: &Cell<i32>) -> &Cell<i32> {
    let new_val = y_cord.get(); // Here I get the value and store it
    y_cord.set(new_val + 1); // Here I modify the stored value and set the incoming param
    y_cord // no semicolon here because it is the return value
}

#[test]
fn it_can_move_up_one_pixel() {
    let origin = Coordinates { x: Cell::new(0), y: Cell::new(0) };
    let origin_test = Coordinates { x: Cell::new(1), y: Cell::new(0) };

    assert_eq!(origin_test.y, origin.y);

    move_up(&origin.y);

    assert_eq!(1, origin.y.get());

    move_up(&origin.y);
    move_up(&origin.y);
    move_up(&origin.y);

    assert_eq!(4, origin.y.get())
}
<commit_msg>removed a println since the tests prove it works<commit_after>use std::cell::Cell;

struct Coordinates {
    x: Cell<i32>,
    y: Cell<i32>,
}

fn main() {
    let origin = Coordinates { x: Cell::new(0), y: Cell::new(0) };

    move_up(&origin.y); // borrowing the value
    move_up(&origin.y); // so that I can change it

    println!("X is {:?} and Y is {:?}", origin.x, origin.y);
}

fn move_up(y_cord: &Cell<i32>) -> &Cell<i32> {
    let new_val = y_cord.get(); // Here I get the value and store it
    y_cord.set(new_val + 1); // Here I modify the stored value and set the incoming param
    y_cord // no semicolon here because it is the return value
}

#[test]
fn it_can_move_up_one_pixel() {
    let origin = Coordinates { x: Cell::new(0), y: Cell::new(0) };

    assert_eq!(0, origin.y.get());

    move_up(&origin.y);

    assert_eq!(1, origin.y.get());

    move_up(&origin.y);
    move_up(&origin.y);
    move_up(&origin.y);

    assert_eq!(4, origin.y.get())
}
<|endoftext|>


<commit_before>use std::env;
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::str::Chars;

enum Builtin {
    dot,
    plus,
    minus,
    times,
    divide,
}

#[derive(Clone)]
enum Word {
    //custom(Vec<String>),
    //custom(usize),
    custom(Rc<Vec<String>>),
    builtin(Builtin),
    colon,
    semicolon,
    _if,
    then,
    _else,
    //ifelse(Vec<String>, Vec<String>),
    //define(String, Vec<String>),
    //dot,
    //plus,
    //minus,
    //times,
    //divide,
    //dotquote(<String>),
    dotquote,
    int(i32),
    float(f32),
}

enum Branch {
    //word(Word),
    custom(Rc<Vec<String>>)
    //custom(Vec<String>),
    builtin(Builtin),
    ifelse(Vec<String>, Vec<String>),
    dotquote(<String>)
}

struct Dictionary {
    items: HashMap<String, Word>
}

impl Dictionary {
    fn get(&self, name: &str) -> Option<Word> {
        if let Some(word) = self.get(name) {
            Some(word)
        } else if let Ok(num) = name.parse::<i32>() {
            Some(Word::int(num))
        } else if let Ok(num) = name.parse::<f32>() {
            Some(Word::float(num))
        } else {
            None
        }
    }
    fn set(&self, name: &str, value: Word) {
        if self.items.contains_key(name) {
            // XXX display debug message another way
            println!("Redefined {}", name);
        }
    }
}

impl Default for Dictionary {
    fn default() -> Dictionary {
        dict = HashMap::new();
        dict.insert(".\"", Word::dotquote);
        dict.insert(".", Word::builtin(Builtin::dot));
        dict.insert("+", Word::builtin(Builtin::plus));
        dict.insert("-", Word::builtin(Buitlin::minus));
        dict.insert("*", Word::builtin(Buitlin::times));
        dict.insert("/", Word::builtin(Buitlin::divide));
        dict.insert(":", Word::colon);
        dict.insert(";", Word::semicolon);
        dict.insert("if", Word::_if);
        dict.insert("then", Word::_then);
        dict.insert("else", Word::_else);
        Dictionary{items: dict}
    }
}

fn parse_next_word(code: &Chars, dict: &Dictionary) -> Some(Branch) {
    let mut word_str = String::new();
    let mut branch = None;
    while let Some(c) = chars.next() {
        if c == ' ' || c == '\n' {
            if let Some(word) = dict.get(word_str) {
                match word {
                    //stop => { return (words, true); },
                    Word::custom(_) | Word::builtin(_) | Word::int(_) | Word::float(_) => {
                        branch = Some(Branch::word(word.clone()))
                    }
                    Word::dotquote => {
                        let text = chars.take_while(|x| x != '"').collect();
                        branch = Branch::dotquote(text);
                    }
                    Word::colon => {
                        let mut name = String::new();
                        while let Some(c) = chars.next() {
                            if c == ' ' || c == '\n' {
                                break;
                            }
                            name.push(c);
                        }

                    }
                }
            break;
            }
        } else {
            word_str.push(c);
        }
    }

    branch
}

fn parse(code: &Chars) -> Vec<Branch> {
    let mut branches: Vec<Branch> = Vec::new();
    let mut word_str = String::new();
    let dict = Dictionary::default();
    while let Some(branch) = parse_next_word(code, &Dictionary) {
        branches.push(branch);
    }

    branches
}

fn main() {
    let path = env::args().nth(1).unwrap();
    let mut file = File::open(&path).unwrap();
    let mut code = String::new();
    file.read_to_string(&mut code).unwrap();

    println!("{:#?}", parse(&code.iter(), None).0);
}
<commit_msg>Remove commented lines<commit_after>use std::env;
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::str::Chars;

enum Builtin {
    dot,
    plus,
    minus,
    times,
    divide,
}

#[derive(Clone)]
enum Word {
    custom(Rc<Vec<String>>),
    builtin(Builtin),
    colon,
    semicolon,
    _if,
    then,
    _else,
    dotquote,
    int(i32),
    float(f32),
}

enum Branch {
    custom(Rc<Vec<String>>)
    builtin(Builtin),
    ifelse(Vec<String>, Vec<String>),
    dotquote(<String>)
}

struct Dictionary {
    items: HashMap<String, Word>
}

impl Dictionary {
    fn get(&self, name: &str) -> Option<Word> {
        if let Some(word) = self.get(name) {
            Some(word)
        } else if let Ok(num) = name.parse::<i32>() {
            Some(Word::int(num))
        } else if let Ok(num) = name.parse::<f32>() {
            Some(Word::float(num))
        } else {
            None
        }
    }
    fn set(&self, name: &str, value: Word) {
        if self.items.contains_key(name) {
            // XXX display debug message another way
            println!("Redefined {}", name);
        }
    }
}

impl Default for Dictionary {
    fn default() -> Dictionary {
        dict = HashMap::new();
        dict.insert(".\"", Word::dotquote);
        dict.insert(".", Word::builtin(Builtin::dot));
        dict.insert("+", Word::builtin(Builtin::plus));
        dict.insert("-", Word::builtin(Buitlin::minus));
        dict.insert("*", Word::builtin(Buitlin::times));
        dict.insert("/", Word::builtin(Buitlin::divide));
        dict.insert(":", Word::colon);
        dict.insert(";", Word::semicolon);
        dict.insert("if", Word::_if);
        dict.insert("then", Word::_then);
        dict.insert("else", Word::_else);
        Dictionary{items: dict}
    }
}

fn parse_next_word(code: &Chars, dict: &Dictionary) -> Some(Branch) {
    let mut word_str = String::new();
    let mut branch = None;
    while let Some(c) = chars.next() {
        if c == ' ' || c == '\n' {
            if let Some(word) = dict.get(word_str) {
                match word {
                    //stop => { return (words, true); },
                    Word::custom(_) | Word::builtin(_) | Word::int(_) | Word::float(_) => {
                        branch = Some(Branch::word(word.clone()))
                    }
                    Word::dotquote => {
                        let text = chars.take_while(|x| x != '"').collect();
                        branch = Branch::dotquote(text);
                    }
                    Word::colon => {
                        let mut name = String::new();
                        while let Some(c) = chars.next() {
                            if c == ' ' || c == '\n' {
                                break;
                            }
                            name.push(c);
                        }

                    }
                }
            break;
            }
        } else {
            word_str.push(c);
        }
    }

    branch
}

fn parse(code: &Chars) -> Vec<Branch> {
    let mut branches: Vec<Branch> = Vec::new();
    let mut word_str = String::new();
    let dict = Dictionary::default();
    while let Some(branch) = parse_next_word(code, &Dictionary) {
        branches.push(branch);
    }

    branches
}

fn main() {
    let path = env::args().nth(1).unwrap();
    let mut file = File::open(&path).unwrap();
    let mut code = String::new();
    file.read_to_string(&mut code).unwrap();

    println!("{:#?}", parse(&code.iter(), None).0);
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate router;

use std::io::Read;

use iron::prelude::*;
use iron::status;
use router::Router;

fn main() {
    let mut router = Router::new();

    fn index(_: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Ok, "Hello World!")))
    }

    router.get("/", index);

    fn count(req: &mut Request) -> IronResult<Response> {
        let ref index = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

        let mut payload = String::new();
        req.body.read_to_string(&mut payload).unwrap();

        // TODO

        let mut response = Response::with((status::Ok, "{\"count\": 0}"));
        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
        Ok(response)
    }

    router.get("/:index/_count", count);

    fn search(req: &mut Request) -> IronResult<Response> {
        let ref index = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

        let mut payload = String::new();
        req.body.read_to_string(&mut payload).unwrap();

        // TODO

        let mut response = Response::with((status::Ok, "{\"hits\": {\"total\": 0, \"hits\": []}}"));
        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
        Ok(response)
    }

    router.get("/:index/_search", search);

    fn put(req: &mut Request) -> IronResult<Response> {
        let ref index = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");
        let ref mapping = req.extensions.get::<Router>().unwrap().find("mapping").unwrap_or("");
        let ref doc = req.extensions.get::<Router>().unwrap().find("doc").unwrap_or("");

        let mut payload = String::new();
        req.body.read_to_string(&mut payload).unwrap();

        // TODO

        let mut response = Response::with((status::Ok, "{}"));
        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
        Ok(response)
    }

    router.put("/:index/:mapping/:doc", put);

    Iron::new(router).http("localhost:9200").unwrap();
}
<commit_msg>Added Index struct<commit_after>extern crate iron;
extern crate router;

use std::io::Read;
use std::collections::HashMap;

use iron::prelude::*;
use iron::status;
use router::Router;

#[derive(Debug)]
struct Index;

impl Index {
    fn new() -> Index {
        Index
    }
}

fn main() {
    let mut indices = HashMap::new();
    indices.insert("wagtail", Index::new());

    let mut router = Router::new();

    fn index(_: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Ok, "Hello World!")))
    }

    router.get("/", index);

    fn count(req: &mut Request) -> IronResult<Response> {
        let ref index = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

        let mut payload = String::new();
        req.body.read_to_string(&mut payload).unwrap();

        // TODO

        let mut response = Response::with((status::Ok, "{\"count\": 0}"));
        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
        Ok(response)
    }

    router.get("/:index/_count", count);

    fn search(req: &mut Request) -> IronResult<Response> {
        let ref index = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

        let mut payload = String::new();
        req.body.read_to_string(&mut payload).unwrap();

        // TODO

        let mut response = Response::with((status::Ok, "{\"hits\": {\"total\": 0, \"hits\": []}}"));
        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
        Ok(response)
    }

    router.get("/:index/_search", search);

    fn put(req: &mut Request) -> IronResult<Response> {
        let ref index = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");
        let ref mapping = req.extensions.get::<Router>().unwrap().find("mapping").unwrap_or("");
        let ref doc = req.extensions.get::<Router>().unwrap().find("doc").unwrap_or("");

        let mut payload = String::new();
        req.body.read_to_string(&mut payload).unwrap();

        // TODO

        let mut response = Response::with((status::Ok, "{}"));
        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
        Ok(response)
    }

    router.put("/:index/:mapping/:doc", put);

    Iron::new(router).http("localhost:9200").unwrap();
}
<|endoftext|>


<commit_before>//! A cargo subcommand for displaying line counts of source code in projects,
//! including a niave `unsafe` counter for Rust source files. This subcommand
//! was originally based off and inspired by the project
//! [tokei](https://github.com/aaronepower/tokei) by
//! [Aaronepower](https://github.com/aaronepower)
//!
//! ## Demo
//!
//! To count the source code in the [Rust](https://github.com/rust-lang/rust)
//! repository (checkout `4c99649`), and print some naive statistics on how much
//! "unsafe" code exists.
//!
//! **NOTE:** The Rust repository is quite large, if you're on a slow internet
//! connection consider using a smaller repository, such as the `cargo-count`
//! repo.
//!
//! ```ignore
//! $ git clone https://github.com/rust-lang/rust
//! $ cd rust
//! $ cargo count --separator , --unsafe-statistics
//! Gathering information...
//!          Language    Files  Lines    Blanks  Comments  Code     Unsafe (%)
//!          --------    -----  -----    ------  --------  ----     ----------
//! Rust        6,018  528,510  66,984  133,698   327,792  3,163
//! (0.96%)
//! C           54     9,962    1,445   1,492     7,025    7,025
//! (100.00%)
//!          CSS         4      1,266    149     52        1,065
//!          JavaScript  4      1,118    131     166       821
//!          Python      31     4,797    843     585       3,369
//! C Header    13     1,865    284     585       996      996
//! (100.00%)
//! C++         4      1,611    185     81        1,345    1,345
//! (100.00%)
//!          --------    -----  -----    ------  --------  ----     ----------
//! Totals:              6,128  549,129  70,021  136,659   342,413  12,529
//! (3.66%)
//!
//! ```
//!
//! The `--separator ,` sets a `,` character as the thousands separator, and
//! `--unsafe-statistics` looks for, and counts lines of `unsafe`.
//!
//! ## Compiling
//!
//! Follow these instructions to compile `cargo-count`, then skip down to
//! Installation.
//!
//!  1. Ensure you have current version of `cargo` and
//!     [Rust](https://www.rust-lang.org) installed
//!  2. Clone the project
//!     `$ git clone https://github.com/kbknapp/cargo-count && cd cargo-count`
//!  3. Build the project `$ cargo build --release` (**NOTE:** There is a large
//!     performance differnce when compiling without optimizations, so I
//!     recommend alwasy using `--release` to enable to them)
//!  4. Once complete, the binary will be located at
//!     `target/release/cargo-count`
//!
//! ## Installation and Usage
//!
//! All you need to do is place `cargo-count` somewhere in your `$PATH`. Then
//! run `cargo count` anywhere in your project directory. For full details see
//! below.
//!
//! ### Linux / OS X
//!
//! You have two options, place `cargo-count` into a directory that is already
//! located in your `$PATH` variable (To see which directories those are, open
//! a terminal and type `echo "${PATH//:/\n}"`, the quotation marks are
//! important), or you can add a custom directory to your `$PATH`
//!
//! **Option 1**
//! If you have write permission to a directory listed in your `$PATH` or you
//! have root permission (or via `sudo`), simply copy the `cargo-count` to that
//! directory `# sudo cp cargo-count /usr/local/bin`
//!
//! **Option 2**
//! If you do not have root, `sudo`, or write permission to any directory
//! already in `$PATH` you can create a directory inside your home directory,
//! and add that. Many people use `$HOME/.bin` to keep it hidden (and not
//! clutter your home directory), or `$HOME/bin` if you want it to be always
//! visible. Here is an example to make the directory, add it to `$PATH`, and
//! copy `cargo-count` there.
//!
//! Simply change `bin` to whatever you'd like to name the directory, and
//! `.bashrc` to whatever your shell startup file is (usually `.bashrc`,
//! `.bash_profile`, or `.zshrc`)
//!
//! ```sh
//! $ mkdir ~/bin
//! $ echo "export PATH=$PATH:$HOME/bin" >> ~/.bashrc
//! $ cp cargo-count ~/bin
//! $ source ~/.bashrc
//! ```
//!
//! ### Windows
//!
//! On Windows 7/8 you can add directory to the `PATH` variable by opening a
//! command line as an administrator and running
//!
//! ```sh
//! C:\> setx path "%path%;C:\path\to\cargo-count\binary"
//! ```
//!
//! Otherwise, ensure you have the `cargo-count` binary in the directory which
//! you operating in the command line from, because Windows automatically adds
//! your current directory to PATH (i.e. if you open a command line to
//! `C:\my_project\` to use `cargo-count` ensure `cargo-count.exe` is inside
//! that directory as well).
//!
//!
//! ### Options
//!
//! There are a few options for using `cargo-count` which should be somewhat
//! self explanitory.
//!
//! ```ignore
//! USAGE:
//!     cargo count [FLAGS] [OPTIONS] [--] [ARGS]
//!
//! FLAGS:
//! -S, --follow-symlinks      Follows symlinks and counts source files it
//! finds
//! -a, --all                  Do not ignore .gitignored paths
//!                                (Defaults to false when omitted)
//!     -h, --help                 Prints help information
//! --unsafe-statistics    Displays lines and percentages of "unsafe"
//! code
//!     -V, --version              Prints version information
//!     -v, --verbose              Print verbose output
//!
//! OPTIONS:
//! -l, --language <exts>...    Only count these languges (by source code
//! extension)
//!                                 (i.e. '-l js py cpp')
//! -e, --exclude <paths>...    Files or directories to exclude
//! (automatically includes '.git')
//! --utf8-rule <rule>      Sets the UTF-8 parsing rule (Defaults to
//! 'strict')
//!                                  [values: ignore lossy strict]
//! -s, --separator <sep>       Set the thousands separator for pretty
//! printing
//!
//! ARGS:
//!     to_count...    The files or directories (including children) to count
//!                    (defaults to current working directory when omitted)
//!
//! When using '--exclude <path>' the path given can either be relative to the
//! current
//! directory, or absolute. When '<path>' is a file, it must be relative to the
//! current
//! directory or it will not be found. Example, if the current directory has a
//! child
//! directory named 'target' with a child fild 'test.rs' and you use `--exclude
//! target/test.rs'
//!
//! Globs are also supported. For example, to eclude 'test.rs' files from all
//! child directories
//! of the current directory you could do '--exclude */test.rs'.
//! ```
//!
//! ## License
//!
//! `cargo-count` is released under the terms of the MIT. See the LICENSE-MIT
//! file for the details.
#![cfg_attr(feature = "nightly", feature(plugin))]
#![cfg_attr(feature = "lints", plugin(clippy))]
#![cfg_attr(feature = "lints", allow(explicit_iter_loop))]
#![cfg_attr(feature = "lints", allow(should_implement_trait))]
#![cfg_attr(feature = "lints", allow(unstable_features))]
#![cfg_attr(feature = "lints", deny(warnings))]
#![cfg_attr(not(any(feature = "nightly", feature = "unstable")), deny(unstable_features))]
#![deny(missing_docs,
        missing_debug_implementations,
        missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unused_import_braces,
        unused_qualifications)]

#[macro_use]
extern crate clap;
#[cfg(feature = "color")]
extern crate ansi_term;
extern crate tabwriter;
extern crate glob;
extern crate regex;
extern crate gitignore;

#[cfg(feature = "debug")]
use std::env;

use clap::{App, AppSettings, Arg, SubCommand};

use config::Config;
use count::Counts;
use error::{CliError, CliResult};
use fmt::Format;

#[macro_use]
mod macros;
mod comment;
mod config;
mod count;
mod error;
mod fmt;
mod fsutil;
mod language;

static UTF8_RULES: [&'static str; 3] = ["strict", "lossy", "ignore"];

fn main() {
    debugln!("executing; cmd=cargo-count; args={:?}",
             env::args().collect::<Vec<_>>());
    let m = App::new("cargo-count")
        .version(&*format!("v{}", crate_version!()))
    // We have to lie about our binary name since this will be a third party
    // subcommand for cargo but we want usage strings to generated properly
        .bin_name("cargo")
    // Global version uses the version we supplied (Cargo.toml) for all subcommands
    // as well
        .settings(&[AppSettings::GlobalVersion,
                    AppSettings::SubcommandRequired])
    // We use a subcommand because everything parsed after `cargo` is sent to the
    // third party
    // plugin which will then be interpreted as a subcommand/positional arg by clap
        .subcommand(SubCommand::with_name("count")
            .author("Kevin K. <kbknapp@gmail.com>")
            .about("Displays line counts of code for cargo projects")
            .args_from_usage("-e, --exclude [paths]...    'Files or directories to exclude (automatically includes \'.git\')'
                              -a, --all                   'Do not ignore .gitignore'd paths'
                              --unsafe-statistics         'Displays lines and percentages of \"unsafe\" code'
                              -l, --language [exts]...    'Only count these languges (i.e. \'-l js py cpp\')'
                              -v, --verbose               'Print verbose output'
                              -S, --follow-symlinks       'Follows symlinks and counts source files it finds (Defaults to false when omitted)'
                              [to_count]...               'The files or directories (including children) to count{n}\
                                                           (defaults to current working directory when omitted)'")
            .arg(Arg::from_usage("-s, --separator [sep]   'Set the thousands separator for pretty printing'")
                .validator(single_char))
            .arg(Arg::from_usage("--utf8-rule [rule]     'Sets the UTF-8 parsing rule (Defaults to \'strict\'){n}'")
                .possible_values(&UTF8_RULES))
            .after_help("When using '--exclude <path>' the path given can either be relative to the current \n\
                         directory, or absolute. When '<path>' is a file, it must be relative to the current \n\
                         directory or it will not be found. Example, if the current directory has a child \n\
                         directory named 'target' with a child fild 'test.rs' and you use `--exclude target/test.rs' \n\
                         \n\
                         Globs are also supported. For example, to eclude 'test.rs' files from all child directories \n\
                         of the current directory you could do '--exclude */test.rs'."))
        .get_matches();

    if let Some(m) = m.subcommand_matches("count") {
        let cfg = Config::from_matches(m).unwrap_or_else(|e| e.exit());
        println!("Gathering information...");
        if let Err(e) = execute(cfg) {
            e.exit();
        }
    }
}

fn execute(cfg: Config) -> CliResult<()> {
    debugln!("executing; cmd=execute;");
    verboseln!(cfg, "{}: {:?}", Format::Warning("Excluding"), cfg.exclude);
    verbose!(cfg,
             "{}",
             if cfg.exts.is_some() {
                 format!("{} including files with extension: {}\n",
                         Format::Warning("Only"),
                         cfg.exts
                            .as_ref()
                            .unwrap()
                            .join(", "))
             } else {
                 "".to_owned()
             });

    debugln!("Checking for files or dirs to count from cli");

    let mut counts = Counts::new(&cfg);
    counts.fill_from();
    cli_try!(counts.count());
    cli_try!(counts.write_results());
    Ok(())
}

fn single_char(s: String) -> Result<(), String> {
    if s.len() == 1 {
        Ok(())
    } else {
        Err(
          format!(
            "the --separator argument option only accepts a single character but found '{}'",
             Format::Warning(s)))
    }
}
<commit_msg>imp: updates clap and uses new features<commit_after>//! A cargo subcommand for displaying line counts of source code in projects,
//! including a niave `unsafe` counter for Rust source files. This subcommand
//! was originally based off and inspired by the project
//! [tokei](https://github.com/aaronepower/tokei) by
//! [Aaronepower](https://github.com/aaronepower)
//!
//! ## Demo
//!
//! To count the source code in the [Rust](https://github.com/rust-lang/rust)
//! repository (checkout `4c99649`), and print some naive statistics on how much
//! "unsafe" code exists.
//!
//! **NOTE:** The Rust repository is quite large, if you're on a slow internet
//! connection consider using a smaller repository, such as the `cargo-count`
//! repo.
//!
//! ```ignore
//! $ git clone https://github.com/rust-lang/rust
//! $ cd rust
//! $ cargo count --separator , --unsafe-statistics
//! Gathering information...
//!          Language    Files  Lines    Blanks  Comments  Code     Unsafe (%)
//!          --------    -----  -----    ------  --------  ----     ----------
//! Rust        6,018  528,510  66,984  133,698   327,792  3,163
//! (0.96%)
//! C           54     9,962    1,445   1,492     7,025    7,025
//! (100.00%)
//!          CSS         4      1,266    149     52        1,065
//!          JavaScript  4      1,118    131     166       821
//!          Python      31     4,797    843     585       3,369
//! C Header    13     1,865    284     585       996      996
//! (100.00%)
//! C++         4      1,611    185     81        1,345    1,345
//! (100.00%)
//!          --------    -----  -----    ------  --------  ----     ----------
//! Totals:              6,128  549,129  70,021  136,659   342,413  12,529
//! (3.66%)
//!
//! ```
//!
//! The `--separator ,` sets a `,` character as the thousands separator, and
//! `--unsafe-statistics` looks for, and counts lines of `unsafe`.
//!
//! ## Compiling
//!
//! Follow these instructions to compile `cargo-count`, then skip down to
//! Installation.
//!
//!  1. Ensure you have current version of `cargo` and
//!     [Rust](https://www.rust-lang.org) installed
//!  2. Clone the project
//!     `$ git clone https://github.com/kbknapp/cargo-count && cd cargo-count`
//!  3. Build the project `$ cargo build --release` (**NOTE:** There is a large
//!     performance differnce when compiling without optimizations, so I
//!     recommend alwasy using `--release` to enable to them)
//!  4. Once complete, the binary will be located at
//!     `target/release/cargo-count`
//!
//! ## Installation and Usage
//!
//! All you need to do is place `cargo-count` somewhere in your `$PATH`. Then
//! run `cargo count` anywhere in your project directory. For full details see
//! below.
//!
//! ### Linux / OS X
//!
//! You have two options, place `cargo-count` into a directory that is already
//! located in your `$PATH` variable (To see which directories those are, open
//! a terminal and type `echo "${PATH//:/\n}"`, the quotation marks are
//! important), or you can add a custom directory to your `$PATH`
//!
//! **Option 1**
//! If you have write permission to a directory listed in your `$PATH` or you
//! have root permission (or via `sudo`), simply copy the `cargo-count` to that
//! directory `# sudo cp cargo-count /usr/local/bin`
//!
//! **Option 2**
//! If you do not have root, `sudo`, or write permission to any directory
//! already in `$PATH` you can create a directory inside your home directory,
//! and add that. Many people use `$HOME/.bin` to keep it hidden (and not
//! clutter your home directory), or `$HOME/bin` if you want it to be always
//! visible. Here is an example to make the directory, add it to `$PATH`, and
//! copy `cargo-count` there.
//!
//! Simply change `bin` to whatever you'd like to name the directory, and
//! `.bashrc` to whatever your shell startup file is (usually `.bashrc`,
//! `.bash_profile`, or `.zshrc`)
//!
//! ```sh
//! $ mkdir ~/bin
//! $ echo "export PATH=$PATH:$HOME/bin" >> ~/.bashrc
//! $ cp cargo-count ~/bin
//! $ source ~/.bashrc
//! ```
//!
//! ### Windows
//!
//! On Windows 7/8 you can add directory to the `PATH` variable by opening a
//! command line as an administrator and running
//!
//! ```sh
//! C:\> setx path "%path%;C:\path\to\cargo-count\binary"
//! ```
//!
//! Otherwise, ensure you have the `cargo-count` binary in the directory which
//! you operating in the command line from, because Windows automatically adds
//! your current directory to PATH (i.e. if you open a command line to
//! `C:\my_project\` to use `cargo-count` ensure `cargo-count.exe` is inside
//! that directory as well).
//!
//!
//! ### Options
//!
//! There are a few options for using `cargo-count` which should be somewhat
//! self explanitory.
//!
//! ```ignore
//! USAGE:
//!     cargo count [FLAGS] [OPTIONS] [--] [ARGS]
//!
//! FLAGS:
//! -S, --follow-symlinks      Follows symlinks and counts source files it
//! finds
//! -a, --all                  Do not ignore .gitignored paths
//!                                (Defaults to false when omitted)
//!     -h, --help                 Prints help information
//! --unsafe-statistics    Displays lines and percentages of "unsafe"
//! code
//!     -V, --version              Prints version information
//!     -v, --verbose              Print verbose output
//!
//! OPTIONS:
//! -l, --language <exts>...    Only count these languges (by source code
//! extension)
//!                                 (i.e. '-l js py cpp')
//! -e, --exclude <paths>...    Files or directories to exclude
//! (automatically includes '.git')
//! --utf8-rule <rule>      Sets the UTF-8 parsing rule (Defaults to
//! 'strict')
//!                                  [values: ignore lossy strict]
//! -s, --separator <sep>       Set the thousands separator for pretty
//! printing
//!
//! ARGS:
//!     to_count...    The files or directories (including children) to count
//!                    (defaults to current working directory when omitted)
//!
//! When using '--exclude <path>' the path given can either be relative to the
//! current
//! directory, or absolute. When '<path>' is a file, it must be relative to the
//! current
//! directory or it will not be found. Example, if the current directory has a
//! child
//! directory named 'target' with a child fild 'test.rs' and you use `--exclude
//! target/test.rs'
//!
//! Globs are also supported. For example, to eclude 'test.rs' files from all
//! child directories
//! of the current directory you could do '--exclude */test.rs'.
//! ```
//!
//! ## License
//!
//! `cargo-count` is released under the terms of the MIT. See the LICENSE-MIT
//! file for the details.
#![cfg_attr(feature = "nightly", feature(plugin))]
#![cfg_attr(feature = "lints", plugin(clippy))]
#![cfg_attr(feature = "lints", allow(explicit_iter_loop))]
#![cfg_attr(feature = "lints", allow(should_implement_trait))]
#![cfg_attr(feature = "lints", allow(unstable_features))]
#![cfg_attr(feature = "lints", deny(warnings))]
#![cfg_attr(not(any(feature = "nightly", feature = "unstable")), deny(unstable_features))]
#![deny(missing_docs,
        missing_debug_implementations,
        missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unused_import_braces,
        unused_qualifications)]

#[macro_use]
extern crate clap;
#[cfg(feature = "color")]
extern crate ansi_term;
extern crate tabwriter;
extern crate glob;
extern crate regex;
extern crate gitignore;

#[cfg(feature = "debug")]
use std::env;

use clap::{App, AppSettings, Arg, SubCommand};

use config::Config;
use count::Counts;
use error::{CliError, CliResult};
use fmt::Format;

#[macro_use]
mod macros;
mod comment;
mod config;
mod count;
mod error;
mod fmt;
mod fsutil;
mod language;

static UTF8_RULES: [&'static str; 3] = ["strict", "lossy", "ignore"];

fn main() {
    debugln!("executing; cmd=cargo-count; args={:?}",
             env::args().collect::<Vec<_>>());
    let m = App::new("cargo-count")
        .version(&*format!("v{}", crate_version!()))
    // We have to lie about our binary name since this will be a third party
    // subcommand for cargo but we want usage strings to generated properly
        .bin_name("cargo")
    // Global version uses the version we supplied (Cargo.toml) for all subcommands
    // as well
        .settings(&[AppSettings::GlobalVersion,
                    AppSettings::SubcommandRequired])
    // We use a subcommand because everything parsed after `cargo` is sent to the
    // third party
    // plugin which will then be interpreted as a subcommand/positional arg by clap
        .subcommand(SubCommand::with_name("count")
            .author("Kevin K. <kbknapp@gmail.com>")
            .about("Displays line counts of code for cargo projects")
            .args_from_usage("
-e, --exclude [PATH]...    'Files or directories to exclude (automatically includes \'.git\')'
-a, --all                  'Do not ignore .gitignore'd paths'
--unsafe-statistics        'Displays lines and percentages of \"unsafe\" code'
-l, --language [EXT]...    'Only count these languges (i.e. \'-l js py cpp\')'
-v, --verbose              'Print verbose output'
-S, --follow-symlinks      'Follows symlinks and counts source files it finds [default: false]'
[PATH]...                  'The files or directories (including children) to count (defaults to \
                            current working directory when omitted)'")
            .arg(Arg::from_usage(
                    "-s, --separator [CHAR]   'Set the thousands separator for pretty printing'")
                .validator(single_char))
            .arg(Arg::from_usage("--utf8-rule [RULE]     'Sets the UTF-8 parsing rule'")
                .default_value("strict")
                .possible_values(&UTF8_RULES))
            .after_help("\
When using '--exclude <PATH>' the path given can either be relative to the current directory, or \
absolute. When '--exclude <PATH>' is a file or path, it must be relative to the current directory \
or it will not be found. Example, if the current directory has a child directory named 'target' \
with a child fild 'test.rs' and you use `--exclude target/test.rs'
{n}{n}\
Globs are also supported. For example, to eclude 'test.rs' files from all child directories of \
the current directory you could do '--exclude */test.rs'."))
        .get_matches();

    if let Some(m) = m.subcommand_matches("count") {
        let cfg = Config::from_matches(m).unwrap_or_else(|e| e.exit());
        println!("Gathering information...");
        if let Err(e) = execute(cfg) {
            e.exit();
        }
    }
}

fn execute(cfg: Config) -> CliResult<()> {
    debugln!("executing; cmd=execute;");
    verboseln!(cfg, "{}: {:?}", Format::Warning("Excluding"), cfg.exclude);
    verbose!(cfg,
             "{}",
             if cfg.exts.is_some() {
                 format!("{} including files with extension: {}\n",
                         Format::Warning("Only"),
                         cfg.exts
                            .as_ref()
                            .unwrap()
                            .join(", "))
             } else {
                 "".to_owned()
             });

    debugln!("Checking for files or dirs to count from cli");

    let mut counts = Counts::new(&cfg);
    counts.fill_from();
    cli_try!(counts.count());
    cli_try!(counts.write_results());
    Ok(())
}

fn single_char(s: String) -> Result<(), String> {
    if s.len() == 1 {
        Ok(())
    } else {
        Err(
          format!(
            "the --separator argument option only accepts a single character but found '{}'",
             Format::Warning(s)))
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate tera;

#[macro_use] extern crate lazy_static;

extern crate iron;
extern crate router;
extern crate hyper;
extern crate regex;

use std::env;
use std::io::prelude::*;
use std::fs::File;

use tera::Tera;
use tera::Context;

use regex::Regex;

use iron::prelude::*;

use iron::{BeforeMiddleware, AroundMiddleware, AfterMiddleware, Handler};

use router::{Router, NoRoute};
use std::collections::HashMap;
use std::sync::{Arc, RwLock};

use hyper::header::ContentType;
use hyper::mime::{Mime, TopLevel, SubLevel};

struct Custom404;

impl AfterMiddleware for Custom404 {
    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        if let Some(_) = err.error.downcast::<NoRoute>() {
            Ok(Response::with((iron::status::NotFound, "Custom 404 response")))
        } else {
            Err(err)
        }
    }
}

#[derive(Default,Clone)]
struct Spaceship {
    cache: Arc<RwLock<HashMap<String, String>>>,
    tera: Arc<RwLock<Tera>>,
}

impl Spaceship {
	fn new() -> Spaceship {
		Spaceship{tera: Arc::new(RwLock::new(compile_templates!("templates/**/*"))), ..Default::default()}
	}
	fn tera<'a>(&'a self) -> &'a Arc<RwLock<Tera>> {
		&self.tera
	}
	fn cache<'a>(&'a self) -> &'a Arc<RwLock<HashMap<String, String>>> {
		&self.cache
	}
}

impl Handler for Spaceship {

	fn handle(&self, req: &mut Request) -> IronResult<Response> {
		let mut ctx = Context::new();
		ctx.add("title", &"spaceship!");
		ctx.add("body", &"it's working");

		let obj = match self.tera().read() {
		    Ok(x) => x,
		    Err(_) => return Ok(Response::with((iron::status::InternalServerError)))
		};
		let content = match obj.render("index.html", ctx) {
			Ok(x) => x,
			Err(_) => return Ok(Response::with((iron::status::InternalServerError)))
		};
		let mut resp = Response::with((iron::status::Ok, content));
		resp.headers.set(ContentType(Mime(TopLevel::Text, SubLevel::Html, vec![])));
		Ok(resp)
	}
}

#[derive(Default,Clone)]
struct CssHandler {
    cache: Arc<RwLock<HashMap<String, String>>>
}

impl CssHandler {
	fn new() -> CssHandler {
		CssHandler { ..Default::default()}
	}

	fn read_css_to_string(&self, path: &String) -> Option<String> {
		lazy_static! {
			static ref CSS_REGEX: Regex = Regex::new(r".*\.css").unwrap();
		}
		if CSS_REGEX.is_match(path) {
			return File::open(path).and_then(|mut f| {
						let mut s = String::new();
						f.read_to_string(&mut s).and_then(|_| {Ok(s)})
					}).ok();
		}
		None
	}
}

impl Handler for CssHandler {
	fn handle(&self, req: &mut Request) -> IronResult<Response> {
		let mut chunks = req.url.path();
		chunks.retain(|&x| x != "");
		let path = chunks.join("/");
		println!("lookup {:?} {}", chunks, path);
		match self.read_css_to_string(&String::from(path)) {
			Some(content) => {
				let mut resp = Response::with((iron::status::Ok, content));
				resp.headers.set(ContentType(Mime(TopLevel::Text, SubLevel::Css, vec![])));
				return Ok(resp);
			},
			None => {}
		}
		Ok(Response::with((iron::status::InternalServerError)))
	}
}

impl AroundMiddleware for CssHandler {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
		Box::new(CssHandler::new()) as Box<Handler>
    }
}

fn main() {
	let address = env::var("SPACESHIP_ADDRESS").unwrap_or(String::from("0.0.0.0"));
	let port = env::var("SPACESHIP_PORT").unwrap_or(String::from("8080"));

    let spaceship = Spaceship::new();
    let mut router = Router::new();

	let css_handler = CssHandler::new();
    router.get("/static/*", css_handler, "css");

    Iron::new(router).http(format!("{}:{}",address,port)).unwrap();
}
<commit_msg>core/refactor: more spaceship middleware related changes, includes cc 404 handler<commit_after>#[macro_use] extern crate tera;

#[macro_use] extern crate lazy_static;

extern crate iron;
extern crate router;
extern crate hyper;
extern crate regex;

use std::env;
use std::io::prelude::*;
use std::fs::File;

use tera::Tera;
use tera::Context;

use regex::Regex;

use iron::prelude::*;

use iron::{BeforeMiddleware, AroundMiddleware, AfterMiddleware, Handler};

use router::{Router, NoRoute};
use std::collections::HashMap;
use std::sync::{Arc, RwLock};

use hyper::header::ContentType;
use hyper::mime::{Mime, TopLevel, SubLevel};

use std::error::Error;
use std::fmt::{self, Debug};

#[derive(Debug)]
struct StringError(String);

impl fmt::Display for StringError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self, f)
    }
}

impl Error for StringError {
    fn description(&self) -> &str { &*self.0 }
}

struct Custom404;

impl AfterMiddleware for Custom404 {
    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        Ok(Response::with((iron::status::NotFound, "Custom 404 response")))
    }
}

#[derive(Default,Clone)]
struct Spaceship {
    cache: Arc<RwLock<HashMap<String, String>>>,
    tera: Arc<RwLock<Tera>>,
}

impl Spaceship {
	fn new() -> Spaceship {
		Spaceship{tera: Arc::new(RwLock::new(compile_templates!("templates/**/*"))), ..Default::default()}
	}
	fn tera<'a>(&'a self) -> &'a Arc<RwLock<Tera>> {
		&self.tera
	}
	fn cache<'a>(&'a self) -> &'a Arc<RwLock<HashMap<String, String>>> {
		&self.cache
	}

	fn render(&self, req: &mut Request) -> Option<String> {
		let mut chunks = req.url.path();
		chunks.retain(|&x| x != "");
		let path = chunks.join("/");

		let mut ctx = Context::new();
		ctx.add("title", &"spaceship!");
		ctx.add("body", &format!("\"{}\" is still work in progress", path));

		match self.tera().read() {
			Ok(x) => {
				x.render("index.html", ctx).and_then(|content| {Ok(content)}).ok()
				},
			Err(_) => None,
		}
	}
}

impl Handler for Spaceship {

	fn handle(&self, req: &mut Request) -> IronResult<Response> {

		match self.render(req) {
			Some(content) => {
								let mut resp = Response::with((iron::status::Ok, content));
								resp.headers.set(ContentType(Mime(TopLevel::Text, SubLevel::Html, vec![])));
								return Ok(resp);
								},
			None => {},
		}
		Err(IronError::new(StringError("Error".to_string()), iron::status::InternalServerError))
	}
}

#[derive(Default,Clone)]
struct CssHandler {
    cache: Arc<RwLock<HashMap<String, String>>>
}

impl CssHandler {
	fn new() -> CssHandler {
		CssHandler { ..Default::default()}
	}

	fn read_css_to_string(&self, path: &String) -> Option<String> {
		lazy_static! {
			static ref CSS_REGEX: Regex = Regex::new(r".*\.css").unwrap();
		}
		if CSS_REGEX.is_match(path) {
			return File::open(path).and_then(|mut f| {
						let mut s = String::new();
						f.read_to_string(&mut s).and_then(|_| {Ok(s)})
					}).ok();
		}
		None
	}
}

impl Handler for CssHandler {
	fn handle(&self, req: &mut Request) -> IronResult<Response> {
		let mut chunks = req.url.path();
		chunks.retain(|&x| x != "");
		let path = chunks.join("/");
		println!("lookup {:?} {}", chunks, path);
		match self.read_css_to_string(&String::from(path)) {
			Some(content) => {
				let mut resp = Response::with((iron::status::Ok, content));
				resp.headers.set(ContentType(Mime(TopLevel::Text, SubLevel::Css, vec![])));
				return Ok(resp);
			},
			None => {}
		}
		Err(IronError::new(StringError("Error".to_string()), iron::status::BadRequest))
	}
}

impl AroundMiddleware for CssHandler {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
		Box::new(CssHandler::new()) as Box<Handler>
    }
}

fn main() {
	let address = env::var("SPACESHIP_ADDRESS").unwrap_or(String::from("0.0.0.0"));
	let port = env::var("SPACESHIP_PORT").unwrap_or(String::from("8080"));

    let mut router = Router::new();

	let css_handler = CssHandler::new();
    router.get("/static/*", css_handler, "css");

    let spaceship_handler = Spaceship::new();
    // router.get("/*", spaceship_handler.clone(), "spaceship");
    router.get("/", spaceship_handler.clone(), "index");

    let mut chain = Chain::new(router);
    // chain.link_before(MyMiddleware);
    chain.link_after(Custom404);

    Iron::new(chain).http(format!("{}:{}",address,port)).unwrap();
}
<|endoftext|>


<commit_before>#![allow(unstable)]

extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;

use std::io::File;
use std::os;
use git2::{Repository, Oid};
use git2::Error as GitError;
use rustc_serialize::json;

#[derive(RustcDecodable, RustcEncodable)]
struct Commit {
    hash: String,
    author: String,
    date: i64,
    message: String
}

fn fetch_commits(repo: &Repository, start: &Option<Oid>, query: &str, amount: usize) -> Result<Vec<Commit>, GitError> {
    let mut revs = try!(repo.revwalk());
    match *start {
        Some(commit_id) => try!(revs.push(commit_id)),
        _ => try!(revs.push_head()),
    }

    let commits = revs
    .filter_map(|commit_id| { repo.find_commit(commit_id).ok() })
    .filter_map(|commit| {
        match commit.message().and_then(|msg| { Some(msg.contains(query)) }) {
            Some(true) => Some(commit),
            _ => None
        }
    })
    .map(|commit| {
        Commit {
            hash: commit.id().to_string(),
            author: commit.author().name()
                .or(commit.author().email())
                .unwrap_or("Some dude").trim().to_string(),
            date: commit.time().seconds(),
            message: commit.message().unwrap_or("").trim().to_string()
        }
    })
    .take(amount)
    .collect();

    Result::Ok(commits)
}

fn main() {
    let args = os::args();
    let start = if args.len() >= 2 { Some(Oid::from_str(&args[1][]).unwrap()) } else { None };

    let cwd = os::getcwd().unwrap();
    let repo = Repository::open(&cwd.join("rust")).unwrap();

    let mut output = File::create(&cwd.join("log.json")).unwrap();

    let commits = fetch_commits(&repo, &start, "[breaking-change]", 100).unwrap();

    match write!(&mut output, "{}", json::as_pretty_json(&commits)) {
        Ok(_) => println!("wrote commits to `log.json`."),
        Err(e) => panic!("failed to write commits to file: {}", e),
    };
}
<commit_msg>Specify Revwalk Sorting!<commit_after>#![allow(unstable)]

extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;

use std::io::File;
use std::os;
use git2::{Repository, Oid};
use git2::Error as GitError;
use rustc_serialize::json;

#[derive(RustcDecodable, RustcEncodable)]
struct Commit {
    hash: String,
    author: String,
    date: i64,
    message: String
}

fn fetch_commits(repo: &Repository, start: &Option<Oid>, query: &str, amount: usize) -> Result<Vec<Commit>, GitError> {
    let mut revs = try!(repo.revwalk());
    match *start {
        Some(commit_id) => try!(revs.push(commit_id)),
        _ => try!(revs.push_head()),
    }

    revs.set_sorting(git2::SORT_TOPOLOGICAL | git2::SORT_TIME);

    let commits = revs
    .filter_map(|commit_id| { repo.find_commit(commit_id).ok() })
    .filter_map(|commit| {
        match commit.message().and_then(|msg| { Some(msg.contains(query)) }) {
            Some(true) => Some(commit),
            _ => None
        }
    })
    .map(|commit| {
        Commit {
            hash: commit.id().to_string(),
            author: commit.author().name()
                .or(commit.author().email())
                .unwrap_or("Some dude").trim().to_string(),
            date: commit.time().seconds(),
            message: commit.message().unwrap_or("").trim().to_string()
        }
    })
    .take(amount)
    .collect();

    Result::Ok(commits)
}

fn main() {
    let args = os::args();
    let start = if args.len() >= 2 { Some(Oid::from_str(&args[1][]).unwrap()) } else { None };

    let cwd = os::getcwd().unwrap();
    let repo = Repository::open(&cwd.join("rust")).unwrap();

    let mut output = File::create(&cwd.join("log.json")).unwrap();

    let commits = fetch_commits(&repo, &start, "[breaking-change]", 100).unwrap();

    match write!(&mut output, "{}", json::as_pretty_json(&commits)) {
        Ok(_) => println!("wrote commits to `log.json`."),
        Err(e) => panic!("failed to write commits to file: {}", e),
    };
}
<|endoftext|>


<commit_before>// Copyright 2015-2017 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

extern crate czmq;
extern crate docopt;
extern crate inapi;
extern crate rustc_serialize;
extern crate ssh2;
#[cfg(test)]
extern crate tempdir;
extern crate time;
extern crate zdaemon;

mod auth;
mod bootstrap;
mod cert;
mod error;
mod language;
mod payload;
mod project;

use auth::Auth;
use bootstrap::Bootstrap;
use docopt::Docopt;
use error::Result;
use language::language_from_str;
use payload::Payload;
use project::Project;
use std::{env, io};
use std::path::Path;
use std::process::exit;

const API_VERSION: &'static str = "{ git = \"https://github.com/intecture/api\" }";
const VERSION: &'static str = env!("CARGO_PKG_VERSION");

static USAGE: &'static str = "
Intecture CLI.

Usage:
  incli run [<arg>...]
  incli project init <name> <lang>
  incli payload init <name> <lang>
  incli payload build [<names>...]
  incli host (add | delete) [(-s | --silent)] <hostname>
  incli host bootstrap <hostname> [-u <username>] [-P <password>] [-i <identity_file>] [-p <ssh_port>] [-m <preinstall_script>] [-n <postinstall_script>]
  incli host list
  incli user (add | delete) [(-s | --silent)] <username>
  incli user list
  incli (-h | --help)
  incli --version

Options:
  -h --help                 Show this screen.
  -i <identity_file>        Path to SSH private key.
  -m <preinstall_script>    Script to run before attempting to install Agent.
  -n <postinstall_script>   Script to run after successfully installing Agent.
  -p <ssh_port>             SSH port number.
  -P <password>             SSH password.
  -s --silent               Save private key instead of printing it.
  -u <username>             SSH username.
  -v --verbose              Verbose output.
  --version                 Print this script's version.
";

#[derive(Debug, RustcDecodable)]
#[allow(non_snake_case)]
struct Args {
    cmd_add: bool,
    cmd_bootstrap: bool,
    cmd_build: bool,
    cmd_delete: bool,
    cmd_host: bool,
    cmd_init: bool,
    cmd_list: bool,
    cmd_payload: bool,
    cmd_project: bool,
    cmd_run: bool,
    cmd_user: bool,
    flag_h: bool,
    flag_help: bool,
    flag_i: Option<String>,
    flag_m: Option<String>,
    flag_n: Option<String>,
    flag_p: Option<u32>,
    flag_P: Option<String>,
    flag_s: bool,
    flag_silent: bool,
    flag_version: bool,
    flag_u: Option<String>,
    arg_arg: Vec<String>,
    arg_hostname: String,
    arg_lang: String,
    arg_name: String,
    arg_names: Option<Vec<String>>,
    arg_username: String,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if let Err(e) = run(&args) {
        println!("{}", e);
        println!("{:?}", e);
        exit(1);
    }
}

fn run(args: &Args) -> Result<()> {
    if args.flag_version {
        println!("{}", VERSION);
    }
    else if args.cmd_run {
        let project = try!(Project::load(&mut env::current_dir().unwrap()));
        let args_deref: Vec<&str> = args.arg_arg.iter().map(AsRef::as_ref).collect();
        let status = try!(project.run(&args_deref));

        if !status.success() {
            exit(status.code().unwrap_or(1));
        }
    }
    else if args.cmd_project && args.cmd_init {
        try!(Project::create(&Path::new(&args.arg_name), try!(language_from_str(&args.arg_lang))));
    }
    else if args.cmd_payload {
        if args.cmd_init {
            try!(Payload::create(&Path::new(&args.arg_name), try!(language_from_str(&args.arg_lang))));
        }
        else if args.cmd_build {
            let payloads = if let Some(ref names) = args.arg_names {
                let n: Vec<&str> = names.iter().map(|n| &**n).collect();
                try!(Payload::find(".", Some(&*n)))
            } else {
                try!(Payload::find(".", None))
            };
            for payload in payloads {
                try!(payload.build());
            }
        }
    }
    else if args.cmd_host || args.cmd_user {
        let cert_type = if args.cmd_host { "host" } else { "user" };
        let name = if args.cmd_host { &args.arg_hostname } else { &args.arg_username };

        let mut auth = try!(Auth::new(&env::current_dir().unwrap()));

        if args.cmd_add {
            let cert = try!(auth.add(cert_type, name));
            if args.flag_s || args.flag_silent {
                try!(cert.save_secret(&format!("{}.crt", name)));
            } else {
                println!("Please distribute this certificate securely.

------------------------COPY BELOW THIS LINE-------------------------
{}
------------------------COPY ABOVE THIS LINE-------------------------", cert.secret());
            }
        }
        else if args.cmd_delete {
            if args.flag_s || args.flag_silent {
                try!(auth.delete(name));
            } else {
                println!("Are you sure you want to delete this certificate?");
                loop {
                    println!("Please enter [y/n]: ");
                    let mut input = String::new();
                    match io::stdin().read_line(&mut input) {
                        Ok(_) => match { input.as_ref() as &str }.trim() {
                            "y" => {
                                try!(auth.delete(name));
                                break;
                            },
                            "n" => break,
                            _ => (),
                        },
                        Err(e) => {
                            println!("Stdin error: {}", e);
                            exit(1);
                        },
                    }
                }
            }
        }
        else if args.cmd_list {
            let names = try!(auth.list(cert_type));

            if names.is_empty() {
                println!("No {}s found", cert_type);
            } else {
                for name in names {
                    println!("{}", name);
                }
            }
        }
        else if args.cmd_bootstrap && args.cmd_host {
            print!("Connecting to {}...", args.arg_hostname);
            let mut bootstrap = Bootstrap::new(&args.arg_hostname,
                                               args.flag_p,
                                               args.flag_u.as_ref().map(|u| &**u),
                                               args.flag_P.as_ref().map(|p| &**p),
                                               args.flag_i.as_ref().map(|i| &**i))?;
            println!("done");

            print!("Bootstrapping...");
            match bootstrap.run(args.flag_m.as_ref().map(|m| &**m), args.flag_n.as_ref().map(|n| &**n)) {
                Ok(()) => println!("done"),
                Err(e) => {
                    println!("error!");
                    return Err(e);
                }
            }
        }
    }

    Ok(())
}
<commit_msg>Change stable API version<commit_after>// Copyright 2015-2017 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

extern crate czmq;
extern crate docopt;
extern crate inapi;
extern crate rustc_serialize;
extern crate ssh2;
#[cfg(test)]
extern crate tempdir;
extern crate time;
extern crate zdaemon;

mod auth;
mod bootstrap;
mod cert;
mod error;
mod language;
mod payload;
mod project;

use auth::Auth;
use bootstrap::Bootstrap;
use docopt::Docopt;
use error::Result;
use language::language_from_str;
use payload::Payload;
use project::Project;
use std::{env, io};
use std::path::Path;
use std::process::exit;

const API_VERSION: &'static str = "0.3";
const VERSION: &'static str = env!("CARGO_PKG_VERSION");

static USAGE: &'static str = "
Intecture CLI.

Usage:
  incli run [<arg>...]
  incli project init <name> <lang>
  incli payload init <name> <lang>
  incli payload build [<names>...]
  incli host (add | delete) [(-s | --silent)] <hostname>
  incli host bootstrap <hostname> [-u <username>] [-P <password>] [-i <identity_file>] [-p <ssh_port>] [-m <preinstall_script>] [-n <postinstall_script>]
  incli host list
  incli user (add | delete) [(-s | --silent)] <username>
  incli user list
  incli (-h | --help)
  incli --version

Options:
  -h --help                 Show this screen.
  -i <identity_file>        Path to SSH private key.
  -m <preinstall_script>    Script to run before attempting to install Agent.
  -n <postinstall_script>   Script to run after successfully installing Agent.
  -p <ssh_port>             SSH port number.
  -P <password>             SSH password.
  -s --silent               Save private key instead of printing it.
  -u <username>             SSH username.
  -v --verbose              Verbose output.
  --version                 Print this script's version.
";

#[derive(Debug, RustcDecodable)]
#[allow(non_snake_case)]
struct Args {
    cmd_add: bool,
    cmd_bootstrap: bool,
    cmd_build: bool,
    cmd_delete: bool,
    cmd_host: bool,
    cmd_init: bool,
    cmd_list: bool,
    cmd_payload: bool,
    cmd_project: bool,
    cmd_run: bool,
    cmd_user: bool,
    flag_h: bool,
    flag_help: bool,
    flag_i: Option<String>,
    flag_m: Option<String>,
    flag_n: Option<String>,
    flag_p: Option<u32>,
    flag_P: Option<String>,
    flag_s: bool,
    flag_silent: bool,
    flag_version: bool,
    flag_u: Option<String>,
    arg_arg: Vec<String>,
    arg_hostname: String,
    arg_lang: String,
    arg_name: String,
    arg_names: Option<Vec<String>>,
    arg_username: String,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if let Err(e) = run(&args) {
        println!("{}", e);
        println!("{:?}", e);
        exit(1);
    }
}

fn run(args: &Args) -> Result<()> {
    if args.flag_version {
        println!("{}", VERSION);
    }
    else if args.cmd_run {
        let project = try!(Project::load(&mut env::current_dir().unwrap()));
        let args_deref: Vec<&str> = args.arg_arg.iter().map(AsRef::as_ref).collect();
        let status = try!(project.run(&args_deref));

        if !status.success() {
            exit(status.code().unwrap_or(1));
        }
    }
    else if args.cmd_project && args.cmd_init {
        try!(Project::create(&Path::new(&args.arg_name), try!(language_from_str(&args.arg_lang))));
    }
    else if args.cmd_payload {
        if args.cmd_init {
            try!(Payload::create(&Path::new(&args.arg_name), try!(language_from_str(&args.arg_lang))));
        }
        else if args.cmd_build {
            let payloads = if let Some(ref names) = args.arg_names {
                let n: Vec<&str> = names.iter().map(|n| &**n).collect();
                try!(Payload::find(".", Some(&*n)))
            } else {
                try!(Payload::find(".", None))
            };
            for payload in payloads {
                try!(payload.build());
            }
        }
    }
    else if args.cmd_host || args.cmd_user {
        let cert_type = if args.cmd_host { "host" } else { "user" };
        let name = if args.cmd_host { &args.arg_hostname } else { &args.arg_username };

        let mut auth = try!(Auth::new(&env::current_dir().unwrap()));

        if args.cmd_add {
            let cert = try!(auth.add(cert_type, name));
            if args.flag_s || args.flag_silent {
                try!(cert.save_secret(&format!("{}.crt", name)));
            } else {
                println!("Please distribute this certificate securely.

------------------------COPY BELOW THIS LINE-------------------------
{}
------------------------COPY ABOVE THIS LINE-------------------------", cert.secret());
            }
        }
        else if args.cmd_delete {
            if args.flag_s || args.flag_silent {
                try!(auth.delete(name));
            } else {
                println!("Are you sure you want to delete this certificate?");
                loop {
                    println!("Please enter [y/n]: ");
                    let mut input = String::new();
                    match io::stdin().read_line(&mut input) {
                        Ok(_) => match { input.as_ref() as &str }.trim() {
                            "y" => {
                                try!(auth.delete(name));
                                break;
                            },
                            "n" => break,
                            _ => (),
                        },
                        Err(e) => {
                            println!("Stdin error: {}", e);
                            exit(1);
                        },
                    }
                }
            }
        }
        else if args.cmd_list {
            let names = try!(auth.list(cert_type));

            if names.is_empty() {
                println!("No {}s found", cert_type);
            } else {
                for name in names {
                    println!("{}", name);
                }
            }
        }
        else if args.cmd_bootstrap && args.cmd_host {
            print!("Connecting to {}...", args.arg_hostname);
            let mut bootstrap = Bootstrap::new(&args.arg_hostname,
                                               args.flag_p,
                                               args.flag_u.as_ref().map(|u| &**u),
                                               args.flag_P.as_ref().map(|p| &**p),
                                               args.flag_i.as_ref().map(|i| &**i))?;
            println!("done");

            print!("Bootstrapping...");
            match bootstrap.run(args.flag_m.as_ref().map(|m| &**m), args.flag_n.as_ref().map(|n| &**n)) {
                Ok(()) => println!("done"),
                Err(e) => {
                    println!("error!");
                    return Err(e);
                }
            }
        }
    }

    Ok(())
}
<|endoftext|>