Class: Minestrone::CLI

Inherits:
Object
  • Object
show all
Includes:
Help, Options
Defined in:
lib/minestrone/cli.rb,
lib/minestrone/cli/help.rb,
lib/minestrone/cli/options.rb

Overview

The CLI class encapsulates the behavior of minestrone when it is invoked as a command-line utility. This allows other programs to embed Minestrone and preserve its command-line semantics.

Defined Under Namespace

Modules: Help, Options

Constant Summary

Constants included from Help

Help::HEADER_LEN, Help::LINE_PADDING, Help::MIN_MAX_LEN

Instance Attribute Summary collapse

Attributes included from Options

#options

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Help

#execute_requested_actions_with_help, #explain_task, #format_text, included, #long_help, #output_columns, #task_list

Methods included from Options

#coerce_variable, #coerce_variable_types!, #default_dotfile, #default_sysconf, #extract_environment_variables!, #home_directory, #look_for_default_recipe_file!, #option_parser, #parse_options!, #sysconf_directory

Constructor Details

#initialize(args) ⇒ CLI

Create a new CLI instance using the given array of command-line parameters to initialize it. By default, ARGV is used, but you can specify a different set of parameters (such as when embedded ‘min` in a program):

require 'minestrone/cli'
Minestrone::CLI.parse(%W(-vvvv -f config/deploy update_code)).execute!

Note that you can also embed ‘min` directly by creating a new Configuration instance and setting it up, The above snippet, redone using the Configuration class directly, would look like:

require 'minestrone'
require 'minestrone/cli'
config = Minestrone::Configuration.new
config.logger.level = Minestrone::Logger::TRACE
config.set(:password) { Minestrone::CLI.password_prompt } # sudo password
config.load "config/deploy"
config.update_code

There may be times that you want/need the additional control offered by manipulating the Configuration directly, but generally interfacing with the CLI class is recommended.



82
83
84
85
# File 'lib/minestrone/cli.rb', line 82

def initialize(args)
  @args = args.dup
  $stdout.sync = true # so that Net::SSH prompts show up
end

Instance Attribute Details

#argsObject (readonly)

The array of (unparsed) command-line options



22
23
24
# File 'lib/minestrone/cli.rb', line 22

def args
  @args
end

Class Method Details

.debug_prompt(cmd) ⇒ Object

Debug mode prompt



48
49
50
51
52
53
54
55
56
57
# File 'lib/minestrone/cli.rb', line 48

def self.debug_prompt(cmd)
  ui.say("Preparing to execute command: #{cmd}")
  prompt = "Execute ([Yes], No, Abort) "
  ui.ask("#{prompt}?  ") do |q|
    q.overwrite = false
    q.default = 'y'
    q.validate = /(y(es)?)|(no?)|(a(bort)?|\n)/i
    q.responses[:not_valid] = prompt
  end
end

.executeObject

Invoke minestrone using the ARGV array as the option parameters. This is what the command-line minestrone utility does.



32
33
34
# File 'lib/minestrone/cli.rb', line 32

def self.execute
  parse(ARGV).execute!
end

.parse(args) ⇒ Object

Return a new CLI instance with the given arguments pre-parsed and ready for execution.



26
27
28
# File 'lib/minestrone/cli.rb', line 26

def self.parse(args)
  self.new(args).tap { |c| c.parse_options! }
end

.password_prompt(prompt = "Password: ") ⇒ Object

Prompt for a password using echo suppression.



43
44
45
# File 'lib/minestrone/cli.rb', line 43

def self.password_prompt(prompt = "Password: ")
  ui.ask(prompt) { |q| q.echo = false }
end

.uiObject

Return the object that provides UI-specific methods, such as prompts and more.



38
39
40
# File 'lib/minestrone/cli.rb', line 38

def self.ui
  @ui ||= HighLine.new
end

Instance Method Details

#execute!Object

Using the options build when the command-line was parsed, instantiate a new Minestrone configuration, initialize it, and execute the requested actions.

Returns the Configuration instance used, if successful.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/minestrone/cli.rb', line 93

def execute!
  config = instantiate_configuration(options)

  config.debug = options[:debug]
  config.dry_run = options[:dry_run]
  config.logger.level = options[:verbose]

  set_pre_vars(config)
  load_recipes(config)

  config.trigger(:load)
  execute_requested_actions(config)
  config.trigger(:exit)

  config
rescue Exception => error
  handle_error(error)
end

#execute_requested_actions(config) ⇒ Object



112
113
114
115
116
117
118
# File 'lib/minestrone/cli.rb', line 112

def execute_requested_actions(config)
  Array(options[:vars]).each { |name, value| config.set(name, value) }

  Array(options[:actions]).each do |action|
    config.find_and_execute_task(action, :before => :start, :after => :finish)
  end
end

#handle_error(error) ⇒ Object

:nodoc:



145
146
147
148
149
150
151
152
153
154
# File 'lib/minestrone/cli.rb', line 145

def handle_error(error) #:nodoc:
  case error
  when Net::SSH::AuthenticationFailed
    abort "authentication failed for `#{error.message}'"
  when Minestrone::Error
    abort(error.message)
  else
    raise error
  end
end

#instantiate_configuration(options = {}) ⇒ Object

Primarily useful for testing, but subclasses of CLI could conceivably override this method to return a Configuration subclass or replacement.



141
142
143
# File 'lib/minestrone/cli.rb', line 141

def instantiate_configuration(options = {})
  Minestrone::Configuration.new(options)
end

#load_recipes(config) ⇒ Object

:nodoc:



125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/minestrone/cli.rb', line 125

def load_recipes(config) #:nodoc:
  # load the standard recipe definition
  config.load 'standard'

  # load systemwide config/recipe definition
  config.load(options[:sysconf]) if options[:sysconf] && File.file?(options[:sysconf])

  # load user config/recipe definition
  config.load(options[:dotfile]) if options[:dotfile] && File.file?(options[:dotfile])

  Array(options[:recipes]).each { |recipe| config.load(recipe) }
end

#set_pre_vars(config) ⇒ Object

:nodoc:



120
121
122
123
# File 'lib/minestrone/cli.rb', line 120

def set_pre_vars(config) #:nodoc:
  config.set :password, options[:password]
  Array(options[:pre_vars]).each { |name, value| config.set(name, value) }
end