Mercurial > lbo > hg > myi3stat
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..]); +}