4
# This class handles all the aspects of a Puppet application/executable
7
# * choosing what to run
10
# The application is a Puppet::Application object that register itself in the list
11
# of available application. Each application needs a +name+ and a getopt +options+
14
# The executable uses the application object like this:
15
# Puppet::Application[:example].run
18
# Puppet::Application.new(:example) do
21
# # perform some pre initialization
25
# # dispatch is called to know to what command to call
30
# option("--arg ARGUMENT") do |v|
34
# option("--debug", "-d") do |v|
38
# option("--all", "-a:) do |v|
42
# unknown do |opt,arg|
43
# # last chance to manage an option
45
# # let's say to the framework we finally handle this option
60
# The preinit block is the first code to be called in your application, before option parsing,
61
# setup or command execution.
64
# Puppet::Application uses +OptionParser+ to manage the application options.
65
# Options are defined with the +option+ method to which are passed various
66
# arguments, including the long option, the short option, a description...
67
# Refer to +OptionParser+ documentation for the exact format.
68
# * If the option method is given a block, this one will be called whenever
69
# the option is encountered in the command-line argument.
70
# * If the option method has no block, a default functionnality will be used, that
71
# stores the argument (or true/false if the option doesn't require an argument) in
72
# the global (to the application) options array.
73
# * If a given option was not defined by a the +option+ method, but it exists as a Puppet settings:
74
# * if +unknown+ was used with a block, it will be called with the option name and argument
75
# * if +unknown+ wasn't used, then the option/argument is handed to Puppet.settings.handlearg for
78
# --help is managed directly by the Puppet::Application class, but can be overriden.
81
# Applications can use the setup block to perform any initialization.
82
# The defaul +setup+ behaviour is to: read Puppet configuration and manage log level and destination
84
# === What and how to run
85
# If the +dispatch+ block is defined it is called. This block should return the name of the registered command
87
# If it doesn't exist, it defaults to execute the +main+ command if defined.
89
class Puppet::Application
97
attr_reader :options, :opt_parser
100
name = symbolize(name)
104
def should_parse_config
108
def should_not_parse_config
109
@parse_config = false
112
def should_parse_config?
113
unless @parse_config.nil?
119
# used to declare a new command
120
def command(name, &block)
121
meta_def(symbolize(name), &block)
124
# used as a catch-all for unknown option
126
meta_def(:handle_unknown, &block)
129
# used to declare code that handle an option
130
def option(*options, &block)
131
long = options.find { |opt| opt =~ /^--/ }.gsub(/^--(?:\[no-\])?([^ =]+).*$/, '\1' ).gsub('-','_')
132
fname = "handle_#{long}"
134
meta_def(symbolize(fname), &block)
136
meta_def(symbolize(fname)) do |value|
137
self.options["#{long}".to_sym] = value
140
@opt_parser.on(*options) do |value|
141
self.send(symbolize(fname), value)
145
# used to declare accessor in a more natural way in the
146
# various applications
147
def attr_accessor(*args)
150
instance_variable_get("@#{arg}".to_sym)
152
meta_def("#{arg}=") do |value|
153
instance_variable_set("@#{arg}".to_sym, value)
158
# used to declare code run instead the default setup
160
meta_def(:run_setup, &block)
163
# used to declare code to choose which command to run
165
meta_def(:get_command, &block)
168
# used to execute code before running anything else
170
meta_def(:run_preinit, &block)
173
def initialize(name, banner = nil, &block)
174
@opt_parser = OptionParser.new(banner)
176
name = symbolize(name)
182
instance_eval(&block) if block_given?
184
@@applications[name] = self
187
# initialize default application behaviour
201
option("--version", "-V") do |arg|
202
puts "%s" % Puppet.version
206
option("--help", "-h") do |v|
211
# This is the main application entry point
213
exit_on_fail("initialize") { run_preinit }
214
exit_on_fail("parse options") { parse_options }
215
exit_on_fail("parse configuration file") { Puppet.settings.parse } if should_parse_config?
216
exit_on_fail("prepare for execution") { run_setup }
217
exit_on_fail("run") { run_command }
221
raise NotImplementedError, "No valid command or main"
225
if command = get_command() and respond_to?(command)
233
# Handle the logging settings
234
if options[:debug] or options[:verbose]
235
Puppet::Util::Log.newdestination(:console)
237
Puppet::Util::Log.level = :debug
239
Puppet::Util::Log.level = :info
243
unless options[:setdest]
244
Puppet::Util::Log.newdestination(:syslog)
249
# get all puppet options
251
optparse_opt = Puppet.settings.optparse_addargs(optparse_opt)
253
# convert them to OptionParser format
254
optparse_opt.each do |option|
255
@opt_parser.on(*option) do |arg|
256
handlearg(option[0], arg)
260
# scan command line argument
263
rescue OptionParser::ParseError => detail
265
$stderr.puts "Try '#{$0} --help'"
270
def handlearg(opt, arg)
271
# rewrite --[no-]option to --no-option if that's what was given
272
if opt =~ /\[no-\]/ and !arg
273
opt = opt.gsub(/\[no-\]/,'no-')
275
# otherwise remove the [no-] prefix to not confuse everybody
276
opt = opt.gsub(/\[no-\]/, '')
277
unless respond_to?(:handle_unknown) and send(:handle_unknown, opt, arg)
278
# Puppet.settings.handlearg doesn't handle direct true/false :-)
279
if arg.is_a?(FalseClass)
281
elsif arg.is_a?(TrueClass)
284
Puppet.settings.handlearg(opt, arg)
288
# this is used for testing
294
if Puppet.features.usage?
295
::RDoc::usage && exit
297
puts "No help available unless you have RDoc::usage installed"
304
def exit_on_fail(message, code = 1)
307
rescue RuntimeError, NotImplementedError => detail
308
puts detail.backtrace if Puppet[:trace]
309
$stderr.puts "Could not %s: %s" % [message, detail]