<commit_before>//! If you use enough force, you can actually use this GC to implement a toy VM.

#[macro_use] extern crate cell_gc;
use cell_gc::{Heap, with_heap};
use std::rc::Rc;

gc_heap_type! {
    #[derive(Debug)]
    struct Pair / PairRef / PairStorage <'h> {
        car / set_car: Value<'h>,
        cdr / set_cdr: Value<'h>
    }
}

gc_heap_type! {
    #[derive(Clone, Debug, PartialEq)]
    enum Value / ValueStorage <'h> {
        Nil,
        Int(i32),
        Symbol(Rc<String>),
        Cons(PairRef<'h>),
        Lambda(PairRef<'h>),
        Builtin(Box<BuiltinFnPtr>)
    }
}

use Value::*;

type BuiltinFnTrait = for<'b> fn (Vec<Value<'b>>) -> Result<Value<'b>, String>;

#[derive(Clone)]
struct BuiltinFnPtr(&'static BuiltinFnTrait);

impl PartialEq for BuiltinFnPtr {
    fn eq(&self, other: &BuiltinFnPtr) -> bool {
        *self.0 as usize == *other.0 as usize
    }
}

impl std::fmt::Debug for BuiltinFnPtr {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "BuiltinFn({:p})", *self.0 as usize as *const ());
        Ok(())
    }
}

impl<'h> Value<'h> {
    fn push_env(&mut self, heap: &mut Heap<'h>, key: Rc<String>, value: Value<'h>) {
        let pair = Cons(heap.alloc(Pair {
            car: Symbol(key),
            cdr: value
        }));
        *self = Cons(heap.alloc(Pair {
            car: pair,
            cdr: self.clone()
        }));
    }
}

macro_rules! lisp {
    { ( ) , $_heap:expr } => {
        Nil
    };
    { ( $h:tt $($t:tt)* ) , $heap:expr } => {
        {
            let h = lisp!($h, $heap);
            let t = lisp!(($($t)*), $heap);
            Cons($heap.alloc(Pair { car: h, cdr: t }))
        }
    };
    { $s:tt , $_heap:expr } => {
        {
            let s = stringify!($s);  // lame, but nothing else matches after an `ident` match fails
            if s.starts_with(|c: char| c.is_digit(10)) {
                Int(s.parse().expect("invalid numeric literal in `lisp!`"))
            } else {
                Symbol(Rc::new(s.to_string()))
            }
        }
    };
}

fn parse_pair<'h>(v: Value<'h>, msg: &'static str) -> Result<(Value<'h>, Value<'h>), String> {
    match v {
        Cons(r) => Ok((r.car(), r.cdr())),
        _ => Err(msg.to_string())
    }
}

fn lookup<'h>(mut env: Value<'h>, name: Rc<String>) -> Result<Value<'h>, String> {
    let v = Symbol(name.clone());
    while let Cons(p) = env {
        let (key, value) = try!(parse_pair(p.car(), "internal error: bad environment structure"));
        if key == v {
            return Ok(value);
        }
        env = p.cdr();
    }
    Err(format!("undefined symbol: {:?}", *name))
}

fn map_eval<'h>(heap: &mut Heap<'h>, mut exprs: Value<'h>, env: &Value<'h>)
    -> Result<Vec<Value<'h>>, String>
{
    let mut v = vec![];
    while let Cons(pair) = exprs {
        v.push(try!(eval(heap, pair.car(), env)));
        exprs = pair.cdr();
    }
    Ok(v)
}

fn apply<'h>(heap: &mut Heap<'h>, fval: Value<'h>, args: Vec<Value<'h>>) -> Result<Value<'h>, String> {
    match fval {
        Builtin(f) => (*f.0)(args),
        Lambda(pair) => {
            let mut env = pair.cdr();
            let (mut params, rest) = try!(parse_pair(pair.car(), "syntax error in lambda"));
            let (body, rest) = try!(parse_pair(rest, "syntax error in lambda"));
            if rest != Nil {
                return Err("syntax error in lambda".to_string());
            }

            let mut i = 0;
            while let Cons(pair) = params {
                if i > args.len() {
                    return Err("apply: not enough arguments".to_string());
                }
                if let Symbol(s) = pair.car() {
                    let pair = Cons(heap.alloc(Pair {
                        car: Symbol(s),
                        cdr: args[i].clone()
                    }));
                    env = Cons(heap.alloc(Pair {
                        car: pair,
                        cdr: env
                    }));
                } else {
                    return Err("syntax error in lambda arguments".to_string());
                }
                params = pair.cdr();
                i += 1;
            }
            if i < args.len() {
                return Err("apply: too many arguments".to_string());
            }
            eval(heap, body, &env)
        }
        _ => Err("apply: not a function".to_string())
    }
}

fn eval<'h>(heap: &mut Heap<'h>, expr: Value<'h>, env: &Value<'h>) -> Result<Value<'h>, String> {
    match expr {
        Symbol(s) => lookup(env.clone(), s),
        Cons(p) => {
            let f = p.car();
            if let Symbol(ref s) = f {
                if &**s == "lambda" {
                    return Ok(Lambda(heap.alloc(Pair {
                        car: p.cdr(),
                        cdr: env.clone()
                    })));
                } else if &**s == "if" {
                    let (cond, rest) = try!(parse_pair(p.cdr(), "(if) with no arguments"));
                    let (t_expr, rest) = try!(parse_pair(rest, "missing arguments after (if COND)"));
                    let (f_expr, rest) = try!(parse_pair(rest, "missing 'else' argument after (if COND X)"));
                    match rest {
                        Nil => {}
                        _ => return Err("too many arguments in (if) expression".to_string())
                    };
                    let cond_result = try!(eval(heap, cond, env));
                    let selected_expr = if cond_result == Nil { f_expr } else { t_expr };
                    return eval(heap, selected_expr, env);
                }
            }
            let fval = try!(eval(heap, f, env));
            let args = try!(map_eval(heap, p.cdr(), env));
            apply(heap, fval, args)
        }
        Builtin(_) => Err(format!("builtin function found in source code")),
        _ => Ok(expr)  // nil and numbers are self-evaluating
    }
}

fn add<'h>(args: Vec<Value<'h>>) -> Result<Value<'h>, String> {
    let mut total = 0;
    for v in args {
        if let Int(n) = v {
            total += n;
        } else {
            return Err("add: non-numeric argument".to_string());
        }
    }
    Ok(Int(total))
}

const add_ptr: &'static BuiltinFnTrait = &(add as BuiltinFnTrait);

fn main() {
    with_heap(|heap| {
        let mut env = Nil;
        env.push_env(heap, Rc::new("+".to_string()), Builtin(Box::new(BuiltinFnPtr(add_ptr))));
        let program = lisp!(
            ((lambda (x y z) (+ x (+ y z))) 3 4 5)
            , heap);
        let result = eval(heap, program, &env);
        assert_eq!(result, Ok(Int(12)));
    });
}
<commit_msg>In tests/run-pass/toy_vm.rs, use function pointers correctly.<commit_after>//! If you use enough force, you can actually use this GC to implement a toy VM.

#[macro_use] extern crate cell_gc;
use cell_gc::{Heap, with_heap, GCLeaf};
use std::rc::Rc;

gc_heap_type! {
    #[derive(Debug)]
    struct Pair / PairRef / PairStorage <'h> {
        car / set_car: Value<'h>,
        cdr / set_cdr: Value<'h>
    }
}

gc_heap_type! {
    #[derive(Clone, Debug, PartialEq)]
    enum Value / ValueStorage <'h> {
        Nil,
        Int(i32),
        Symbol(Rc<String>),
        Cons(PairRef<'h>),
        Lambda(PairRef<'h>),
        Builtin(Box<BuiltinFnPtr>)
    }
}

use Value::*;

struct BuiltinFnPtr(for<'b> fn(Vec<Value<'b>>) -> Result<Value<'b>, String>);

// This can't be #[derive]d because function pointers aren't Clone.
// But they are Copy. A very weird thing about Rust.
impl Clone for BuiltinFnPtr {
    fn clone(&self) -> BuiltinFnPtr { BuiltinFnPtr(self.0) }
}

impl PartialEq for BuiltinFnPtr {
    fn eq(&self, other: &BuiltinFnPtr) -> bool {
        self.0 as usize == other.0 as usize
    }
}

impl std::fmt::Debug for BuiltinFnPtr {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "BuiltinFn({:p})", self.0 as usize as *mut ());
        Ok(())
    }
}

impl<'h> Value<'h> {
    fn push_env(&mut self, heap: &mut Heap<'h>, key: Rc<String>, value: Value<'h>) {
        let pair = Cons(heap.alloc(Pair {
            car: Symbol(key),
            cdr: value
        }));
        *self = Cons(heap.alloc(Pair {
            car: pair,
            cdr: self.clone()
        }));
    }
}

macro_rules! lisp {
    { ( ) , $_heap:expr } => {
        Nil
    };
    { ( $h:tt $($t:tt)* ) , $heap:expr } => {
        {
            let h = lisp!($h, $heap);
            let t = lisp!(($($t)*), $heap);
            Cons($heap.alloc(Pair { car: h, cdr: t }))
        }
    };
    { $s:tt , $_heap:expr } => {
        {
            let s = stringify!($s);  // lame, but nothing else matches after an `ident` match fails
            if s.starts_with(|c: char| c.is_digit(10)) {
                Int(s.parse().expect("invalid numeric literal in `lisp!`"))
            } else {
                Symbol(Rc::new(s.to_string()))
            }
        }
    };
}

fn parse_pair<'h>(v: Value<'h>, msg: &'static str) -> Result<(Value<'h>, Value<'h>), String> {
    match v {
        Cons(r) => Ok((r.car(), r.cdr())),
        _ => Err(msg.to_string())
    }
}

fn lookup<'h>(mut env: Value<'h>, name: Rc<String>) -> Result<Value<'h>, String> {
    let v = Symbol(name.clone());
    while let Cons(p) = env {
        let (key, value) = try!(parse_pair(p.car(), "internal error: bad environment structure"));
        if key == v {
            return Ok(value);
        }
        env = p.cdr();
    }
    Err(format!("undefined symbol: {:?}", *name))
}

fn map_eval<'h>(heap: &mut Heap<'h>, mut exprs: Value<'h>, env: &Value<'h>)
    -> Result<Vec<Value<'h>>, String>
{
    let mut v = vec![];
    while let Cons(pair) = exprs {
        v.push(try!(eval(heap, pair.car(), env)));
        exprs = pair.cdr();
    }
    Ok(v)
}

fn apply<'h>(heap: &mut Heap<'h>, fval: Value<'h>, args: Vec<Value<'h>>) -> Result<Value<'h>, String> {
    match fval {
        Builtin(f) => (f.0)(args),
        Lambda(pair) => {
            let mut env = pair.cdr();
            let (mut params, rest) = try!(parse_pair(pair.car(), "syntax error in lambda"));
            let (body, rest) = try!(parse_pair(rest, "syntax error in lambda"));
            if rest != Nil {
                return Err("syntax error in lambda".to_string());
            }

            let mut i = 0;
            while let Cons(pair) = params {
                if i > args.len() {
                    return Err("apply: not enough arguments".to_string());
                }
                if let Symbol(s) = pair.car() {
                    let pair = Cons(heap.alloc(Pair {
                        car: Symbol(s),
                        cdr: args[i].clone()
                    }));
                    env = Cons(heap.alloc(Pair {
                        car: pair,
                        cdr: env
                    }));
                } else {
                    return Err("syntax error in lambda arguments".to_string());
                }
                params = pair.cdr();
                i += 1;
            }
            if i < args.len() {
                return Err("apply: too many arguments".to_string());
            }
            eval(heap, body, &env)
        }
        _ => Err("apply: not a function".to_string())
    }
}

fn eval<'h>(heap: &mut Heap<'h>, expr: Value<'h>, env: &Value<'h>) -> Result<Value<'h>, String> {
    match expr {
        Symbol(s) => lookup(env.clone(), s),
        Cons(p) => {
            let f = p.car();
            if let Symbol(ref s) = f {
                if &**s == "lambda" {
                    return Ok(Lambda(heap.alloc(Pair {
                        car: p.cdr(),
                        cdr: env.clone()
                    })));
                } else if &**s == "if" {
                    let (cond, rest) = try!(parse_pair(p.cdr(), "(if) with no arguments"));
                    let (t_expr, rest) = try!(parse_pair(rest, "missing arguments after (if COND)"));
                    let (f_expr, rest) = try!(parse_pair(rest, "missing 'else' argument after (if COND X)"));
                    match rest {
                        Nil => {}
                        _ => return Err("too many arguments in (if) expression".to_string())
                    };
                    let cond_result = try!(eval(heap, cond, env));
                    let selected_expr = if cond_result == Nil { f_expr } else { t_expr };
                    return eval(heap, selected_expr, env);
                }
            }
            let fval = try!(eval(heap, f, env));
            let args = try!(map_eval(heap, p.cdr(), env));
            apply(heap, fval, args)
        }
        Builtin(_) => Err(format!("builtin function found in source code")),
        _ => Ok(expr)  // nil and numbers are self-evaluating
    }
}

fn add<'h>(args: Vec<Value<'h>>) -> Result<Value<'h>, String> {
    let mut total = 0;
    for v in args {
        if let Int(n) = v {
            total += n;
        } else {
            return Err("add: non-numeric argument".to_string());
        }
    }
    Ok(Int(total))
}

fn main() {
    with_heap(|heap| {
        let mut env = Nil;
        env.push_env(heap, Rc::new("+".to_string()), Builtin(Box::new(BuiltinFnPtr(add))));
        let program = lisp!(
            ((lambda (x y z) (+ x (+ y z))) 3 4 5)
            , heap);
        let result = eval(heap, program, &env);
        assert_eq!(result, Ok(Int(12)));
    });
}
<|endoftext|>


<commit_before>// A dirty prototype to see what prometheus would look like
// Split up into domain based functions
// Provide some mechanism for benchmarking the overhead of
// prometheus
use metrics::metric::Metric;
use registry::{Registry, StdRegistry};
use std::thread;
use std::sync::Arc;
use reporter::base::Reporter;
use time;
use promo_proto::MetricFamily;
use router::Router;
use iron;
use iron::typemap::Key;
use iron::prelude::*;
use iron::status;

use promo_proto;
use persistent::Read;
use protobuf::Message;
use protobuf::repeated::RepeatedField;
use promo_proto::LabelPair;
use std::collections::HashMap;
use metrics::metric::MetricValue::{Counter, Gauge, Histogram, Meter};

// TODO terrible name and wrong caps please rename
#[derive(Copy, Clone)]
struct foo;

pub struct PrometheusReporter {
    host_and_port: &'static str,
    prefix: &'static str,
    registry: Arc<StdRegistry<'static>>,
    reporter_name: &'static str,
}

impl Key for foo {
    type Value = Arc<StdRegistry<'static>>;
}

impl Reporter for PrometheusReporter {
    fn get_unique_reporter_name(&self) -> &'static str {
        self.reporter_name
    }
}

fn prefix(metric_line: String, prefix_str: &'static str) -> String {
    format!("{}.{}", prefix_str, metric_line)
}

impl PrometheusReporter {
    pub fn new(registry: Arc<StdRegistry<'static>>,
               reporter_name: &'static str,
               host_and_port: &'static str,
               prefix: &'static str)
               -> PrometheusReporter {
        PrometheusReporter {
            host_and_port: host_and_port,
            prefix: prefix,
            registry: registry,
            reporter_name: reporter_name,
        }
    }

    pub fn start(self) -> thread::JoinHandle<iron::Listening> {
        thread::spawn(move || {
            let mut router = Router::new();
            router.get("/metrics", handler);
            let mut chain = Chain::new(router);
            // The double long ARC pointer FTW!
            chain.link_before(Read::<foo>::one(self.registry));
            // TODO -> Result<iron::Listening, iron::error::Error>
            Iron::new(chain).http(self.host_and_port).unwrap()
        })
    }
}

// TODO get an i64 instead?
fn timestamp() -> f64 {
    let timespec = time::get_time();
    // 1459440009.113178
    let mills: f64 = timespec.sec as f64 + (timespec.nsec as f64 / 1000.0 / 1000.0 / 1000.0);
    mills
}

fn handler(req: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, families_to_u8(to_pba(req.get::<Read<foo>>().unwrap())))))
}

fn families_to_u8(metric_families: Vec<promo_proto::MetricFamily>) -> Vec<u8> {
    let mut buf = Vec::new();
    for family in metric_families {
        family.write_length_delimited_to_writer(&mut buf).unwrap();
    }
    buf
}

fn to_repeated_fields_labels(labels: HashMap<String, String>) -> RepeatedField<LabelPair> {
    let mut repeated_fields = Vec::new();
    // name/value is what they call it in the protobufs *shrug*
    for (name, value) in labels {
        let mut label_pair = LabelPair::new();
        label_pair.set_name(name);
        label_pair.set_value(value);
        repeated_fields.push(label_pair);
    }
    RepeatedField::from_vec(repeated_fields)
}

// This is totally terrible, it'd be much better to use macros
// and serde once nightly is stable. I'd consider setting a feature flag but
// it still might increase complexity to deploy
// To an array of MetricFamily
fn to_pba(registry: Arc<Arc<StdRegistry<'static>>>) -> Vec<promo_proto::MetricFamily> {
    let mut metric_families = Vec::new();
    let metric_names = registry.get_metrics_names();
    for metric_by_name in metric_names {
        let mut metric_family = MetricFamily::new();
        let mut pb_metric = promo_proto::Metric::new();
        let metric = registry.get(metric_by_name);
        let formated_metric = format!("{}_{}_{}", "application_name", metric_by_name, "bytes");
        metric_family.set_name(String::from(formated_metric));
        let ts = timestamp() as i64;
        pb_metric.set_timestamp_ms(ts);
        pb_metric.set_label(to_repeated_fields_labels(registry.labels()));

        match metric.export_metric() {
            Counter(x) => {
                let mut counter = promo_proto::Counter::new();
                counter.set_value(x.value);
                pb_metric.set_counter(counter);
                metric_family.set_field_type(promo_proto::MetricType::COUNTER);
            }
            Gauge(x) => {
                let mut gauge = promo_proto::Gauge::new();
                gauge.set_value(x.value);
                pb_metric.set_gauge(gauge);
                metric_family.set_field_type(promo_proto::MetricType::GAUGE);

            }
            Meter(x) => {
                // TODO ask the prometheus guys what we want to do
                pb_metric.set_summary(promo_proto::Summary::new());
                metric_family.set_field_type(promo_proto::MetricType::SUMMARY);

            }
            Histogram(x) => {
                pb_metric.set_histogram(promo_proto::Histogram::new());
                metric_family.set_field_type(promo_proto::MetricType::HISTOGRAM);
            }
        }

        metric_family.set_metric(RepeatedField::from_vec(vec![pb_metric,]));
        metric_families.push(metric_family);
    }
    metric_families
}

#[cfg(test)]
mod test {
    use metrics::meter::{Meter, StdMeter};
    use metrics::counter::{Counter, StdCounter};
    use metrics::gauge::{Gauge, StdGauge};
    use registry::{Registry, StdRegistry};
    use reporter::prometheus::PrometheusReporter;
    use std::sync::Arc;
    use std::time::Duration;
    use std::thread;
    use histogram::*;
    use std::collections::HashMap;

    #[test]
    fn add_some_stats_and_slurp_them_with_http() {
        extern crate hyper;
        let m = StdMeter::new();
        m.mark(100);

        let mut c: StdCounter = StdCounter::new();
        c.inc();

        let mut g: StdGauge = StdGauge { value: 0f64 };
        g.set(1.2);

        let mut hc = HistogramConfig::new();
        hc.max_value(100).precision(1);
        let mut h = Histogram::configured(hc).unwrap();

        h.record(1, 1);

        let mut r = StdRegistry::new_with_labels(HashMap::new());
        r.insert("meter1", m);
        r.insert("counter1", c);
        r.insert("gauge1", g);
        r.insert("histogram", h);

        let arc_registry = Arc::new(r);
        let reporter =
            PrometheusReporter::new(arc_registry.clone(), "test", "0.0.0.0:8080", "asd.asdf");
        reporter.start();

        let client = hyper::client::Client::new();
        // Seems as though iron isn't running maybe
        thread::sleep(Duration::from_millis(1024 as u64));
        let res = client.get("http://127.0.0.1:8080").send().unwrap();
        // TODO fix url and check to make sure we got a valid protobuf
    }
}
<commit_msg>Clean up prometheus docs<commit_after>// Simple prometheus support. Still a work in progress.
// TODO
// We aren't collecting metrics properly we should be
// on the regular collecting metrics, and snapshoting them
// and sending them all up when prometheus comes to scrape.
use metrics::metric::Metric;
use registry::{Registry, StdRegistry};
use std::thread;
use std::sync::Arc;
use reporter::base::Reporter;
use time;
use promo_proto::MetricFamily;
use router::Router;
use iron;
use iron::typemap::Key;
use iron::prelude::*;
use iron::status;

use promo_proto;
use persistent::Read;
use protobuf::Message;
use protobuf::repeated::RepeatedField;
use promo_proto::LabelPair;
use std::collections::HashMap;
use metrics::metric::MetricValue::{Counter, Gauge, Histogram, Meter};

// TODO terrible name and wrong caps please rename
#[derive(Copy, Clone)]
struct foo;

pub struct PrometheusReporter {
    host_and_port: &'static str,
    prefix: &'static str,
    registry: Arc<StdRegistry<'static>>,
    reporter_name: &'static str,
}

impl Key for foo {
    type Value = Arc<StdRegistry<'static>>;
}

impl Reporter for PrometheusReporter {
    fn get_unique_reporter_name(&self) -> &'static str {
        self.reporter_name
    }
}

fn prefix(metric_line: String, prefix_str: &'static str) -> String {
    format!("{}.{}", prefix_str, metric_line)
}

impl PrometheusReporter {
    pub fn new(registry: Arc<StdRegistry<'static>>,
               reporter_name: &'static str,
               host_and_port: &'static str,
               prefix: &'static str)
               -> PrometheusReporter {
        PrometheusReporter {
            host_and_port: host_and_port,
            prefix: prefix,
            registry: registry,
            reporter_name: reporter_name,
        }
    }

    pub fn start(self) -> thread::JoinHandle<iron::Listening> {
        thread::spawn(move || {
            let mut router = Router::new();
            router.get("/metrics", handler);
            let mut chain = Chain::new(router);
            // The double long ARC pointer FTW!
            chain.link_before(Read::<foo>::one(self.registry));
            // TODO -> Result<iron::Listening, iron::error::Error>
            Iron::new(chain).http(self.host_and_port).unwrap()
        })
    }
}

// TODO get an i64 instead?
fn timestamp() -> f64 {
    let timespec = time::get_time();
    // 1459440009.113178
    let mills: f64 = timespec.sec as f64 + (timespec.nsec as f64 / 1000.0 / 1000.0 / 1000.0);
    mills
}

fn handler(req: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, families_to_u8(to_pba(req.get::<Read<foo>>().unwrap())))))
}

fn families_to_u8(metric_families: Vec<promo_proto::MetricFamily>) -> Vec<u8> {
    let mut buf = Vec::new();
    for family in metric_families {
        family.write_length_delimited_to_writer(&mut buf).unwrap();
    }
    buf
}

fn to_repeated_fields_labels(labels: HashMap<String, String>) -> RepeatedField<LabelPair> {
    let mut repeated_fields = Vec::new();
    // name/value is what they call it in the protobufs *shrug*
    for (name, value) in labels {
        let mut label_pair = LabelPair::new();
        label_pair.set_name(name);
        label_pair.set_value(value);
        repeated_fields.push(label_pair);
    }
    RepeatedField::from_vec(repeated_fields)
}

// This is totally terrible, it'd be much better to use macros
// and serde once nightly is stable. I'd consider setting a feature flag but
// it still might increase complexity to deploy
// To an array of MetricFamily
fn to_pba(registry: Arc<Arc<StdRegistry<'static>>>) -> Vec<promo_proto::MetricFamily> {
    let mut metric_families = Vec::new();
    let metric_names = registry.get_metrics_names();
    for metric_by_name in metric_names {
        let mut metric_family = MetricFamily::new();
        let mut pb_metric = promo_proto::Metric::new();
        let metric = registry.get(metric_by_name);
        let formated_metric = format!("{}_{}_{}", "application_name", metric_by_name, "bytes");
        metric_family.set_name(String::from(formated_metric));
        let ts = timestamp() as i64;
        pb_metric.set_timestamp_ms(ts);
        pb_metric.set_label(to_repeated_fields_labels(registry.labels()));

        match metric.export_metric() {
            Counter(x) => {
                let mut counter = promo_proto::Counter::new();
                counter.set_value(x.value);
                pb_metric.set_counter(counter);
                metric_family.set_field_type(promo_proto::MetricType::COUNTER);
            }
            Gauge(x) => {
                let mut gauge = promo_proto::Gauge::new();
                gauge.set_value(x.value);
                pb_metric.set_gauge(gauge);
                metric_family.set_field_type(promo_proto::MetricType::GAUGE);

            }
            Meter(x) => {
                // TODO ask the prometheus guys what we want to do
                pb_metric.set_summary(promo_proto::Summary::new());
                metric_family.set_field_type(promo_proto::MetricType::SUMMARY);

            }
            Histogram(x) => {
                pb_metric.set_histogram(promo_proto::Histogram::new());
                metric_family.set_field_type(promo_proto::MetricType::HISTOGRAM);
            }
        }

        metric_family.set_metric(RepeatedField::from_vec(vec![pb_metric,]));
        metric_families.push(metric_family);
    }
    metric_families
}

#[cfg(test)]
mod test {
    use metrics::meter::{Meter, StdMeter};
    use metrics::counter::{Counter, StdCounter};
    use metrics::gauge::{Gauge, StdGauge};
    use registry::{Registry, StdRegistry};
    use reporter::prometheus::PrometheusReporter;
    use std::sync::Arc;
    use std::time::Duration;
    use std::thread;
    use histogram::*;
    use std::collections::HashMap;

    #[test]
    fn add_some_stats_and_slurp_them_with_http() {
        extern crate hyper;
        let m = StdMeter::new();
        m.mark(100);

        let mut c: StdCounter = StdCounter::new();
        c.inc();

        let mut g: StdGauge = StdGauge { value: 0f64 };
        g.set(1.2);

        let mut hc = HistogramConfig::new();
        hc.max_value(100).precision(1);
        let mut h = Histogram::configured(hc).unwrap();

        h.record(1, 1);

        let mut r = StdRegistry::new_with_labels(HashMap::new());
        r.insert("meter1", m);
        r.insert("counter1", c);
        r.insert("gauge1", g);
        r.insert("histogram", h);

        let arc_registry = Arc::new(r);
        let reporter =
            PrometheusReporter::new(arc_registry.clone(), "test", "0.0.0.0:8080", "asd.asdf");
        reporter.start();

        let client = hyper::client::Client::new();
        // Seems as though iron isn't running maybe
        thread::sleep(Duration::from_millis(1024 as u64));
        let res = client.get("http://127.0.0.1:8080").send().unwrap();
        // TODO fix url and check to make sure we got a valid protobuf
    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Nick Platt <platt.nicholas@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.

// spell-checker:ignore (ToDO) filetime strptime utcoff strs datetime MMDDhhmm

pub extern crate filetime;

#[macro_use]
extern crate uucore;

use clap::{App, Arg};
use filetime::*;
use std::fs::{self, File};
use std::io::Error;
use std::path::Path;

static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
pub mod options {
    pub mod sources {
        pub static DATE: &str = "date";
        pub static REFERENCE: &str = "reference";
        pub static CURRENT: &str = "current";
    }
    pub static ACCESS: &str = "access";
    pub static MODIFICATION: &str = "modification";
    pub static NO_CREATE: &str = "no-create";
    pub static NO_DEREF: &str = "no-dereference";
    pub static TIME: &str = "time";
}

static ARG_FILES: &str = "files";

// Since touch's date/timestamp parsing doesn't account for timezone, the
// returned value from time::strptime() is UTC. We get system's timezone to
// localize the time.
macro_rules! to_local(
    ($exp:expr) => ({
        let mut tm = $exp;
        tm.tm_utcoff = time::now().tm_utcoff;
        tm
    })
);

macro_rules! local_tm_to_filetime(
    ($exp:expr) => ({
        let ts = $exp.to_timespec();
        FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32)
    })
);

fn get_usage() -> String {
    format!("{0} [OPTION]... [USER]", executable!())
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .arg(
            Arg::with_name(options::ACCESS)
                .short("a")
                .help("change only the access time"),
        )
        .arg(
            Arg::with_name(options::sources::CURRENT)
                .short("t")
                .help("use [[CC]YY]MMDDhhmm[.ss] instead of the current time")
                .value_name("STAMP")
                .takes_value(true),
        )
        .arg(
            Arg::with_name(options::sources::DATE)
                .short("d")
                .long(options::sources::DATE)
                .help("parse argument and use it instead of current time")
                .value_name("STRING"),
        )
        .arg(
            Arg::with_name(options::MODIFICATION)
                .short("m")
                .help("change only the modification time"),
        )
        .arg(
            Arg::with_name(options::NO_CREATE)
                .short("c")
                .long(options::NO_CREATE)
                .help("do not create any files"),
        )
        .arg(
            Arg::with_name(options::NO_DEREF)
                .short("h")
                .long(options::NO_DEREF)
                .help(
                    "affect each symbolic link instead of any referenced file \
                     (only for systems that can change the timestamps of a symlink)",
                ),
        )
        .arg(
            Arg::with_name(options::sources::REFERENCE)
                .short("r")
                .long(options::sources::REFERENCE)
                .help("use this file's times instead of the current time")
                .value_name("FILE"),
        )
        .arg(
            Arg::with_name(options::TIME)
                .long(options::TIME)
                .help(
                    "change only the specified time: \"access\", \"atime\", or \
                     \"use\" are equivalent to -a; \"modify\" or \"mtime\" are \
                     equivalent to -m",
                )
                .value_name("WORD")
                .possible_values(&["access", "atime", "use"])
                .takes_value(true),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .min_values(1),
        )
        .get_matches_from(args);

    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    if matches.is_present(options::sources::DATE)
        && (matches.is_present(options::sources::REFERENCE)
            || matches.is_present(options::sources::CURRENT))
        || matches.is_present(options::sources::REFERENCE)
            && (matches.is_present(options::sources::DATE)
                || matches.is_present(options::sources::CURRENT))
        || matches.is_present(options::sources::CURRENT)
            && (matches.is_present(options::sources::DATE)
                || matches.is_present(options::sources::REFERENCE))
    {
        panic!("Invalid options: cannot specify reference time from more than one source");
    }

    let (mut atime, mut mtime) = if matches.is_present(options::sources::REFERENCE) {
        stat(
            &matches.value_of(options::sources::REFERENCE).unwrap()[..],
            !matches.is_present(options::NO_DEREF),
        )
    } else if matches.is_present(options::sources::DATE)
        || matches.is_present(options::sources::CURRENT)
    {
        let timestamp = if matches.is_present(options::sources::DATE) {
            parse_date(matches.value_of(options::sources::DATE).unwrap().as_ref())
        } else {
            parse_timestamp(
                matches
                    .value_of(options::sources::CURRENT)
                    .unwrap()
                    .as_ref(),
            )
        };
        (timestamp, timestamp)
    } else {
        let now = local_tm_to_filetime!(time::now());
        (now, now)
    };

    for filename in &files {
        let path = &filename[..];

        if !Path::new(path).exists() {
            // no-dereference included here for compatibility
            if matches.is_present(options::NO_CREATE) || matches.is_present(options::NO_DEREF) {
                continue;
            }

            if let Err(e) = File::create(path) {
                show_warning!("cannot touch '{}': {}", path, e);
                continue;
            };

            // Minor optimization: if no reference time was specified, we're done.
            if !(matches.is_present(options::sources::DATE)
                || matches.is_present(options::sources::REFERENCE)
                || matches.is_present(options::sources::CURRENT))
            {
                continue;
            }
        }

        // If changing "only" atime or mtime, grab the existing value of the other.
        // Note that "-a" and "-m" may be passed together; this is not an xor.
        if matches.is_present(options::ACCESS)
            || matches.is_present(options::MODIFICATION)
            || matches.is_present(options::TIME)
        {
            let st = stat(path, !matches.is_present(options::NO_DEREF));
            let time = matches.value_of(options::TIME).unwrap_or("");

            if !(matches.is_present(options::ACCESS)
                || time.contains(&"access".to_owned())
                || time.contains(&"atime".to_owned())
                || time.contains(&"use".to_owned()))
            {
                atime = st.0;
            }

            if !(matches.is_present(options::MODIFICATION)
                || time.contains(&"modify".to_owned())
                || time.contains(&"mtime".to_owned()))
            {
                mtime = st.1;
            }
        }

        if matches.is_present(options::NO_DEREF) {
            if let Err(e) = set_symlink_file_times(path, atime, mtime) {
                show_warning!("cannot touch '{}': {}", path, e);
            }
        } else if let Err(e) = filetime::set_file_times(path, atime, mtime) {
            show_warning!("cannot touch '{}': {}", path, e);
        }
    }

    0
}

fn stat(path: &str, follow: bool) -> (FileTime, FileTime) {
    let metadata = if follow {
        fs::symlink_metadata(path)
    } else {
        fs::metadata(path)
    };

    match metadata {
        Ok(m) => (
            FileTime::from_last_access_time(&m),
            FileTime::from_last_modification_time(&m),
        ),
        Err(_) => crash!(
            1,
            "failed to get attributes of '{}': {}",
            path,
            Error::last_os_error()
        ),
    }
}

fn parse_date(str: &str) -> FileTime {
    // This isn't actually compatible with GNU touch, but there doesn't seem to
    // be any simple specification for what format this parameter allows and I'm
    // not about to implement GNU parse_datetime.
    // http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/parse-datetime.y
    match time::strptime(str, "%c") {
        Ok(tm) => local_tm_to_filetime!(to_local!(tm)),
        Err(e) => panic!("Unable to parse date\n{}", e),
    }
}

fn parse_timestamp(s: &str) -> FileTime {
    let now = time::now();
    let (format, ts) = match s.chars().count() {
        15 => ("%Y%m%d%H%M.%S", s.to_owned()),
        12 => ("%Y%m%d%H%M", s.to_owned()),
        13 => ("%y%m%d%H%M.%S", s.to_owned()),
        10 => ("%y%m%d%H%M", s.to_owned()),
        11 => ("%Y%m%d%H%M.%S", format!("{}{}", now.tm_year + 1900, s)),
        8 => ("%Y%m%d%H%M", format!("{}{}", now.tm_year + 1900, s)),
        _ => panic!("Unknown timestamp format"),
    };

    match time::strptime(&ts, format) {
        Ok(tm) => local_tm_to_filetime!(to_local!(tm)),
        Err(e) => panic!("Unable to parse timestamp\n{}", e),
    }
}
<commit_msg>touch: use arggroup for sources<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Nick Platt <platt.nicholas@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.

// spell-checker:ignore (ToDO) filetime strptime utcoff strs datetime MMDDhhmm

pub extern crate filetime;

#[macro_use]
extern crate uucore;

use clap::{App, Arg, ArgGroup};
use filetime::*;
use std::fs::{self, File};
use std::io::Error;
use std::path::Path;

static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
pub mod options {
    pub mod sources {
        pub static DATE: &str = "date";
        pub static REFERENCE: &str = "reference";
        pub static CURRENT: &str = "current";
    }
    pub static ACCESS: &str = "access";
    pub static MODIFICATION: &str = "modification";
    pub static NO_CREATE: &str = "no-create";
    pub static NO_DEREF: &str = "no-dereference";
    pub static TIME: &str = "time";
}

static ARG_FILES: &str = "files";

// Since touch's date/timestamp parsing doesn't account for timezone, the
// returned value from time::strptime() is UTC. We get system's timezone to
// localize the time.
macro_rules! to_local(
    ($exp:expr) => ({
        let mut tm = $exp;
        tm.tm_utcoff = time::now().tm_utcoff;
        tm
    })
);

macro_rules! local_tm_to_filetime(
    ($exp:expr) => ({
        let ts = $exp.to_timespec();
        FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32)
    })
);

fn get_usage() -> String {
    format!("{0} [OPTION]... [USER]", executable!())
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .arg(
            Arg::with_name(options::ACCESS)
                .short("a")
                .help("change only the access time"),
        )
        .arg(
            Arg::with_name(options::sources::CURRENT)
                .short("t")
                .help("use [[CC]YY]MMDDhhmm[.ss] instead of the current time")
                .value_name("STAMP")
                .takes_value(true),
        )
        .arg(
            Arg::with_name(options::sources::DATE)
                .short("d")
                .long(options::sources::DATE)
                .help("parse argument and use it instead of current time")
                .value_name("STRING"),
        )
        .arg(
            Arg::with_name(options::MODIFICATION)
                .short("m")
                .help("change only the modification time"),
        )
        .arg(
            Arg::with_name(options::NO_CREATE)
                .short("c")
                .long(options::NO_CREATE)
                .help("do not create any files"),
        )
        .arg(
            Arg::with_name(options::NO_DEREF)
                .short("h")
                .long(options::NO_DEREF)
                .help(
                    "affect each symbolic link instead of any referenced file \
                     (only for systems that can change the timestamps of a symlink)",
                ),
        )
        .arg(
            Arg::with_name(options::sources::REFERENCE)
                .short("r")
                .long(options::sources::REFERENCE)
                .help("use this file's times instead of the current time")
                .value_name("FILE"),
        )
        .arg(
            Arg::with_name(options::TIME)
                .long(options::TIME)
                .help(
                    "change only the specified time: \"access\", \"atime\", or \
                     \"use\" are equivalent to -a; \"modify\" or \"mtime\" are \
                     equivalent to -m",
                )
                .value_name("WORD")
                .possible_values(&["access", "atime", "use"])
                .takes_value(true),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .min_values(1),
        )
        .group(ArgGroup::with_name("sources").args(&[
            options::sources::CURRENT,
            options::sources::DATE,
            options::sources::REFERENCE,
        ]))
        .get_matches_from(args);

    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    let (mut atime, mut mtime) = if matches.is_present(options::sources::REFERENCE) {
        stat(
            &matches.value_of(options::sources::REFERENCE).unwrap()[..],
            !matches.is_present(options::NO_DEREF),
        )
    } else if matches.is_present(options::sources::DATE)
        || matches.is_present(options::sources::CURRENT)
    {
        let timestamp = if matches.is_present(options::sources::DATE) {
            parse_date(matches.value_of(options::sources::DATE).unwrap().as_ref())
        } else {
            parse_timestamp(
                matches
                    .value_of(options::sources::CURRENT)
                    .unwrap()
                    .as_ref(),
            )
        };
        (timestamp, timestamp)
    } else {
        let now = local_tm_to_filetime!(time::now());
        (now, now)
    };

    for filename in &files {
        let path = &filename[..];

        if !Path::new(path).exists() {
            // no-dereference included here for compatibility
            if matches.is_present(options::NO_CREATE) || matches.is_present(options::NO_DEREF) {
                continue;
            }

            if let Err(e) = File::create(path) {
                show_warning!("cannot touch '{}': {}", path, e);
                continue;
            };

            // Minor optimization: if no reference time was specified, we're done.
            if !matches.is_present("sources") {
                continue;
            }
        }

        // If changing "only" atime or mtime, grab the existing value of the other.
        // Note that "-a" and "-m" may be passed together; this is not an xor.
        if matches.is_present(options::ACCESS)
            || matches.is_present(options::MODIFICATION)
            || matches.is_present(options::TIME)
        {
            let st = stat(path, !matches.is_present(options::NO_DEREF));
            let time = matches.value_of(options::TIME).unwrap_or("");

            if !(matches.is_present(options::ACCESS)
                || time.contains(&"access".to_owned())
                || time.contains(&"atime".to_owned())
                || time.contains(&"use".to_owned()))
            {
                atime = st.0;
            }

            if !(matches.is_present(options::MODIFICATION)
                || time.contains(&"modify".to_owned())
                || time.contains(&"mtime".to_owned()))
            {
                mtime = st.1;
            }
        }

        if matches.is_present(options::NO_DEREF) {
            if let Err(e) = set_symlink_file_times(path, atime, mtime) {
                show_warning!("cannot touch '{}': {}", path, e);
            }
        } else if let Err(e) = filetime::set_file_times(path, atime, mtime) {
            show_warning!("cannot touch '{}': {}", path, e);
        }
    }

    0
}

fn stat(path: &str, follow: bool) -> (FileTime, FileTime) {
    let metadata = if follow {
        fs::symlink_metadata(path)
    } else {
        fs::metadata(path)
    };

    match metadata {
        Ok(m) => (
            FileTime::from_last_access_time(&m),
            FileTime::from_last_modification_time(&m),
        ),
        Err(_) => crash!(
            1,
            "failed to get attributes of '{}': {}",
            path,
            Error::last_os_error()
        ),
    }
}

fn parse_date(str: &str) -> FileTime {
    // This isn't actually compatible with GNU touch, but there doesn't seem to
    // be any simple specification for what format this parameter allows and I'm
    // not about to implement GNU parse_datetime.
    // http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/parse-datetime.y
    match time::strptime(str, "%c") {
        Ok(tm) => local_tm_to_filetime!(to_local!(tm)),
        Err(e) => panic!("Unable to parse date\n{}", e),
    }
}

fn parse_timestamp(s: &str) -> FileTime {
    let now = time::now();
    let (format, ts) = match s.chars().count() {
        15 => ("%Y%m%d%H%M.%S", s.to_owned()),
        12 => ("%Y%m%d%H%M", s.to_owned()),
        13 => ("%y%m%d%H%M.%S", s.to_owned()),
        10 => ("%y%m%d%H%M", s.to_owned()),
        11 => ("%Y%m%d%H%M.%S", format!("{}{}", now.tm_year + 1900, s)),
        8 => ("%Y%m%d%H%M", format!("{}{}", now.tm_year + 1900, s)),
        _ => panic!("Unknown timestamp format"),
    };

    match time::strptime(&ts, format) {
        Ok(tm) => local_tm_to_filetime!(to_local!(tm)),
        Err(e) => panic!("Unable to parse timestamp\n{}", e),
    }
}
<|endoftext|>


<commit_before>//#![feature(trace_macros)]
#![allow(dead_code)]
#![cfg_attr(feature = "cargo-clippy", allow(redundant_closure))]

#[macro_use]
extern crate nom;
extern crate regex;

use nom::{space, Err, IResult, Needed, le_u64};
use nom::types::{CompleteStr, CompleteByteSlice};

#[allow(dead_code)]
struct Range {
  start: char,
  end: char,
}

pub fn take_char(input: &[u8]) -> IResult<&[u8], char> {
  if !input.is_empty() {
    Ok((&input[1..], input[0] as char))
  } else {
    Err(Err::Incomplete(Needed::Size(1)))
  }
}

//trace_macros!(true);

#[allow(dead_code)]
named!(range<&[u8], Range>,
    alt!(
        do_parse!(
            start: take_char >>
            tag!("-")        >>
            end: take_char   >>
            (Range {
                start: start,
                end:   end,
            })
        ) |
        map!(
            take_char,
            |c| {
                Range {
                    start: c,
                    end:   c,
                }
            }
        )
    )
);

#[allow(dead_code)]
named!(literal<&[u8], Vec<char> >,
    map!(
        many1!(take_char),
        |cs| {
          cs
        }
    )
);

#[test]
fn issue_58() {
  let _ = range(&b"abcd"[..]);
  let _ = literal(&b"abcd"[..]);
}

//trace_macros!(false);

#[cfg(feature = "std")]
mod parse_int {
  use nom::HexDisplay;
  use nom::{digit, space, IResult};
  use std::str;

  named!(parse_ints<Vec<i32>>, many0!(spaces_or_int));

  fn spaces_or_int(input: &[u8]) -> IResult<&[u8], i32> {
    println!("{}", input.to_hex(8));
    do_parse!(
      input,
      opt!(complete!(space)) >> res: map!(complete!(digit), |x| {
        println!("x: {:?}", x);
        let result = str::from_utf8(x).unwrap();
        println!("Result: {}", result);
        println!("int is empty?: {}", x.is_empty());
        match result.parse() {
          Ok(i) => i,
          Err(e) => panic!("UH OH! NOT A DIGIT! {:?}", e),
        }
      }) >> (res)
    )
  }

  #[test]
  fn issue_142() {
    let subject = parse_ints(&b"12 34 5689a"[..]);
    let expected = Ok((&b"a"[..], vec![12, 34, 5689]));
    assert_eq!(subject, expected);

    let subject = parse_ints(&b"12 34 5689 "[..]);
    let expected = Ok((&b" "[..], vec![12, 34, 5689]));
    assert_eq!(subject, expected)
  }
}

#[test]
fn usize_length_bytes_issue() {
  use nom::be_u16;
  let _: IResult<&[u8], &[u8], u32> = length_bytes!(b"012346", be_u16);
}

/*
 DOES NOT COMPILE
#[test]
fn issue_152() {
  named!(take4, take!(4));
  named!(xyz, tag!("XYZ"));
  named!(abc, tag!("abc"));

  named!(sw,
    switch!(take4,
      b"abcd" => xyz |
      b"efgh" => abc
    )
  );
}
*/

#[test]
fn take_till_issue() {
  named!(nothing, take_till!(call!(|_| true)));

  assert_eq!(nothing(b""), Err(Err::Incomplete(Needed::Size(1))));
  assert_eq!(nothing(b"abc"), Ok((&b"abc"[..], &b""[..])));
}

named!(
  issue_498<Vec<&[u8]>>,
  separated_nonempty_list!(opt!(space), tag!("abcd"))
);

named!(issue_308(&str) -> bool,
    do_parse! (
        tag_s! ("foo") >>
        b: alt_complete! (
            map! (tag_s! ("1"), |_: &str|->bool {true}) |
            value! (false)
        ) >>
        (b) ));

#[cfg(feature = "alloc")]
fn issue_302(input: &[u8]) -> IResult<&[u8], Option<Vec<u64>>> {
  do_parse!(input, entries: cond!(true, count!(le_u64, 3)) >> (entries))
}

#[test]
fn issue_655() {
  use nom::{line_ending, not_line_ending};
  named!(twolines(&str) -> (&str, &str),
    do_parse!(
      l1 : not_line_ending >>
           line_ending >>
      l2 : not_line_ending >>
           line_ending >>
      ((l1, l2))
    )
  );

  assert_eq!(twolines("foo\nbar\n"), Ok(("", ("foo", "bar"))));
  assert_eq!(twolines("féo\nbar\n"), Ok(("", ("féo", "bar"))));
  assert_eq!(twolines("foé\nbar\n"), Ok(("", ("foé", "bar"))));
  assert_eq!(twolines("foé\r\nbar\n"), Ok(("", ("foé", "bar"))));
}

#[cfg(feature = "std")]
named!(issue_666 <CompleteByteSlice, CompleteByteSlice>, dbg_dmp!(tag!("abc")));

#[test]
fn issue_667() {
  use nom::alpha;

  named!(foo <CompleteByteSlice, Vec<CompleteByteSlice>>,
    many0!(
      alt!(alpha | is_a!("_"))
    )
  );
  assert_eq!(
    foo(CompleteByteSlice(b"")),
    Ok((CompleteByteSlice(b""), vec![]))
  );
  assert_eq!(
    foo(CompleteByteSlice(b"loremipsum")),
    Ok((
      CompleteByteSlice(b""),
      vec![CompleteByteSlice(b"loremipsum")]
    ))
  );
  assert_eq!(
    foo(CompleteByteSlice(b"lorem_ipsum")),
    Ok((
      CompleteByteSlice(b""),
      vec![
        CompleteByteSlice(b"lorem"),
        CompleteByteSlice(b"_"),
        CompleteByteSlice(b"ipsum"),
      ]
    ))
  );
  assert_eq!(
    foo(CompleteByteSlice(b"_lorem_ipsum")),
    Ok((
      CompleteByteSlice(b""),
      vec![
        CompleteByteSlice(b"_"),
        CompleteByteSlice(b"lorem"),
        CompleteByteSlice(b"_"),
        CompleteByteSlice(b"ipsum"),
      ]
    ))
  );
  assert_eq!(
    foo(CompleteByteSlice(b"!@#$")),
    Ok((CompleteByteSlice(b"!@#$"), vec![]))
  );
}

#[test]
fn issue_721() {
  assert_eq!(parse_to!("1234", u16), Ok(("", 1234)));
  assert_eq!(parse_to!("foo", String), Ok(("", "foo".to_string())));
}

#[cfg(feature = "alloc")]
named!(issue_717<&[u8], Vec<&[u8]> >,
  separated_list!(tag!([0x0]), is_not!([0x0u8]))
);

struct NoPartialEq {
  value: i32,
}

named!(issue_724<&str, i32>,
  do_parse!(
    metadata: permutation!(
      map!(tag!("hello"), |_| NoPartialEq { value: 1 }),
      map!(tag!("world"), |_| NoPartialEq { value: 2 })
    ) >>
    (metadata.0.value + metadata.1.value)
  )
);

named!(issue_741_str<CompleteStr, CompleteStr>, re_match!(r"^_?[A-Za-z][0-9A-Z_a-z-]*"));
named!(issue_741_bytes<CompleteByteSlice, CompleteByteSlice>, re_bytes_match!(r"^_?[A-Za-z][0-9A-Z_a-z-]*"));

#[test]
fn issue_752() {
    assert_eq!(
        Err::Error(nom::Context::Code("ab", nom::ErrorKind::ParseTo)),
        parse_to!("ab", usize).unwrap_err(),
    )
}

fn atom_specials(c: u8) -> bool {
    c == b'q'
}

named!(
    capability<&str>,
    do_parse!(tag_s!(" ") >> _atom: map_res!(take_till1!(atom_specials), std::str::from_utf8) >> ("a"))
);

#[test]
fn issue_759() {
    assert_eq!(capability(b" abcqd"), Ok((&b"qd"[..], "a")));
}

named_args!(issue_771(count: usize)<Vec<u32>>,
  length_count!(value!(count), call!(nom::be_u32))
);

/// This test is in a separate module to check that all required symbols are imported in
/// `escaped_transform!()`. Without the module, the `use`-es of the current module would
/// mask the error ('"Use of undeclared type or module `Needed`" in escaped_transform!').
mod issue_780 {
  named!(issue_780<&str, String>,
    escaped_transform!(call!(::nom::alpha), '\\', tag!("n"))
  );
}
<commit_msg>add tests from issues<commit_after>//#![feature(trace_macros)]
#![allow(dead_code)]
#![cfg_attr(feature = "cargo-clippy", allow(redundant_closure))]

#[macro_use]
extern crate nom;
extern crate regex;

use nom::{space, Err, IResult, Needed, le_u64, is_digit};
use nom::types::{CompleteStr, CompleteByteSlice};

#[allow(dead_code)]
struct Range {
  start: char,
  end: char,
}

pub fn take_char(input: &[u8]) -> IResult<&[u8], char> {
  if !input.is_empty() {
    Ok((&input[1..], input[0] as char))
  } else {
    Err(Err::Incomplete(Needed::Size(1)))
  }
}

//trace_macros!(true);

#[allow(dead_code)]
named!(range<&[u8], Range>,
    alt!(
        do_parse!(
            start: take_char >>
            tag!("-")        >>
            end: take_char   >>
            (Range {
                start: start,
                end:   end,
            })
        ) |
        map!(
            take_char,
            |c| {
                Range {
                    start: c,
                    end:   c,
                }
            }
        )
    )
);

#[allow(dead_code)]
named!(literal<&[u8], Vec<char> >,
    map!(
        many1!(take_char),
        |cs| {
          cs
        }
    )
);

#[test]
fn issue_58() {
  let _ = range(&b"abcd"[..]);
  let _ = literal(&b"abcd"[..]);
}

//trace_macros!(false);

#[cfg(feature = "std")]
mod parse_int {
  use nom::HexDisplay;
  use nom::{digit, space, IResult};
  use std::str;

  named!(parse_ints<Vec<i32>>, many0!(spaces_or_int));

  fn spaces_or_int(input: &[u8]) -> IResult<&[u8], i32> {
    println!("{}", input.to_hex(8));
    do_parse!(
      input,
      opt!(complete!(space)) >> res: map!(complete!(digit), |x| {
        println!("x: {:?}", x);
        let result = str::from_utf8(x).unwrap();
        println!("Result: {}", result);
        println!("int is empty?: {}", x.is_empty());
        match result.parse() {
          Ok(i) => i,
          Err(e) => panic!("UH OH! NOT A DIGIT! {:?}", e),
        }
      }) >> (res)
    )
  }

  #[test]
  fn issue_142() {
    let subject = parse_ints(&b"12 34 5689a"[..]);
    let expected = Ok((&b"a"[..], vec![12, 34, 5689]));
    assert_eq!(subject, expected);

    let subject = parse_ints(&b"12 34 5689 "[..]);
    let expected = Ok((&b" "[..], vec![12, 34, 5689]));
    assert_eq!(subject, expected)
  }
}

#[test]
fn usize_length_bytes_issue() {
  use nom::be_u16;
  let _: IResult<&[u8], &[u8], u32> = length_bytes!(b"012346", be_u16);
}

/*
 DOES NOT COMPILE
#[test]
fn issue_152() {
  named!(take4, take!(4));
  named!(xyz, tag!("XYZ"));
  named!(abc, tag!("abc"));

  named!(sw,
    switch!(take4,
      b"abcd" => xyz |
      b"efgh" => abc
    )
  );
}
*/

#[test]
fn take_till_issue() {
  named!(nothing, take_till!(call!(|_| true)));

  assert_eq!(nothing(b""), Err(Err::Incomplete(Needed::Size(1))));
  assert_eq!(nothing(b"abc"), Ok((&b"abc"[..], &b""[..])));
}

named!(
  issue_498<Vec<&[u8]>>,
  separated_nonempty_list!(opt!(space), tag!("abcd"))
);

named!(issue_308(&str) -> bool,
    do_parse! (
        tag_s! ("foo") >>
        b: alt_complete! (
            map! (tag_s! ("1"), |_: &str|->bool {true}) |
            value! (false)
        ) >>
        (b) ));

#[cfg(feature = "alloc")]
fn issue_302(input: &[u8]) -> IResult<&[u8], Option<Vec<u64>>> {
  do_parse!(input, entries: cond!(true, count!(le_u64, 3)) >> (entries))
}

#[test]
fn issue_655() {
  use nom::{line_ending, not_line_ending};
  named!(twolines(&str) -> (&str, &str),
    do_parse!(
      l1 : not_line_ending >>
           line_ending >>
      l2 : not_line_ending >>
           line_ending >>
      ((l1, l2))
    )
  );

  assert_eq!(twolines("foo\nbar\n"), Ok(("", ("foo", "bar"))));
  assert_eq!(twolines("féo\nbar\n"), Ok(("", ("féo", "bar"))));
  assert_eq!(twolines("foé\nbar\n"), Ok(("", ("foé", "bar"))));
  assert_eq!(twolines("foé\r\nbar\n"), Ok(("", ("foé", "bar"))));
}

#[cfg(feature = "std")]
named!(issue_666 <CompleteByteSlice, CompleteByteSlice>, dbg_dmp!(tag!("abc")));

#[test]
fn issue_667() {
  use nom::alpha;

  named!(foo <CompleteByteSlice, Vec<CompleteByteSlice>>,
    many0!(
      alt!(alpha | is_a!("_"))
    )
  );
  assert_eq!(
    foo(CompleteByteSlice(b"")),
    Ok((CompleteByteSlice(b""), vec![]))
  );
  assert_eq!(
    foo(CompleteByteSlice(b"loremipsum")),
    Ok((
      CompleteByteSlice(b""),
      vec![CompleteByteSlice(b"loremipsum")]
    ))
  );
  assert_eq!(
    foo(CompleteByteSlice(b"lorem_ipsum")),
    Ok((
      CompleteByteSlice(b""),
      vec![
        CompleteByteSlice(b"lorem"),
        CompleteByteSlice(b"_"),
        CompleteByteSlice(b"ipsum"),
      ]
    ))
  );
  assert_eq!(
    foo(CompleteByteSlice(b"_lorem_ipsum")),
    Ok((
      CompleteByteSlice(b""),
      vec![
        CompleteByteSlice(b"_"),
        CompleteByteSlice(b"lorem"),
        CompleteByteSlice(b"_"),
        CompleteByteSlice(b"ipsum"),
      ]
    ))
  );
  assert_eq!(
    foo(CompleteByteSlice(b"!@#$")),
    Ok((CompleteByteSlice(b"!@#$"), vec![]))
  );
}

#[test]
fn issue_721() {
  assert_eq!(parse_to!("1234", u16), Ok(("", 1234)));
  assert_eq!(parse_to!("foo", String), Ok(("", "foo".to_string())));
}

#[cfg(feature = "alloc")]
named!(issue_717<&[u8], Vec<&[u8]> >,
  separated_list!(tag!([0x0]), is_not!([0x0u8]))
);

struct NoPartialEq {
  value: i32,
}

named!(issue_724<&str, i32>,
  do_parse!(
    metadata: permutation!(
      map!(tag!("hello"), |_| NoPartialEq { value: 1 }),
      map!(tag!("world"), |_| NoPartialEq { value: 2 })
    ) >>
    (metadata.0.value + metadata.1.value)
  )
);

named!(issue_741_str<CompleteStr, CompleteStr>, re_match!(r"^_?[A-Za-z][0-9A-Z_a-z-]*"));
named!(issue_741_bytes<CompleteByteSlice, CompleteByteSlice>, re_bytes_match!(r"^_?[A-Za-z][0-9A-Z_a-z-]*"));

#[test]
fn issue_752() {
    assert_eq!(
        Err::Error(nom::Context::Code("ab", nom::ErrorKind::ParseTo)),
        parse_to!("ab", usize).unwrap_err(),
    )
}

fn atom_specials(c: u8) -> bool {
    c == b'q'
}

named!(
    capability<&str>,
    do_parse!(tag_s!(" ") >> _atom: map_res!(take_till1!(atom_specials), std::str::from_utf8) >> ("a"))
);

#[test]
fn issue_759() {
    assert_eq!(capability(b" abcqd"), Ok((&b"qd"[..], "a")));
}

named_args!(issue_771(count: usize)<Vec<u32>>,
  length_count!(value!(count), call!(nom::be_u32))
);

/// This test is in a separate module to check that all required symbols are imported in
/// `escaped_transform!()`. Without the module, the `use`-es of the current module would
/// mask the error ('"Use of undeclared type or module `Needed`" in escaped_transform!').
mod issue_780 {
  named!(issue_780<&str, String>,
    escaped_transform!(call!(::nom::alpha), '\\', tag!("n"))
  );
}

// issue 617
named!(digits, take_while1!( is_digit ));
named!(multi_617<&[u8], () >, fold_many0!( digits, (), |_, _| {}));

// Sad :(
named!(multi_617_fails<&[u8], () >, fold_many0!( take_while1!( is_digit ), (), |_, _| {}));

mod issue_647 {
  use nom::{Err,be_f64};
  pub type Input<'a> = &'a [u8];

  #[derive(PartialEq, Debug, Clone)]
  struct Data {
      c: f64,
      v: Vec<f64>
  }

  fn list<'a,'b>(input: Input<'a>, _cs: &'b f64) -> Result<(Input<'a>,Vec<f64>), Err<&'a [u8]>> {
      separated_list_complete!(input, tag!(","),be_f64)
  }

  named!(data<Input,Data>, map!(
      do_parse!(
          c: be_f64 >>
          tag!("\n") >>
          v: call!(list,&c) >>
          (c,v)
      ), |(c,v)| {
          Data {
              c: c,
              v: v
          }
      }
  ));
}

named!(issue_775, take_till1!(|_| true));
<|endoftext|>


<commit_before>#[macro_escape];

pub macro_rules! wxApp(
    ($f: ident) => (
        fn start(argc: int, argv: **u8) -> int {
            #[start];

            use std::libc::c_void;
            use std::vec;

            use wx::base::wxClosure;
            use wx::core::ELJApp;

            static nullptr: *mut c_void = 0 as *mut c_void;

            do native::start(argc, argv) {
                let closure = wxClosure::new($f as *mut c_void, nullptr);
                let args: ~[*i32] = ~[];
                ELJApp::initializeC(closure, args.len() as i32, args.as_ptr() as *mut *mut i8);
            }
        }
    )
)
<commit_msg>Remove the do syntax as the Rust master removes it (https://github.com/mozilla/rust/commit/e1580f6d09f0cd990c3eed55b1d6181af3258791).<commit_after>#[macro_escape];

pub macro_rules! wxApp(
    ($f: ident) => (
        fn start(argc: int, argv: **u8) -> int {
            #[start];

            use std::libc::c_void;
            use std::vec;

            use wx::base::wxClosure;
            use wx::core::ELJApp;

            static nullptr: *mut c_void = 0 as *mut c_void;

            native::start(argc, argv, proc() {
                let closure = wxClosure::new($f as *mut c_void, nullptr);
                let args: ~[*i32] = ~[];
                ELJApp::initializeC(closure, args.len() as i32, args.as_ptr() as *mut *mut i8);
            });
        }
    )
)
<|endoftext|>


<commit_before>extern crate erased_serde;
extern crate serde_json;
extern crate serde_cbor;

use std::collections::BTreeMap as Map;
use std::io;

use erased_serde::{Serialize, Serializer};

#[test]
fn serialization() {
    // Construct some serializers.
    let json = &mut serde_json::ser::Serializer::new(io::stdout());
    let cbor = &mut serde_cbor::ser::Serializer::new(io::stdout());

    // The values in this map are boxed trait objects. Ordinarily this would not
    // be possible with serde::Serializer because of object safety, but type
    // erasure makes it possible with erased_serde::Serializer.
    let mut formats: Map<&str, Box<Serializer>> = Map::new();
    formats.insert("json", Box::new(Serializer::erase(json)));
    formats.insert("cbor", Box::new(Serializer::erase(cbor)));

    // These are boxed trait objects as well. Same thing here - type erasure
    // makes this possible.
    let mut values: Map<&str, Box<Serialize>> = Map::new();
    values.insert("vec", Box::new(vec!["a", "b"]));
    values.insert("int", Box::new(65536));

    // Pick a Serializer out of the formats map.
    let format = formats.get_mut("json").unwrap();

    // Pick a Serialize out of the values map.
    let value = values.get("vec").unwrap();

    // This line prints `["a","b"]` to stdout.
    value.erased_serialize(&mut **format).unwrap();
}

/*
#[test]
fn deserialization() {
    static JSON: &'static [u8] = br#"{"A": 65, "B": 66}"#;
    static CBOR: &'static [u8] = &[162, 97, 65, 24, 65, 97, 66, 24, 66];

    // The values in this map are boxed trait objects, which is not possible
    // with the normal serde::Deserializer because of object safety.
    let mut formats: Map<&str, Box<Deserializer>> = Map::new();
    formats.insert("json", Box::new(serde_json::de::Deserializer::new(JSON.bytes())));
    formats.insert("cbor", Box::new(serde_cbor::de::Deserializer::new(CBOR)));

    // Pick a Deserializer out of the formats map.
    let format = formats.get_mut("json").unwrap();

    let data: Map<String, usize> = erased_serde::deserialize(format).unwrap();

    println!("{}", data["A"] + data["B"]);
}
*/
<commit_msg>Re-enable readme deserialize test<commit_after>extern crate erased_serde;
extern crate serde_json;
extern crate serde_cbor;

use std::collections::BTreeMap as Map;
use std::io;

use erased_serde::{Serialize, Serializer, Deserializer};

#[test]
fn serialization() {
    // Construct some serializers.
    let json = &mut serde_json::ser::Serializer::new(io::stdout());
    let cbor = &mut serde_cbor::ser::Serializer::new(io::stdout());

    // The values in this map are boxed trait objects. Ordinarily this would not
    // be possible with serde::Serializer because of object safety, but type
    // erasure makes it possible with erased_serde::Serializer.
    let mut formats: Map<&str, Box<Serializer>> = Map::new();
    formats.insert("json", Box::new(Serializer::erase(json)));
    formats.insert("cbor", Box::new(Serializer::erase(cbor)));

    // These are boxed trait objects as well. Same thing here - type erasure
    // makes this possible.
    let mut values: Map<&str, Box<Serialize>> = Map::new();
    values.insert("vec", Box::new(vec!["a", "b"]));
    values.insert("int", Box::new(65536));

    // Pick a Serializer out of the formats map.
    let format = formats.get_mut("json").unwrap();

    // Pick a Serialize out of the values map.
    let value = values.get("vec").unwrap();

    // This line prints `["a","b"]` to stdout.
    value.erased_serialize(&mut **format).unwrap();
}

#[test]
fn deserialization() {
    static JSON: &'static [u8] = br#"{"A": 65, "B": 66}"#;
    static CBOR: &'static [u8] = &[162, 97, 65, 24, 65, 97, 66, 24, 66];

    // Construct some deserializers.
    let json = &mut serde_json::de::Deserializer::from_slice(JSON);
    let cbor = &mut serde_cbor::de::Deserializer::new(CBOR);

    // The values in this map are boxed trait objects, which is not possible
    // with the normal serde::Deserializer because of object safety.
    let mut formats: Map<&str, Box<Deserializer>> = Map::new();
    formats.insert("json", Box::new(Deserializer::erase(json)));
    formats.insert("cbor", Box::new(Deserializer::erase(cbor)));

    // Pick a Deserializer out of the formats map.
    let format = formats.get_mut("json").unwrap();

    let data: Map<String, usize> = erased_serde::deserialize(&mut **format).unwrap();

    println!("{}", data["A"] + data["B"]);
}
<|endoftext|>


<commit_before>// System tests for compiling C code.
//
// Copyright 2016 Mozilla Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(dead_code, unused_imports)]

extern crate assert_cmd;
extern crate cc;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate predicates;
extern crate sccache;
extern crate serde_json;
extern crate tempdir;
extern crate which;

use assert_cmd::prelude::*;
use log::LogLevel::Trace;
use predicates::prelude::*;
use sccache::server::ServerInfo;
use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr,OsString};
use std::fmt;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::{Path,PathBuf};
use std::process::{
    Command,
    Output,
    Stdio,
};
use std::str;
use tempdir::TempDir;
use which::which_in;

struct Compiler {
    pub name: &'static str,
    pub exe: OsString,
    pub env_vars: Vec<(OsString, OsString)>,
}

// Test GCC + clang on non-OS X platforms.
#[cfg(all(unix, not(target_os="macos")))]
const COMPILERS: &'static [&'static str] = &["gcc", "clang"];

// OS X ships a `gcc` that's just a clang wrapper, so only test clang there.
#[cfg(target_os="macos")]
const COMPILERS: &'static [&'static str] = &["clang"];

//TODO: could test gcc when targeting mingw.

fn stop() {
    trace!("sccache --stop-server");
    drop(Command::main_binary().unwrap()
         .arg("--stop-server")
         .stdout(Stdio::null())
         .stderr(Stdio::null())
         .status());
}

fn zero_stats() {
    trace!("sccache --zero-stats");
    drop(Command::main_binary().unwrap()
         .arg("--zero-stats")
         .stdout(Stdio::null())
         .stderr(Stdio::null())
         .status());
}

macro_rules! vec_from {
    ( $t:ty, $( $x:expr ),* ) => {
        vec!($( Into::<$t>::into(&$x), )*)
    };
}

fn compile_cmdline<T: AsRef<OsStr>>(compiler: &str, exe: T, input: &str, output: &str) -> Vec<OsString> {
    match compiler {
        "gcc" | "clang" => vec_from!(OsString, exe.as_ref(), "-c", input, "-o", output),
        "cl.exe" => vec_from!(OsString, exe, "-c", input, format!("-Fo{}", output)),
        _ => panic!("Unsupported compiler: {}", compiler),
    }
}

fn get_stats<F: 'static + Fn(ServerInfo)>(f: F) {
    Command::main_binary().unwrap()
        .args(&["--show-stats", "--stats-format=json"])
        .assert()
        .success()
        .stdout(predicate::function(move |output: &[u8]| {
            let s = str::from_utf8(output).expect("Output not UTF-8");
            f(serde_json::from_str(s).expect("Failed to parse JSON stats"));
            true
        }));
}

fn write_source(path: &Path, filename: &str, contents: &str) {
    let p = path.join(filename);
    let mut f = File::create(&p).unwrap();
    f.write_all(contents.as_bytes()).unwrap();
}

fn run_sccache_command_test(compiler: Compiler, tempdir: &Path) {
    let Compiler { name, exe, env_vars } = compiler;
    // Ensure there's no existing sccache server running.
    stop();
    // Create a subdir for the cache.
    let cache = tempdir.join("cache");
    fs::create_dir_all(&cache).unwrap();
    // Start a server.
    trace!("start server");
    // Don't run this with run() because on Windows `wait_with_output`
    // will hang because the internal server process is not detached.
    Command::main_binary().unwrap()
        .arg("--start-server")
        .env("SCCACHE_DIR", &cache)
        .status()
        .unwrap()
        .success();
    trace!("run_sccache_command_test: {}", name);
    // Compile a source file.
    const INPUT: &'static str = "test.c";
    const INPUT_ERR: &'static str = "test_err.c";
    const OUTPUT: &'static str = "test.o";
    // Copy the source files into the tempdir so we can compile with relative paths, since the commandline winds up in the hash key.
    for f in &[INPUT, INPUT_ERR] {
        let original_source_file = Path::new(file!()).parent().unwrap().join(f);
        let source_file = tempdir.join(f);
        trace!("fs::copy({:?}, {:?})", original_source_file, source_file);
        fs::copy(&original_source_file, &source_file).unwrap();
    }

    let out_file = tempdir.join("test.o");
    trace!("compile");
    Command::main_binary().unwrap()
        .args(&compile_cmdline(name, &exe, INPUT, OUTPUT))
        .current_dir(tempdir)
        .envs(env_vars.clone())
        .assert()
        .success();
    assert_eq!(true, fs::metadata(&out_file).and_then(|m| Ok(m.len() > 0)).unwrap());
    trace!("request stats");
    get_stats(|info| {
        assert_eq!(1, info.stats.compile_requests);
        assert_eq!(1, info.stats.requests_executed);
        assert_eq!(0, info.stats.cache_hits);
        assert_eq!(1, info.stats.cache_misses);
    });
    trace!("compile");
    fs::remove_file(&out_file).unwrap();
    Command::main_binary().unwrap()
        .args(&compile_cmdline(name, &exe, INPUT, OUTPUT))
        .current_dir(tempdir)
.envs(env_vars.clone())
        .assert()
        .success();
    assert_eq!(true, fs::metadata(&out_file).and_then(|m| Ok(m.len() > 0)).unwrap());
    trace!("request stats");
    get_stats(|info| {
        assert_eq!(2, info.stats.compile_requests);
        assert_eq!(2, info.stats.requests_executed);
        assert_eq!(1, info.stats.cache_hits);
        assert_eq!(1, info.stats.cache_misses);
    });
    if name == "cl.exe" {
        // Check that -deps works.
        trace!("compile with -deps");
        let mut args = compile_cmdline(name, &exe, INPUT, OUTPUT);
        args.push("-depstest.d".into());
        Command::main_binary().unwrap()
            .args(&args)
            .current_dir(tempdir)
            .envs(env_vars.clone())
            .assert()
            .success();
        // Check the contents
        let mut f = File::open(tempdir.join("test.d")).expect("Failed to open dep file");
        let mut buf = String::new();
        // read_to_string should be safe because we're supplying all the filenames here,
        // and there are no absolute paths.
        f.read_to_string(&mut buf).expect("Failed to read dep file");
        let lines: Vec<_> = buf.lines().map(|l| l.trim_right()).collect();
        let expected = format!("{output}: {input}\n{input}:\n", output=OUTPUT, input=INPUT);
        let expected_lines: Vec<_> = expected.lines().collect();
        assert_eq!(lines, expected_lines);
    }
    if name == "gcc" {
        trace!("test -MP with -Werror");
        let mut args = compile_cmdline(name, &exe, INPUT_ERR, OUTPUT);
        args.extend(vec_from!(OsString, "-MD", "-MP", "-MF", "foo.pp", "-Werror"));
        // This should fail, but the error should be from the #error!
        Command::main_binary().unwrap()
            .args(&args)
            .current_dir(tempdir)
    .envs(env_vars.clone())
            .assert()
            .failure()
            .stderr(predicates::str::contains(
                "to generate dependencies you must specify either -M or -MM").from_utf8().not());
        trace!("test -fprofile-generate with different source inputs");
        zero_stats();
        const SRC: &str = "source.c";
        write_source(&tempdir, SRC, "/*line 1*/
#ifndef UNDEFINED
/*unused line 1*/
#endif

int main(int argc, char** argv) {
  return 0;
}
");
        let mut args = compile_cmdline(name, &exe, SRC, OUTPUT);
        args.extend(vec_from!(OsString, "-fprofile-generate"));
        trace!("compile source.c (1)");
        Command::main_binary().unwrap()
            .args(&args)
            .current_dir(tempdir)
            .envs(env_vars.clone())
            .assert()
            .success();
        get_stats(|info| {
            assert_eq!(0, info.stats.cache_hits);
            assert_eq!(1, info.stats.cache_misses);
        });
        // Compile the same source again to ensure we can get a cache hit.
        trace!("compile source.c (2)");
        Command::main_binary().unwrap()
            .args(&args)
            .current_dir(tempdir)
            .envs(env_vars.clone())
            .assert()
            .success();
        get_stats(|info| {
            assert_eq!(1, info.stats.cache_hits);
            assert_eq!(1, info.stats.cache_misses);
        });
        // Now write out a slightly different source file that will preprocess to the same thing,
        // modulo line numbers. This should not be a cache hit because line numbers are important
        // with -fprofile-generate.
        write_source(&tempdir, SRC, "/*line 1*/
#ifndef UNDEFINED
/*unused line 1*/
/*unused line 2*/
#endif

int main(int argc, char** argv) {
  return 0;
}
");
        trace!("compile source.c (3)");
        Command::main_binary().unwrap()
            .args(&args)
            .current_dir(tempdir)
            .envs(env_vars.clone())
            .assert()
            .success();
        get_stats(|info| {
            assert_eq!(1, info.stats.cache_hits);
            assert_eq!(2, info.stats.cache_misses);
        });
    }
    trace!("stop server");
    stop();
}

#[cfg(unix)]
fn find_compilers() -> Vec<Compiler> {
    let cwd = env::current_dir().unwrap();
    COMPILERS.iter()
        .filter_map(|c| {
            match which_in(c, env::var_os("PATH"), &cwd) {
                Ok(full_path) => match full_path.canonicalize() {
                    Ok(full_path_canon) => Some(Compiler {
                        name: *c,
                        exe: full_path_canon.into_os_string(),
                        env_vars: vec![],
                    }),
                    Err(_) => None,
                },
                Err(_) => None,
            }
        })
        .collect::<Vec<_>>()
}

#[cfg(target_env="msvc")]
fn find_compilers() -> Vec<Compiler> {
    let tool = cc::Build::new()
        .opt_level(1)
        .host("x86_64-pc-windows-msvc")
        .target("x86_64-pc-windows-msvc")
        .debug(false)
        .get_compiler();
    vec![
        Compiler {
            name: "cl.exe",
            exe: tool.path().as_os_str().to_os_string(),
            env_vars: tool.env().to_vec(),
        },
    ]
}

#[test]
#[cfg(any(unix, target_env="msvc"))]
fn test_sccache_command() {
    match env_logger::init() {
        Ok(_) => {},
        Err(_) => {},
    }
    let tempdir = TempDir::new("sccache_system_test").unwrap();
    let compilers = find_compilers();
    if compilers.is_empty() {
        warn!("No compilers found, skipping test");
    } else {
        for compiler in compilers {
            run_sccache_command_test(compiler, tempdir.path())
        }
    }
}
<commit_msg>Start/stop sccache server once per compiler type in system tests<commit_after>// System tests for compiling C code.
//
// Copyright 2016 Mozilla Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(dead_code, unused_imports)]

extern crate assert_cmd;
extern crate cc;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate predicates;
extern crate sccache;
extern crate serde_json;
extern crate tempdir;
extern crate which;

use assert_cmd::prelude::*;
use log::LogLevel::Trace;
use predicates::prelude::*;
use sccache::server::ServerInfo;
use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr,OsString};
use std::fmt;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::{Path,PathBuf};
use std::process::{
    Command,
    Output,
    Stdio,
};
use std::str;
use tempdir::TempDir;
use which::which_in;

struct Compiler {
    pub name: &'static str,
    pub exe: OsString,
    pub env_vars: Vec<(OsString, OsString)>,
}

// Test GCC + clang on non-OS X platforms.
#[cfg(all(unix, not(target_os="macos")))]
const COMPILERS: &'static [&'static str] = &["gcc", "clang"];

// OS X ships a `gcc` that's just a clang wrapper, so only test clang there.
#[cfg(target_os="macos")]
const COMPILERS: &'static [&'static str] = &["clang"];

//TODO: could test gcc when targeting mingw.

fn stop() {
    trace!("sccache --stop-server");
    drop(Command::main_binary().unwrap()
         .arg("--stop-server")
         .stdout(Stdio::null())
         .stderr(Stdio::null())
         .status());
}

fn zero_stats() {
    trace!("sccache --zero-stats");
    drop(Command::main_binary().unwrap()
         .arg("--zero-stats")
         .stdout(Stdio::null())
         .stderr(Stdio::null())
         .status());
}

macro_rules! vec_from {
    ( $t:ty, $( $x:expr ),* ) => {
        vec!($( Into::<$t>::into(&$x), )*)
    };
}

fn compile_cmdline<T: AsRef<OsStr>>(compiler: &str, exe: T, input: &str, output: &str) -> Vec<OsString> {
    match compiler {
        "gcc" | "clang" => vec_from!(OsString, exe.as_ref(), "-c", input, "-o", output),
        "cl.exe" => vec_from!(OsString, exe, "-c", input, format!("-Fo{}", output)),
        _ => panic!("Unsupported compiler: {}", compiler),
    }
}

fn get_stats<F: 'static + Fn(ServerInfo)>(f: F) {
    Command::main_binary().unwrap()
        .args(&["--show-stats", "--stats-format=json"])
        .assert()
        .success()
        .stdout(predicate::function(move |output: &[u8]| {
            let s = str::from_utf8(output).expect("Output not UTF-8");
            f(serde_json::from_str(s).expect("Failed to parse JSON stats"));
            true
        }));
}

fn write_source(path: &Path, filename: &str, contents: &str) {
    let p = path.join(filename);
    let mut f = File::create(&p).unwrap();
    f.write_all(contents.as_bytes()).unwrap();
}

fn run_sccache_command_test(compiler: Compiler, tempdir: &Path) {
    let Compiler { name, exe, env_vars } = compiler;
    trace!("run_sccache_command_test: {}", name);
    // Compile a source file.
    const INPUT: &'static str = "test.c";
    const INPUT_ERR: &'static str = "test_err.c";
    const OUTPUT: &'static str = "test.o";
    // Copy the source files into the tempdir so we can compile with relative paths, since the commandline winds up in the hash key.
    for f in &[INPUT, INPUT_ERR] {
        let original_source_file = Path::new(file!()).parent().unwrap().join(f);
        let source_file = tempdir.join(f);
        trace!("fs::copy({:?}, {:?})", original_source_file, source_file);
        fs::copy(&original_source_file, &source_file).unwrap();
    }

    let out_file = tempdir.join("test.o");
    trace!("compile");
    Command::main_binary().unwrap()
        .args(&compile_cmdline(name, &exe, INPUT, OUTPUT))
        .current_dir(tempdir)
        .envs(env_vars.clone())
        .assert()
        .success();
    assert_eq!(true, fs::metadata(&out_file).and_then(|m| Ok(m.len() > 0)).unwrap());
    trace!("request stats");
    get_stats(|info| {
        assert_eq!(1, info.stats.compile_requests);
        assert_eq!(1, info.stats.requests_executed);
        assert_eq!(0, info.stats.cache_hits);
        assert_eq!(1, info.stats.cache_misses);
    });
    trace!("compile");
    fs::remove_file(&out_file).unwrap();
    Command::main_binary().unwrap()
        .args(&compile_cmdline(name, &exe, INPUT, OUTPUT))
        .current_dir(tempdir)
.envs(env_vars.clone())
        .assert()
        .success();
    assert_eq!(true, fs::metadata(&out_file).and_then(|m| Ok(m.len() > 0)).unwrap());
    trace!("request stats");
    get_stats(|info| {
        assert_eq!(2, info.stats.compile_requests);
        assert_eq!(2, info.stats.requests_executed);
        assert_eq!(1, info.stats.cache_hits);
        assert_eq!(1, info.stats.cache_misses);
    });
    if name == "cl.exe" {
        // Check that -deps works.
        trace!("compile with -deps");
        let mut args = compile_cmdline(name, &exe, INPUT, OUTPUT);
        args.push("-depstest.d".into());
        Command::main_binary().unwrap()
            .args(&args)
            .current_dir(tempdir)
            .envs(env_vars.clone())
            .assert()
            .success();
        // Check the contents
        let mut f = File::open(tempdir.join("test.d")).expect("Failed to open dep file");
        let mut buf = String::new();
        // read_to_string should be safe because we're supplying all the filenames here,
        // and there are no absolute paths.
        f.read_to_string(&mut buf).expect("Failed to read dep file");
        let lines: Vec<_> = buf.lines().map(|l| l.trim_right()).collect();
        let expected = format!("{output}: {input}\n{input}:\n", output=OUTPUT, input=INPUT);
        let expected_lines: Vec<_> = expected.lines().collect();
        assert_eq!(lines, expected_lines);
    }
    if name == "gcc" {
        trace!("test -MP with -Werror");
        let mut args = compile_cmdline(name, &exe, INPUT_ERR, OUTPUT);
        args.extend(vec_from!(OsString, "-MD", "-MP", "-MF", "foo.pp", "-Werror"));
        // This should fail, but the error should be from the #error!
        Command::main_binary().unwrap()
            .args(&args)
            .current_dir(tempdir)
    .envs(env_vars.clone())
            .assert()
            .failure()
            .stderr(predicates::str::contains(
                "to generate dependencies you must specify either -M or -MM").from_utf8().not());
        trace!("test -fprofile-generate with different source inputs");
        zero_stats();
        const SRC: &str = "source.c";
        write_source(&tempdir, SRC, "/*line 1*/
#ifndef UNDEFINED
/*unused line 1*/
#endif

int main(int argc, char** argv) {
  return 0;
}
");
        let mut args = compile_cmdline(name, &exe, SRC, OUTPUT);
        args.extend(vec_from!(OsString, "-fprofile-generate"));
        trace!("compile source.c (1)");
        Command::main_binary().unwrap()
            .args(&args)
            .current_dir(tempdir)
            .envs(env_vars.clone())
            .assert()
            .success();
        get_stats(|info| {
            assert_eq!(0, info.stats.cache_hits);
            assert_eq!(1, info.stats.cache_misses);
        });
        // Compile the same source again to ensure we can get a cache hit.
        trace!("compile source.c (2)");
        Command::main_binary().unwrap()
            .args(&args)
            .current_dir(tempdir)
            .envs(env_vars.clone())
            .assert()
            .success();
        get_stats(|info| {
            assert_eq!(1, info.stats.cache_hits);
            assert_eq!(1, info.stats.cache_misses);
        });
        // Now write out a slightly different source file that will preprocess to the same thing,
        // modulo line numbers. This should not be a cache hit because line numbers are important
        // with -fprofile-generate.
        write_source(&tempdir, SRC, "/*line 1*/
#ifndef UNDEFINED
/*unused line 1*/
/*unused line 2*/
#endif

int main(int argc, char** argv) {
  return 0;
}
");
        trace!("compile source.c (3)");
        Command::main_binary().unwrap()
            .args(&args)
            .current_dir(tempdir)
            .envs(env_vars.clone())
            .assert()
            .success();
        get_stats(|info| {
            assert_eq!(1, info.stats.cache_hits);
            assert_eq!(2, info.stats.cache_misses);
        });
    }
}

#[cfg(unix)]
fn find_compilers() -> Vec<Compiler> {
    let cwd = env::current_dir().unwrap();
    COMPILERS.iter()
        .filter_map(|c| {
            match which_in(c, env::var_os("PATH"), &cwd) {
                Ok(full_path) => match full_path.canonicalize() {
                    Ok(full_path_canon) => Some(Compiler {
                        name: *c,
                        exe: full_path_canon.into_os_string(),
                        env_vars: vec![],
                    }),
                    Err(_) => None,
                },
                Err(_) => None,
            }
        })
        .collect::<Vec<_>>()
}

#[cfg(target_env="msvc")]
fn find_compilers() -> Vec<Compiler> {
    let tool = cc::Build::new()
        .opt_level(1)
        .host("x86_64-pc-windows-msvc")
        .target("x86_64-pc-windows-msvc")
        .debug(false)
        .get_compiler();
    vec![
        Compiler {
            name: "cl.exe",
            exe: tool.path().as_os_str().to_os_string(),
            env_vars: tool.env().to_vec(),
        },
    ]
}

#[test]
#[cfg(any(unix, target_env="msvc"))]
fn test_sccache_command() {
    match env_logger::init() {
        Ok(_) => {},
        Err(_) => {},
    }
    let tempdir = TempDir::new("sccache_system_test").unwrap();
    let compilers = find_compilers();
    if compilers.is_empty() {
        warn!("No compilers found, skipping test");
    } else {
        // Ensure there's no existing sccache server running.
        stop();
        // Create a subdir for the cache.
        let cache = tempdir.path().join("cache");
        fs::create_dir_all(&cache).unwrap();
        // Start a server.
        trace!("start server");
        // Don't run this with run() because on Windows `wait_with_output`
        // will hang because the internal server process is not detached.
        Command::main_binary().unwrap()
            .arg("--start-server")
            .env("SCCACHE_DIR", &cache)
            .status()
            .unwrap()
            .success();
        for compiler in compilers {
            run_sccache_command_test(compiler, tempdir.path());
            zero_stats();
        }
        stop();
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use super::{Error, Result};
use crate::utils::definitions::IdExt;
use pkg_schema::definitions::{
    target_permissions::{Gid, Uid},
    Filesystem,
};
use std::{io, path::Path};
use sys_mount::{Mount, Unmount, UnmountDrop};

pub(crate) fn ensure_disk_space(target: &Path, required: u64) -> Result<()> {
    let stat = nix::sys::statvfs::statvfs(target)?;
    if required > stat.block_size() * stat.blocks_free() {
        return Err(Error::NotEnoughSpace);
    }
    Ok(())
}

pub(crate) fn is_executable_in_path(cmd: &str) -> Result<()> {
    match quale::which(cmd) {
        Some(_) => Ok(()),
        None => Err(Error::ExecutableNotInPath(cmd.to_owned())),
    }
}

pub(crate) fn format(target: &Path, fs: Filesystem, options: &Option<String>) -> Result<()> {
    let target = target.display();
    let options = options.clone().unwrap_or_else(|| "".to_string());

    let cmd = match fs {
        Filesystem::Jffs2 => format!("flash_erase -j {} {} 0 0", options, target),
        Filesystem::Ext2 | Filesystem::Ext3 | Filesystem::Ext4 => {
            format!("mkfs.{} -F {} {}", fs, options, target)
        }
        Filesystem::Ubifs => format!("mkfs.{} -y {} {}", fs, options, target),
        Filesystem::Xfs => format!("mkfs.{} -f {} {}", fs, options, target),
        Filesystem::Btrfs | Filesystem::Vfat | Filesystem::F2fs => {
            format!("mkfs.{} {} {}", fs, options, target)
        }
    };

    easy_process::run(&cmd)?;
    Ok(())
}

pub(crate) fn mount_map<F, T>(source: &Path, fs: Filesystem, options: &str, f: F) -> Result<T>
where
    F: FnOnce(&Path) -> T,
{
    let tmpdir = tempfile::tempdir()?;
    let tmpdir = tmpdir.path();

    // We need to keep a guard otherwise it is dropped before the
    // closure is run.
    let _guard = mount(source, &tmpdir, fs, options)?;

    Ok(f(tmpdir))
}

pub(crate) fn mount(
    source: &Path,
    dest: &Path,
    fs: Filesystem,
    options: &str,
) -> io::Result<UnmountDrop<Mount>> {
    Ok(Mount::new(
        source,
        dest,
        format!("{}", fs).as_str(),
        sys_mount::MountFlags::empty(),
        Some(options),
    )?
    .into_unmount_drop(sys_mount::UnmountFlags::DETACH))
}

pub(crate) fn chmod(path: &Path, mode: u32) -> Result<()> {
    nix::sys::stat::fchmodat(
        None,
        path,
        nix::sys::stat::Mode::from_bits(mode).unwrap(),
        nix::sys::stat::FchmodatFlags::FollowSymlink,
    )?;

    Ok(())
}

pub(crate) fn chown(path: &Path, uid: &Option<Uid>, gid: &Option<Gid>) -> Result<()> {
    Ok(nix::unistd::chown(
        path,
        uid.as_ref().map(|id| nix::unistd::Uid::from_raw(id.as_u32())),
        gid.as_ref().map(|id| nix::unistd::Gid::from_raw(id.as_u32())),
    )?)
}
<commit_msg>updatehub: Fix arch compatibility issue<commit_after>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use super::{Error, Result};
use crate::utils::definitions::IdExt;
use pkg_schema::definitions::{
    target_permissions::{Gid, Uid},
    Filesystem,
};
use std::{io, path::Path};
use sys_mount::{Mount, Unmount, UnmountDrop};

pub(crate) fn ensure_disk_space(target: &Path, required: u64) -> Result<()> {
    let stat = nix::sys::statvfs::statvfs(target)?;

    // stat fields might be 32 or 64 bytes depending on host arch
    let available = stat.block_size() as u64 * stat.blocks_free() as u64;

    if required > available {
        return Err(Error::NotEnoughSpace);
    }
    Ok(())
}

pub(crate) fn is_executable_in_path(cmd: &str) -> Result<()> {
    match quale::which(cmd) {
        Some(_) => Ok(()),
        None => Err(Error::ExecutableNotInPath(cmd.to_owned())),
    }
}

pub(crate) fn format(target: &Path, fs: Filesystem, options: &Option<String>) -> Result<()> {
    let target = target.display();
    let options = options.clone().unwrap_or_else(|| "".to_string());

    let cmd = match fs {
        Filesystem::Jffs2 => format!("flash_erase -j {} {} 0 0", options, target),
        Filesystem::Ext2 | Filesystem::Ext3 | Filesystem::Ext4 => {
            format!("mkfs.{} -F {} {}", fs, options, target)
        }
        Filesystem::Ubifs => format!("mkfs.{} -y {} {}", fs, options, target),
        Filesystem::Xfs => format!("mkfs.{} -f {} {}", fs, options, target),
        Filesystem::Btrfs | Filesystem::Vfat | Filesystem::F2fs => {
            format!("mkfs.{} {} {}", fs, options, target)
        }
    };

    easy_process::run(&cmd)?;
    Ok(())
}

pub(crate) fn mount_map<F, T>(source: &Path, fs: Filesystem, options: &str, f: F) -> Result<T>
where
    F: FnOnce(&Path) -> T,
{
    let tmpdir = tempfile::tempdir()?;
    let tmpdir = tmpdir.path();

    // We need to keep a guard otherwise it is dropped before the
    // closure is run.
    let _guard = mount(source, &tmpdir, fs, options)?;

    Ok(f(tmpdir))
}

pub(crate) fn mount(
    source: &Path,
    dest: &Path,
    fs: Filesystem,
    options: &str,
) -> io::Result<UnmountDrop<Mount>> {
    Ok(Mount::new(
        source,
        dest,
        format!("{}", fs).as_str(),
        sys_mount::MountFlags::empty(),
        Some(options),
    )?
    .into_unmount_drop(sys_mount::UnmountFlags::DETACH))
}

pub(crate) fn chmod(path: &Path, mode: u32) -> Result<()> {
    nix::sys::stat::fchmodat(
        None,
        path,
        nix::sys::stat::Mode::from_bits(mode).unwrap(),
        nix::sys::stat::FchmodatFlags::FollowSymlink,
    )?;

    Ok(())
}

pub(crate) fn chown(path: &Path, uid: &Option<Uid>, gid: &Option<Gid>) -> Result<()> {
    Ok(nix::unistd::chown(
        path,
        uid.as_ref().map(|id| nix::unistd::Uid::from_raw(id.as_u32())),
        gid.as_ref().map(|id| nix::unistd::Gid::from_raw(id.as_u32())),
    )?)
}
<|endoftext|>