Skip to content

Commit

Permalink
Add configuration file
Browse files Browse the repository at this point in the history
  • Loading branch information
vladgh committed Jun 12, 2014
1 parent 9def83a commit f928415
Show file tree
Hide file tree
Showing 17 changed files with 316 additions and 85 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ Automation daemon.
### Gem installation
`gem install vscripts`

## Configuration

VScripts looks for a configuration file in the following locations(in order):
- a file specified in the `--config` command line option
- `.vscripts.yml` in the $HOME directory
- `/etc/vscripts/config.yml`

## Usage

Expand All @@ -26,8 +32,9 @@ vscripts GLOBAL-OPTIONS COMMAND OPTIONS

### Global Options
```
-h|--help: Displays VScripts help.
-v|--version: Displays the version number.
--config, -c <s>: Specify configuration file
--help, -h : Displays VScripts help
--version, -v : Displays the version number
```


Expand Down
2 changes: 1 addition & 1 deletion bin/vscripts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env ruby

require 'vscripts'
VScripts.run(ARGV)
VScripts.run
17 changes: 13 additions & 4 deletions lib/vscripts.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
require 'vscripts/commands'
require 'vscripts/command_line'
require 'vscripts/config'

# Main VScripts module
module VScripts
# Reads the command line arguments
def self.cli
@cli ||= CommandLine.new # Parses command line
end

# Reads the configuration files
def self.config
@config ||= VScripts::Config.new(cli.global.config) # Parses configuration
end

# Reads the arguments and runs the given command
def self.run(argv)
cli = CommandLine.new(argv)
command = VScripts::Commands.const_get(cli.command).new(cli.arguments)
command.execute
def self.run
VScripts::Commands.const_get(cli.command).new(cli.arguments).execute
end
end # module VScripts
24 changes: 13 additions & 11 deletions lib/vscripts/command_line.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ class CommandLine
attr_reader :command

# Builds command line arguments
def initialize(argv = [])
def initialize(argv = ARGV)
@arguments ||= argv
@global ||= parse_cli_options
@command ||= verify_command
end

# Specifies command line options
Expand All @@ -32,36 +31,39 @@ def parser # rubocop:disable MethodLength
Available commands:
#{available}
Usage:
USAGE:
vscripts GLOBAL-OPTIONS COMMAND OPTIONS
For help on an individual command:
vscripts COMMAND --help
Global Options:
GLOBAL OPTIONS:
EOS
opt :config, 'Specify configuration file',
type: :string, short: '-c'
stop_on_unknown
stop_on available
end
end

# @return [Hash] the command line arguments
def parse_cli_options
Trollop.with_standard_exception_handling parser do
fail Trollop::HelpNeeded if arguments.empty?
parser.parse arguments
@cli_options = parser.parse arguments
fail Trollop::HelpNeeded if arguments.empty? || !verify_command
end
@cli_options
end

# Ensures command is available
# @return [String] the command name
def verify_command
command_cli = arguments.shift
return unless command_cli
command_cls = command_cli.capitalize.to_sym
if Commands.list.include?(command_cls)
return command_cls
else
abort "Error: unknown subcommand '#{command_cli}'\nTry --help."
end
abort "Error: unknown subcommand '#{command_cli}'\nTry --help." \
unless Commands.list.include?(command_cls)
@command ||= command_cls
end
end # class CommandLine
end # module VScripts
55 changes: 55 additions & 0 deletions lib/vscripts/config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
require 'yaml'

module VScripts
# VScripts Configuration
class Config
# User's configuration file
DOT_FILE = "#{File.expand_path('~')}/.vscripts.yml"
# Global configuration file
SYSTEM_CONFIG_FILE = '/etc/vscripts/config.yml'
# Global defaults
GLOBAL_DEFAULTS = {}

# @return [Hash] all configuration options
attr_reader :get

# Loads class
# @param cfg_file [String] the path to the configuration file
def initialize(cfg_file = nil)
@cfg_file ||= cfg_file
end

# @return [Hash] the configuration options
def get
@get ||= GLOBAL_DEFAULTS.merge(options)
end

# Parses the configuration files in order
# @return [Hash] the first configuration hash found
def options
parse(@cfg_file) ||
parse(DOT_FILE) ||
parse(SYSTEM_CONFIG_FILE) ||
{}
end

# Parses the configuration
# @param file [String] the path to the configuration file
# @return [Hash] the configuration hash
def parse(file)
YAML.load(read(file)) if check_config(file)
end

# @param (see #parse)
# @return [String] the contents of the file
def read(file)
File.read(file)
end

# @param (see #parse)
# @return [Boolean] true if the file exists
def check_config(file)
file && File.exist?(file)
end
end # class Config
end # module VScripts
38 changes: 22 additions & 16 deletions spec/integration/commands/identify_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,34 @@
describe 'Command: Identify' do
include_context 'System files'
include_context 'Suppressed output'

subject { VScripts }
include_context 'VScripts'

before(:each) do
allow_any_instance_of(VScripts::Commands::Identify)
.to receive('`')
allow_any_instance_of(identify).to receive('`')
end

context 'when \'--help\'' do
it 'returns command specific help' do
expect{subject.run(['identify', '--help'])}.to raise_error(SystemExit)
stub_cli_with('identify --help')
expect{subject.run}.to raise_error(SystemExit)
expect($stdout.string).to match(/USAGE:/)
expect($stdout.string).to match(/OPTIONS:/)
end
end

context 'when unknown argument' do
it 'returns error with message' do
expect{subject.run(['identify', '--xyz'])}.to raise_error(SystemExit)
stub_cli_with('identify --xyz')
expect{subject.run}.to raise_error(SystemExit)
expect($stderr.string).to match(/Error: unknown argument/)
end
end

context 'when not an EC2 instance' do
include_context 'Not an EC2 Instance'
it 'returns error with message' do
expect{subject.run(['identify'])}.to raise_error(SystemExit)
stub_cli_with('identify')
expect{subject.run}.to raise_error(SystemExit)
expect($stderr.string)
.to match('FATAL: NOT an EC2 instance or could not connect to Metadata')
end
Expand All @@ -40,43 +41,48 @@

context 'without tags' do
it 'writes default hostname' do
allow_any_instance_of(VScripts::Commands::Identify).to receive(:tag)
subject.run(['identify'])
stub_cli_with('identify')
allow_any_instance_of(identify).to receive(:tag)
subject.run
expect(IO.read(hostname_file)).to eq('1')
expect($stdout.string).to match('Done.')
end
end

context 'and when \'--ec2-tag-theme\'' do
it 'returns the themed host' do
allow_any_instance_of(VScripts::Commands::Identify).to receive(:tag)
stub_cli_with('identify --ec2-tag-theme=Test-#')
allow_any_instance_of(identify).to receive(:tag)
.and_return('TestValue')
subject.run(['identify', '--ec2-tag-theme=Test-#'])
subject.run
expect(IO.read(hostname_file)).to eq('TestValue-1')
end
end

context 'and when \'--host\'' do
it 'returns the new host' do
subject.run(['identify', '--host=test-host'])
stub_cli_with('identify --host=test-host')
subject.run
expect(IO.read(hostname_file)).to eq('test-host')
end
end

context 'and when \'--domain\'' do
it 'returns the new domain' do
subject.run(['identify', '--domain=example.tld'])
stub_cli_with('identify --domain=example.tld')
subject.run
expect(IO.read(hosts_file)).to match('example.tld')
end
end

context 'and when similar found' do
it 'returns the incremented host' do
allow_any_instance_of(VScripts::Commands::Identify).to receive(:tag)
stub_cli_with('identify --ec2-tag-theme=Test-#')
allow_any_instance_of(identify).to receive(:tag)
.and_return('TestName')
allow_any_instance_of(VScripts::Commands::Identify).to receive(:domain)
allow_any_instance_of(identify).to receive(:domain)
.and_return('TestDomain.tld')
subject.run(['identify', '--ec2-tag-theme=Test-#'])
subject.run
expect(IO.read(hostname_file)).to eq('TestName-2')
expect(IO.read(hosts_file)).to match('TestName-2.TestDomain.tld')
end
Expand Down
32 changes: 19 additions & 13 deletions spec/integration/commands/tags2facts_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,33 @@
describe 'Command: Tags2Facts' do
include_context 'Suppressed output'
include_context 'Temporary'
include_context 'VScripts'

subject { VScripts }
before(:each) do
stub_cli_with('tags2facts')
end

context 'when \'--help\'' do
it 'returns command specific help' do
expect{subject.run(['tags2facts', '--help'])}.to raise_error(SystemExit)
stub_cli_with('tags2facts --help')
expect{subject.run}.to raise_error(SystemExit)
expect($stdout.string).to match(/USAGE:/)
expect($stdout.string).to match(/OPTIONS:/)
end
end

context 'when unknown argument' do
it 'returns error with message' do
expect{subject.run(['tags2facts', '--xyz'])}.to raise_error(SystemExit)
stub_cli_with('tags2facts --xyz')
expect{subject.run}.to raise_error(SystemExit)
expect($stderr.string).to match(/Error: unknown argument/)
end
end

context 'when not an EC2 instance' do
include_context 'Not an EC2 Instance'
it 'returns error with message' do
expect{subject.run(['tags2facts'])}.to raise_error(SystemExit)
expect{subject.run}.to raise_error(SystemExit)
expect($stderr.string)
.to match('FATAL: NOT an EC2 instance or could not connect to Metadata')
end
Expand All @@ -34,7 +39,7 @@
context 'without tags' do
include_context 'EC2 Instance without tags'
it 'returns error with message' do
expect{subject.run(['tags2facts'])}.to raise_error(SystemExit)
expect{subject.run}.to raise_error(SystemExit)
expect($stderr.string).to match(/No tags were found/)
end
end
Expand All @@ -51,34 +56,35 @@
context '--all specified' do
include_context 'EC2 Instance with tags'
it 'creates file' do
allow_any_instance_of(VScripts::Commands::Tags2facts)
.to receive_message_chain('cli.all').and_return(true)
subject.run(['tags2facts', '--all'])
expect(IO.read(test_file))
.to match(tags['Name'])
stub_cli_with('tags2facts --all')
allow_any_instance_of(VScripts::Commands::Tags2facts)
.to receive_message_chain('cli.all').and_return(true)
subject.run
expect(IO.read(test_file)).to match(tags['Name'])
end
end

context '--all not specified' do
include_context 'EC2 Instance with tags'
it 'creates file' do
subject.run(['tags2facts'])
subject.run
expect(IO.read(test_file)).to match(tags.keys.last)
end
end

context '--file specified' do
include_context 'EC2 Instance with tags'
it 'creates file' do
subject.run(['tags2facts', "--file #{test_file}"])
stub_cli_with("tags2facts --file #{test_file}")
subject.run
expect(IO.read(test_file)).to match(tags.keys.last)
end
end

context '--file not specified' do
include_context 'EC2 Instance with tags'
it 'creates file' do
subject.run(['tags2facts'])
subject.run
expect(IO.read(test_file)).to match(tags.keys.last)
end
end
Expand Down
6 changes: 3 additions & 3 deletions spec/integration/commands_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

describe 'Command: Unknown' do
include_context 'Suppressed output'

subject { VScripts }
include_context 'VScripts'

it 'returns error with message' do
expect{subject.run(['xyz'])}.to raise_error(SystemExit)
stub_any_cli_with('xyz')
expect{subject.run}.to raise_error(SystemExit)
expect($stderr.string).to match(/Error: unknown subcommand/)
end
end
Loading

0 comments on commit f928415

Please sign in to comment.