configurability 3.2.0 → 4.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.
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
-