cowtech-lib 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +17 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +16 -0
- data/cowtech-lib.gemspec +56 -0
- data/lib/cowtech-lib/console.rb +314 -0
- data/lib/cowtech-lib/option_parser.rb +342 -0
- data/lib/cowtech-lib/script.rb +122 -0
- data/lib/cowtech-lib/shell.rb +374 -0
- data/lib/cowtech-lib/version.rb +12 -0
- data/lib/cowtech-lib.rb +29 -0
- metadata +104 -0
data/.document
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Shogun
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
= cowtech-lib
|
2
|
+
|
3
|
+
A general purpose utility library.
|
4
|
+
http://github.com/ShogunPanda/cowtech-lib
|
5
|
+
|
6
|
+
== Contributing to cowtech-lib
|
7
|
+
|
8
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
9
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
10
|
+
* Fork the project
|
11
|
+
* Start a feature/bugfix branch
|
12
|
+
* Commit and push until you are happy with your contribution
|
13
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
14
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
15
|
+
|
16
|
+
== Copyright
|
17
|
+
|
18
|
+
Copyright (c) 2011 Shogun. See LICENSE.txt for further details.
|
19
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'jeweler'
|
3
|
+
require "./lib/cowtech-lib/version.rb"
|
4
|
+
|
5
|
+
Jeweler::Tasks.new do |gem|
|
6
|
+
gem.name = "cowtech-lib"
|
7
|
+
gem.homepage = "http://github.com/ShogunPanda/cowtech-lib"
|
8
|
+
gem.license = "MIT"
|
9
|
+
gem.summary = %Q{A general purpose utility library.}
|
10
|
+
gem.description = %Q{A general purpose utility library.}
|
11
|
+
gem.email = "shogun_panda@me.com"
|
12
|
+
gem.authors = ["Shogun"]
|
13
|
+
gem.version = Cowtech::Lib::Version::STRING
|
14
|
+
end
|
15
|
+
|
16
|
+
Jeweler::RubygemsDotOrgTasks.new
|
data/cowtech-lib.gemspec
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{cowtech-lib}
|
8
|
+
s.version = "1.9.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Shogun"]
|
12
|
+
s.date = %q{2011-02-21}
|
13
|
+
s.description = %q{A general purpose utility library.}
|
14
|
+
s.email = %q{shogun_panda@me.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
"Gemfile",
|
22
|
+
"Gemfile.lock",
|
23
|
+
"LICENSE.txt",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"cowtech-lib.gemspec",
|
27
|
+
"lib/cowtech-lib.rb",
|
28
|
+
"lib/cowtech-lib/console.rb",
|
29
|
+
"lib/cowtech-lib/option_parser.rb",
|
30
|
+
"lib/cowtech-lib/script.rb",
|
31
|
+
"lib/cowtech-lib/shell.rb",
|
32
|
+
"lib/cowtech-lib/version.rb"
|
33
|
+
]
|
34
|
+
s.homepage = %q{http://github.com/ShogunPanda/cowtech-lib}
|
35
|
+
s.licenses = ["MIT"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = %q{1.3.7}
|
38
|
+
s.summary = %q{A general purpose utility library.}
|
39
|
+
|
40
|
+
if s.respond_to? :specification_version then
|
41
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
42
|
+
s.specification_version = 3
|
43
|
+
|
44
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
45
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
|
46
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
47
|
+
else
|
48
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
49
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
50
|
+
end
|
51
|
+
else
|
52
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
53
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
@@ -0,0 +1,314 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# cowtech-lib
|
4
|
+
# Author: Shogun <shogun_panda@me.com>
|
5
|
+
# Copyright © 2011 and above Shogun
|
6
|
+
# Released under the MIT License, which follows.
|
7
|
+
#
|
8
|
+
# The MIT License
|
9
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
10
|
+
# of this software and associated documentation files (the "Software"), to deal
|
11
|
+
# in the Software without restriction, including without limitation the rights
|
12
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
13
|
+
# copies of the Software, and to permit persons to whom the Software is
|
14
|
+
# furnished to do so, subject to the following conditions:
|
15
|
+
#
|
16
|
+
# The above copyright notice and this permission notice shall be included in
|
17
|
+
# all copies or substantial portions of the Software.
|
18
|
+
#
|
19
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
20
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
21
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
22
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
23
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
24
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
25
|
+
# THE SOFTWARE.
|
26
|
+
#
|
27
|
+
|
28
|
+
require "rexml/document"
|
29
|
+
require "open4"
|
30
|
+
require "find"
|
31
|
+
require "fileutils"
|
32
|
+
|
33
|
+
class String
|
34
|
+
def to_a
|
35
|
+
[self]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module CowtechLib
|
40
|
+
=begin rdoc
|
41
|
+
A class which provides some method to operate with files and to format pretty messages.
|
42
|
+
=end
|
43
|
+
class Console
|
44
|
+
public
|
45
|
+
|
46
|
+
# Indentation level
|
47
|
+
attr :indent_level
|
48
|
+
|
49
|
+
# Whether show executed commands
|
50
|
+
attr :show_commands
|
51
|
+
|
52
|
+
# Whether show output of executed commands
|
53
|
+
attr :show_outputs
|
54
|
+
|
55
|
+
# Whether simply print commands rather than executing them
|
56
|
+
attr :skip_commands
|
57
|
+
|
58
|
+
# Exit status for commands
|
59
|
+
attr_reader :statuses
|
60
|
+
|
61
|
+
# Indentation string(s)
|
62
|
+
attr :indentator, true
|
63
|
+
|
64
|
+
# Sets indentation level.
|
65
|
+
# Arguments:
|
66
|
+
# * <em>indent</em>: The new indentation level
|
67
|
+
# * <em></em>: If the level is absolute or relative to the current level
|
68
|
+
def indent_set(level, absolute = false)
|
69
|
+
@indent_level = Math.max((!absolute ? @indent_level : 0) + level, 0)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Resets indentation level to 0.
|
73
|
+
def indent_reset
|
74
|
+
@indent_level = 0
|
75
|
+
end
|
76
|
+
|
77
|
+
# Execute codes in an indented block
|
78
|
+
def indent_region(level, absolute = false, &block)
|
79
|
+
old_level = @indent_level
|
80
|
+
self.indent_set(level, absolute)
|
81
|
+
yield
|
82
|
+
@indent_level = old_level
|
83
|
+
end
|
84
|
+
|
85
|
+
# Indents a message.
|
86
|
+
#
|
87
|
+
# Arguments:
|
88
|
+
# * <em>msg</em>: The message to indent
|
89
|
+
# * <em>add_additional</em>: Whether add extra space to align to initial message "*"
|
90
|
+
# Returns: The indentated message
|
91
|
+
def indent(msg, level = nil)
|
92
|
+
(@@indentator * (level || @indent_level)) + msg
|
93
|
+
end
|
94
|
+
|
95
|
+
=begin rdoc
|
96
|
+
Substitute tag with color.
|
97
|
+
|
98
|
+
Arguments:
|
99
|
+
* <em>node</em>: The node which operate on
|
100
|
+
* <em>stack</em>: The stack of old styles. <b>Do not set this by yourself!</b>
|
101
|
+
|
102
|
+
Returns: The new text
|
103
|
+
=end
|
104
|
+
def subst_color(node, stack = [])
|
105
|
+
rv = ""
|
106
|
+
styles = (node.name == "text" and node.attributes["style"]) ? node.attributes["style"].split(" ") : nil
|
107
|
+
|
108
|
+
# Add style of current tag
|
109
|
+
if styles then
|
110
|
+
styles.each do |style|
|
111
|
+
rv += @@styles[style] || ""
|
112
|
+
end
|
113
|
+
|
114
|
+
stack.push(styles)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Now parse subnodes
|
118
|
+
node.children.each do |child|
|
119
|
+
if child.node_type == :text then
|
120
|
+
rv += child.to_s
|
121
|
+
elsif child.name == "text" then
|
122
|
+
rv += self.subst_color(child, stack)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Remove style of current tag
|
127
|
+
if styles then
|
128
|
+
stack.pop()
|
129
|
+
|
130
|
+
# Restore previous style
|
131
|
+
(stack.pop || ["default"]).each do |style|
|
132
|
+
rv += @@styles[style]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
rv
|
137
|
+
end
|
138
|
+
|
139
|
+
# Prints a message.
|
140
|
+
# Arguments:
|
141
|
+
# * <em>msg</em>: The message to print
|
142
|
+
# * <em>dots</em>: Whether add "..." to the message
|
143
|
+
# * <em>newline</em>: Whether add a newline to the message
|
144
|
+
# * <em>plain</em>: Whether ignore tags
|
145
|
+
# * <em>must_indent</em>: Whether indent the message
|
146
|
+
# * <em>internal</em>: If the method is called by another method. <b>Do not set this by yourself!</b>
|
147
|
+
def write(*args)
|
148
|
+
msg = args[:msg]
|
149
|
+
|
150
|
+
# Check some alternative syntax
|
151
|
+
[:begin, :warn, :error, :debug, :info, :right, :end].each do |t|
|
152
|
+
if args[t] then
|
153
|
+
msg = args[t]
|
154
|
+
args[:type] = :t
|
155
|
+
args[t] = nil
|
156
|
+
end
|
157
|
+
args[:fatal] = true if args[:status] == :fail
|
158
|
+
|
159
|
+
# Check for specific msg type
|
160
|
+
if [:begin, :warn, :error, :debug, :info].include?(args[:type]) then
|
161
|
+
mc = {:begin => "bold green", :warn => "bold yellow", :error => "bold red", :debug => "magenta", :info => "bold cyan"}
|
162
|
+
color = args[:color] || mc[args[:type]]
|
163
|
+
|
164
|
+
if args[:full_color] then
|
165
|
+
msg = "<text style=\"#{color}\">*</text> #{self.indent(msg)}"
|
166
|
+
else
|
167
|
+
msg = "<text style=\"#{color}\">* #{self.indent(msg)}</text>"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Add dots and indentation if needed
|
172
|
+
msg = self.indent(msg + (args[:trailing_dots] ? "..." : ""), args[:indent] ? @indent_level : -1)
|
173
|
+
|
174
|
+
# Parse the message
|
175
|
+
unless args[:plain] then
|
176
|
+
begin
|
177
|
+
msg = self.parse_message(REXML::Document.new("<text>#{msg}</text>").root)
|
178
|
+
rescue Exception => e
|
179
|
+
print "[ERROR] Invalid message tagging, check XML syntax (or color requested) of the following message:\n\n\t#{msg}\n\n"
|
180
|
+
exit(1)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Add newline if needed
|
185
|
+
msg += "\n" if args[:newline]
|
186
|
+
|
187
|
+
if args[:internal] then
|
188
|
+
msg
|
189
|
+
else
|
190
|
+
if [:end, :right].include?(args[:type]) then
|
191
|
+
# Get screen width
|
192
|
+
@tty_width = `tput cols`.to_i if @tty_width < 0
|
193
|
+
|
194
|
+
# Get padding
|
195
|
+
pad = @tty_width - msg.inspect.gsub(/(\\e\[[0-9]+m)|(\")|(\\n)/, "").length
|
196
|
+
|
197
|
+
print "\033[A" if args[:up]
|
198
|
+
print "\033[0G\033[#{pad}C"
|
199
|
+
end
|
200
|
+
|
201
|
+
print(msg)
|
202
|
+
end
|
203
|
+
|
204
|
+
exit(args[:code] || 0) if args[:exit_after] || args[:fatal]
|
205
|
+
end
|
206
|
+
|
207
|
+
# Syntatic sugar
|
208
|
+
# Prints a warning message.
|
209
|
+
def warn(msg, *args)
|
210
|
+
args[:warn] = msg
|
211
|
+
self.write(*args)
|
212
|
+
end
|
213
|
+
|
214
|
+
# Prints an error message.
|
215
|
+
def error(msg, *args)
|
216
|
+
args[:error] = msg
|
217
|
+
self.write(*args)
|
218
|
+
end
|
219
|
+
|
220
|
+
# Prints and error message then abort.
|
221
|
+
def fatal(msg, *args)
|
222
|
+
args[:error] = msg
|
223
|
+
args[:exit_after] = true
|
224
|
+
args[:code] ||= 1
|
225
|
+
self.write(*args)
|
226
|
+
end
|
227
|
+
|
228
|
+
# Prints an error status
|
229
|
+
def status(*args)
|
230
|
+
args[:end] = @@statuses[status] || @@statuses[:ok]
|
231
|
+
self.write(*args)
|
232
|
+
end
|
233
|
+
|
234
|
+
# Read input from the user.
|
235
|
+
#
|
236
|
+
# Arguments:
|
237
|
+
# * <em>msg</em>: The prompt to show
|
238
|
+
# * <em>valids</em>: A list of regexp to validate the input
|
239
|
+
# * <em>case_sensitive</em>: Wheter the validation is case_sensitive
|
240
|
+
#
|
241
|
+
# Returns: The read input
|
242
|
+
def read(*args)
|
243
|
+
# Adjust prompt
|
244
|
+
msg = args[:msg] + (msg !~ /([:?](\s*))$/) ? ":" : "")
|
245
|
+
msg += " " unless msg =~ / ^/
|
246
|
+
|
247
|
+
# Turn choices into regular expressions
|
248
|
+
regexps = (args[:valids] || []).to_a.collect do |valid|
|
249
|
+
unless valid.is_a?(Regexp) then
|
250
|
+
valid = Regexp.new((valid !~ /^\^/ ? "^" : "") + valid + (valid !~ /\$$/ ? "$" : ""), Regexp::EXTENDED + (args[:case_sensitive] ? Regexp::IGNORECASE : 0), "U")
|
251
|
+
else
|
252
|
+
valid
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
rv = nil
|
257
|
+
|
258
|
+
# Read input
|
259
|
+
while true do
|
260
|
+
# Show message
|
261
|
+
print(msg)
|
262
|
+
|
263
|
+
# Get reply
|
264
|
+
bufs = gets.chop()
|
265
|
+
|
266
|
+
# If we don't have any regexp
|
267
|
+
if regexps.length == 0 then
|
268
|
+
rv = bufs
|
269
|
+
break
|
270
|
+
end
|
271
|
+
|
272
|
+
# Validate inputs
|
273
|
+
regexps.each do |re|
|
274
|
+
if bufs =~ re then
|
275
|
+
rv = bufs
|
276
|
+
break
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
break if rv
|
281
|
+
self.write(:warn => "Sorry, your reply was not understood. Please try again")
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
# Create a new Console.
|
286
|
+
def initialize
|
287
|
+
@indent_level = 0
|
288
|
+
@show_commands = false
|
289
|
+
@show_outputs = false
|
290
|
+
@skip_commands = false
|
291
|
+
@tty_width = -1
|
292
|
+
@@indentator= " "
|
293
|
+
|
294
|
+
@@styles = {
|
295
|
+
# Default color
|
296
|
+
"default" => "\33[0m",
|
297
|
+
# Text style
|
298
|
+
"bold" => "\33[1m", "underline" => "\33[4m", "blink" => "\33[5m", "reverse" => "\33[7m", "concealed" => "\33[8m",
|
299
|
+
# Foreground colors
|
300
|
+
"black" => "\33[30m", "red" => "\33[31m", "green" => "\33[32m", "yellow" => "\33[33m", "blue" => "\33[34m", "magenta" => "\33[35m", "cyan" => "\33[36m", "white" => "\33[37m",
|
301
|
+
# Background colors
|
302
|
+
"bg_black" => "\33[40m", "bg_red" => "\33[41m", "bg_green" => "\33[42m", "bg_yellow" => "\33[43m", "bg_blue" => "\33[44m", "bg_magenta" => "\33[45m", "bg_cyan" => "\33[46m", "bg_white" => "\33[47m"
|
303
|
+
}
|
304
|
+
|
305
|
+
@@statuses = {
|
306
|
+
:ok => '<text style="bold blue">[ <text style="bold green">OK</text> ]</text> ',
|
307
|
+
:pass => '<text style="bold blue">[<text style="bold cyan">PASS</text>]</text> ',
|
308
|
+
:fail => '<text style="bold blue">[<text style="bold red">FAIL</text>]</text> ',
|
309
|
+
:warn => '<text style="bold blue">[<text style="bold yellow">WARN</text>]</text> ',
|
310
|
+
}
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|