birr 0.1
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.
- checksums.yaml +7 -0
- data/LICENSE +202 -0
- data/README.md +164 -0
- data/Rakefile +41 -0
- data/bin/birr +35 -0
- data/lib/birr.rb +5 -0
- data/lib/megam/app.rb +190 -0
- data/lib/megam/birr.rb +176 -0
- data/lib/megam/birr_options.rb +59 -0
- data/lib/megam/cmd_verb.rb +48 -0
- data/lib/megam/config.rb +56 -0
- data/lib/megam/core/exceptions.rb +32 -0
- data/lib/megam/core/file_cache.rb +12 -0
- data/lib/megam/core/log.rb +34 -0
- data/lib/megam/core/text.rb +121 -0
- data/lib/megam/install.rb +125 -0
- data/lib/megam/transferarea.rb +41 -0
- data/lib/megam/version.rb +6 -0
- data/lib/megam/workarea.rb +96 -0
- data/lib/megam/workarea_loader.rb +83 -0
- data/spec/dump_spec.rb +18 -0
- metadata +298 -0
data/lib/birr.rb
ADDED
data/lib/megam/app.rb
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
#
|
2
|
+
# License:: Apache License, Version 2.0
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require 'pp'
|
17
|
+
require 'megam/config'
|
18
|
+
require 'megam/birr'
|
19
|
+
require 'mixlib/cli'
|
20
|
+
require 'tmpdir'
|
21
|
+
require 'rbconfig'
|
22
|
+
|
23
|
+
class Megam::App
|
24
|
+
include Mixlib::CLI
|
25
|
+
#include(a_module) is called inside a class, and adds module methods as instance methods.
|
26
|
+
#extend(a_module) adds all module methods to the instance it is called on.
|
27
|
+
|
28
|
+
NO_COMMAND_GIVEN = "You need to pass a command with option (e.g., birr -i <install_path>)\n"
|
29
|
+
|
30
|
+
banner "Usage: birr (options)"
|
31
|
+
|
32
|
+
option :install_file,
|
33
|
+
:short => "-i INSTALL",
|
34
|
+
:long => "--install INSTALL",
|
35
|
+
:required => true,
|
36
|
+
:description => "The installation file path to use",
|
37
|
+
:proc => lambda { |path| File.expand_path(path, Dir.pwd) }
|
38
|
+
|
39
|
+
verbosity_level = 0
|
40
|
+
option :verbosity,
|
41
|
+
:short => '-V',
|
42
|
+
:long => '--verbose',
|
43
|
+
:description => "More verbose output. Use twice for max verbosity",
|
44
|
+
:proc => Proc.new { verbosity_level += 1},
|
45
|
+
:default => 0
|
46
|
+
|
47
|
+
option :help,
|
48
|
+
:short => "-h",
|
49
|
+
:long => "--help",
|
50
|
+
:description => "Show this message",
|
51
|
+
:on => :tail,
|
52
|
+
:boolean => true,
|
53
|
+
:show_options => true,
|
54
|
+
:exit => 0
|
55
|
+
|
56
|
+
option :yes,
|
57
|
+
:short => "-y",
|
58
|
+
:long => "--yes",
|
59
|
+
:description => "Say yes to all prompts for confirmation"
|
60
|
+
|
61
|
+
option :version,
|
62
|
+
:short => "-v",
|
63
|
+
:long => "--version",
|
64
|
+
:description => "Show birr version",
|
65
|
+
:boolean => true,
|
66
|
+
:proc => lambda {|v| puts "Birr: #{::Megam::VERSION}"},
|
67
|
+
:exit => 0
|
68
|
+
|
69
|
+
#attr_accessors are setters/getters in ruby. The arguments are filtered and available for use
|
70
|
+
#to subclasses.
|
71
|
+
attr_accessor :name_args
|
72
|
+
|
73
|
+
attr_accessor :text
|
74
|
+
def initialize
|
75
|
+
super # The super calls the mixlib cli.
|
76
|
+
|
77
|
+
##Traps are being set for the following when an application starts.
|
78
|
+
##SIGHUP 1 Term Hangup detected on controlling terminal
|
79
|
+
## or death of controlling process
|
80
|
+
##SIGINT 2 Term Interrupt from keyboard
|
81
|
+
##SIGQUIT 3 Core Quit from keyboard
|
82
|
+
trap("TERM") do
|
83
|
+
Megam::App.fatal!("SIGTERM received, stopping", 1)
|
84
|
+
end
|
85
|
+
|
86
|
+
trap("INT") do
|
87
|
+
Megam::App.fatal!("SIGINT received, stopping", 2)
|
88
|
+
end
|
89
|
+
|
90
|
+
trap("QUIT") do
|
91
|
+
Megam::Log.info("SIGQUIT received, call stack:\n " + caller.join("\n "))
|
92
|
+
end
|
93
|
+
|
94
|
+
@text ||= Megam::Text.new(STDOUT, STDERR, STDIN, {})
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
# Run the "birr app". Let it roam and stay by our side.[Go birr..Does it remind of the Hutch adv.].
|
99
|
+
# The first thing run does is it parses the options. Once the first level of parsing is done,
|
100
|
+
# ie the help, no_command, sub_command entry is verified it proceeds to call
|
101
|
+
# Megam_Birr with the user entered options and arguments (ARGV)
|
102
|
+
def run
|
103
|
+
Mixlib::Log::Formatter.show_time = false
|
104
|
+
validate_and_parse_options
|
105
|
+
Megam::Birr.new.run(@named_args, config)
|
106
|
+
exit 0
|
107
|
+
end
|
108
|
+
|
109
|
+
def parse_options(args)
|
110
|
+
super
|
111
|
+
rescue OptionParser::InvalidOption => e
|
112
|
+
puts "Error: " + e.to_s
|
113
|
+
puts self.opt_parser
|
114
|
+
exit(1)
|
115
|
+
end
|
116
|
+
|
117
|
+
##A few private helper methods being used by app itself.
|
118
|
+
##If you run an application for ever, you might pool all the executions and gather the stacktrace.
|
119
|
+
private
|
120
|
+
|
121
|
+
# A check is performed to see if an option is entered, help or version
|
122
|
+
def validate_and_parse_options
|
123
|
+
# Checking ARGV validity *before* parse_options because parse_options
|
124
|
+
# mangles ARGV in some situations
|
125
|
+
if no_command_given?
|
126
|
+
print_help_and_exit(1, NO_COMMAND_GIVEN)
|
127
|
+
elsif (want_help? || want_version?)
|
128
|
+
print_help_and_exit
|
129
|
+
else
|
130
|
+
@named_args = parse_options(ARGV)
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
def no_subcommand_given?
|
136
|
+
ARGV[0] =~ /^-/
|
137
|
+
end
|
138
|
+
|
139
|
+
def no_command_given?
|
140
|
+
ARGV.empty?
|
141
|
+
end
|
142
|
+
|
143
|
+
def want_help?
|
144
|
+
ARGV[0] =~ /^(--help|-h)$/
|
145
|
+
end
|
146
|
+
|
147
|
+
def want_version?
|
148
|
+
ARGV[0] =~ /^(--version|-v)$/
|
149
|
+
end
|
150
|
+
|
151
|
+
# Print the help message with the exit code. If no command is given, then a fatal message is printed.
|
152
|
+
# The options are parsed by calling the parse_options present in the mixlib cli as extended by the app.
|
153
|
+
# A error gets caught and results in an ugly stack trace, which probably needs to be shown in an elegant way.
|
154
|
+
# The stacK should be logged using the debug_stacktrace method in the app class.
|
155
|
+
def print_help_and_exit(exitcode=1, fatal_message=nil)
|
156
|
+
Megam::Log.error(fatal_message) if fatal_message
|
157
|
+
parse_options(ARGV)
|
158
|
+
exit exitcode
|
159
|
+
end
|
160
|
+
|
161
|
+
class << self
|
162
|
+
#The exception in ruby carries the class, message and the trace.
|
163
|
+
#http://www.ruby-doc.org/core-2.0/Exception.html
|
164
|
+
def debug_stacktrace(e)
|
165
|
+
message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
166
|
+
megam_stacktrace_out = "Generated at #{Time.now.to_s}\n"
|
167
|
+
megam_stacktrace_out += message
|
168
|
+
|
169
|
+
#after the message is formulated in the variable megam_stack_trace_out, its
|
170
|
+
#stored in a file named megam-stacktrace.out
|
171
|
+
Megam::FileCache.store("megam-stacktrace.out", megam_stacktrace_out)
|
172
|
+
|
173
|
+
##The same error is logged in the log file saying, go look at megam-stacktrace.out for error.
|
174
|
+
Megam::Log.fatal("Stacktrace dumped to #{Megam::FileCache.load("megam-stacktrace.out", false)}")
|
175
|
+
Megam::Log.debug(message)
|
176
|
+
true
|
177
|
+
end
|
178
|
+
|
179
|
+
# Log a fatal error message to both STDERR and the Logger, exit the application
|
180
|
+
def fatal!(msg, err = -1)
|
181
|
+
Megam::Log.fatal(msg)
|
182
|
+
Process.exit err
|
183
|
+
end
|
184
|
+
|
185
|
+
def exit!(msg, err = -1)
|
186
|
+
Megam::Log.debug(msg)
|
187
|
+
Process.exit err
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
data/lib/megam/birr.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
#
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
#
|
15
|
+
|
16
|
+
require 'pp'
|
17
|
+
require 'megam/core/text'
|
18
|
+
|
19
|
+
#Main entry for the command line, after validating the class, run the install_file
|
20
|
+
class Megam::Birr
|
21
|
+
|
22
|
+
attr_accessor :text
|
23
|
+
attr_accessor :config
|
24
|
+
#text is used to print stuff in the terminal (message, log, info, warn etc.)
|
25
|
+
def self.text
|
26
|
+
@text ||= Megam::Text.new(STDOUT, STDERR, STDIN, {})
|
27
|
+
end
|
28
|
+
|
29
|
+
# I don't think we need this method. Will remove it later.
|
30
|
+
# We need to just call text.msg
|
31
|
+
def self.msg(msg="")
|
32
|
+
text.msg(msg)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Create a new instance of the current class configured for the given
|
36
|
+
# arguments and options
|
37
|
+
def initialize()
|
38
|
+
end
|
39
|
+
|
40
|
+
# Run Birr for the given +args+ (ARGV), adding +options+ to the list of
|
41
|
+
# CLI options that the subcommand knows how to handle.
|
42
|
+
# ===Arguments
|
43
|
+
# args::: usually ARGV
|
44
|
+
# options::: A Mixlib::CLI option parser hash. These +options+ are how
|
45
|
+
# subcommands know about global Birr CLI options
|
46
|
+
def run(args=[], config={})
|
47
|
+
@config = config.dup
|
48
|
+
@text ||= Megam::Text.new(STDOUT, STDERR, STDIN, config)
|
49
|
+
# configure your Birr.
|
50
|
+
configure_birr
|
51
|
+
end
|
52
|
+
|
53
|
+
# configure meggy, to startwith locate the config file under .meggy/Birr.rb
|
54
|
+
# Once located, read the Birr.rb config file. parse them, and report any ruby syntax errors.
|
55
|
+
# if not merge then inside Meggy::Config object.
|
56
|
+
def configure_birr
|
57
|
+
# look for a .birr/birr.rb for configuration. Not used currently.
|
58
|
+
unless config[:install_file]
|
59
|
+
locate_install_file
|
60
|
+
end
|
61
|
+
|
62
|
+
# Now load the installation file provided as input {-i} parm.
|
63
|
+
if config[:install_file]
|
64
|
+
@text.info "Using #{config[:install_file]}"
|
65
|
+
apply_computed_config
|
66
|
+
read_config_file(config[:install_file])
|
67
|
+
else
|
68
|
+
text.warn("No birr configuration file found")
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
def locate_install_file
|
74
|
+
# Look for $HOME/.meggy/birr.rb, this aint' supported currently
|
75
|
+
# the idea is to allow configuration of the options used here.
|
76
|
+
if ENV['HOME']
|
77
|
+
user_config_file = File.expand_path(File.join(ENV['HOME'], '.birr', 'birr.rb'))
|
78
|
+
end
|
79
|
+
|
80
|
+
if File.exist?(user_config_file)
|
81
|
+
config[:install_file] = user_config_file
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Catch-all method that does any massaging needed for various config
|
86
|
+
# components, such as expanding file paths and converting verbosity level
|
87
|
+
# into log level.
|
88
|
+
def apply_computed_config
|
89
|
+
|
90
|
+
case config[:verbosity]
|
91
|
+
when 0, nil
|
92
|
+
config[:log_level] = :error
|
93
|
+
when 1
|
94
|
+
config[:log_level] = :info
|
95
|
+
else
|
96
|
+
config[:log_level] = :debug
|
97
|
+
end
|
98
|
+
|
99
|
+
Mixlib::Log::Formatter.show_time = false
|
100
|
+
Megam::Log.init(config[:log_location] || STDOUT)
|
101
|
+
Megam::Log.level(config[:log_level] || :error)
|
102
|
+
|
103
|
+
config.each do |key, val|
|
104
|
+
Megam::Config[key] = val
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
# load the content as provided in -i {installation_file}
|
110
|
+
# ruby errors get reported or else the file is executed.
|
111
|
+
def read_config_file(file)
|
112
|
+
self.instance_eval(IO.read(file), file, 1)
|
113
|
+
rescue SyntaxError => e
|
114
|
+
@text.error "You have invalid ruby syntax in your config file #{file}"
|
115
|
+
@text.info(text.color(e.message, :red))
|
116
|
+
if file_line = e.message[/#{Regexp.escape(file)}:[\d]+/]
|
117
|
+
line = file_line[/:([\d]+)$/, 1].to_i
|
118
|
+
highlight_config_error(file, line)
|
119
|
+
end
|
120
|
+
exit 1
|
121
|
+
rescue Exception => e
|
122
|
+
@text.error "You have an error in your config file #{file}"
|
123
|
+
@text.info "#{e.class.name}: #{e.message}"
|
124
|
+
filtered_trace = e.backtrace.grep(/#{Regexp.escape(file)}/)
|
125
|
+
filtered_trace.each {|line| text.msg(" " + text.color(line, :red))}
|
126
|
+
if !filtered_trace.empty?
|
127
|
+
line_nr = filtered_trace.first[/#{Regexp.escape(file)}:([\d]+)/, 1]
|
128
|
+
highlight_config_error(file, line_nr.to_i)
|
129
|
+
end
|
130
|
+
|
131
|
+
exit 1
|
132
|
+
end
|
133
|
+
|
134
|
+
#ERROR: You have invalid ruby syntax in your config file /home/ram/.meggy/Birr.rb
|
135
|
+
#/home/ram/.meggy/Birr.rb:9: syntax error, unexpected '='
|
136
|
+
#Birr[:username] > = "admin"
|
137
|
+
# ^
|
138
|
+
# # /home/ram/.meggy/Birr.rb
|
139
|
+
# 8: meggy_server_url 'http://localhost:6167'
|
140
|
+
# 9: Birr[:username] > = "admin"
|
141
|
+
# 10: Birr[:password] = "team4dog"
|
142
|
+
# Line 9 is marked in red, and the 3rd line where the error is show is highlighted in red.
|
143
|
+
#This is in case of a ruby parse error.
|
144
|
+
def highlight_config_error(file, line)
|
145
|
+
config_file_lines = []
|
146
|
+
|
147
|
+
# A file line is split into the line number (index) and the line content.
|
148
|
+
# The line number is converted to string (to_s), right justified 3 characters with a colon, and its trimmed (chomp)
|
149
|
+
|
150
|
+
IO.readlines(file).each_with_index {|l, i| config_file_lines << "#{(i + 1).to_s.rjust(3)}: #{l.chomp}"}
|
151
|
+
# mark the appropriate line with a red color, if its just one line, then mark the zeroth line.
|
152
|
+
# if not get the range (deducting 2), and mark the second line.
|
153
|
+
if line == 1
|
154
|
+
lines = config_file_lines[0..3]
|
155
|
+
lines[0] = text.color(lines[0], :red)
|
156
|
+
else
|
157
|
+
lines = config_file_lines[Range.new(line - 2, line)]
|
158
|
+
lines[1] = text.color(lines[1], :red)
|
159
|
+
end
|
160
|
+
text.msg ""
|
161
|
+
# print the name of the file in white
|
162
|
+
text.msg text.color(" # #{file}", :white)
|
163
|
+
# print the rest of the line.
|
164
|
+
lines.each {|l| text.msg(l)}
|
165
|
+
text.msg ""
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def self.working_directory
|
173
|
+
ENV['PWD'] || Dir.pwd
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#The birr options class takes the block in the initialize method.
|
2
|
+
#it uses the custom attr_accessors, namely (setter, varargs_setters) to
|
3
|
+
#inject the value by defining methods with the dsl defined ones.
|
4
|
+
#
|
5
|
+
class Megam
|
6
|
+
class BirrOptions
|
7
|
+
def self.setter(*method_names)
|
8
|
+
method_names.each do |name|
|
9
|
+
send :define_method, name do |data|
|
10
|
+
instance_variable_set "@#{name}".to_sym, data
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.varargs_setter(*method_names)
|
16
|
+
method_names.each do |name|
|
17
|
+
send :define_method, name do |*data|
|
18
|
+
instance_variable_set "@#{name}".to_sym, data
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
setter :sudo, :start_time, :tarball
|
24
|
+
varargs_setter :directory, :command
|
25
|
+
attr_reader :commands, :sudo
|
26
|
+
|
27
|
+
def initialize(&block)
|
28
|
+
# defaults
|
29
|
+
@tarball = nil
|
30
|
+
@sudo = false
|
31
|
+
@directory = []
|
32
|
+
@command = []
|
33
|
+
@commands = []
|
34
|
+
@start_time = Time.now
|
35
|
+
instance_eval(&block)
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def commands
|
40
|
+
@commands = @command.flatten if @command
|
41
|
+
end
|
42
|
+
|
43
|
+
def sudo?
|
44
|
+
@sudo
|
45
|
+
end
|
46
|
+
|
47
|
+
def tarball_file
|
48
|
+
@tarball_file ||= @tarball
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
tmps = ""
|
53
|
+
tmps << "sudo :" + @sudo.to_s + "\n"
|
54
|
+
tmps << "dir :" + @directory.to_s + "\n"
|
55
|
+
tmps << "cmd :" + commands.to_s + "\n"
|
56
|
+
tmps << "strt :" + @start_time.to_s
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
#
|
2
|
+
# License:: Apache License, Version 2.0
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
require "megam/core/text"
|
16
|
+
require "megam/birr"
|
17
|
+
|
18
|
+
class Megam::CmdVerb
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
end
|
22
|
+
|
23
|
+
# cp -r -s <from directory> <to directory>
|
24
|
+
def self.cp(opts={})
|
25
|
+
cp =""
|
26
|
+
cp << "sudo " if opts[:sudo]
|
27
|
+
cp << "cp"
|
28
|
+
cp << " -r " if opts[:recursive]
|
29
|
+
# cp << " -u " if opts[:copy_on_new] #copy only when the SOURCE file is newer than
|
30
|
+
cp << opts[:from_dir] if opts[:from_dir] or raise Megam::Exceptions::FileNotFound
|
31
|
+
cp << " "
|
32
|
+
cp << opts[:to_dir] if opts[:to_dir] or raise Megam::Exceptions::FileNotFound
|
33
|
+
cp
|
34
|
+
end
|
35
|
+
|
36
|
+
#gunzip -c foo.tar.gz | tar xvf -
|
37
|
+
def self.untar(opts={})
|
38
|
+
untar = "gunzip -c "
|
39
|
+
untar << opts[:tar_file] if opts[:tar_file]
|
40
|
+
untar << " | tar xvf - -C "
|
41
|
+
untar << opts[:to_dir] if opts[:to_dir]
|
42
|
+
untar
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
"cmdverb -> [supports cp, untar *only]"
|
47
|
+
end
|
48
|
+
end
|