configurability 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,76 +0,0 @@
1
- #
2
- # Dependency-checking and Installation Rake Tasks
3
-
4
- #
5
-
6
- require 'rubygems/dependency_installer'
7
- require 'rubygems/source_index'
8
- require 'rubygems/requirement'
9
- require 'rubygems/doc_manager'
10
-
11
- ### Install the specified +gems+ if they aren't already installed.
12
- def install_gems( gems )
13
-
14
- defaults = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({
15
- :generate_rdoc => true,
16
- :generate_ri => true,
17
- :install_dir => Gem.dir,
18
- :format_executable => false,
19
- :test => false,
20
- :version => Gem::Requirement.default,
21
- })
22
-
23
- # Check for root
24
- if Process.euid != 0
25
- $stderr.puts "This probably won't work, as you aren't root, but I'll try anyway"
26
- end
27
-
28
- gemindex = Gem::SourceIndex.from_installed_gems
29
-
30
- gems.each do |gemname, reqstring|
31
- requirement = Gem::Requirement.new( reqstring )
32
- trace "requirement is: %p" % [ requirement ]
33
-
34
- trace "Searching for an installed #{gemname}..."
35
- specs = gemindex.find_name( gemname )
36
- trace "...found %d specs: %s" %
37
- [ specs.length, specs.collect {|s| "%s %s" % [s.name, s.version] }.join(', ') ]
38
-
39
- if spec = specs.find {|spec| requirement.satisfied_by?(spec.version) }
40
- log "Version %s of %s is already installed (needs %s); skipping..." %
41
- [ spec.version, spec.name, requirement ]
42
- next
43
- end
44
-
45
- rgv = Gem::Version.new( Gem::RubyGemsVersion )
46
- installer = nil
47
-
48
- log "Trying to install #{gemname.inspect} #{requirement}..."
49
- if rgv >= Gem::Version.new( '1.1.1' )
50
- installer = Gem::DependencyInstaller.new
51
- installer.install( gemname, requirement )
52
- else
53
- installer = Gem::DependencyInstaller.new( gemname )
54
- installer.install
55
- end
56
-
57
- installer.installed_gems.each do |spec|
58
- log "Installed: %s" % [ spec.full_name ]
59
- end
60
-
61
- end
62
- end
63
-
64
-
65
- ### Task: install runtime dependencies
66
- desc "Install runtime dependencies as gems"
67
- task :install_dependencies do
68
- install_gems( DEPENDENCIES )
69
- end
70
-
71
- ### Task: install gems for development tasks
72
- desc "Install development dependencies as gems"
73
- task :install_dev_dependencies do
74
- install_gems( DEVELOPMENT_DEPENDENCIES )
75
- end
76
-
@@ -1,123 +0,0 @@
1
- #
2
- # Documentation Rake tasks
3
- #
4
-
5
- require 'rake/clean'
6
-
7
-
8
- # Append docs/lib to the load path if it exists for documentation
9
- # helpers.
10
- DOCSLIB = DOCSDIR + 'lib'
11
- $LOAD_PATH.unshift( DOCSLIB.to_s ) if DOCSLIB.exist?
12
-
13
- # Make relative string paths of all the stuff we need to generate docs for
14
- DOCFILES = Rake::FileList[ LIB_FILES + EXT_FILES + GEMSPEC.extra_rdoc_files ]
15
-
16
- # Documentation coverage constants
17
- COVERAGE_DIR = BASEDIR + 'coverage'
18
- COVERAGE_REPORT = COVERAGE_DIR + 'documentation.txt'
19
-
20
-
21
- # Prefer YARD, fallback to RDoc
22
- begin
23
- require 'yard'
24
- require 'yard/rake/yardoc_task'
25
-
26
- # Undo the lazy-assed monkeypatch yard/globals.rb installs and
27
- # re-install them as mixins as they should have been from the
28
- # start
29
- # <metamonkeypatch>
30
- class Object
31
- remove_method :log
32
- remove_method :P
33
- end
34
-
35
- module YardGlobals
36
- def P(namespace, name = nil)
37
- namespace, name = nil, namespace if name.nil?
38
- YARD::Registry.resolve(namespace, name, false, true)
39
- end
40
-
41
- def log
42
- YARD::Logger.instance
43
- end
44
- end
45
-
46
- class YARD::CLI::Base; include YardGlobals; end
47
- class YARD::CLI::Command; include YardGlobals; end
48
- class YARD::Parser::SourceParser; extend YardGlobals; include YardGlobals; end
49
- class YARD::Parser::CParser; include YardGlobals; end
50
- class YARD::CodeObjects::Base; include YardGlobals; end
51
- class YARD::Handlers::Base; include YardGlobals; end
52
- class YARD::Handlers::Processor; include YardGlobals; end
53
- class YARD::Serializers::Base; include YardGlobals; end
54
- class YARD::RegistryStore; include YardGlobals; end
55
- class YARD::Docstring; include YardGlobals; end
56
- module YARD::Templates::Helpers::ModuleHelper; include YardGlobals; end
57
- module YARD::Templates::Helpers::HtmlHelper; include YardGlobals; end
58
-
59
- if vvec(RUBY_VERSION) >= vvec("1.9.1")
60
- # Monkeypatched to allow more than two '#' characters at the beginning
61
- # of the comment line.
62
- # Patched from yard-0.5.8
63
- require 'yard/parser/ruby/ruby_parser'
64
- class YARD::Parser::Ruby::RipperParser < Ripper
65
- def on_comment(comment)
66
- visit_ns_token(:comment, comment)
67
- case comment
68
- when /\A# @group\s+(.+)\s*\Z/
69
- @groups.unshift [lineno, $1]
70
- return
71
- when /\A# @endgroup\s*\Z/
72
- @groups.unshift [lineno, nil]
73
- return
74
- end
75
-
76
- comment = comment.gsub(/^\#+\s{0,1}/, '').chomp
77
- append_comment = @comments[lineno - 1]
78
-
79
- if append_comment && @comments_last_column == column
80
- @comments.delete(lineno - 1)
81
- comment = append_comment + "\n" + comment
82
- end
83
-
84
- @comments[lineno] = comment
85
- @comments_last_column = column
86
- end
87
- end # class YARD::Parser::Ruby::RipperParser
88
- end
89
-
90
- # </metamonkeypatch>
91
-
92
- YARD_OPTIONS = [] unless defined?( YARD_OPTIONS )
93
-
94
- yardoctask = YARD::Rake::YardocTask.new( :apidocs ) do |task|
95
- task.files = DOCFILES
96
- task.options = YARD_OPTIONS
97
- task.options << '--debug' << '--verbose' if $trace
98
- end
99
- yardoctask.before = lambda {
100
- trace "Calling yardoc like:",
101
- " yardoc %s" % [ quotelist(yardoctask.options + yardoctask.files).join(' ') ]
102
- }
103
-
104
- YARDOC_CACHE = BASEDIR + '.yardoc'
105
- CLOBBER.include( YARDOC_CACHE.to_s )
106
-
107
- rescue LoadError
108
- require 'rdoc/task'
109
-
110
- desc "Build API documentation in #{API_DOCSDIR}"
111
- RDoc::Task.new( :apidocs ) do |task|
112
- task.main = "README"
113
- task.rdoc_files.include( DOCFILES )
114
- task.rdoc_dir = API_DOCSDIR.to_s
115
- task.options = RDOC_OPTIONS
116
- end
117
- end
118
-
119
- # Need the DOCFILES to exist to build the API docs
120
- task :apidocs => DOCFILES
121
-
122
- CLEAN.include( API_DOCSDIR.to_s )
123
-
@@ -1,502 +0,0 @@
1
- # encoding: utf-8
2
-
3
- #####################################################################
4
- ### G L O B A L H E L P E R F U N C T I O N S
5
- #####################################################################
6
-
7
-
8
- require 'pathname'
9
- require 'uri'
10
-
11
- begin
12
- require 'readline'
13
- include Readline
14
- rescue LoadError
15
- # Fall back to a plain prompt
16
- def readline( text )
17
- $stderr.print( text.chomp )
18
- return $stdin.gets
19
- end
20
- end
21
-
22
- module RakefileHelpers
23
- # Set some ANSI escape code constants (Shamelessly stolen from Perl's
24
- # Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
25
- ANSI_ATTRIBUTES = {
26
- 'clear' => 0,
27
- 'reset' => 0,
28
- 'bold' => 1,
29
- 'dark' => 2,
30
- 'underline' => 4,
31
- 'underscore' => 4,
32
- 'blink' => 5,
33
- 'reverse' => 7,
34
- 'concealed' => 8,
35
-
36
- 'black' => 30, 'on_black' => 40,
37
- 'red' => 31, 'on_red' => 41,
38
- 'green' => 32, 'on_green' => 42,
39
- 'yellow' => 33, 'on_yellow' => 43,
40
- 'blue' => 34, 'on_blue' => 44,
41
- 'magenta' => 35, 'on_magenta' => 45,
42
- 'cyan' => 36, 'on_cyan' => 46,
43
- 'white' => 37, 'on_white' => 47
44
- }
45
-
46
-
47
- MULTILINE_PROMPT = <<-'EOF'
48
- Enter one or more values for '%s'.
49
- A blank line finishes input.
50
- EOF
51
-
52
-
53
- CLEAR_TO_EOL = "\e[K"
54
- CLEAR_CURRENT_LINE = "\e[2K"
55
-
56
-
57
- TAR_OPTS = { :compression => :gzip }
58
-
59
-
60
- ###############
61
- module_function
62
- ###############
63
-
64
- ### Output a logging message
65
- def log( *msg )
66
- output = colorize( msg.flatten.join(' '), 'cyan' )
67
- $stderr.puts( output )
68
- end
69
-
70
-
71
- ### Output a logging message if tracing is on
72
- def trace( *msg )
73
- return unless $trace
74
- output = colorize( msg.flatten.join(' '), 'yellow' )
75
- $stderr.puts( output )
76
- end
77
-
78
-
79
- ### Return the specified args as a string, quoting any that have a space.
80
- def quotelist( *args )
81
- return args.flatten.collect {|part| part =~ /\s/ ? part.inspect : part}
82
- end
83
-
84
-
85
- ### Run the specified command +cmd+ with system(), failing if the execution
86
- ### fails.
87
- def run( *cmd )
88
- cmd.flatten!
89
-
90
- if cmd.length > 1
91
- trace( quotelist(*cmd) )
92
- else
93
- trace( cmd )
94
- end
95
-
96
- if $dryrun
97
- $stderr.puts "(dry run mode)"
98
- else
99
- system( *cmd )
100
- unless $?.success?
101
- fail "Command failed: [%s]" % [cmd.join(' ')]
102
- end
103
- end
104
- end
105
-
106
-
107
- ### Run the given +cmd+ with the specified +args+ without interpolation by the shell and
108
- ### return anything written to its STDOUT.
109
- def read_command_output( cmd, *args )
110
- trace "Reading output from: %s" % [ cmd, quotelist(cmd, *args) ]
111
- output = IO.read( '|-' ) or exec cmd, *args
112
- return output
113
- end
114
-
115
-
116
- ### Run a subordinate Rake process with the same options and the specified +targets+.
117
- def rake( *targets )
118
- opts = ARGV.select {|arg| arg[0,1] == '-' }
119
- args = opts + targets.map {|t| t.to_s }
120
- run 'rake', '-N', *args
121
- end
122
-
123
-
124
- ### Open a pipe to a process running the given +cmd+ and call the given block with it.
125
- def pipeto( *cmd )
126
- $DEBUG = true
127
-
128
- cmd.flatten!
129
- log( "Opening a pipe to: ", cmd.collect {|part| part =~ /\s/ ? part.inspect : part} )
130
- if $dryrun
131
- $stderr.puts "(dry run mode)"
132
- else
133
- open( '|-', 'w+' ) do |io|
134
-
135
- # Parent
136
- if io
137
- yield( io )
138
-
139
- # Child
140
- else
141
- exec( *cmd )
142
- fail "Command failed: [%s]" % [cmd.join(' ')]
143
- end
144
- end
145
- end
146
- end
147
-
148
-
149
- ### Download the file at +sourceuri+ via HTTP and write it to +targetfile+.
150
- def download( sourceuri, targetfile=nil )
151
- oldsync = $stdout.sync
152
- $stdout.sync = true
153
- require 'open-uri'
154
-
155
- targetpath = Pathname.new( targetfile )
156
-
157
- log "Downloading %s to %s" % [sourceuri, targetfile]
158
- trace " connecting..."
159
- ifh = open( sourceuri ) do |ifh|
160
- trace " connected..."
161
- targetpath.open( File::WRONLY|File::TRUNC|File::CREAT, 0644 ) do |ofh|
162
- log "Downloading..."
163
- buf = ''
164
-
165
- while ifh.read( 16384, buf )
166
- until buf.empty?
167
- bytes = ofh.write( buf )
168
- buf.slice!( 0, bytes )
169
- end
170
- end
171
-
172
- log "Done."
173
- end
174
-
175
- end
176
-
177
- return targetpath
178
- ensure
179
- $stdout.sync = oldsync
180
- end
181
-
182
-
183
- ### Return the fully-qualified path to the specified +program+ in the PATH.
184
- def which( program )
185
- return nil unless ENV['PATH']
186
- ENV['PATH'].split(/:/).
187
- collect {|dir| Pathname.new(dir) + program }.
188
- find {|path| path.exist? && path.executable? }
189
- end
190
-
191
-
192
- ### Create a string that contains the ANSI codes specified and return it
193
- def ansi_code( *attributes )
194
- attributes.flatten!
195
- attributes.collect! {|at| at.to_s }
196
- # $stderr.puts "Returning ansicode for TERM = %p: %p" %
197
- # [ ENV['TERM'], attributes ]
198
- return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
199
- attributes = ANSI_ATTRIBUTES.values_at( *attributes ).compact.join(';')
200
-
201
- # $stderr.puts " attr is: %p" % [attributes]
202
- if attributes.empty?
203
- return ''
204
- else
205
- return "\e[%sm" % attributes
206
- end
207
- end
208
-
209
-
210
- ### Colorize the given +string+ with the specified +attributes+ and return it, handling
211
- ### line-endings, color reset, etc.
212
- def colorize( *args )
213
- string = ''
214
-
215
- if block_given?
216
- string = yield
217
- else
218
- string = args.shift
219
- end
220
-
221
- ending = string[/(\s)$/] || ''
222
- string = string.rstrip
223
-
224
- return ansi_code( args.flatten ) + string + ansi_code( 'reset' ) + ending
225
- end
226
-
227
-
228
- ### Output the specified <tt>msg</tt> as an ANSI-colored error message
229
- ### (white on red).
230
- def error_message( msg, details='' )
231
- $stderr.puts colorize( 'bold', 'white', 'on_red' ) { msg } + details
232
- end
233
- alias :error :error_message
234
-
235
-
236
- ### Highlight and embed a prompt control character in the given +string+ and return it.
237
- def make_prompt_string( string )
238
- return CLEAR_CURRENT_LINE + colorize( 'bold', 'green' ) { string + ' ' }
239
- end
240
-
241
-
242
- ### Output the specified <tt>prompt_string</tt> as a prompt (in green) and
243
- ### return the user's input with leading and trailing spaces removed. If a
244
- ### test is provided, the prompt will repeat until the test returns true.
245
- ### An optional failure message can also be passed in.
246
- def prompt( prompt_string, failure_msg="Try again." ) # :yields: response
247
- prompt_string.chomp!
248
- prompt_string << ":" unless /\W$/.match( prompt_string )
249
- response = nil
250
-
251
- begin
252
- prompt = make_prompt_string( prompt_string )
253
- response = readline( prompt ) || ''
254
- response.strip!
255
- if block_given? && ! yield( response )
256
- error_message( failure_msg + "\n\n" )
257
- response = nil
258
- end
259
- end while response.nil?
260
-
261
- return response
262
- end
263
-
264
-
265
- ### Prompt the user with the given <tt>prompt_string</tt> via #prompt,
266
- ### substituting the given <tt>default</tt> if the user doesn't input
267
- ### anything. If a test is provided, the prompt will repeat until the test
268
- ### returns true. An optional failure message can also be passed in.
269
- def prompt_with_default( prompt_string, default, failure_msg="Try again." )
270
- response = nil
271
-
272
- begin
273
- default ||= '~'
274
- response = prompt( "%s [%s]" % [ prompt_string, default ] )
275
- response = default.to_s if !response.nil? && response.empty?
276
-
277
- trace "Validating response %p" % [ response ]
278
-
279
- # the block is a validator. We need to make sure that the user didn't
280
- # enter '~', because if they did, it's nil and we should move on. If
281
- # they didn't, then call the block.
282
- if block_given? && response != '~' && ! yield( response )
283
- error_message( failure_msg + "\n\n" )
284
- response = nil
285
- end
286
- end while response.nil?
287
-
288
- return nil if response == '~'
289
- return response
290
- end
291
-
292
-
293
- ### Prompt for an array of values
294
- def prompt_for_multiple_values( label, default=nil )
295
- $stderr.puts( MULTILINE_PROMPT % [label] )
296
- if default
297
- $stderr.puts "Enter a single blank line to keep the default:\n %p" % [ default ]
298
- end
299
-
300
- results = []
301
- result = nil
302
-
303
- begin
304
- result = readline( make_prompt_string("> ") )
305
- if result.nil? || result.empty?
306
- results << default if default && results.empty?
307
- else
308
- results << result
309
- end
310
- end until result.nil? || result.empty?
311
-
312
- return results.flatten
313
- end
314
-
315
-
316
- ### Turn echo and masking of input on/off.
317
- def noecho( masked=false )
318
- require 'termios'
319
-
320
- rval = nil
321
- term = Termios.getattr( $stdin )
322
-
323
- begin
324
- newt = term.dup
325
- newt.c_lflag &= ~Termios::ECHO
326
- newt.c_lflag &= ~Termios::ICANON if masked
327
-
328
- Termios.tcsetattr( $stdin, Termios::TCSANOW, newt )
329
-
330
- rval = yield
331
- ensure
332
- Termios.tcsetattr( $stdin, Termios::TCSANOW, term )
333
- end
334
-
335
- return rval
336
- end
337
-
338
-
339
- ### Prompt the user for her password, turning off echo if the 'termios' module is
340
- ### available.
341
- def prompt_for_password( prompt="Password: " )
342
- return noecho( true ) do
343
- $stderr.print( prompt )
344
- ($stdin.gets || '').chomp
345
- end
346
- end
347
-
348
-
349
- ### Display a description of a potentially-dangerous task, and prompt
350
- ### for confirmation. If the user answers with anything that begins
351
- ### with 'y', yield to the block. If +abort_on_decline+ is +true+,
352
- ### any non-'y' answer will fail with an error message.
353
- def ask_for_confirmation( description, abort_on_decline=true )
354
- puts description
355
-
356
- answer = prompt_with_default( "Continue?", 'n' ) do |input|
357
- input =~ /^[yn]/i
358
- end
359
-
360
- if answer =~ /^y/i
361
- return yield
362
- elsif abort_on_decline
363
- error "Aborted."
364
- fail
365
- end
366
-
367
- return false
368
- end
369
- alias :prompt_for_confirmation :ask_for_confirmation
370
-
371
-
372
- ### Search line-by-line in the specified +file+ for the given +regexp+, returning the
373
- ### first match, or nil if no match was found. If the +regexp+ has any capture groups,
374
- ### those will be returned in an Array, else the whole matching line is returned.
375
- def find_pattern_in_file( regexp, file )
376
- rval = nil
377
-
378
- File.open( file, 'r' ).each do |line|
379
- if (( match = regexp.match(line) ))
380
- rval = match.captures.empty? ? match[0] : match.captures
381
- break
382
- end
383
- end
384
-
385
- return rval
386
- end
387
-
388
-
389
- ### Search line-by-line in the output of the specified +cmd+ for the given +regexp+,
390
- ### returning the first match, or nil if no match was found. If the +regexp+ has any
391
- ### capture groups, those will be returned in an Array, else the whole matching line
392
- ### is returned.
393
- def find_pattern_in_pipe( regexp, *cmd )
394
- require 'open3'
395
- output = []
396
-
397
- log( cmd.collect {|part| part =~ /\s/ ? part.inspect : part} )
398
- Open3.popen3( *cmd ) do |stdin, stdout, stderr|
399
- stdin.close
400
-
401
- output << stdout.gets until stdout.eof?
402
- output << stderr.gets until stderr.eof?
403
- end
404
-
405
- result = output.find { |line| regexp.match(line) }
406
- return $1 || result
407
- end
408
-
409
-
410
- ### Invoke the user's editor on the given +filename+ and return the exit code
411
- ### from doing so.
412
- def edit( filename )
413
- editor = ENV['EDITOR'] || ENV['VISUAL'] || DEFAULT_EDITOR
414
- system editor, filename
415
- unless $?.success? || editor =~ /vim/i
416
- fail "Editor exited uncleanly."
417
- end
418
- end
419
-
420
-
421
- ### Extract all the non Rake-target arguments from ARGV and return them.
422
- def get_target_args
423
- args = ARGV.reject {|arg| arg =~ /^-/ || Rake::Task.task_defined?(arg) }
424
- return args
425
- end
426
-
427
-
428
- ### Log a subdirectory change, execute a block, and exit the subdirectory
429
- def in_subdirectory( subdir )
430
- block = Proc.new
431
-
432
- log "Entering #{subdir}"
433
- Dir.chdir( subdir, &block )
434
- log "Leaving #{subdir}"
435
- end
436
-
437
-
438
- ### Make an easily-comparable version vector out of +ver+ and return it.
439
- def vvec( ver )
440
- return ver.split('.').collect {|char| char.to_i }.pack('N*')
441
- end
442
-
443
-
444
- ### Archive::Tar::Reader#extract (as of 0.9.0) is broken w.r.t.
445
- ### permissions, so we have to do this ourselves.
446
- def untar( tarfile, targetdir )
447
- require 'archive/tar'
448
- targetdir = Pathname( targetdir )
449
- raise "No such directory: #{targetdir}" unless targetdir.directory?
450
-
451
- reader = Archive::Tar::Reader.new( tarfile.to_s, TAR_OPTS )
452
-
453
- mkdir_p( targetdir )
454
- reader.each( true ) do |header, body|
455
- path = targetdir + header[:path]
456
- # trace "Header is: %p" % [ header ]
457
-
458
- case header[:type]
459
- when :file
460
- trace " #{path}"
461
- path.open( File::WRONLY|File::EXCL|File::CREAT|File::TRUNC, header[:mode] ) do |fio|
462
- bytesize = header[:size]
463
- fio.write( body[0,bytesize] )
464
- end
465
-
466
- when :directory
467
- trace " #{path}"
468
- path.mkpath
469
-
470
- when :link
471
- linktarget = targetdir + header[:dest]
472
- trace " #{path} => #{linktarget}"
473
- path.make_link( linktarget.to_s )
474
-
475
- when :symlink
476
- linktarget = targetdir + header[:dest]
477
- trace " #{path} -> #{linktarget}"
478
- path.make_symlink( linktarget )
479
- end
480
- end
481
-
482
- end
483
-
484
-
485
- ### Extract the contents of the specified +zipfile+ into the given +targetdir+.
486
- def unzip( zipfile, targetdir, *files )
487
- require 'zip/zip'
488
- targetdir = Pathname( targetdir )
489
- raise "No such directory: #{targetdir}" unless targetdir.directory?
490
-
491
- Zip::ZipFile.foreach( zipfile ) do |entry|
492
- # trace " entry is: %p" % [ entry ]
493
- next unless files.empty? || files.include?( entry.name )
494
- target_path = targetdir + entry.name
495
- # trace " would extract to: %s" % [ target_path ]
496
- entry.extract( target_path ) { true }
497
- end
498
- end
499
-
500
- end # module Rakefile::Helpers
501
-
502
-