racker 0.1.6 → 0.2.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/CHANGELOG.md +5 -0
- data/README.md +27 -13
- data/Rakefile +2 -2
- data/bin/racker +20 -33
- data/lib/racker.rb +1 -0
- data/lib/racker/builders/amazon.rb +3 -4
- data/lib/racker/builders/builder.rb +6 -5
- data/lib/racker/builders/digitalocean.rb +4 -5
- data/lib/racker/builders/docker.rb +3 -4
- data/lib/racker/builders/google.rb +4 -5
- data/lib/racker/builders/null.rb +4 -5
- data/lib/racker/builders/openstack.rb +3 -4
- data/lib/racker/builders/parallels.rb +3 -4
- data/lib/racker/builders/qemu.rb +3 -4
- data/lib/racker/builders/virtualbox.rb +4 -5
- data/lib/racker/builders/vmware.rb +4 -5
- data/lib/racker/cli.rb +59 -34
- data/lib/racker/log_support.rb +47 -0
- data/lib/racker/processor.rb +10 -23
- data/lib/racker/smash/deep_merge_modified.rb +1 -1
- data/lib/racker/template.rb +10 -10
- data/lib/racker/version.rb +2 -2
- data/spec/fixtures/high_priority_template.rb +6 -0
- data/spec/fixtures/low_priority_template.rb +7 -0
- data/spec/integration/output_to_file_spec.rb +21 -0
- data/spec/integration/output_to_stdout_spec.rb +16 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/unit/cli_spec.rb +201 -0
- data/spec/unit/log_support_spec.rb +62 -0
- data/spec/unit/processor_spec.rb +163 -0
- metadata +14 -5
data/lib/racker/cli.rb
CHANGED
@@ -2,12 +2,15 @@
|
|
2
2
|
require 'optparse'
|
3
3
|
require 'racker/processor'
|
4
4
|
require 'racker/version'
|
5
|
-
require 'log4r'
|
6
5
|
|
7
6
|
module Racker
|
8
7
|
# The CLI is a class responsible for handling the command line interface
|
9
8
|
# logic.
|
10
9
|
class CLI
|
10
|
+
include Racker::LogSupport
|
11
|
+
|
12
|
+
STDOUT_TOKEN = '-'
|
13
|
+
|
11
14
|
attr_reader :options
|
12
15
|
|
13
16
|
def initialize(argv)
|
@@ -15,74 +18,60 @@ module Racker
|
|
15
18
|
end
|
16
19
|
|
17
20
|
def execute!
|
18
|
-
# Get the global logger
|
19
|
-
log = Log4r::Logger['racker']
|
20
|
-
|
21
21
|
# Parse our arguments
|
22
22
|
option_parser.parse!(@argv)
|
23
23
|
|
24
24
|
# Set the logging level specified by the command line
|
25
|
-
|
26
|
-
log.info("Log level set to: #{options[:log_level]}")
|
25
|
+
Racker::LogSupport.level = options[:log_level]
|
27
26
|
|
28
27
|
# Display the options if a minimum of 1 template and an output file is not provided
|
29
28
|
if @argv.length < 2
|
30
|
-
puts option_parser
|
29
|
+
puts option_parser
|
31
30
|
Kernel.exit!(1)
|
32
31
|
end
|
33
32
|
|
34
|
-
# Set the output file to the last arg
|
35
|
-
|
36
|
-
|
33
|
+
# Set the output file to the last arg. A single dash can be supplied to
|
34
|
+
# indicate that the compiled template should be written to STDOUT. Output
|
35
|
+
# to STDOUT assumes the quiet option.
|
36
|
+
options[:output] = output = @argv.pop
|
37
|
+
logger.debug("Output file set to: #{output}")
|
38
|
+
|
39
|
+
# Output to STDOUT assumes quiet mode
|
40
|
+
@options[:quiet] = true if output == STDOUT_TOKEN
|
37
41
|
|
38
42
|
# Set the input files to the remaining args
|
39
43
|
options[:templates] = @argv
|
40
44
|
|
41
45
|
# Run through Racker
|
42
|
-
|
43
|
-
Processor.new(options).execute!
|
44
|
-
|
46
|
+
logger.debug('Executing the Racker Processor...')
|
47
|
+
template = Processor.new(options).execute!
|
48
|
+
|
49
|
+
write(output, template)
|
45
50
|
|
46
51
|
# Thats all folks!
|
52
|
+
logger.debug('Processing complete.')
|
47
53
|
puts "Processing complete!" unless options[:quiet]
|
48
54
|
puts "Packer file generated: #{options[:output]}" unless options[:quiet]
|
49
55
|
|
50
56
|
return 0
|
51
57
|
end
|
52
|
-
|
53
|
-
private
|
54
58
|
|
55
|
-
|
56
|
-
case level
|
57
|
-
when /fatal/
|
58
|
-
Log4r::FATAL
|
59
|
-
when /error/
|
60
|
-
Log4r::ERROR
|
61
|
-
when /warn/
|
62
|
-
Log4r::WARN
|
63
|
-
when /info/
|
64
|
-
Log4r::INFO
|
65
|
-
when /debug/
|
66
|
-
Log4r::DEBUG
|
67
|
-
else
|
68
|
-
Log4r::INFO
|
69
|
-
end
|
70
|
-
end
|
59
|
+
private
|
71
60
|
|
72
61
|
def options
|
73
62
|
@options ||= {
|
74
63
|
log_level: :warn,
|
75
|
-
knockout: '~~',
|
64
|
+
knockout: '~~',
|
76
65
|
output: '',
|
77
66
|
templates: [],
|
78
|
-
quiet: false,
|
67
|
+
quiet: false,
|
79
68
|
}
|
80
69
|
end
|
81
70
|
|
82
71
|
def option_parser
|
83
72
|
@option_parser ||= OptionParser.new do |opts|
|
84
73
|
opts.banner = "Usage: #{opts.program_name} [options] [TEMPLATE1, TEMPLATE2, ...] OUTPUT"
|
85
|
-
|
74
|
+
|
86
75
|
opts.on('-l', '--log-level [LEVEL]', [:fatal, :error, :warn, :info, :debug], 'Set log level') do |v|
|
87
76
|
options[:log_level] = v
|
88
77
|
end
|
@@ -106,5 +95,41 @@ module Racker
|
|
106
95
|
end
|
107
96
|
end
|
108
97
|
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def write(output_path, template)
|
102
|
+
if output_path == STDOUT_TOKEN
|
103
|
+
write_to_stdout(template)
|
104
|
+
else
|
105
|
+
write_to_file(template, output_path)
|
106
|
+
end
|
107
|
+
true
|
108
|
+
end
|
109
|
+
|
110
|
+
def write_to_file(template, path)
|
111
|
+
path = File.expand_path(path)
|
112
|
+
output_dir = File.dirname(path)
|
113
|
+
|
114
|
+
# Create output directory if it does not exist
|
115
|
+
unless File.directory?(output_dir)
|
116
|
+
logger.info(%Q[Creating output directory "#{output_dir}"])
|
117
|
+
FileUtils.mkdir_p(output_dir)
|
118
|
+
end
|
119
|
+
|
120
|
+
File.open(path, 'w') { |file| write_to_stream(template, file, path) }
|
121
|
+
end
|
122
|
+
|
123
|
+
def write_to_stdout(template)
|
124
|
+
write_to_stream(template, $stdout, :STDOUT)
|
125
|
+
end
|
126
|
+
|
127
|
+
def write_to_stream(template, stream, stream_name)
|
128
|
+
logger.info("Writing packer template to #{stream_name}")
|
129
|
+
stream.write(template)
|
130
|
+
stream.flush if stream.respond_to?(:flush)
|
131
|
+
logger.info("Writing packer template to #{stream_name} complete.")
|
132
|
+
end
|
133
|
+
|
109
134
|
end
|
110
135
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module Racker
|
4
|
+
module LogSupport
|
5
|
+
unless Log4r::Logger['racker']
|
6
|
+
# Create the initial logger
|
7
|
+
logger = Log4r::Logger.new('racker')
|
8
|
+
|
9
|
+
# Set the output to STDOUT
|
10
|
+
logger.outputters = Log4r::Outputter.stdout
|
11
|
+
|
12
|
+
# We set the initial log level to ERROR
|
13
|
+
logger.level = Log4r::ERROR
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.level=(level)
|
17
|
+
log_level = log4r_level_for(level)
|
18
|
+
logger.level = log_level
|
19
|
+
logger.info("Log level set to: #{log_level}")
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.log4r_level_for(level)
|
23
|
+
case level
|
24
|
+
when /fatal/
|
25
|
+
Log4r::FATAL
|
26
|
+
when /error/
|
27
|
+
Log4r::ERROR
|
28
|
+
when /warn/
|
29
|
+
Log4r::WARN
|
30
|
+
when /info/
|
31
|
+
Log4r::INFO
|
32
|
+
when /debug/
|
33
|
+
Log4r::DEBUG
|
34
|
+
else
|
35
|
+
Log4r::INFO
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.logger
|
40
|
+
Log4r::Logger['racker']
|
41
|
+
end
|
42
|
+
|
43
|
+
def logger
|
44
|
+
Racker::LogSupport.logger
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/racker/processor.rb
CHANGED
@@ -8,6 +8,7 @@ require 'pp'
|
|
8
8
|
module Racker
|
9
9
|
# This class handles command line options.
|
10
10
|
class Processor
|
11
|
+
include Racker::LogSupport
|
11
12
|
|
12
13
|
CONFIGURE_MUTEX = Mutex.new
|
13
14
|
|
@@ -16,30 +17,20 @@ module Racker
|
|
16
17
|
end
|
17
18
|
|
18
19
|
def execute!
|
19
|
-
# Get the global logger
|
20
|
-
log = Log4r::Logger['racker']
|
21
|
-
|
22
20
|
# Verify that the templates exist
|
23
21
|
@options[:templates].each do |template|
|
24
22
|
raise "File does not exist! (#{template})" unless ::File.exists?(template)
|
25
23
|
end
|
26
24
|
|
27
|
-
# Check that the output directory exists
|
28
|
-
output_dir = File.dirname(File.expand_path(@options[:output]))
|
29
|
-
|
30
|
-
# If the output directory doesnt exist
|
31
|
-
log.info('Creating the output directory if it does not exist...')
|
32
|
-
FileUtils.mkdir_p output_dir unless File.exists? output_dir
|
33
|
-
|
34
25
|
# Load the templates
|
35
26
|
templates = []
|
36
27
|
|
37
28
|
# Load the template procs
|
38
|
-
|
29
|
+
logger.info('Loading racker templates...')
|
39
30
|
template_procs = load(@options[:templates])
|
40
31
|
|
41
32
|
# Load the actual templates
|
42
|
-
|
33
|
+
logger.info('Processing racker templates...')
|
43
34
|
template_procs.each do |version,proc|
|
44
35
|
# Create the new template
|
45
36
|
template = Racker::Template.new
|
@@ -50,27 +41,23 @@ module Racker
|
|
50
41
|
# Store the template
|
51
42
|
templates << template
|
52
43
|
end
|
53
|
-
|
44
|
+
logger.info('Racker template processing complete.')
|
54
45
|
|
55
46
|
# Get the first template and merge each subsequent one on the latest
|
56
|
-
|
47
|
+
logger.info('Merging racker templates...')
|
57
48
|
current_template = templates.shift
|
58
49
|
|
59
50
|
# Overlay the templates
|
60
51
|
templates.each do |template|
|
61
52
|
current_template = current_template.deep_merge!(template, {:knockout_prefix => @options[:knockout]})
|
62
53
|
end
|
63
|
-
|
54
|
+
|
64
55
|
# Compact the residual template to remove nils
|
65
|
-
|
56
|
+
logger.info('Compacting racker template...')
|
66
57
|
compact_template = current_template.compact(:recurse => true)
|
67
58
|
|
68
|
-
#
|
69
|
-
|
70
|
-
log.info('Writing packer template...')
|
71
|
-
file.write(JSON.pretty_generate(compact_template.to_packer))
|
72
|
-
log.info('Writing packer template complete.')
|
73
|
-
end
|
59
|
+
# Pretty-print the JSON template
|
60
|
+
JSON.pretty_generate(compact_template.to_packer)
|
74
61
|
end
|
75
62
|
|
76
63
|
def load(templates)
|
@@ -98,4 +85,4 @@ module Racker
|
|
98
85
|
end
|
99
86
|
end
|
100
87
|
end
|
101
|
-
end
|
88
|
+
end
|
@@ -62,7 +62,7 @@ module DeepMergeModified
|
|
62
62
|
# dest = {:x => [{:z => 2}]}
|
63
63
|
# dest.deep_merge!(source, {:merge_hash_arrays => true})
|
64
64
|
# Results: {:x => [{:y => 1, :z => 2}]}
|
65
|
-
#
|
65
|
+
#
|
66
66
|
# There are many tests for this library - and you can learn more about the features
|
67
67
|
# and usages of deep_merge! by just browsing the test examples
|
68
68
|
def self.deep_merge!(source, dest, options = {})
|
data/lib/racker/template.rb
CHANGED
@@ -7,6 +7,7 @@ require 'racker/builders/docker'
|
|
7
7
|
require 'racker/builders/google'
|
8
8
|
require 'racker/builders/null'
|
9
9
|
require 'racker/builders/openstack'
|
10
|
+
require 'racker/builders/parallels'
|
10
11
|
require 'racker/builders/qemu'
|
11
12
|
require 'racker/builders/virtualbox'
|
12
13
|
require 'racker/builders/vmware'
|
@@ -14,22 +15,21 @@ require 'racker/builders/vmware'
|
|
14
15
|
module Racker
|
15
16
|
# This class handles the bulk of the legwork working with Racker templates
|
16
17
|
class Template < Smash
|
18
|
+
include Racker::LogSupport
|
19
|
+
|
17
20
|
# This formats the template into packer format hash
|
18
21
|
def to_packer
|
19
|
-
# Get the global logger
|
20
|
-
log = Log4r::Logger['racker']
|
21
|
-
|
22
22
|
# Create the new smash
|
23
23
|
packer = Smash.new
|
24
24
|
|
25
25
|
# Variables
|
26
26
|
packer['variables'] = self['variables'].dup unless self['variables'].nil? || self['variables'].empty?
|
27
|
-
|
27
|
+
|
28
28
|
# Builders
|
29
29
|
packer['builders'] = [] unless self['builders'].nil? || self['builders'].empty?
|
30
|
-
|
30
|
+
logger.info("Processing builders...")
|
31
31
|
self['builders'].each do |name,config|
|
32
|
-
|
32
|
+
logger.info("Processing builder: #{name} with type: #{config['type']}")
|
33
33
|
|
34
34
|
# Get the builder for this config
|
35
35
|
builder = get_builder(config['type'])
|
@@ -40,19 +40,19 @@ module Racker
|
|
40
40
|
|
41
41
|
# Provisioners
|
42
42
|
packer['provisioners'] = [] unless self['provisioners'].nil? || self['provisioners'].empty?
|
43
|
-
|
43
|
+
logger.info("Processing provisioners...")
|
44
44
|
self['provisioners'].sort.map do |index, provisioners|
|
45
45
|
provisioners.each do |name,config|
|
46
|
-
|
46
|
+
logger.debug("Processing provisioner: #{name}")
|
47
47
|
packer['provisioners'] << config.dup
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
51
|
# Post-Processors
|
52
52
|
packer['post-processors'] = [] unless self['postprocessors'].nil? || self['postprocessors'].empty?
|
53
|
-
|
53
|
+
logger.info("Processing post-processors...")
|
54
54
|
self['postprocessors'].each do |name,config|
|
55
|
-
|
55
|
+
logger.debug("Processing post-processor: #{name}")
|
56
56
|
packer['post-processors'] << config.dup unless config.nil?
|
57
57
|
end
|
58
58
|
|
data/lib/racker/version.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe :output_to_file do
|
4
|
+
before(:all) do
|
5
|
+
@output_path = "/tmp/#{SecureRandom.uuid}/this_directory_should_not_exist/template.json"
|
6
|
+
@instance = Racker::CLI.new(['-q', fixture_path('low_priority_template.rb'), @output_path])
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'when successful' do
|
10
|
+
it 'writes the computed template to the given path' do
|
11
|
+
output_dir = File.dirname(@output_path)
|
12
|
+
FileUtils.rm_rf(output_dir) if Dir.exists?(output_dir)
|
13
|
+
|
14
|
+
@instance.execute!
|
15
|
+
expect(File.exists?(@output_path)).to eq(true)
|
16
|
+
|
17
|
+
result = JSON.parse(File.read(@output_path))
|
18
|
+
expect(result).to eq(parsed_low_priority_template)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe :output_to_stdout do
|
4
|
+
before(:all) do
|
5
|
+
@instance = Racker::CLI.new([fixture_path('low_priority_template.rb'), '-'])
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'when successful' do
|
9
|
+
it 'writes the computed template to $stdout' do
|
10
|
+
pretty_output = JSON.pretty_generate(parsed_low_priority_template)
|
11
|
+
expect(@instance).to receive(:puts).never
|
12
|
+
expect($stdout).to receive(:write).with(pretty_output)
|
13
|
+
@instance.execute!
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'racker'
|
2
|
+
|
3
|
+
class RSpec::Core::ExampleGroup
|
4
|
+
FIXTURE_DIR = File.expand_path('../fixtures', __FILE__)
|
5
|
+
PARSED_LOW_PRIORITY_TEMPLATE = {
|
6
|
+
'variables' => {
|
7
|
+
'iso_url' => 'os.img',
|
8
|
+
'password' => 'password',
|
9
|
+
},
|
10
|
+
}.freeze
|
11
|
+
|
12
|
+
def fixture_path(filename)
|
13
|
+
File.join(FIXTURE_DIR, filename.to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
def parsed_low_priority_template
|
17
|
+
PARSED_LOW_PRIORITY_TEMPLATE
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Racker::CLI do
|
4
|
+
|
5
|
+
context '#execute!' do
|
6
|
+
it 'exits with a status of 1 if fewer than 2 arguments were received' do
|
7
|
+
allow(Kernel).to receive(:exit!)
|
8
|
+
|
9
|
+
instance = Racker::CLI.new(['template.rb'])
|
10
|
+
allow(instance).to receive(:puts)
|
11
|
+
|
12
|
+
# This next call is going to break somewhere because we stubbed the exit!
|
13
|
+
# call, so catch any error that occurs.
|
14
|
+
instance.execute! rescue nil
|
15
|
+
|
16
|
+
# set expextation on puts to silence output
|
17
|
+
expect(instance).to have_received(:puts)
|
18
|
+
expect(Kernel).to have_received(:exit!).with(1)
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with valid options' do
|
22
|
+
before(:each) do
|
23
|
+
@immutable_argv = ['template.rb', 'environment.rb', 'template.json'].freeze
|
24
|
+
@argv = @immutable_argv.dup
|
25
|
+
@instance = Racker::CLI.new(@argv)
|
26
|
+
@options = @instance.send(:options)
|
27
|
+
@options[:quiet] = true
|
28
|
+
# Prevent fake file from being written
|
29
|
+
allow(File).to receive(:open)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'uses the last argument for the value of the output option' do
|
33
|
+
allow_any_instance_of(Racker::Processor).to receive(:execute!)
|
34
|
+
@instance.execute!
|
35
|
+
expect(@options[:output]).to eq(@immutable_argv.last)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'uses all arguments except the last for the value of the templates option' do
|
39
|
+
allow_any_instance_of(Racker::Processor).to receive(:execute!)
|
40
|
+
@instance.execute!
|
41
|
+
expect(@options[:templates]).to eq(@immutable_argv[0..-2])
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'initializes and executes a new Racker::Processor with the given options' do
|
45
|
+
processor_instance = Racker::Processor.new(@options)
|
46
|
+
expect(Racker::Processor).to receive(:new) { processor_instance }.with(@options)
|
47
|
+
expect(processor_instance).to receive(:execute!)
|
48
|
+
@instance.execute!
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'outputs no message when quieted' do
|
52
|
+
@options[:quiet] = true
|
53
|
+
allow_any_instance_of(Racker::Processor).to receive(:execute!)
|
54
|
+
expect(@instance).not_to receive(:puts)
|
55
|
+
@instance.execute!
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'outputs a message upon success when not quieted' do
|
59
|
+
@options[:quiet] = false
|
60
|
+
allow_any_instance_of(Racker::Processor).to receive(:execute!)
|
61
|
+
expect(@instance).to receive(:puts).at_least(1)
|
62
|
+
@instance.execute!
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns 0 on success' do
|
66
|
+
allow_any_instance_of(Racker::Processor).to receive(:execute!)
|
67
|
+
expect(@instance.execute!).to eq(0)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context '#initialize' do
|
73
|
+
it 'sets the @argv instance variable to the provided argument' do
|
74
|
+
instance = described_class.new(argv = [])
|
75
|
+
expect(instance.instance_variable_get(:@argv).object_id).to eq(argv.object_id)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context '#option_parser' do
|
80
|
+
before(:each) { @instance = described_class.new([]) }
|
81
|
+
|
82
|
+
it 'returns a new default OptionParser if none exists' do
|
83
|
+
expect(@instance.instance_variable_get(:@option_parser)).to eq(nil)
|
84
|
+
expect(@instance.send(:option_parser)).to be_an(OptionParser)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'returns the same OptionParser on subsequent calls' do
|
88
|
+
first_option_parser = @instance.send(:option_parser)
|
89
|
+
second_option_parser = @instance.send(:option_parser)
|
90
|
+
expect(second_option_parser).to be(first_option_parser)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context '#options' do
|
95
|
+
before(:each) { @instance = described_class.new([]) }
|
96
|
+
|
97
|
+
it 'returns a Hash of default options if none exists' do
|
98
|
+
expect(@instance.instance_variable_get(:@options)).to eq(nil)
|
99
|
+
options = @instance.send(:options)
|
100
|
+
expect(options).to eq({
|
101
|
+
log_level: :warn,
|
102
|
+
knockout: '~~',
|
103
|
+
output: '',
|
104
|
+
templates: [],
|
105
|
+
quiet: false,
|
106
|
+
})
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'returns the same Hash on subsequent calls' do
|
110
|
+
first_options = @instance.send(:options)
|
111
|
+
second_options = @instance.send(:options)
|
112
|
+
expect(second_options).to be(first_options)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'option parser' do
|
117
|
+
before(:all) { @instance = described_class.new([]) }
|
118
|
+
before(:each) do
|
119
|
+
@instance.instance_variable_set(:@option_parser, nil)
|
120
|
+
@instance.instance_variable_set(:@options, nil)
|
121
|
+
@parser = @instance.send(:option_parser)
|
122
|
+
@options = @instance.send(:options)
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'log_level' do
|
126
|
+
%w[-l --log-level].each do |format|
|
127
|
+
it "is triggered by the #{format} arg" do
|
128
|
+
@options.delete(:log_level)
|
129
|
+
@parser.parse!(%W[#{format} fatal])
|
130
|
+
expect(@options[:log_level]).to be(:fatal)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
%w[debug error fatal info warn].each do |log_level|
|
135
|
+
it "supports a log level of #{log_level}" do
|
136
|
+
@options.delete(:log_level)
|
137
|
+
@parser.parse!(%W[-l #{log_level}])
|
138
|
+
expect(@options[:log_level]).to be(log_level.to_sym)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'defaults invalid log levels to nil' do
|
143
|
+
@options.delete(:log_level)
|
144
|
+
@parser.parse!(%W[-l foo])
|
145
|
+
expect(@options[:log_level]).to be(nil)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'knockout' do
|
150
|
+
%w[-k --knockout].each do |format|
|
151
|
+
it "is triggered by the #{format} arg" do
|
152
|
+
@options.delete(:knockout)
|
153
|
+
@parser.parse!(%W[#{format} xxx])
|
154
|
+
expect(@options[:knockout]).to eq('xxx')
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'quiet' do
|
160
|
+
%w[-q --quiet].each do |format|
|
161
|
+
it "is triggered by the #{format} arg" do
|
162
|
+
@options.delete(:quiet)
|
163
|
+
@parser.parse!([format])
|
164
|
+
expect(@options[:quiet]).to eq(true)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context 'help' do
|
170
|
+
%w[-h --help].each do |format|
|
171
|
+
it "is triggered by the #{format} arg" do
|
172
|
+
expect(@instance).to receive(:puts)
|
173
|
+
expect(Kernel).to receive(:exit!)
|
174
|
+
@parser.parse!([format])
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'outputs help then exits with a status of 0' do
|
179
|
+
expect(@instance).to receive(:puts)
|
180
|
+
expect(Kernel).to receive(:exit!).with(0)
|
181
|
+
@parser.parse!(['--help'])
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context 'version' do
|
186
|
+
%w[-v --version].each do |format|
|
187
|
+
it "is triggered by the #{format} arg" do
|
188
|
+
expect(@instance).to receive(:puts)
|
189
|
+
expect(Kernel).to receive(:exit!)
|
190
|
+
@parser.parse!([format])
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'outputs the version then exits with a status of 0' do
|
195
|
+
expect(@instance).to receive(:puts)
|
196
|
+
expect(Kernel).to receive(:exit!).with(0)
|
197
|
+
@parser.parse!(['--version'])
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|