salticid 0.9.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/LICENSE +7 -0
- data/README.markdown +11 -0
- data/lib/monkeypatch.rb +21 -0
- data/lib/salticid.rb +205 -0
- data/lib/salticid/config.rb +17 -0
- data/lib/salticid/gateway.rb +23 -0
- data/lib/salticid/group.rb +99 -0
- data/lib/salticid/host.rb +600 -0
- data/lib/salticid/host/ip.rb +19 -0
- data/lib/salticid/interface.rb +192 -0
- data/lib/salticid/interface/conversation_view.rb +150 -0
- data/lib/salticid/interface/host_view.rb +123 -0
- data/lib/salticid/interface/ncurses.rb +30 -0
- data/lib/salticid/interface/resizable.rb +28 -0
- data/lib/salticid/interface/tab_view.rb +134 -0
- data/lib/salticid/interface/view.rb +49 -0
- data/lib/salticid/message.rb +8 -0
- data/lib/salticid/role.rb +98 -0
- data/lib/salticid/role_proxy.rb +26 -0
- data/lib/salticid/task.rb +49 -0
- data/lib/salticid/version.rb +3 -0
- data/lib/snippets/init.rb +5 -0
- data/lib/snippets/object/__dir__.rb +23 -0
- data/lib/snippets/object/instance_exec.rb +14 -0
- data/lib/snippets/string/slash.rb +6 -0
- data/lib/snippets/symbol/slash.rb +6 -0
- data/lib/snippets/symbol/to_proc.rb +15 -0
- metadata +167 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Ncurses
|
|
2
|
+
# Returns size of screen [y, x]
|
|
3
|
+
def self.dimensions
|
|
4
|
+
x = Array.new
|
|
5
|
+
y = Array.new
|
|
6
|
+
Ncurses.getmaxyx(Ncurses.stdscr, y, x)
|
|
7
|
+
[y.first, x.first]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class WINDOW
|
|
11
|
+
# Adds a FormattedString
|
|
12
|
+
def add_formatted_string(string)
|
|
13
|
+
string.each do |part|
|
|
14
|
+
# Set attributes
|
|
15
|
+
part[1..-1].each {| attribute| attron attribute }
|
|
16
|
+
addstr part[0]
|
|
17
|
+
# Unset attributes
|
|
18
|
+
part[1..-1].each {| attribute| attroff attribute }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns cursor y and x coordinates.
|
|
23
|
+
def cursor
|
|
24
|
+
y = Array.new
|
|
25
|
+
x = Array.new
|
|
26
|
+
getyx y, x
|
|
27
|
+
[y.first, x.first]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
class Salticid
|
|
2
|
+
class Interface
|
|
3
|
+
module Resizeable
|
|
4
|
+
def resize(dimensions = nil)
|
|
5
|
+
case dimensions
|
|
6
|
+
when Hash
|
|
7
|
+
# Resize self
|
|
8
|
+
@height = dimensions[:height] if dimensions[:height]
|
|
9
|
+
@width = dimensions[:width] if dimensions[:width]
|
|
10
|
+
@top = dimensions[:top] if dimensions[:top]
|
|
11
|
+
@left = dimensions[:left] if dimensions[:left]
|
|
12
|
+
|
|
13
|
+
if @window
|
|
14
|
+
# Resize window
|
|
15
|
+
@window.mvwin @top, @left
|
|
16
|
+
@window.resize @height, @width
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
true
|
|
20
|
+
else
|
|
21
|
+
# Resize parent
|
|
22
|
+
@interface.resize
|
|
23
|
+
false
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
class Salticid
|
|
2
|
+
class Interface
|
|
3
|
+
class TabView < View
|
|
4
|
+
|
|
5
|
+
def initialize(interface, params = {})
|
|
6
|
+
super
|
|
7
|
+
|
|
8
|
+
@tabs = []
|
|
9
|
+
@active = -1
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Gets the active tab
|
|
13
|
+
def active
|
|
14
|
+
@tabs[@active] || nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Sets the active tab
|
|
18
|
+
def active=(tab)
|
|
19
|
+
@active = @tabs.index tab
|
|
20
|
+
render
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Adds a tab (and switches to it by default)
|
|
24
|
+
def add(tab)
|
|
25
|
+
@tabs << tab
|
|
26
|
+
@active = @tabs.size - 1
|
|
27
|
+
render
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
alias :<< :add
|
|
31
|
+
|
|
32
|
+
# Deletes a tab and switches to the previous tab
|
|
33
|
+
def delete(tab)
|
|
34
|
+
@tabs.delete tab
|
|
35
|
+
previous
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Iterates over each tab
|
|
39
|
+
def each(&block)
|
|
40
|
+
@tabs.each &block
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Advances to the next tab
|
|
44
|
+
def next
|
|
45
|
+
scroll 1
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Goes to the previous tab
|
|
49
|
+
def previous
|
|
50
|
+
scroll -1
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Draws to screen
|
|
54
|
+
def render
|
|
55
|
+
return false if @tabs.empty?
|
|
56
|
+
# Divide into regions
|
|
57
|
+
|
|
58
|
+
# Ignore dividers
|
|
59
|
+
width = @width - size + 1
|
|
60
|
+
base_width = width / size
|
|
61
|
+
regions = Array.new(size, base_width)
|
|
62
|
+
|
|
63
|
+
# Add remainder to successive tabs.
|
|
64
|
+
(width - base_width * size).times do |i|
|
|
65
|
+
regions[i] += 1
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Move to start
|
|
69
|
+
@window.move 0,0
|
|
70
|
+
|
|
71
|
+
@tabs.each_with_index do |tab, i|
|
|
72
|
+
if i > 0
|
|
73
|
+
@window.addch Ncurses::ACS_VLINE
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
color = Interface::COLOR_PAIRS[tab.state]
|
|
77
|
+
@window.attron color if color
|
|
78
|
+
@window.attron Ncurses::A_BOLD
|
|
79
|
+
@window.attron Ncurses::A_REVERSE if i == @active
|
|
80
|
+
@window.addstr tab.to_s.slice(0,regions[i]).center(regions[i])
|
|
81
|
+
@window.attroff Ncurses::A_REVERSE if i == @active
|
|
82
|
+
@window.attroff Ncurses::A_BOLD
|
|
83
|
+
@window.attroff color if color
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
@window.refresh
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def resize(dimensions = nil)
|
|
90
|
+
return unless super
|
|
91
|
+
|
|
92
|
+
@tabs.each do |tab|
|
|
93
|
+
tab.resize(
|
|
94
|
+
:top => 1,
|
|
95
|
+
:left => 0,
|
|
96
|
+
:height => height - 1,
|
|
97
|
+
:width => width
|
|
98
|
+
)
|
|
99
|
+
end
|
|
100
|
+
active.render
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Moves by a number of tabs
|
|
104
|
+
def scroll(delta = 1)
|
|
105
|
+
active.hide rescue NoMethodError
|
|
106
|
+
@active = (@active + delta).modulo(@tabs.size)
|
|
107
|
+
active.show
|
|
108
|
+
render
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def shutdown
|
|
112
|
+
@tabs.each do |tab|
|
|
113
|
+
tab.shutdown
|
|
114
|
+
end
|
|
115
|
+
@tabs = []
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Number of tabs
|
|
119
|
+
def size
|
|
120
|
+
@tabs.size
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Switches the active tab to the specified label
|
|
124
|
+
def switch_to_label(label)
|
|
125
|
+
if index = @tabs.map{ |tab| tab.to_s }.index(label)
|
|
126
|
+
@active = index
|
|
127
|
+
render
|
|
128
|
+
else
|
|
129
|
+
raise RuntimeError.new("no tab labeled #{label}")
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
class Salticid
|
|
2
|
+
class Interface
|
|
3
|
+
class View
|
|
4
|
+
include Resizeable
|
|
5
|
+
|
|
6
|
+
attr_accessor :window, :height, :width, :top, :left
|
|
7
|
+
|
|
8
|
+
def initialize(interface, params = {})
|
|
9
|
+
@interface = interface
|
|
10
|
+
@height = params[:height] || Ncurses.LINES
|
|
11
|
+
@width = params[:width] || Ncurses.COLS
|
|
12
|
+
@top = params[:top] || 0
|
|
13
|
+
@left = params[:left] || 0
|
|
14
|
+
|
|
15
|
+
@window = Ncurses::WINDOW.new @height, @width, @top, @left
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def height=(height)
|
|
19
|
+
@height = height
|
|
20
|
+
@window.resize @height, @width
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def hide
|
|
24
|
+
@hidden = true
|
|
25
|
+
@window.erase
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def left=(left)
|
|
29
|
+
@left = left
|
|
30
|
+
@window.mvwin @top, @left
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def show
|
|
34
|
+
@hidden = false
|
|
35
|
+
render
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def top=(top)
|
|
39
|
+
@top = top
|
|
40
|
+
@window.mvwin @top, @left
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def width=(width)
|
|
44
|
+
@width = width
|
|
45
|
+
@window.resize @height, @width
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
class Salticid::Role
|
|
2
|
+
# A role is a list of tasks.
|
|
3
|
+
attr_reader :name, :tasks, :salticid
|
|
4
|
+
|
|
5
|
+
def initialize(name, opts = {})
|
|
6
|
+
@name = name.to_s
|
|
7
|
+
@tasks = []
|
|
8
|
+
@salticid = opts[:salticid]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Runs the block in the context of each.
|
|
12
|
+
def each_host(&block)
|
|
13
|
+
hosts.each do |host|
|
|
14
|
+
host.instance_exec &block
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Returns an array of all hosts in this salticid which include this role.
|
|
19
|
+
def hosts
|
|
20
|
+
@salticid.hosts.select do |host|
|
|
21
|
+
host.roles.include? self
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def inspect
|
|
26
|
+
"#<Role #{name} tasks=#{@tasks.inspect}>"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Sets or gets the name of this role.
|
|
30
|
+
def name(name = nil)
|
|
31
|
+
if name
|
|
32
|
+
@name = name.to_s
|
|
33
|
+
else
|
|
34
|
+
@name
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Finds (and optionally defines) a task.
|
|
39
|
+
#
|
|
40
|
+
# Tasks are first resolved in the role's task list, then in the Salticid's task
|
|
41
|
+
# list. Finally, tasks are created from scratch. Any invocation of task adds
|
|
42
|
+
# that task to this role.
|
|
43
|
+
#
|
|
44
|
+
# If a block is given, the block is assigned to the local (role) task. The
|
|
45
|
+
# task is dup'ed to prevent modifying a possible global task.
|
|
46
|
+
#
|
|
47
|
+
# The task is returned at the end of the method.
|
|
48
|
+
def task(name, &block)
|
|
49
|
+
name = name.to_s
|
|
50
|
+
|
|
51
|
+
if task = @tasks.find{|t| t.name == name}
|
|
52
|
+
# Found in self
|
|
53
|
+
elsif (task = @salticid.tasks.find{|t| t.name == name}) and not block_given?
|
|
54
|
+
# Found in salticid
|
|
55
|
+
@tasks << task
|
|
56
|
+
else
|
|
57
|
+
# Create new task in self
|
|
58
|
+
task = Salticid::Task.new(name, :salticid => @salticid)
|
|
59
|
+
@tasks << task
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
if block_given?
|
|
63
|
+
# Remove the task from our list, and replace it with a copy.
|
|
64
|
+
# This is to prevent local declarations from clobbering global tasks.
|
|
65
|
+
i = @tasks.index(task) || @task.size
|
|
66
|
+
task = task.dup
|
|
67
|
+
task.block = block
|
|
68
|
+
@tasks[i] = task
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
task
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def to_s
|
|
75
|
+
@name.to_s
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def to_string
|
|
79
|
+
r = "Role #{@name}:\n"
|
|
80
|
+
r << " Tasks:\n"
|
|
81
|
+
r << tasks.map { |t| " #{t}" }.sort!.join("\n")
|
|
82
|
+
r << "\n Hosts:\n"
|
|
83
|
+
r << hosts.map { |h| " #{h}" }.join("\n")
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# When a task name is called on a role, it is automatically run on every host
|
|
87
|
+
# associated with that role.
|
|
88
|
+
#
|
|
89
|
+
# role(:myapp).deploy => role(:myapp).each_host { |h| h.myapp.deploy }
|
|
90
|
+
def method_missing(meth, *args, &block)
|
|
91
|
+
name = meth.to_s
|
|
92
|
+
if task = @tasks.find { |t| t.name == name }
|
|
93
|
+
hosts.each do |host|
|
|
94
|
+
task.run(host, *args)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
class RoleProxy
|
|
2
|
+
# Wraps a Role in the context of a Host: calls to the RoleProxy are passed to
|
|
3
|
+
# the Role it wraps, but called with the host as the first argument. This
|
|
4
|
+
# allows role-method chaining for nice namespaces.
|
|
5
|
+
#
|
|
6
|
+
# RoleProxy.new(host, role).some_task(*args) =>
|
|
7
|
+
# role.some_task(host, *args)
|
|
8
|
+
#
|
|
9
|
+
# RoleProxies are created on the fly by Hosts; you shouldn't have to
|
|
10
|
+
# instantiate them directly. They're involved when you do something like:
|
|
11
|
+
#
|
|
12
|
+
# host :foo do
|
|
13
|
+
# my_role.some_task
|
|
14
|
+
# end
|
|
15
|
+
|
|
16
|
+
undef_method(*(instance_methods.map(&:intern) - [:__id__, :__send__, :respond_to?, :object_id]))
|
|
17
|
+
|
|
18
|
+
def initialize(host, role)
|
|
19
|
+
@host = host
|
|
20
|
+
@role = role
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def method_missing(meth, *args, &block)
|
|
24
|
+
@role.tasks.find{|t| t.name == meth.to_s}.run(@host, *args, &block)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
class Salticid::Task
|
|
2
|
+
# A named block, runnable in some context
|
|
3
|
+
attr_accessor :name, :block
|
|
4
|
+
|
|
5
|
+
def initialize(name, opts = {})
|
|
6
|
+
@name = name.to_s
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def ==(other)
|
|
10
|
+
self.name == other.name and
|
|
11
|
+
self.block == other.block
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def dup
|
|
15
|
+
dup = Salticid::Task.new(@name)
|
|
16
|
+
dup.block = @block
|
|
17
|
+
dup
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def inspect
|
|
21
|
+
"#<Task #{@name}>"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Sets or gets the name of this task.
|
|
25
|
+
def name(name = nil)
|
|
26
|
+
if name
|
|
27
|
+
@name = name.to_s
|
|
28
|
+
else
|
|
29
|
+
@name
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Runs the task in a given context
|
|
34
|
+
def run(context = nil, *args)
|
|
35
|
+
if context
|
|
36
|
+
context.instance_exec(*args, &@block)
|
|
37
|
+
else
|
|
38
|
+
@block.call(*args)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def to_s
|
|
43
|
+
@name.to_s
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def to_string
|
|
47
|
+
"Task #{self}"
|
|
48
|
+
end
|
|
49
|
+
end
|