salticid 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|