configurability 3.2.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
metadata.gz.sig CHANGED
Binary file
@@ -1,335 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # vim: set nosta noet ts=4 sw=4:
3
-
4
- require 'configurability'
5
- require 'configurability/config'
6
- require 'trollop'
7
- require 'highline'
8
-
9
- # Have to do it this way to avoid the vendored 'sysexits' under OSX.
10
- gem 'sysexits'
11
- require 'sysexits'
12
-
13
-
14
- # A tool for setting up and running Configurability apps
15
- class Configurability::Command
16
- extend ::Sysexits,
17
- Loggability
18
- include Sysexits
19
-
20
- # Loggability API -- log messages through the Configurability module's logger
21
- log_to :configurability
22
-
23
- # Make a HighLine color scheme
24
- COLOR_SCHEME = HighLine::ColorScheme.new do |scheme|
25
- scheme[:header] = [ :bold, :yellow ]
26
- scheme[:subheader] = [ :bold, :white ]
27
- scheme[:key] = [ :white ]
28
- scheme[:value] = [ :bold, :white ]
29
- scheme[:error] = [ :red ]
30
- scheme[:warning] = [ :yellow ]
31
- scheme[:message] = [ :reset ]
32
- end
33
-
34
-
35
- # Class instance variables
36
- @command_help = Hash.new {|h,k| h[k] = { :desc => nil, :usage => ''} }
37
- @prompt = @option_parser = nil
38
-
39
-
40
- ### Run the utility with the given +args+.
41
- def self::run( args )
42
- HighLine.color_scheme = COLOR_SCHEME
43
-
44
- oparser = self.make_option_parser
45
- opts = Trollop.with_standard_exception_handling( oparser ) do
46
- oparser.parse( args )
47
- end
48
-
49
- command = oparser.leftovers.shift
50
- self.new( opts ).run( command, *oparser.leftovers )
51
- exit :ok
52
-
53
- rescue => err
54
- self.log.fatal "Oops: %s: %s" % [ err.class.name, err.message ]
55
- self.log.debug { ' ' + err.backtrace.join("\n ") }
56
-
57
- exit :software_error
58
- end
59
-
60
-
61
- ### Return a String that describes the available commands, e.g., for the 'help'
62
- ### command.
63
- def self::make_command_table
64
- commands = self.available_commands
65
-
66
- # Build the command table
67
- col1len = commands.map( &:length ).max
68
- return commands.collect do |cmd|
69
- helptext = self.help( cmd.to_sym ) or next # no help == invisible command
70
- "%s %s" % [
71
- self.prompt.color(cmd.rjust(col1len), :key),
72
- self.prompt.color(helptext, :value)
73
- ]
74
- end.compact
75
- end
76
-
77
-
78
- ### Return an Array of the available commands.
79
- def self::available_commands
80
- return self.public_instance_methods( false ).
81
- map( &:to_s ).
82
- grep( /_command$/ ).
83
- map {|methodname| methodname.sub(/_command$/, '') }.
84
- sort
85
- end
86
-
87
-
88
- ### Create and configure a command-line option parser for the command.
89
- ### Returns a Trollop::Parser.
90
- def self::make_option_parser
91
- unless @option_parser
92
- progname = File.basename( $0 )
93
-
94
- # Make a list of the log level names and the available commands
95
- loglevels = Loggability::LOG_LEVELS.
96
- sort_by {|name,lvl| lvl }.
97
- collect {|name,lvl| name.to_s }.
98
- join( ', ' )
99
- command_table = self.make_command_table
100
-
101
- @option_parser = Trollop::Parser.new do
102
- banner "Configurability Reports"
103
-
104
- text ''
105
- command_table.each {|line| text(line) }
106
- text ''
107
-
108
- text 'Global Options'
109
- opt :require, "Require one or more additional libraries.",
110
- :multi => true, :type => :string
111
- opt :include, "Add additional directories to the load path.",
112
- :multi => true, :type => :string, :short => :I
113
- text ''
114
-
115
- text 'Other Options:'
116
- opt :debug, "Turn debugging on. Also sets the --loglevel to 'debug'."
117
- opt :loglevel, "Set the logging level. Must be one of: #{loglevels}",
118
- :default => Configurability.logger.level.to_s
119
- end
120
- end
121
-
122
- return @option_parser
123
- end
124
-
125
-
126
- ### Add a help string for the given +command+.
127
- def self::help( command, helpstring=nil )
128
- if helpstring
129
- @command_help[ command.to_sym ][:desc] = helpstring
130
- end
131
-
132
- return @command_help[ command.to_sym ][:desc]
133
- end
134
-
135
-
136
- ### Add/fetch the +usagestring+ for +command+.
137
- def self::usage( command, usagestring=nil )
138
- if usagestring
139
- prefix = usagestring[ /\A(\s+)/, 1 ]
140
- usagestring.gsub!( /^#{prefix}/m, '' ) if prefix
141
-
142
- @command_help[ command.to_sym ][:usage] = usagestring
143
- end
144
-
145
- return @command_help[ command.to_sym ][:usage]
146
- end
147
-
148
-
149
- ### Return the global Highline prompt object, creating it if necessary.
150
- def self::prompt
151
- unless @prompt
152
- @prompt = HighLine.new
153
-
154
- columns = @prompt.output_cols.nonzero? || 80
155
- rows = @prompt.output_rows.nonzero? || 1000
156
-
157
- @prompt.page_at = rows - 5
158
- @prompt.wrap_at = columns - 2
159
- end
160
-
161
- return @prompt
162
- end
163
-
164
-
165
- #################################################################
166
- ### I N S T A N C E M E T H O D S
167
- #################################################################
168
-
169
- ### Create a new instance of the command and set it up with the given
170
- ### +options+.
171
- def initialize( options )
172
- Loggability.format_with( :color ) if $stderr.tty?
173
- @options = options
174
-
175
- if @options.debug
176
- $DEBUG = true
177
- $VERBOSE = true
178
- Loggability.level = :debug
179
- elsif @options.loglevel
180
- Loggability.level = @options.loglevel
181
- end
182
-
183
- self.log.debug "Options are: %p" % [ options ]
184
- end
185
-
186
-
187
- ######
188
- public
189
- ######
190
-
191
- # The Trollop options hash the command will read its configuration from
192
- attr_reader :options
193
-
194
-
195
- # Delegate the instance #prompt method to the class method instead
196
- define_method( :prompt, &self.method(:prompt) )
197
-
198
-
199
- ### Run the command with the specified +command+ and +args+.
200
- def run( command, *args )
201
- command ||= 'info'
202
- cmd_method = nil
203
- loglevel = Configurability.logger.level
204
-
205
- # Unshift directories to the load path specified with -I
206
- self.options[:include].each do |path|
207
- dirs = path.split( File::PATH_SEPARATOR )
208
- self.log.debug "Prepending %p to the load path..." % [ dirs ]
209
- $LOAD_PATH.unshift( *dirs )
210
- end
211
-
212
- # Require libraries specified with -r
213
- self.options[:require].each do |lib|
214
- $stderr.puts "Requiring %p..." % [ lib ]
215
- require( lib )
216
- end
217
-
218
- Loggability.level = loglevel
219
- begin
220
- cmd_method = self.method( "#{command}_command" )
221
- rescue NameError => err
222
- error "No such command %p" % [ command ]
223
- exit :usage
224
- end
225
-
226
- cmd_method.call( *args )
227
- end
228
-
229
-
230
- #
231
- # Commands
232
- #
233
-
234
- ### The 'help' command
235
- def help_command( *args )
236
-
237
- # Subcommand help
238
- if !args.empty?
239
- command = args.shift
240
-
241
- if self.class.available_commands.include?( command )
242
- header( self.class.help(command) )
243
- desc = "\n" + 'Usage: ' + command + ' ' + self.class.usage(command) + "\n"
244
- message( desc )
245
- else
246
- error "No such command %p" % [ command ]
247
- end
248
-
249
- # Help by itself show the table of available commands
250
- else
251
- command_table = self.class.make_command_table
252
- header "Available Commands"
253
- message( *command_table )
254
- end
255
-
256
- end
257
- help :help, "Show help for a single COMMAND if given, or list available commands if not"
258
- usage :help, "[COMMAND]"
259
-
260
-
261
- ### The 'info' command
262
- def info_command( *args )
263
- header "Configurability Report"
264
-
265
- cobjects = Configurability.configurable_objects
266
-
267
- if cobjects.empty?
268
- message "No objects extended with Configurability were loaded.",
269
- "You can use the -I and -r flags to include library paths",
270
- "and require libraries."
271
- else
272
- colwidth = cobjects.map {|obj| obj.config_key.length }.max
273
- colwidth = 10 if colwidth < 10
274
-
275
- subheader "%*s %s" % [ colwidth, "Config Key", "Configurable Object" ]
276
- cobjects.each do |obj|
277
- message "%*s : %p" % [ colwidth, obj.config_key, obj ]
278
- end
279
- end
280
- end
281
- help :info, "Show objects with Configurability in loaded code. Use -r " +
282
- "to require additional libraries."
283
-
284
-
285
- ### The 'version' command
286
- def version_command( *args )
287
- message( "<%= color 'Version:', :header %> " + Configurability.version_string(true) )
288
- end
289
- help :version, "Prints the Configurability version."
290
-
291
-
292
- #
293
- # Helper methods
294
- #
295
-
296
-
297
-
298
- #
299
- # Utility methods
300
- #
301
-
302
- ### Output normal output
303
- def message( *parts )
304
- self.prompt.say( parts.map(&:to_s).join($/) )
305
- end
306
-
307
-
308
- ### Output the given +text+ highlighted as a header.
309
- def header( text )
310
- message( self.prompt.color(text, :header) )
311
- end
312
-
313
-
314
- ### Output the given +text+ highlighted as a subheader.
315
- def subheader( text )
316
- message( self.prompt.color(text, :subheader) )
317
- end
318
-
319
-
320
- ### Output the given +text+ highlighted as an error.
321
- def error( text )
322
- message( self.prompt.color(text, :error) )
323
- end
324
-
325
-
326
- ### Output the given +items+ as a columnar list.
327
- def list( *items )
328
- message( self.prompt.list(items.flatten.compact.map(&:to_s), :columns_down) )
329
- end
330
-
331
- end # class Configurability::Command
332
-
333
-
334
- Configurability::Command.run( ARGV.dup )
335
-