rudy 0.3.2 → 0.4.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/CHANGES.txt +53 -3
- data/README.rdoc +9 -5
- data/bin/rudy +115 -292
- data/bin/rudy-ec2 +107 -0
- data/lib/console.rb +322 -278
- data/lib/rudy.rb +78 -55
- data/lib/rudy/aws/ec2.rb +63 -5
- data/lib/rudy/command/addresses.rb +18 -13
- data/lib/rudy/command/backups.rb +175 -0
- data/lib/rudy/command/base.rb +664 -146
- data/lib/rudy/command/config.rb +77 -0
- data/lib/rudy/command/deploy.rb +12 -0
- data/lib/rudy/command/disks.rb +165 -195
- data/lib/rudy/command/environment.rb +42 -64
- data/lib/rudy/command/groups.rb +21 -19
- data/lib/rudy/command/images.rb +34 -19
- data/lib/rudy/command/instances.rb +46 -92
- data/lib/rudy/command/machines.rb +161 -0
- data/lib/rudy/command/metadata.rb +14 -30
- data/lib/rudy/command/release.rb +174 -0
- data/lib/rudy/command/volumes.rb +26 -10
- data/lib/rudy/config.rb +93 -0
- data/lib/rudy/metadata/backup.rb +1 -1
- data/lib/rudy/metadata/disk.rb +15 -50
- data/lib/rudy/scm/svn.rb +32 -21
- data/lib/rudy/utils.rb +2 -3
- data/lib/storable.rb +4 -0
- data/lib/tryouts.rb +40 -0
- data/rudy.gemspec +25 -9
- data/support/mailtest +40 -0
- data/support/rudy-ec2-startup +41 -15
- data/tryouts/console_tryout.rb +91 -0
- metadata +86 -11
- data/lib/drydock.rb +0 -524
- data/lib/rudy/command/stage.rb +0 -45
- data/lib/rudy/metadata/config.rb +0 -8
- data/lib/rudy/metadata/environment.rb +0 -0
data/bin/rudy-ec2
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# Rudy -- Your friend in staging and deploying to EC2
|
4
|
+
#
|
5
|
+
# See rudy -h for usage
|
6
|
+
#
|
7
|
+
|
8
|
+
#
|
9
|
+
# No Ruby 1.9.1 support. Only 1.8.x for now :[
|
10
|
+
unless RUBY_VERSION < "1.9"
|
11
|
+
puts "Sorry! We're using the right_aws gem and it doesn't support Ruby 1.9 (md5 error)."
|
12
|
+
exit 1
|
13
|
+
else
|
14
|
+
require 'rubygems'
|
15
|
+
end
|
16
|
+
|
17
|
+
RUDY_HOME = File.join(File.dirname(__FILE__), '..')
|
18
|
+
RUDY_LIB = File.join(RUDY_HOME, 'lib')
|
19
|
+
$:.unshift RUDY_LIB # Put our local lib in first place
|
20
|
+
|
21
|
+
require 'drydock'
|
22
|
+
extend Drydock
|
23
|
+
|
24
|
+
project "Rudy" # This also runs require 'ruby'
|
25
|
+
|
26
|
+
debug :on
|
27
|
+
|
28
|
+
capture :stderr
|
29
|
+
|
30
|
+
global :A, :accesskey, String, "AWS Access Key"
|
31
|
+
global :S, :secretkey, String, "AWS Secret Access Key"
|
32
|
+
global :R, :region, String, "Connect to a specific EC2 region (default: #{Rudy::DEFAULT_REGION})"
|
33
|
+
global :z, :zone, String, "Connect to a specific EC2 zone (default: #{Rudy::DEFAULT_ZONE})"
|
34
|
+
global :q, :quiet, "Run with less output"
|
35
|
+
global :v, :verbose, "Increase verbosity of output (i.e. -v or -vv or -vvv)" do
|
36
|
+
@verbose ||= 0
|
37
|
+
@verbose += 1
|
38
|
+
end
|
39
|
+
global :V, :version, "Display version number" do
|
40
|
+
puts "Rudy version: #{Rudy::VERSION}"
|
41
|
+
exit 0
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
# ----------------------------------- AMAZON EC2 COMMANDS --------
|
49
|
+
# ------------------------------------------------------------------
|
50
|
+
|
51
|
+
usage "rudy [global options] addresses [-A address instance ID]"
|
52
|
+
desc "Manage Amazon Elastic IP addresses"
|
53
|
+
argv :address, :instanceid
|
54
|
+
action :A, :associate, "Associate an address to a running instance"
|
55
|
+
command :addresses => Rudy::Command::Addresses
|
56
|
+
command_alias :addresses, :address
|
57
|
+
|
58
|
+
|
59
|
+
usage "rudy images [-C -i name [-b bucket -a account]] [-D AMI-ID]"
|
60
|
+
desc "Manage EC2 Machine Images (AMIs)"
|
61
|
+
option :a, :account, String, "Your Amazon Account Number"
|
62
|
+
option :i, :image_name, String, "The name of the image"
|
63
|
+
option :b, :bucket_name, String, "The name of the bucket that will store the image"
|
64
|
+
action :C, :create, "Create an image"
|
65
|
+
#action :P, :prepare, "Prepare a running instance to be used as an image"
|
66
|
+
action :D, :destroy, "Deregister an image (currently _does not_ remove images files from S3)"
|
67
|
+
argv :ami
|
68
|
+
command :images => Rudy::Command::Images
|
69
|
+
command_alias :images, :image
|
70
|
+
|
71
|
+
|
72
|
+
desc "Manage EC2 Volumes"
|
73
|
+
action :D, :destroy, "Destroy a volume"
|
74
|
+
argv :vol
|
75
|
+
command :volumes => Rudy::Command::Volumes
|
76
|
+
command_alias :volumes, :volume
|
77
|
+
|
78
|
+
|
79
|
+
usage "rudy [global options] instances [-D] [-S -i image ID] [instance ID OR group name]"
|
80
|
+
desc "Manage EC2 Instances"
|
81
|
+
option :all, "Display all instances"
|
82
|
+
option :a, :address, String, "Amazon elastic IP"
|
83
|
+
option :i, :image, String, "Amazon machine image ID (ami)"
|
84
|
+
#option :v, :volume, String, "Amazon volume ID"
|
85
|
+
action :D, :destroy, "Destroy the given instance IDs. All data will be lost!"
|
86
|
+
#action :S, :start, "Start an instance"
|
87
|
+
#action :R, :restart, "Restart an instance"
|
88
|
+
argv :filter
|
89
|
+
command :instances => Rudy::Command::Instances
|
90
|
+
command_alias :instances, :instance
|
91
|
+
|
92
|
+
|
93
|
+
usage "rudy [global options] groups [-C] [-a IP addresses] [-p ports] [group name]"
|
94
|
+
desc "Manage EC2 Security Groups"
|
95
|
+
option :all, "Display all security groups"
|
96
|
+
option :r, :protocols, Array, "Comma-separated list of protocols. One of: tcp (default), udp, icmp"
|
97
|
+
option :p, :ports, Array, "List of comma-separated ports to authorize (default: 22,80,443)"
|
98
|
+
option :a, :addresses, Array, "List of comma-separated IP addresses to authorize (default: your external IP)"
|
99
|
+
action :C, :create, "Create a security group"
|
100
|
+
action :D, :destroy, "Destroy a security group"
|
101
|
+
action :M, :modify, "Modify a security group"
|
102
|
+
argv :group
|
103
|
+
command :groups => Rudy::Command::Groups
|
104
|
+
command_alias :groups, :group
|
105
|
+
|
106
|
+
|
107
|
+
|
data/lib/console.rb
CHANGED
@@ -1,341 +1,385 @@
|
|
1
|
-
|
1
|
+
#---
|
2
2
|
# Adapted from: http://github.com/oneup/ruby-console/tree/tput
|
3
|
+
# See: http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x405.html
|
4
|
+
# See: man terminfo
|
5
|
+
#+++
|
3
6
|
|
4
|
-
if __FILE__ == $0
|
5
|
-
puts "This is a module, don't run it from the command line."
|
6
|
-
exit
|
7
|
-
end
|
8
7
|
|
9
8
|
class String
|
10
|
-
|
11
|
-
|
9
|
+
|
10
|
+
# +col+, +bgcol+, and +attribute+ are symbols corresponding
|
11
|
+
# to Console::COLOURS, Console::BGCOLOURS, and Console::ATTRIBUTES.
|
12
|
+
# Returns the string in the format attributes + string + defaults.
|
13
|
+
#
|
14
|
+
# "MONKEY_JUNK".colour(:blue, :white, :blink) # => "\e[34;47;5mMONKEY_JUNK\e[39;49;0m"
|
15
|
+
#
|
16
|
+
def colour(col, bgcol = nil, attribute = nil)
|
17
|
+
Console.style(col, bgcol, attribute) +
|
12
18
|
self +
|
13
|
-
Console.
|
19
|
+
Console.style(:default, :default, :default)
|
14
20
|
end
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
row = arg[0]
|
23
|
-
end
|
24
|
-
if arg.length > 1
|
25
|
-
col = arg[1]
|
26
|
-
end
|
27
|
-
Cursor.save
|
28
|
-
Cursor.position = row, col
|
29
|
-
print self
|
30
|
-
Cursor.restore
|
21
|
+
alias :color :colour
|
22
|
+
|
23
|
+
# See colour
|
24
|
+
def bgcolour(bgcol = :default)
|
25
|
+
Console.style(nil, bgcol, nil) +
|
26
|
+
self +
|
27
|
+
Console.style(nil, :default, nil)
|
31
28
|
end
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
def
|
36
|
-
|
29
|
+
alias :bgcolor :bgcolour
|
30
|
+
|
31
|
+
# See colour
|
32
|
+
def att(a = :default)
|
33
|
+
Console.style(nil, nil, a) +
|
34
|
+
self +
|
35
|
+
Console.style(nil, nil, :default)
|
37
36
|
end
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
|
38
|
+
|
39
|
+
# Print the string at +x+ +y+. When +minus+ is any true value
|
40
|
+
# the length of the string is subtracted from the value of x
|
41
|
+
# before printing.
|
42
|
+
def print_at(x=nil, y=nil, minus=false)
|
43
|
+
args = {:minus=>minus}
|
44
|
+
args[:x] &&= x
|
45
|
+
args[:y] &&= y
|
46
|
+
Console.print_at(self, args)
|
41
47
|
end
|
42
48
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
:bright => 1,
|
53
|
-
:dim => 2,
|
54
|
-
:underscore => 4,
|
55
|
-
:blink => 5,
|
56
|
-
:reverse => 7,
|
57
|
-
:hidden => 8,
|
58
|
-
:default => 0
|
59
|
-
}
|
60
|
-
fg_color = { # mapper for the foreground color
|
61
|
-
:black => 30,
|
62
|
-
:red => 31,
|
63
|
-
:green => 32,
|
64
|
-
:yellow => 33,
|
65
|
-
:blue => 34,
|
66
|
-
:magenta => 35,
|
67
|
-
:cyan => 36,
|
68
|
-
:white => 37,
|
69
|
-
:default => 39
|
70
|
-
}
|
71
|
-
bg_color = { # mapper for the background color
|
72
|
-
:bg_black => 40,
|
73
|
-
:bg_red => 41,
|
74
|
-
:bg_green => 42,
|
75
|
-
:bg_yellow => 43,
|
76
|
-
:bg_blue => 44,
|
77
|
-
:bg_magenta => 45,
|
78
|
-
:bg_cyan => 46,
|
79
|
-
:bg_white => 47,
|
80
|
-
:bg_default => 49
|
81
|
-
}
|
82
|
-
if arg.length > 0 # turn symbols into numbers
|
83
|
-
arg[0] = attribute[arg[0]] # attributes
|
84
|
-
end
|
85
|
-
if arg.length > 1
|
86
|
-
arg[1] = fg_color[arg[1]] # foreground color
|
87
|
-
end
|
88
|
-
if arg.length > 2
|
89
|
-
arg[2] = bg_color[arg[2]] # background color
|
90
|
-
end
|
91
|
-
"\e[#{arg.join(";")}m" # magic ansi escape sequence
|
49
|
+
# Returns the string with escape code attributes removed.
|
50
|
+
# NOTE: The non-printable attributes count towards the string size.
|
51
|
+
# You can use this method to get the "visible" size:
|
52
|
+
#
|
53
|
+
# "\e[34;47;5mMONKEY_JUNK\e[39;49;0m".noatt.size # => 11
|
54
|
+
# "\e[34;47;5mMONKEY_JUNK\e[39;49;0m".size # => 31
|
55
|
+
#
|
56
|
+
def noatt
|
57
|
+
gsub(/\e\[[\d;]*m/, '')
|
92
58
|
end
|
59
|
+
end
|
93
60
|
|
94
|
-
|
95
|
-
if not arg.is_a?(Array)
|
96
|
-
arg = [arg]
|
97
|
-
end
|
98
|
-
if arg.length == 0
|
99
|
-
arg = :default, :red, :bg_default
|
100
|
-
end
|
101
|
-
print self.color(arg)
|
102
|
-
end
|
61
|
+
class Object
|
103
62
|
|
104
|
-
|
105
|
-
|
63
|
+
# Executes tput +capnam+ with +args+. Returns true if tcap gives
|
64
|
+
# 0 exit status and false otherwise.
|
65
|
+
#
|
66
|
+
# tput :cup, 1, 4
|
67
|
+
# $ tput cup 1 4
|
68
|
+
#
|
69
|
+
def tput(capnam, *args)
|
70
|
+
system("tput #{capnam} #{args.flatten.join(' ')}")
|
106
71
|
end
|
107
|
-
|
108
|
-
|
109
|
-
|
72
|
+
|
73
|
+
# Executes tput +capnam+ with +args+. Returns the output of tput.
|
74
|
+
#
|
75
|
+
# tput_val :cols # => 16
|
76
|
+
# $ tput cols # => 16
|
77
|
+
#
|
78
|
+
def tput_val(capnam, *args)
|
79
|
+
`tput #{capnam} #{args.flatten.join(' ')}`.chomp
|
110
80
|
end
|
111
81
|
end
|
112
82
|
|
113
|
-
class Cursor
|
114
|
-
def self.position
|
115
|
-
row = ""
|
116
|
-
col = ""
|
117
|
-
c = ""
|
118
|
-
|
119
|
-
termsettings = `stty -g`
|
120
|
-
system("stty raw -echo")
|
121
|
-
print "\e[6n"
|
122
|
-
while (c = STDIN.getc.chr) != ";"
|
123
|
-
if c == "\e" or c == "["
|
124
|
-
next
|
125
|
-
else
|
126
|
-
row += c
|
127
|
-
end
|
128
|
-
end
|
129
|
-
while (c = STDIN.getc.chr) != "R"
|
130
|
-
col += c
|
131
|
-
end
|
132
|
-
system("stty #{termsettings}")
|
133
|
-
|
134
|
-
[row, col]
|
135
|
-
end
|
136
83
|
|
137
|
-
def self.position=(arg)
|
138
|
-
row = 0
|
139
|
-
col = 0
|
140
|
-
if not arg.is_a?(Array)
|
141
|
-
arg = [arg]
|
142
|
-
end
|
143
|
-
if arg.length > 0
|
144
|
-
row = arg[0]
|
145
|
-
end
|
146
|
-
if arg.length > 1
|
147
|
-
col = arg[1]
|
148
|
-
end
|
149
|
-
system "tput cup #{row} #{col}"
|
150
|
-
end
|
151
84
|
|
152
|
-
|
153
|
-
|
154
|
-
|
85
|
+
module Console
|
86
|
+
extend self
|
87
|
+
require 'timeout'
|
88
|
+
require 'thread'
|
89
|
+
|
90
|
+
# ANSI escape sequence numbers for text attributes
|
91
|
+
ATTRIBUTES = {
|
92
|
+
:normal => 0,
|
93
|
+
:bright => 1,
|
94
|
+
:dim => 2,
|
95
|
+
:underline => 4,
|
96
|
+
:blink => 5,
|
97
|
+
:reverse => 7,
|
98
|
+
:hidden => 8,
|
99
|
+
:default => 0,
|
100
|
+
}.freeze unless defined? ATTRIBUTES
|
101
|
+
|
102
|
+
# ANSI escape sequence numbers for text colours
|
103
|
+
COLOURS = {
|
104
|
+
:black => 30,
|
105
|
+
:red => 31,
|
106
|
+
:green => 32,
|
107
|
+
:yellow => 33,
|
108
|
+
:blue => 34,
|
109
|
+
:magenta => 35,
|
110
|
+
:cyan => 36,
|
111
|
+
:white => 37,
|
112
|
+
:default => 39,
|
113
|
+
:random => 30 + rand(10).to_i
|
114
|
+
}.freeze unless defined? COLOURS
|
115
|
+
|
116
|
+
# ANSI escape sequence numbers for background colours
|
117
|
+
BGCOLOURS = {
|
118
|
+
:black => 40,
|
119
|
+
:red => 41,
|
120
|
+
:green => 42,
|
121
|
+
:yellow => 43,
|
122
|
+
:blue => 44,
|
123
|
+
:magenta => 45,
|
124
|
+
:cyan => 46,
|
125
|
+
:white => 47,
|
126
|
+
:default => 49,
|
127
|
+
:random => 40 + rand(10).to_i
|
128
|
+
}.freeze unless defined? BGCOLOURS
|
129
|
+
|
130
|
+
|
131
|
+
def print_left(str, props={})
|
132
|
+
props[:x] ||= 0
|
133
|
+
props[:y] ||= Cursor.y
|
134
|
+
# print_at("x:#{props[:x]} y:#{props[:y]}", {:x => 0, :y => 10})
|
135
|
+
print_at(str, props)
|
136
|
+
end
|
137
|
+
def print_right(str, props={})
|
138
|
+
props[:x] ||= width
|
139
|
+
props[:y] ||= Cursor.y
|
140
|
+
props[:minus] = true unless props.has_key?(:minus)
|
141
|
+
print_at(str, props)
|
142
|
+
end
|
143
|
+
def print_spaced(*args)
|
144
|
+
props = (args.last.is_a? Hash) ? args.pop : {}
|
145
|
+
props[:y] = Cursor.y
|
146
|
+
chunk_width = (width / args.flatten.size).to_i
|
147
|
+
chunk_at = 0
|
148
|
+
args.each do |chunk|
|
149
|
+
props[:x] = chunk_at
|
150
|
+
print_at(chunk.to_s[0, chunk_width], props)
|
151
|
+
chunk_at += chunk_width
|
155
152
|
end
|
156
|
-
|
153
|
+
puts
|
154
|
+
end
|
155
|
+
def print_center(str, props={})
|
156
|
+
props[:x] = ((width - str.noatt.length) / 2).to_i-1
|
157
|
+
props[:y] ||= height
|
158
|
+
print_at(str, props)
|
159
|
+
end
|
160
|
+
def print_at(str, props={})
|
161
|
+
print_at_lamb = lambda {
|
162
|
+
#props[:x] ||= 0
|
163
|
+
#props[:y] ||= 0
|
164
|
+
props[:minus] = false unless props.has_key?(:minus)
|
165
|
+
props[:x] = props[:x]-str.noatt.size if props[:x] && props[:minus] # Subtract the str length from the position
|
166
|
+
Cursor.save
|
167
|
+
Cursor.move = 0
|
168
|
+
print str
|
169
|
+
Cursor.restore
|
170
|
+
}
|
171
|
+
RUBY_VERSION =~ /1.9/ ? Thread.exclusive(&print_at_lamb) : print_at_lamb.call
|
157
172
|
end
|
158
|
-
|
159
|
-
def self.
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
173
|
+
|
174
|
+
def self.style(col, bgcol=nil, att=nil)
|
175
|
+
valdor = []
|
176
|
+
valdor << COLOURS[col] if COLOURS.has_key?(col)
|
177
|
+
valdor << BGCOLOURS[bgcol] if BGCOLOURS.has_key?(bgcol)
|
178
|
+
valdor << ATTRIBUTES[att] if ATTRIBUTES.has_key?(att)
|
179
|
+
"\e[#{valdor.join(";")}m" # => \e[8;34;42m
|
164
180
|
end
|
165
|
-
|
166
|
-
def self.
|
167
|
-
|
168
|
-
arg[0] == 1
|
169
|
-
end
|
170
|
-
system "tput cuf #{arg[0]}"
|
181
|
+
|
182
|
+
def self.clear
|
183
|
+
tput :clear
|
171
184
|
end
|
172
185
|
|
173
|
-
def
|
174
|
-
|
175
|
-
arg[0] == 1
|
176
|
-
end
|
177
|
-
system "tput cub #{arg[0]}"
|
186
|
+
def reset
|
187
|
+
tput :reset
|
178
188
|
end
|
179
|
-
|
180
|
-
def
|
181
|
-
|
189
|
+
|
190
|
+
def width
|
191
|
+
tput_val(:cols).to_i
|
182
192
|
end
|
183
193
|
|
184
|
-
def
|
185
|
-
|
194
|
+
def height
|
195
|
+
tput_val(:lines).to_i
|
186
196
|
end
|
187
197
|
end
|
188
198
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
199
|
+
module Cursor
|
200
|
+
extend self
|
201
|
+
|
202
|
+
# Returns [x,y] for the current cursor position.
|
203
|
+
def position
|
204
|
+
yx = [0,0]
|
205
|
+
|
206
|
+
position_lamb = lambda {
|
207
|
+
begin
|
208
|
+
# NOTE: Can we get cursor position from tput?
|
209
|
+
termsettings = `stty -g`
|
210
|
+
|
211
|
+
# DEBUGGING: The following code works in Ruby 1.9 but not 1.8.
|
212
|
+
|
213
|
+
system("stty raw -echo")
|
214
|
+
print "\e[6n" # Forces output of: \e[49;1R (\e is not printable)
|
215
|
+
c = ''
|
216
|
+
(pos ||= '') << c while (c = STDIN.getc) != 'R'# NOTE: There must be a better way!
|
217
|
+
yx = pos.scan(/(\d+);(\d+)/).flatten
|
218
|
+
yx[0] = yx[0].to_i - 1 # It returns 1 for the first column, but we want 0
|
219
|
+
yx[1] = yx[1].to_i - 1
|
220
|
+
ensure
|
221
|
+
system("stty #{termsettings}") # Get out of raw mode
|
222
|
+
end
|
223
|
+
}
|
224
|
+
|
225
|
+
RUBY_VERSION =~ /1.9/ ? Thread.exclusive(&position_lamb) : position_lamb.call
|
226
|
+
yx.reverse
|
200
227
|
end
|
201
228
|
|
202
|
-
def
|
203
|
-
|
204
|
-
end
|
229
|
+
def x; position[0]; end
|
230
|
+
def y; position[1]; end
|
205
231
|
|
206
|
-
def
|
207
|
-
|
232
|
+
def move=(*args)
|
233
|
+
x,y = *args.flatten
|
234
|
+
tput(:cup, y, x) # "tput cup" takes y before x
|
208
235
|
end
|
209
236
|
|
210
|
-
def
|
211
|
-
|
237
|
+
def up(n=1)
|
238
|
+
tput :cuu, n
|
212
239
|
end
|
213
240
|
|
214
|
-
def
|
215
|
-
|
241
|
+
def down(n=1)
|
242
|
+
tput :cud, n
|
216
243
|
end
|
217
244
|
|
218
|
-
def
|
219
|
-
|
245
|
+
def right(x=1)
|
246
|
+
tput :cuf, x
|
220
247
|
end
|
221
248
|
|
222
|
-
def
|
223
|
-
|
249
|
+
def left(x=1)
|
250
|
+
tput :cub, x
|
224
251
|
end
|
225
|
-
|
226
|
-
def
|
227
|
-
|
228
|
-
arg = [arg]
|
229
|
-
end
|
230
|
-
if arg.length > 0
|
231
|
-
@border = arg[0]
|
232
|
-
end
|
233
|
-
if arg.length > 1
|
234
|
-
@bordercolor = arg[1]
|
235
|
-
end
|
252
|
+
|
253
|
+
def line(n=1)
|
254
|
+
tput :il, n
|
236
255
|
end
|
237
|
-
|
238
|
-
def
|
239
|
-
|
256
|
+
|
257
|
+
def save
|
258
|
+
tput :sc
|
240
259
|
end
|
241
260
|
|
242
|
-
def
|
243
|
-
|
244
|
-
arg = [arg]
|
245
|
-
end
|
246
|
-
if arg.length > 0
|
247
|
-
@row = arg[0]
|
248
|
-
end
|
249
|
-
if arg.length > 1
|
250
|
-
@col = arg[1]
|
251
|
-
end
|
261
|
+
def restore
|
262
|
+
tput :rc
|
252
263
|
end
|
253
|
-
|
254
|
-
def
|
255
|
-
|
264
|
+
|
265
|
+
def clear_line
|
266
|
+
tput :el
|
256
267
|
end
|
268
|
+
|
269
|
+
# TODO: replace methods with this kinda thing
|
270
|
+
#@@capnames = {
|
271
|
+
# :restore => [:rc],
|
272
|
+
# :save => [:sc],
|
273
|
+
# :clear_line => [:el],
|
274
|
+
# :line => [:il, 1, 1],
|
275
|
+
#
|
276
|
+
# :up => [:cuu, 1, 1],
|
277
|
+
# :down => [:cud, 1, 1],
|
278
|
+
# :right => [:cuf, 1, 1],
|
279
|
+
# :left => [:cub, 1, 1],
|
280
|
+
#
|
281
|
+
# :move => [:cup, 2, 0, 0]
|
282
|
+
#}
|
283
|
+
#
|
284
|
+
#@@capnames.each_pair do |meth, cap|
|
285
|
+
# module_eval <<-RUBY
|
286
|
+
# def #{meth}(*args)
|
287
|
+
# tput '#{cap[0]}'
|
288
|
+
# end
|
289
|
+
# RUBY
|
290
|
+
#end
|
291
|
+
|
292
|
+
end
|
257
293
|
|
258
|
-
|
259
|
-
|
294
|
+
class Window
|
295
|
+
attr_accessor :row, :col, :width, :height, :text, :fg, :bg
|
296
|
+
attr_reader :threads
|
297
|
+
|
298
|
+
def initialize(*args)
|
299
|
+
@row = 1
|
300
|
+
@col = 1
|
301
|
+
@width = 10
|
302
|
+
@height = 5
|
303
|
+
@text = ""
|
304
|
+
@fg = :default
|
305
|
+
@bg = :default
|
306
|
+
@threads = []
|
260
307
|
end
|
261
308
|
|
262
|
-
def
|
263
|
-
@
|
309
|
+
def position=(x,y=nil)
|
310
|
+
@x = x
|
311
|
+
@y = y if y
|
264
312
|
end
|
265
313
|
|
266
|
-
def
|
267
|
-
@
|
314
|
+
def position
|
315
|
+
[@row, @col]
|
268
316
|
end
|
269
|
-
|
270
|
-
def
|
271
|
-
|
317
|
+
|
318
|
+
def self.bar(len, unit='=')
|
319
|
+
unit*len
|
272
320
|
end
|
273
321
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
:lower_left => "\u255A",
|
295
|
-
:lower_right => "\u255D",
|
296
|
-
:horizontal => "\u2550",
|
297
|
-
:vertical => "\u2551"
|
298
|
-
}
|
299
|
-
round = {
|
300
|
-
:upper_left => "\u256D",
|
301
|
-
:upper_right => "\u256E",
|
302
|
-
:lower_left => "\u2570",
|
303
|
-
:lower_right => "\u256F",
|
304
|
-
:horizontal => "\u2500",
|
305
|
-
:vertical => "\u2502"
|
306
|
-
}
|
307
|
-
mapper = case @border
|
308
|
-
when :single then single
|
309
|
-
when :bold then bold
|
310
|
-
when :double then double
|
311
|
-
when :round then round
|
312
|
-
else single
|
313
|
-
end
|
314
|
-
(mapper[:upper_left] + mapper[:horizontal] * (@width - 2) + mapper[:upper_right]).color(:normal, @bordercolor, @bg).printAt @row, @col
|
315
|
-
(mapper[:lower_left] + mapper[:horizontal] * (@width - 2) + mapper[:lower_right]).color(:normal, @bordercolor, @bg).printAt @row + @height - 1, @col
|
316
|
-
0.upto(@height - 3) do |i|
|
317
|
-
(mapper[:vertical] + " " * (@width - 2) + mapper[:vertical]).color(:normal, @bordercolor, @bg).printAt @row + i + 1, @col
|
322
|
+
|
323
|
+
# Execute the given block every +n+ seconds in a separate thread.
|
324
|
+
# The lower limit for +n+ is 1 second.
|
325
|
+
# Returns a Thread object.
|
326
|
+
def every_n_seconds(n)
|
327
|
+
#n = 1 if n < 1
|
328
|
+
thread = Thread.new do
|
329
|
+
|
330
|
+
begin
|
331
|
+
while true
|
332
|
+
before = Time.now
|
333
|
+
yield
|
334
|
+
interval = n - (Time.now - before)
|
335
|
+
sleep(interval) if interval > 0
|
336
|
+
end
|
337
|
+
rescue Interrupt
|
338
|
+
break
|
339
|
+
ensure
|
340
|
+
thread
|
341
|
+
end
|
318
342
|
end
|
319
343
|
end
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
344
|
+
|
345
|
+
# Print text to the screen via +type+ every +refresh+ seconds.
|
346
|
+
# Print the return value of the block to the screen using the
|
347
|
+
# print_+type+ method. +refresh+ is number of seconds to wait
|
348
|
+
# +props+ is the hash sent to print_+type+.
|
349
|
+
# Returns a Thread object.
|
350
|
+
#
|
351
|
+
# # Print the time in the upper right corner every second
|
352
|
+
# thread1 = Console.static(:right, 1, {:y => 0}) do
|
353
|
+
# Time.now.utc.strftime("%Y-%m-%d %H:%M:%S").colour(:blue, :white, :underline)
|
354
|
+
# end
|
355
|
+
#
|
356
|
+
def static(type, refresh=2, props={}, &b)
|
357
|
+
meth = "print_#{type}"
|
358
|
+
raise "#{meth} is not supported" unless Console.respond_to?(meth)
|
359
|
+
|
360
|
+
refresh ||= 0
|
361
|
+
refreh = refresh.to_s.to_i
|
362
|
+
|
363
|
+
thread = every_n_seconds(refresh) do
|
364
|
+
Console.send(meth, b.call, props.clone)
|
329
365
|
end
|
330
|
-
|
331
|
-
|
332
|
-
|
366
|
+
|
367
|
+
@threads << thread
|
368
|
+
|
369
|
+
thread
|
370
|
+
end
|
371
|
+
|
372
|
+
def join_threads
|
373
|
+
begin
|
374
|
+
@threads.each do |t|
|
375
|
+
t.join
|
333
376
|
end
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
377
|
+
rescue Interrupt
|
378
|
+
ensure
|
379
|
+
@threads.each do |t|
|
380
|
+
t.kill
|
338
381
|
end
|
339
382
|
end
|
340
383
|
end
|
384
|
+
|
341
385
|
end
|