changeset 0:be75e8a90861

Initial commit
author Lewin Bormann <lbo@spheniscida.de>
date Sun, 14 Feb 2016 11:50:16 +0100
parents
children 6e3192a31324
files .hgignore Cargo.lock Cargo.toml src/main.rs
diffstat 4 files changed, 304 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Sun Feb 14 11:50:16 2016 +0100
@@ -0,0 +1,4 @@
+target
+syntax: glob
+*.swp
+*.bk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Cargo.lock	Sun Feb 14 11:50:16 2016 +0100
@@ -0,0 +1,99 @@
+[root]
+name = "myi3stat"
+version = "0.1.0"
+dependencies = [
+ "chrono 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 0.1.48 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "memchr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "chrono"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "getopts"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "kernel32-sys"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "memchr"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num"
+version = "0.1.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "regex"
+version = "0.1.48"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "aho-corasick 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rustc-serialize"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "time"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi-build"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Cargo.toml	Sun Feb 14 11:50:16 2016 +0100
@@ -0,0 +1,10 @@
+[package]
+name = "myi3stat"
+version = "0.1.0"
+authors = ["Lewin Bormann <lbo@spheniscida.de>"]
+
+[dependencies]
+getopts = ">=0.2"
+rustc-serialize = ">=0.3.18"
+regex = ">=0.1"
+chrono = ">=0.2"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main.rs	Sun Feb 14 11:50:16 2016 +0100
@@ -0,0 +1,191 @@
+use std::collections::BTreeMap;
+use std::process;
+use std::env;
+
+extern crate chrono;
+use chrono::Local;
+
+extern crate getopts;
+use getopts::Options;
+
+#[derive(Clone)]
+pub enum Color {
+    /// An HTML color (#1234aa)
+    Arbitrary(String),
+    /// The default
+    Standard,
+    /// Various colors
+    White,
+    Red,
+    Green,
+    Blue,
+    Orange,
+    Purple,
+}
+
+/// An output produced by a metric to be displayed in the bar.
+pub struct RenderResult {
+    pub text: String,
+    pub color: Color,
+}
+
+/// State that is stored in a MetricState between rendering cycles.
+#[derive(Clone)]
+pub enum State {
+    Empty,
+    S(String),
+    I(i64),
+    F(f64),
+    C(Color),
+}
+
+/// State that is passed to and returned from every render cycle.
+pub struct MetricState {
+    /// Arbitrary state
+    state: BTreeMap<String, State>,
+
+    /// Unix epoch in seconds. This is updated by the framework.
+    pub last_called: i64,
+}
+
+impl MetricState {
+    pub fn new() -> MetricState {
+        MetricState {
+            state: BTreeMap::new(),
+            last_called: 0,
+        }
+    }
+    pub fn get(&self, k: String) -> State {
+        self.state.get(&k).unwrap_or(&State::Empty).clone()
+    }
+    pub fn set(&mut self, k: String, v: State) {
+        self.state.insert(k, v);
+    }
+    pub fn now() -> i64 {
+        Local::now().timestamp()
+    }
+}
+
+trait Metric {
+    /// Initializes a metric using the string supplied as parameter to the command line argument.
+    fn init(&self, argvalue: Option<String>) -> MetricState;
+    /// Renders the metric.
+    fn render(&mut self, st: &mut MetricState) -> RenderResult;
+}
+
+/// A metric that is active in the current run and updated for every cycle.
+struct ActiveMetric {
+    name: String,
+    m: Box<Metric>,
+    st: MetricState,
+}
+
+/// Represents a/the set of metrics available for display.
+struct AvailableMetrics {
+    metrics: BTreeMap<String, Box<Metric>>,
+    opts: Options,
+}
+
+impl AvailableMetrics {
+    fn new() -> AvailableMetrics {
+        let mut options = Options::new();
+        options.optopt("",
+                       "ordering",
+                       "Ordering of metrics in status bar. Comma-separated list of metric names \
+                        (default ordering is ASCII-ordered, i.e. case sensitive)",
+                       "METRIC1,METRIC2,METRIC3");
+        options.optopt("",
+                       "interval",
+                       "Interval in seconds between individual render cycles. Default: 1",
+                       "SECONDS");
+        options.optflag("h", "help", "Print a help text");
+
+        AvailableMetrics {
+            metrics: BTreeMap::new(),
+            opts: options,
+        }
+    }
+
+    /// Register a metric under the given name.
+    /// desc and example are for the purpose of documenting the command line option that is added.
+    /// Does 
+    fn register_metric(&mut self, name: &str, desc: &str, example: &str, metric: Box<Metric>) {
+        if !self.metrics.contains_key(&String::from(name)) {
+            self.opts.optopt("", name, desc, example);
+            self.metrics.insert(String::from(name), metric);
+        }
+    }
+
+    fn print_help(&self) {
+        print!("{}", self.opts.usage("Usage: myi3stat [options]"));
+    }
+
+    fn parse_args(&mut self, args: &[String]) -> getopts::Matches {
+        let matches = self.opts.parse(args);
+
+        match matches {
+            Err(_) => {
+                self.print_help();
+                process::exit(1)
+            }
+            Ok(m) => m,
+        }
+    }
+
+    /// Returns a map of metric -> position in ordering list
+    fn make_ordering_map(ord_list: String) -> BTreeMap<String, i32> {
+        let parts = ord_list.split(",");
+        let mut i = 0;
+        let mut ordmap = BTreeMap::new();
+
+        for metric in parts {
+            ordmap.insert(String::from(metric), i);
+            i += 1;
+        }
+        ordmap
+    }
+
+    /// Returns a vec of the selected metrics in the wanted order, and the interval between render
+    /// cycles in seconds.
+    fn evaluate(mut self, args: &[String]) -> (Vec<ActiveMetric>, i32) {
+        let matches = self.parse_args(args);
+        let mut metrics = Vec::new();
+
+        // Look for every defined metric if the user wants to have it displayed.
+        for (metric_name, metric) in self.metrics.into_iter() {
+            if matches.opt_present(&metric_name) {
+                let st = metric.init(matches.opt_str(&metric_name));
+                metrics.push(ActiveMetric {
+                    name: String::from(metric_name),
+                    m: metric,
+                    st: st,
+                });
+            }
+        }
+
+        // Sort metrics by position in the supplied ordering list (or alternatively
+        // alphabetically).
+        let ordmap = AvailableMetrics::make_ordering_map(matches.opt_str("ordering")
+                                                                .unwrap_or(String::from("")));
+        metrics.sort_by(|a, b| {
+            match (ordmap.get(&a.name), ordmap.get(&b.name)) {
+                (Some(i1), Some(i2)) => i1.cmp(i2),
+                (_, _) => a.name.cmp(&b.name),
+            }
+        });
+
+        let interval = i32::from_str_radix(&matches.opt_str("interval")
+                                                   .unwrap_or(String::from("1")),
+                                           10)
+                           .unwrap_or(1);
+
+        (metrics, interval)
+    }
+}
+
+
+fn main() {
+    let args: Vec<String> = env::args().collect();
+    let all_metrics = AvailableMetrics::new();
+    let (selected_metrics, interval) = all_metrics.evaluate(&args[1..]);
+}