dock_driver 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +23 -0
- data/.gemtest +0 -0
- data/.hgignore +2 -0
- data/History.txt +26 -0
- data/Ideas.txt +20 -0
- data/Manifest.txt +17 -0
- data/README.txt +74 -0
- data/Rakefile +12 -0
- data/bin/dock_driver +56 -0
- data/data/example.dock_driver.yml +80 -0
- data/lib/dock_driver/data_rate_poll.rb +141 -0
- data/lib/dock_driver/dock.rb +126 -0
- data/lib/dock_driver/laika_hashutils.rb +74 -0
- data/lib/dock_driver/poll.rb +72 -0
- data/lib/dock_driver.rb +16 -0
- data/spec/dock_driver/dock_spec.rb +40 -0
- data/spec/dock_driver/poll_spec.rb +51 -0
- data/spec/dock_driver_spec.rb +17 -0
- data.tar.gz.sig +1 -0
- metadata +161 -0
- metadata.gz.sig +0 -0
data/.autotest
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'autotest/restart'
|
4
|
+
|
5
|
+
# Autotest.add_hook :initialize do |at|
|
6
|
+
# at.extra_files << "../some/external/dependency.rb"
|
7
|
+
#
|
8
|
+
# at.libs << ":../some/external"
|
9
|
+
#
|
10
|
+
# at.add_exception 'vendor'
|
11
|
+
#
|
12
|
+
# at.add_mapping(/dependency.rb/) do |f, _|
|
13
|
+
# at.files_matching(/test_.*rb$/)
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# %w(TestA TestB).each do |klass|
|
17
|
+
# at.extra_class_map[klass] = "test/test_misc.rb"
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
|
21
|
+
# Autotest.add_hook :run_command do |at|
|
22
|
+
# system "rake build"
|
23
|
+
# end
|
data/.gemtest
ADDED
File without changes
|
data/.hgignore
ADDED
data/History.txt
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
=== 0.1.0 / 2012-05-15
|
2
|
+
|
3
|
+
* 3 minor enhancements
|
4
|
+
|
5
|
+
* bin/dock_driver completed
|
6
|
+
* RSpec tests completed & passing
|
7
|
+
* Several bugs fixed
|
8
|
+
|
9
|
+
=== 0.0.3 / 2012-05-15
|
10
|
+
|
11
|
+
* 1 minor enhancement
|
12
|
+
|
13
|
+
* Doc & Manifest Updates
|
14
|
+
|
15
|
+
=== 0.0.2 / 2012-05-15
|
16
|
+
|
17
|
+
* 1 minor enhancement
|
18
|
+
|
19
|
+
* 100% documentation coverage
|
20
|
+
|
21
|
+
=== 0.0.1 / 2012-05-15
|
22
|
+
|
23
|
+
* 1 major enhancement
|
24
|
+
|
25
|
+
* Birthday!
|
26
|
+
|
data/Ideas.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
= Ideas
|
2
|
+
|
3
|
+
== Without Dependencies
|
4
|
+
|
5
|
+
* Graphing
|
6
|
+
* Automatic Coloring (with definable syntax)
|
7
|
+
* Logging
|
8
|
+
|
9
|
+
== With Dependencies
|
10
|
+
|
11
|
+
* Maildir support
|
12
|
+
* SNMP Poller
|
13
|
+
* gateway / internet latency
|
14
|
+
|
15
|
+
== dzen2 Ideas
|
16
|
+
|
17
|
+
* buttons
|
18
|
+
* events
|
19
|
+
* text window
|
20
|
+
|
data/Manifest.txt
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
.autotest
|
2
|
+
.hgignore
|
3
|
+
History.txt
|
4
|
+
Ideas.txt
|
5
|
+
Manifest.txt
|
6
|
+
README.txt
|
7
|
+
Rakefile
|
8
|
+
bin/dock_driver
|
9
|
+
data/example.dock_driver.yml
|
10
|
+
lib/dock_driver.rb
|
11
|
+
lib/dock_driver/laika_hashutils.rb
|
12
|
+
lib/dock_driver/poll.rb
|
13
|
+
lib/dock_driver/data_rate_poll.rb
|
14
|
+
lib/dock_driver/dock.rb
|
15
|
+
spec/dock_driver/dock_spec.rb
|
16
|
+
spec/dock_driver/poll_spec.rb
|
17
|
+
spec/dock_driver_spec.rb
|
data/README.txt
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
= dock_driver
|
2
|
+
|
3
|
+
* http://hg.musl.org/projects/dock_driver/
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Provides a simple executable to drive a dzen2 (or similar) dock with a
|
8
|
+
single YAML config file.
|
9
|
+
|
10
|
+
Read +example.dock_driver.yml+ for more information about how to get
|
11
|
+
started. It's located in this gem's data directory, which is usually:
|
12
|
+
$GEM_HOME/gems/dock_driver-x.y.z/data/
|
13
|
+
|
14
|
+
== FEATURES/PROBLEMS:
|
15
|
+
|
16
|
+
=== Features:
|
17
|
+
|
18
|
+
* easy, flexible configuration
|
19
|
+
* field extraction with +scan_regex+ (no grep or pipes necessary)
|
20
|
+
|
21
|
+
=== Problems:
|
22
|
+
|
23
|
+
* undiscovered bugs
|
24
|
+
* unwritten test cases
|
25
|
+
* cleanup
|
26
|
+
|
27
|
+
== SYNOPSIS:
|
28
|
+
|
29
|
+
There really isn't an API or interface other than the YAML config file.
|
30
|
+
|
31
|
+
== REQUIREMENTS:
|
32
|
+
|
33
|
+
* This gem proudly has zero dependencies besides ruby and rubygems.
|
34
|
+
|
35
|
+
== INSTALL:
|
36
|
+
|
37
|
+
* sudo gem install dock_driver
|
38
|
+
* copy <gemdir>/etc/example.dock_driver.yml to ~/.dock_driver.yml
|
39
|
+
* edit ~/.dock_driver.yml to taste
|
40
|
+
* run dock_driver from your xsession or ~/.i3/config file.
|
41
|
+
|
42
|
+
== DEVELOPERS:
|
43
|
+
|
44
|
+
After checking out the source, run:
|
45
|
+
|
46
|
+
$ rake newb
|
47
|
+
|
48
|
+
This task will install any missing dependencies, run the tests/specs,
|
49
|
+
and generate the RDoc.
|
50
|
+
|
51
|
+
== LICENSE:
|
52
|
+
|
53
|
+
(The MIT License)
|
54
|
+
|
55
|
+
Copyright (c) 2012 Michael Hix
|
56
|
+
|
57
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
58
|
+
a copy of this software and associated documentation files (the
|
59
|
+
'Software'), to deal in the Software without restriction, including
|
60
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
61
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
62
|
+
permit persons to whom the Software is furnished to do so, subject to
|
63
|
+
the following conditions:
|
64
|
+
|
65
|
+
The above copyright notice and this permission notice shall be included
|
66
|
+
in all copies or substantial portions of the Software.
|
67
|
+
|
68
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
69
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
70
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
71
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
72
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
73
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
74
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
data/bin/dock_driver
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'dock_driver/dock'
|
5
|
+
|
6
|
+
include Signal
|
7
|
+
|
8
|
+
opts = {}
|
9
|
+
parser = OptionParser.new do |p|
|
10
|
+
|
11
|
+
p.on(
|
12
|
+
'-c',
|
13
|
+
'--conf FILE',
|
14
|
+
'Specify an alternate config file. (Default: ~/.dock_driver.yml)'
|
15
|
+
) do |file|
|
16
|
+
opts[:conf] = file
|
17
|
+
end
|
18
|
+
|
19
|
+
p.on(
|
20
|
+
'-d',
|
21
|
+
'--dock COMMAND',
|
22
|
+
'Override the dock command from the config file.'
|
23
|
+
) do |command|
|
24
|
+
opts[:dock] = command
|
25
|
+
end
|
26
|
+
|
27
|
+
p.on( '-e', '--debug', 'Enable $DEBUG' ) { |debug| $DEBUG = true }
|
28
|
+
|
29
|
+
p.on( '-h', '--help', 'Print this help text.' ) do
|
30
|
+
cmd = File.basename( $0 )
|
31
|
+
puts "\n%s\n%s\n\nVersion: %s\n%s\n\n" % [
|
32
|
+
cmd,
|
33
|
+
'=' * cmd.length,
|
34
|
+
DockDriver::VERSION,
|
35
|
+
DockDriver::REVISION,
|
36
|
+
]
|
37
|
+
puts p
|
38
|
+
puts "\nAuthors:\n\t%s\n\n" % [
|
39
|
+
DockDriver::AUTHORS.join( '\n\t' ),
|
40
|
+
]
|
41
|
+
exit
|
42
|
+
end
|
43
|
+
|
44
|
+
end.parse!
|
45
|
+
|
46
|
+
puts "Options: %p" % opts if $DEBUG
|
47
|
+
|
48
|
+
dock = DockDriver::Dock.new( opts[:conf], opts[:dock] )
|
49
|
+
|
50
|
+
trap 'INT' do
|
51
|
+
dock.kill
|
52
|
+
puts "\nKilled!" if $DEBUG
|
53
|
+
end
|
54
|
+
|
55
|
+
dock.run
|
56
|
+
|
@@ -0,0 +1,80 @@
|
|
1
|
+
---
|
2
|
+
# Specify a program to run here. This bit of code was initially meant to run
|
3
|
+
# dzen2 but other docks are certainly appropriate, provided they accept commands
|
4
|
+
# and data over standard input. You'll probably need to adjust your formats and
|
5
|
+
# templates below if you use a different dock program.
|
6
|
+
#
|
7
|
+
dock_command:
|
8
|
+
dzen2 -dock -ta r -x 0 -y 0 -w 1680 -h 24 -bg black -fg white
|
9
|
+
-fn "-*-terminus-medium-r-*-*-12-*-*-*-*-*-*-*"
|
10
|
+
-e "button3="
|
11
|
+
|
12
|
+
# See the manpages for strftime and dzen2.
|
13
|
+
#
|
14
|
+
time_format:
|
15
|
+
^fg(white)%A ^fg(gray80)%Y-%m-%d ^fg(gray60)%H:%M:%S ^fg(gray30)%Z
|
16
|
+
|
17
|
+
# Determines the layout and styling of the dock.
|
18
|
+
#
|
19
|
+
# Processed by +ERB+. +Poll+ objects as defined by the 'commands' section are
|
20
|
+
# available. Since +Poll+ objects respond to to_s intelligently, it's usually
|
21
|
+
# sufficient to just specify the object name. Since they're also subclasses of
|
22
|
+
# +OpenStruct+, you can also reference any method or member here.
|
23
|
+
#
|
24
|
+
# See the dzen2 documentation.
|
25
|
+
#
|
26
|
+
template:
|
27
|
+
^fg(white)rx ^fg(gray60)<%= eth0_rx %> ^fg(gray30)<%= eth0_rx.unit %> ·
|
28
|
+
^fg(white)tx ^fg(gray60)<%= eth0_tx %> ^fg(gray30)<%= eth0_tx.unit %> ·
|
29
|
+
^fg(white)cpu0 ^fg(gray60)<%= cpu0_temp %>^fg(gray30) C ·
|
30
|
+
^fg(white)cpu1 ^fg(gray60)<%= cpu1_temp %>^fg(gray30) C ·
|
31
|
+
^fg(white)gpu ^fg(gray60)<%= gpu_temp %>^fg(gray30) C ·
|
32
|
+
^fg(white)mail <%= mail %>^fg(gray30) ·
|
33
|
+
^fg(gray60)<%= time %>^fg(gray30) ·
|
34
|
+
|
35
|
+
# Commands to poll. Each command will be polled every second, but specifying a
|
36
|
+
# +delay+ greater than one will cache the value and only run the command every
|
37
|
+
# +delay+ seconds. This defaults to evaluating a string with a shell, but if
|
38
|
+
# your YAML fu is strong enough, you can specify a Proc here too.
|
39
|
+
#
|
40
|
+
# To narrow down the output, you may use +scan_regex+. A single-quoted regex
|
41
|
+
# without forward slashes works great. Since scan returns an array, using one
|
42
|
+
# or more capture groups will allow you to pull multiple values from a single
|
43
|
+
# command's output - the values returned will be joined with single spaces.
|
44
|
+
#
|
45
|
+
# To change the class used to poll the command, you can specify a +type+.
|
46
|
+
# Right now, only 'rate' is recognized. It uses a separate class that expects
|
47
|
+
# a string containing a single number. Best to use +scan_regex+ here. It
|
48
|
+
# calculates a running average based on the changes in the value over time.
|
49
|
+
# A unit of measurement (b, kb, mb, gb, tb, pb, eb, zb, yb) or its full name
|
50
|
+
# (bits, kibibits, mebibits, ...) is also useful here. You may also specify a
|
51
|
+
# +number_format+ here if you don't like the default. See +sprintf+ for details
|
52
|
+
# on the format string.
|
53
|
+
#
|
54
|
+
commands:
|
55
|
+
mail:
|
56
|
+
cmd: '/home/joeuser/bin/dockmail'
|
57
|
+
delay: 5
|
58
|
+
cpu0_temp:
|
59
|
+
cmd: 'sensors'
|
60
|
+
scan_regex: 'Core 0:\s+\+(\d+\.\d+)'
|
61
|
+
delay: 30
|
62
|
+
cpu1_temp:
|
63
|
+
cmd: 'sensors'
|
64
|
+
scan_regex: 'Core 1:\s+\+(\d+\.\d+)'
|
65
|
+
delay: 30
|
66
|
+
gpu_temp:
|
67
|
+
cmd: 'nvidia-smi -q -d TEMPERATURE'
|
68
|
+
scan_regex: '(\d+) C'
|
69
|
+
delay: 30
|
70
|
+
eth0_rx:
|
71
|
+
cmd: 'ifconfig eth0'
|
72
|
+
scan_regex: 'RX bytes:(\d+)'
|
73
|
+
type: rate
|
74
|
+
unit: mb
|
75
|
+
eth0_tx:
|
76
|
+
cmd: 'ifconfig eth0'
|
77
|
+
scan_regex: 'TX bytes:(\d+)'
|
78
|
+
type: rate
|
79
|
+
unit: mb
|
80
|
+
|
@@ -0,0 +1,141 @@
|
|
1
|
+
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
require 'dock_driver' unless defined? DockDriver
|
5
|
+
require 'dock_driver/poll'
|
6
|
+
|
7
|
+
# A class to provide simple, periodic command execution, caching, and a
|
8
|
+
# running average in changes in a value.
|
9
|
+
#
|
10
|
+
class DockDriver::DataRatePoll < DockDriver::Poll
|
11
|
+
|
12
|
+
# Default values to populate the OpenStruct with.
|
13
|
+
#
|
14
|
+
DEFAULTS = {
|
15
|
+
:unit => :mb,
|
16
|
+
:history_size => 2,
|
17
|
+
:number_format => '%0.3f',
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
# Create a new DataRatePoll.
|
21
|
+
#
|
22
|
+
# === Arguments:
|
23
|
+
#
|
24
|
+
# +opts+ - A hash containing options. Merged with DEFAULTS.
|
25
|
+
#
|
26
|
+
# +block+ - If a block is given, replace :cmd with that block.
|
27
|
+
#
|
28
|
+
# === Options:
|
29
|
+
#
|
30
|
+
# +:delay+ - Determines the minimum amount of time to let elapse between executions.
|
31
|
+
#
|
32
|
+
# +:cmd+ - A string or block to execute.
|
33
|
+
#
|
34
|
+
# +:scan_regex+ - A bare string to be interpreted as a regex for use with +scan+. Any
|
35
|
+
# capture group matches will be joined with single spaces.
|
36
|
+
#
|
37
|
+
# +:history_size+ - How many samples to keep
|
38
|
+
#
|
39
|
+
# +:unit+ - The unit to use. See the methods and aliases available.
|
40
|
+
# (b, kb, mb, gb, tb, pb, eb, zb, yb, and full names: bits, kibibits, mebibits, ...)
|
41
|
+
#
|
42
|
+
# +:number_format+ - The format used by +to_s+ to turn a number into a string. See: +printf+
|
43
|
+
#
|
44
|
+
def initialize( opts = {} )
|
45
|
+
super DEFAULTS.merge( opts )
|
46
|
+
|
47
|
+
@last_sample = nil
|
48
|
+
@history = Array.new( @table[:history_size] ) { 0 }
|
49
|
+
@average = 0
|
50
|
+
end
|
51
|
+
|
52
|
+
# Runs the command if enough time has elapsed since the last
|
53
|
+
# poll. "Enough Time" is defined by the :delay option. Maintains the
|
54
|
+
# history of output, average and formatting.
|
55
|
+
#
|
56
|
+
def poll
|
57
|
+
return false unless super
|
58
|
+
|
59
|
+
@sample = @sample.to_s.to_f unless @sample.is_a? Float
|
60
|
+
@last_sample ||= @sample
|
61
|
+
sample = 8 * ( @sample - @last_sample )
|
62
|
+
@history.shift if @history.length >= @table[:history_size]
|
63
|
+
@history.push sample
|
64
|
+
@last_sample = @sample
|
65
|
+
@average = @table[:number_format] % send( @table[:unit] )
|
66
|
+
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns the average value in bits.
|
71
|
+
#
|
72
|
+
def bits
|
73
|
+
@history.inject( :+ ) / @history.count.to_f
|
74
|
+
end
|
75
|
+
alias :b :bits
|
76
|
+
|
77
|
+
# Returns the average value in kibibits.
|
78
|
+
#
|
79
|
+
def kibibits
|
80
|
+
bits / 1024.0
|
81
|
+
end
|
82
|
+
alias :kb :kibibits
|
83
|
+
|
84
|
+
# Returns the average value in mebibits.
|
85
|
+
#
|
86
|
+
def mebibits
|
87
|
+
kibibits / 1024.0
|
88
|
+
end
|
89
|
+
alias :mb :mebibits
|
90
|
+
|
91
|
+
# Returns the average value in gibibits.
|
92
|
+
#
|
93
|
+
def gibibits
|
94
|
+
mebibits / 1024.0
|
95
|
+
end
|
96
|
+
alias :gb :gibibits
|
97
|
+
|
98
|
+
# Returns the average value in tebibits.
|
99
|
+
#
|
100
|
+
def tebibits
|
101
|
+
gibibits / 1024.0
|
102
|
+
end
|
103
|
+
alias :tb :tebibits
|
104
|
+
|
105
|
+
# Returns the average value in pebibits.
|
106
|
+
#
|
107
|
+
def pebibits
|
108
|
+
tebibits / 1024.0
|
109
|
+
end
|
110
|
+
alias :pb :pebibits
|
111
|
+
|
112
|
+
# Returns the average value in exbibits.
|
113
|
+
#
|
114
|
+
def exbibits
|
115
|
+
pebibits / 1024.0
|
116
|
+
end
|
117
|
+
alias :eb :exbibits
|
118
|
+
|
119
|
+
# Returns the average value in zebibits.
|
120
|
+
#
|
121
|
+
def zebibits
|
122
|
+
exbibits / 1024.0
|
123
|
+
end
|
124
|
+
alias :zb :zebibits
|
125
|
+
|
126
|
+
# Returns the average value in yobibits.
|
127
|
+
#
|
128
|
+
def yobibits
|
129
|
+
zebibits / 1024.0
|
130
|
+
end
|
131
|
+
alias :yb :yobibits
|
132
|
+
|
133
|
+
# Returns the output of the command this Poll runs, formated as per the
|
134
|
+
# option :number_format.
|
135
|
+
#
|
136
|
+
def to_s
|
137
|
+
@average
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
@@ -0,0 +1,126 @@
|
|
1
|
+
|
2
|
+
require 'erb'
|
3
|
+
require 'yaml'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
require 'dock_driver' unless defined? DockDriver
|
7
|
+
require 'dock_driver/laika_hashutils'
|
8
|
+
require 'dock_driver/poll'
|
9
|
+
require 'dock_driver/data_rate_poll'
|
10
|
+
|
11
|
+
# An object that represents and drives a dock program, periodically
|
12
|
+
# updating what it displays.
|
13
|
+
#
|
14
|
+
class DockDriver::Dock < OpenStruct
|
15
|
+
|
16
|
+
include LAIKA::HashUtilities
|
17
|
+
|
18
|
+
# Default values to populate this OpenStruct with.
|
19
|
+
#
|
20
|
+
DEFAULTS = {
|
21
|
+
:polls => {},
|
22
|
+
:time_format => '%Y-%m-%d %H:%M:%S %Z',
|
23
|
+
:config_file => File.expand_path( '~/.dock_driver.yml' ),
|
24
|
+
:template => '',
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
# Create and start a new Dock.
|
28
|
+
#
|
29
|
+
# === Arguments:
|
30
|
+
#
|
31
|
+
# +:config_file+ - Provide a path to a config file different from
|
32
|
+
# the default: ~/.dock_driver.yml
|
33
|
+
#
|
34
|
+
# +:dock_command+ - Override the dock command from the config file.
|
35
|
+
#
|
36
|
+
def initialize( config_file = nil, dock_command = nil )
|
37
|
+
super DEFAULTS
|
38
|
+
@worker = nil
|
39
|
+
@table[:config_file] = config_file if config_file
|
40
|
+
load_config
|
41
|
+
@table[:dock_command] = dock_command if dock_command
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the result of the template.
|
45
|
+
#
|
46
|
+
def to_s()
|
47
|
+
# Poll everything.
|
48
|
+
@table[:polls].values.map( &:poll )
|
49
|
+
|
50
|
+
# Prepare a binding and render the ERB template.
|
51
|
+
vbind = OpenStruct.new( @table[:polls] ).send( :binding )
|
52
|
+
@table[:template].result( vbind ).gsub( /\s+/, ' ' )
|
53
|
+
end
|
54
|
+
|
55
|
+
# Start thiis Dock if it isn't already running, does nothing otherwise.
|
56
|
+
#
|
57
|
+
def run
|
58
|
+
@worker ||= Thread.new do
|
59
|
+
while true
|
60
|
+
File.popen( @table[:dock_command], 'w' ) do |pipe|
|
61
|
+
while true
|
62
|
+
pipe.puts self
|
63
|
+
pipe.flush
|
64
|
+
sleep 1
|
65
|
+
break if load_config
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
@worker.run unless @worker.status
|
71
|
+
@worker.join
|
72
|
+
end
|
73
|
+
|
74
|
+
# Forcibly stops this Dock if it is running, does nothing otherwise.
|
75
|
+
#
|
76
|
+
def kill
|
77
|
+
@worker.kill if @worker.status
|
78
|
+
end
|
79
|
+
|
80
|
+
#########
|
81
|
+
protected
|
82
|
+
#########
|
83
|
+
|
84
|
+
# Loads the configuration file defined by the option +:config_file+ if it has
|
85
|
+
# changed since this method was last called. If not, returns false.
|
86
|
+
#
|
87
|
+
# === Arguments:
|
88
|
+
#
|
89
|
+
# +force+ - If true, force a reload, even if the config file hasn't changed.
|
90
|
+
#
|
91
|
+
def load_config( force = false )
|
92
|
+
|
93
|
+
mtime = File.mtime @table[:config_file]
|
94
|
+
return false if not force and mtime == @table[:config_mtime]
|
95
|
+
|
96
|
+
@table.delete :template
|
97
|
+
hash = symbolify_keys( YAML.load_file( @table[:config_file] ) )
|
98
|
+
hash.delete :config_file
|
99
|
+
@table.merge! hash
|
100
|
+
@table[:config_mtime] = mtime
|
101
|
+
|
102
|
+
@table[:polls] = {}
|
103
|
+
|
104
|
+
if @table[:commands] and @table[:commands].is_a? Hash
|
105
|
+
@table[:commands].each do |name,hash|
|
106
|
+
klass = DockDriver::Poll
|
107
|
+
case hash[:type]
|
108
|
+
when /rate/i
|
109
|
+
klass = DockDriver::DataRatePoll
|
110
|
+
end
|
111
|
+
@table[:polls][name] = klass.new( hash )
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
if @table[:polls]['time'].nil?
|
116
|
+
@table[:polls]['time'] = DockDriver::Poll.new( { :delay => 1 } ) do
|
117
|
+
Time.now.strftime( @table[:time_format] )
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
@table[:template] = ERB.new( @table[:template] )
|
122
|
+
|
123
|
+
return true
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# A module borrowed from my coworkers at LAIKA.
|
2
|
+
#
|
3
|
+
module LAIKA
|
4
|
+
|
5
|
+
### A collection of utilities for working with Hashes.
|
6
|
+
module HashUtilities
|
7
|
+
|
8
|
+
###############
|
9
|
+
module_function
|
10
|
+
###############
|
11
|
+
|
12
|
+
### Return a version of the given +hash+ with its keys transformed
|
13
|
+
### into Strings from whatever they were before.
|
14
|
+
def stringify_keys( hash )
|
15
|
+
newhash = {}
|
16
|
+
|
17
|
+
hash.each do |key,val|
|
18
|
+
if val.is_a?( Hash )
|
19
|
+
newhash[ key.to_s ] = stringify_keys( val )
|
20
|
+
else
|
21
|
+
newhash[ key.to_s ] = val
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
return newhash
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
### Return a duplicate of the given +hash+ with its identifier-like keys
|
30
|
+
### transformed into symbols from whatever they were before.
|
31
|
+
def symbolify_keys( hash )
|
32
|
+
newhash = {}
|
33
|
+
|
34
|
+
hash.each do |key,val|
|
35
|
+
keysym = key.to_s.dup.untaint.to_sym
|
36
|
+
|
37
|
+
if val.is_a?( Hash )
|
38
|
+
newhash[ keysym ] = symbolify_keys( val )
|
39
|
+
else
|
40
|
+
newhash[ keysym ] = val
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
return newhash
|
45
|
+
end
|
46
|
+
alias_method :internify_keys, :symbolify_keys
|
47
|
+
|
48
|
+
|
49
|
+
# Recursive hash-merge function
|
50
|
+
def merge_recursively( key, oldval, newval )
|
51
|
+
case oldval
|
52
|
+
when Hash
|
53
|
+
case newval
|
54
|
+
when Hash
|
55
|
+
oldval.merge( newval, &method(:merge_recursively) )
|
56
|
+
else
|
57
|
+
newval
|
58
|
+
end
|
59
|
+
|
60
|
+
when Array
|
61
|
+
case newval
|
62
|
+
when Array
|
63
|
+
oldval | newval
|
64
|
+
else
|
65
|
+
newval
|
66
|
+
end
|
67
|
+
|
68
|
+
else
|
69
|
+
newval
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end # HashUtilities
|
74
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
require 'dock_driver' unless defined? DockDriver
|
5
|
+
|
6
|
+
# A class to provide simple, periodic command execution and caching.
|
7
|
+
#
|
8
|
+
class DockDriver::Poll < OpenStruct
|
9
|
+
|
10
|
+
# Default values to populate the OpenStruct with.
|
11
|
+
#
|
12
|
+
DEFAULTS = {
|
13
|
+
:delay => 1,
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
# Create a new Poll.
|
17
|
+
#
|
18
|
+
# === Arguments:
|
19
|
+
#
|
20
|
+
# +opts+ - A hash containing options. Merged with DEFAULTS.
|
21
|
+
#
|
22
|
+
# +block+ - If a block is given, replace :cmd with that block.
|
23
|
+
#
|
24
|
+
# === Options:
|
25
|
+
#
|
26
|
+
# +:delay+ - Determines the minimum amount of time to let elapse between executions.
|
27
|
+
#
|
28
|
+
# +:cmd+ - A string or block to execute.
|
29
|
+
#
|
30
|
+
# +:scan_regex+ - A bare string to be interpreted as a regex for use with +scan+. Any
|
31
|
+
# capture group matches will be joined with single spaces.
|
32
|
+
#
|
33
|
+
def initialize( opts = {}, &block )
|
34
|
+
super DEFAULTS.merge( opts )
|
35
|
+
@sample = nil
|
36
|
+
|
37
|
+
if block_given?
|
38
|
+
@table[:cmd] = block
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Runs the command if enough time has elapsed since the last poll. "Enough Time" is
|
43
|
+
# defined by the :delay option.
|
44
|
+
#
|
45
|
+
def poll
|
46
|
+
return false if @sample and (Time.now - (@table[:last_poll] || 0 )) < @table[:delay]
|
47
|
+
|
48
|
+
@table[:last_poll] = Time.now
|
49
|
+
|
50
|
+
case @table[:cmd]
|
51
|
+
when Proc
|
52
|
+
@sample = @table[:cmd].call
|
53
|
+
else
|
54
|
+
@sample = `#{@table[:cmd].to_s}`
|
55
|
+
end
|
56
|
+
|
57
|
+
if @table[:scan_regex]
|
58
|
+
extract = @sample.scan( Regexp.new( @table[:scan_regex] ) ).flatten
|
59
|
+
@sample = extract.join( ' ' ) unless extract.empty?
|
60
|
+
end
|
61
|
+
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns the output of the command this Poll runs.
|
66
|
+
#
|
67
|
+
def to_s
|
68
|
+
@sample
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
data/lib/dock_driver.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
# A namespace for the project.
|
3
|
+
#
|
4
|
+
module DockDriver
|
5
|
+
|
6
|
+
# Version Constant
|
7
|
+
VERSION = '0.1.0'
|
8
|
+
|
9
|
+
# Revision Constant
|
10
|
+
REVISION = %q$Revision: d17549778789 $
|
11
|
+
|
12
|
+
# Behold the author(s) responsible for this mess.
|
13
|
+
AUTHORS = [ 'Mike Hix <mike@musl.org>' ]
|
14
|
+
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
require 'pathname'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'dock_driver/dock'
|
5
|
+
|
6
|
+
describe DockDriver::Dock do
|
7
|
+
|
8
|
+
subject do
|
9
|
+
conf = Pathname( __FILE__ ).parent.parent.parent + 'data'
|
10
|
+
conf += 'example.dock_driver.yml'
|
11
|
+
dock = Dock.new conf, 'cat'
|
12
|
+
dock
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should be able to load a config file properly' do
|
16
|
+
subject.dock_command.should_not be nil
|
17
|
+
subject.template.should_not be nil
|
18
|
+
subject.polls.should have_at_least( 2 ).things
|
19
|
+
subject.polls.values.each { |p| p.should be_a_kind_of Poll }
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should only attempt to reload a config file with a more recent mtime' do
|
23
|
+
subject.send( :load_config ).should be false
|
24
|
+
FileUtils.touch subject.config_file
|
25
|
+
subject.send( :load_config ).should be true
|
26
|
+
subject.send( :load_config ).should be false
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should produce a string properly' do
|
30
|
+
|
31
|
+
# make sure we don't fail if a particular binary for an example doesn't exist.
|
32
|
+
subject.polls.values.each { |p| p.cmd = 'echo' }
|
33
|
+
|
34
|
+
string = subject.to_s
|
35
|
+
string.should be_a_kind_of String
|
36
|
+
string.should_not be ''
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
require 'dock_driver/poll'
|
3
|
+
require 'dock_driver/data_rate_poll'
|
4
|
+
|
5
|
+
include DockDriver
|
6
|
+
|
7
|
+
shared_examples 'Poll' do |klass|
|
8
|
+
|
9
|
+
it 'should be able to execute shell commands' do
|
10
|
+
p = Poll.new( :cmd => "echo" )
|
11
|
+
lambda { p.poll }.should_not raise_error
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should be able to execute blocks' do
|
15
|
+
p = Poll.new do; end
|
16
|
+
lambda { p.poll }.should_not raise_error
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should return the same object if polled quickly' do
|
20
|
+
p = Poll.new( :cmd => "echo" )
|
21
|
+
p.poll
|
22
|
+
a = p.to_s
|
23
|
+
p.poll
|
24
|
+
b = p.to_s
|
25
|
+
a.object_id.should == b.object_id
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should return a different object if polled slowly' do
|
29
|
+
p = Poll.new( :cmd => "echo", :delay => 0.1 )
|
30
|
+
p.poll
|
31
|
+
a = p.to_s
|
32
|
+
sleep 0.5
|
33
|
+
p.poll
|
34
|
+
b = p.to_s
|
35
|
+
a.object_id.should_not == b.object_id
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
describe Poll do
|
41
|
+
|
42
|
+
include_examples 'Poll', Poll
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
describe DataRatePoll do
|
47
|
+
|
48
|
+
include_examples 'Poll', DataRatePoll
|
49
|
+
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
require 'dock_driver'
|
3
|
+
|
4
|
+
describe DockDriver do
|
5
|
+
|
6
|
+
it 'should have a standard version number' do
|
7
|
+
defined?( VERSION ).should == 'constant'
|
8
|
+
VERSION.should =~ /^\d+\.\d+\.\d+$/
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should have a mercurial revision' do
|
12
|
+
defined?( REVISION ).should == 'constant'
|
13
|
+
REVISION.should =~ /^Revision: [[:xdigit:]]+ $/
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
data.tar.gz.sig
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3k�S���^���p���
|
metadata
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dock_driver
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Michael Hix
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain:
|
17
|
+
- |
|
18
|
+
-----BEGIN CERTIFICATE-----
|
19
|
+
MIIDKDCCAhCgAwIBAgIBADANBgkqhkiG9w0BAQUFADA6MQ0wCwYDVQQDDARtaWtl
|
20
|
+
MRQwEgYKCZImiZPyLGQBGRYEbXVzbDETMBEGCgmSJomT8ixkARkWA29yZzAeFw0x
|
21
|
+
MjA0MjUxODM4MjdaFw0xMzA0MjUxODM4MjdaMDoxDTALBgNVBAMMBG1pa2UxFDAS
|
22
|
+
BgoJkiaJk/IsZAEZFgRtdXNsMRMwEQYKCZImiZPyLGQBGRYDb3JnMIIBIjANBgkq
|
23
|
+
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyYKo5tTirdfMTksMM5DnnwLtGUnAPE++
|
24
|
+
pTPOenB29rVurrI2Vw8ndjbiWtaBOwb6jVdMzEwxBwVBa4r4FdSQO8rzEm1jV/+B
|
25
|
+
LEbl5xvOy/PRAXKvaUrQYCvuYtJA1py1mGIC8evNiH4jxZl0Fn9GrjNzzuRoSi/O
|
26
|
+
nLA4dcI5InCWAtUTUtMkMPn9mz9eZRnqd2yxziciwHzHkXBqVDACeAvo4PZUtTEL
|
27
|
+
aAs/yP3Hc/AH7StrwXb2KUJexSJximkAGg1J0iMCuKTBE9e534OXnE0NgCuyOrle
|
28
|
+
lpPTxF5umMpkiTwHLrmBWez3/JyAt1wt+5YWXamQBO1bGqzG/aGU1QIDAQABozkw
|
29
|
+
NzAdBgNVHQ4EFgQUPdX0JADsZMOtODSP0KlgqTgMG1cwCQYDVR0TBAIwADALBgNV
|
30
|
+
HQ8EBAMCBLAwDQYJKoZIhvcNAQEFBQADggEBADnlpP5hNPaM2x1q/lumvpHi1NU5
|
31
|
+
n1TJ13ZdVbRT1e9HbCs2nQ6TahIdf/1vdVlVldeNRDWxe2yXSG8RrpFZV1ATu+L/
|
32
|
+
mCGPM2NBUh3zT52kMiVJFh4jqI6SWLU/6vojxZms8jpghT7giA5KNQYN6ZK3jrTK
|
33
|
+
yocRBh/rTKHm7C207qTf/iLZj4kG60ozVdkYkZPlrP6/DkfyamnTHrmtN0W30xWC
|
34
|
+
V9AGPfVm7XVfb/wPkWPD3jgA77/j4KJrIH0ML0W9qypcYgH11X3RS0hBM+cx1WcX
|
35
|
+
Edc7ShBTME9+u6K/HFwVxTOH8WJVxkwGTmxKgCevr5mZzbINH/C6LbkmfEA=
|
36
|
+
-----END CERTIFICATE-----
|
37
|
+
|
38
|
+
date: 2012-05-16 00:00:00 Z
|
39
|
+
dependencies:
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: hoe-mercurial
|
42
|
+
prerelease: false
|
43
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ~>
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
hash: 7
|
49
|
+
segments:
|
50
|
+
- 1
|
51
|
+
- 4
|
52
|
+
- 0
|
53
|
+
version: 1.4.0
|
54
|
+
type: :development
|
55
|
+
version_requirements: *id001
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rdoc
|
58
|
+
prerelease: false
|
59
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ~>
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
hash: 19
|
65
|
+
segments:
|
66
|
+
- 3
|
67
|
+
- 10
|
68
|
+
version: "3.10"
|
69
|
+
type: :development
|
70
|
+
version_requirements: *id002
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: hoe
|
73
|
+
prerelease: false
|
74
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ~>
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
hash: 7
|
80
|
+
segments:
|
81
|
+
- 3
|
82
|
+
- 0
|
83
|
+
version: "3.0"
|
84
|
+
type: :development
|
85
|
+
version_requirements: *id003
|
86
|
+
description: |-
|
87
|
+
Provides a simple executable to drive a dzen2 (or similar) dock with a
|
88
|
+
single YAML config file.
|
89
|
+
|
90
|
+
Read +example.dock_driver.yml+ for more information about how to get
|
91
|
+
started. It's located in this gem's data directory, which is usually:
|
92
|
+
$GEM_HOME/gems/dock_driver-x.y.z/data/
|
93
|
+
email:
|
94
|
+
- mike@musl.org
|
95
|
+
executables:
|
96
|
+
- dock_driver
|
97
|
+
extensions: []
|
98
|
+
|
99
|
+
extra_rdoc_files:
|
100
|
+
- History.txt
|
101
|
+
- Ideas.txt
|
102
|
+
- Manifest.txt
|
103
|
+
- README.txt
|
104
|
+
files:
|
105
|
+
- .autotest
|
106
|
+
- .hgignore
|
107
|
+
- History.txt
|
108
|
+
- Ideas.txt
|
109
|
+
- Manifest.txt
|
110
|
+
- README.txt
|
111
|
+
- Rakefile
|
112
|
+
- bin/dock_driver
|
113
|
+
- data/example.dock_driver.yml
|
114
|
+
- lib/dock_driver.rb
|
115
|
+
- lib/dock_driver/laika_hashutils.rb
|
116
|
+
- lib/dock_driver/poll.rb
|
117
|
+
- lib/dock_driver/data_rate_poll.rb
|
118
|
+
- lib/dock_driver/dock.rb
|
119
|
+
- spec/dock_driver/dock_spec.rb
|
120
|
+
- spec/dock_driver/poll_spec.rb
|
121
|
+
- spec/dock_driver_spec.rb
|
122
|
+
- .gemtest
|
123
|
+
homepage: http://hg.musl.org/projects/dock_driver/
|
124
|
+
licenses: []
|
125
|
+
|
126
|
+
post_install_message:
|
127
|
+
rdoc_options:
|
128
|
+
- --main
|
129
|
+
- README.txt
|
130
|
+
require_paths:
|
131
|
+
- lib
|
132
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
133
|
+
none: false
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
hash: 57
|
138
|
+
segments:
|
139
|
+
- 1
|
140
|
+
- 8
|
141
|
+
- 7
|
142
|
+
version: 1.8.7
|
143
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
|
+
none: false
|
145
|
+
requirements:
|
146
|
+
- - ">="
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
hash: 31
|
149
|
+
segments:
|
150
|
+
- 1
|
151
|
+
- 8
|
152
|
+
version: "1.8"
|
153
|
+
requirements: []
|
154
|
+
|
155
|
+
rubyforge_project: dock_driver
|
156
|
+
rubygems_version: 1.8.17
|
157
|
+
signing_key:
|
158
|
+
specification_version: 3
|
159
|
+
summary: Provides a simple executable to drive a dzen2 (or similar) dock with a single YAML config file
|
160
|
+
test_files: []
|
161
|
+
|
metadata.gz.sig
ADDED
Binary file
|