pluginfactory 1.0.2 → 1.0.3

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.
@@ -0,0 +1,62 @@
1
+ #
2
+ # Dependency-checking and Installation Rake Tasks
3
+ # $Id: dependencies.rb 10 2008-07-18 15:52:48Z deveiant $
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
+ gems.flatten!
14
+
15
+ defaults = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({
16
+ :generate_rdoc => true,
17
+ :generate_ri => true,
18
+ :install_dir => Gem.dir,
19
+ :format_executable => false,
20
+ :test => false,
21
+ :version => Gem::Requirement.default,
22
+ })
23
+
24
+ # Check for root
25
+ if Process.euid != 0
26
+ $stderr.puts "This probably won't work, as you aren't root, but I'll try anyway"
27
+ end
28
+
29
+ gemindex = Gem::SourceIndex.from_installed_gems
30
+
31
+ gems.each do |gemname|
32
+ if (( specs = gemindex.search(gemname) )) && ! specs.empty?
33
+ log "Version %s of %s is already installed; skipping..." %
34
+ [ specs.first.version, specs.first.name ]
35
+ next
36
+ end
37
+
38
+ rgv = Gem::Version.new( Gem::RubyGemsVersion )
39
+ installer = nil
40
+
41
+ log "Trying to install #{gemname.inspect}..."
42
+ if rgv >= Gem::Version.new( '1.1.1' )
43
+ installer = Gem::DependencyInstaller.new
44
+ installer.install( gemname )
45
+ else
46
+ installer = Gem::DependencyInstaller.new( gemname )
47
+ installer.install
48
+ end
49
+
50
+ installer.installed_gems.each do |spec|
51
+ log "Installed: %s" % [ spec.full_name ]
52
+ end
53
+
54
+ end
55
+ end
56
+
57
+
58
+ ### Task: install gems for development tasks
59
+ task :install_dependencies do
60
+ install_gems( DEPENDENCIES.keys )
61
+ end
62
+
data/rake/helpers.rb ADDED
@@ -0,0 +1,382 @@
1
+ #####################################################################
2
+ ### G L O B A L H E L P E R F U N C T I O N S
3
+ #####################################################################
4
+
5
+ require 'pathname'
6
+ require 'readline'
7
+
8
+ # Set some ANSI escape code constants (Shamelessly stolen from Perl's
9
+ # Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
10
+ ANSI_ATTRIBUTES = {
11
+ 'clear' => 0,
12
+ 'reset' => 0,
13
+ 'bold' => 1,
14
+ 'dark' => 2,
15
+ 'underline' => 4,
16
+ 'underscore' => 4,
17
+ 'blink' => 5,
18
+ 'reverse' => 7,
19
+ 'concealed' => 8,
20
+
21
+ 'black' => 30, 'on_black' => 40,
22
+ 'red' => 31, 'on_red' => 41,
23
+ 'green' => 32, 'on_green' => 42,
24
+ 'yellow' => 33, 'on_yellow' => 43,
25
+ 'blue' => 34, 'on_blue' => 44,
26
+ 'magenta' => 35, 'on_magenta' => 45,
27
+ 'cyan' => 36, 'on_cyan' => 46,
28
+ 'white' => 37, 'on_white' => 47
29
+ }
30
+
31
+
32
+ MULTILINE_PROMPT = <<-'EOF'
33
+ Enter one or more values for '%s'.
34
+ A blank line finishes input.
35
+ EOF
36
+
37
+
38
+ CLEAR_TO_EOL = "\e[K"
39
+ CLEAR_CURRENT_LINE = "\e[2K"
40
+
41
+
42
+ ### Output a logging message
43
+ def log( *msg )
44
+ output = colorize( msg.flatten.join(' '), 'cyan' )
45
+ $deferr.puts( output )
46
+ end
47
+
48
+
49
+ ### Output a logging message if tracing is on
50
+ def trace( *msg )
51
+ return unless $trace
52
+ output = colorize( msg.flatten.join(' '), 'yellow' )
53
+ $deferr.puts( output )
54
+ end
55
+
56
+
57
+ ### Run the specified command +cmd+ with system(), failing if the execution
58
+ ### fails.
59
+ def run( *cmd )
60
+ cmd.flatten!
61
+
62
+ log( cmd.collect {|part| part =~ /\s/ ? part.inspect : part} )
63
+ if $dryrun
64
+ $deferr.puts "(dry run mode)"
65
+ else
66
+ system( *cmd )
67
+ unless $?.success?
68
+ fail "Command failed: [%s]" % [cmd.join(' ')]
69
+ end
70
+ end
71
+ end
72
+
73
+
74
+ ### Open a pipe to a process running the given +cmd+ and call the given block with it.
75
+ def pipeto( *cmd )
76
+ $DEBUG = true
77
+
78
+ cmd.flatten!
79
+ log( "Opening a pipe to: ", cmd.collect {|part| part =~ /\s/ ? part.inspect : part} )
80
+ if $dryrun
81
+ $deferr.puts "(dry run mode)"
82
+ else
83
+ open( '|-', 'w+' ) do |io|
84
+
85
+ # Parent
86
+ if io
87
+ yield( io )
88
+
89
+ # Child
90
+ else
91
+ exec( *cmd )
92
+ fail "Command failed: [%s]" % [cmd.join(' ')]
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+
99
+ ### Download the file at +sourceuri+ via HTTP and write it to +targetfile+.
100
+ def download( sourceuri, targetfile=nil )
101
+ oldsync = $defout.sync
102
+ $defout.sync = true
103
+ require 'net/http'
104
+ require 'uri'
105
+
106
+ targetpath = Pathname.new( targetfile )
107
+
108
+ log "Downloading %s to %s" % [sourceuri, targetfile]
109
+ targetpath.open( File::WRONLY|File::TRUNC|File::CREAT, 0644 ) do |ofh|
110
+
111
+ url = sourceuri.is_a?( URI ) ? sourceuri : URI.parse( sourceuri )
112
+ downloaded = false
113
+ limit = 5
114
+
115
+ until downloaded or limit.zero?
116
+ Net::HTTP.start( url.host, url.port ) do |http|
117
+ req = Net::HTTP::Get.new( url.path )
118
+
119
+ http.request( req ) do |res|
120
+ if res.is_a?( Net::HTTPSuccess )
121
+ log "Downloading..."
122
+ res.read_body do |buf|
123
+ ofh.print( buf )
124
+ end
125
+ downloaded = true
126
+ puts "done."
127
+
128
+ elsif res.is_a?( Net::HTTPRedirection )
129
+ url = URI.parse( res['location'] )
130
+ log "...following redirection to: %s" % [ url ]
131
+ limit -= 1
132
+ sleep 0.2
133
+ next
134
+
135
+ else
136
+ res.error!
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ end
143
+
144
+ return targetpath
145
+ ensure
146
+ $defout.sync = oldsync
147
+ end
148
+
149
+
150
+ ### Return the fully-qualified path to the specified +program+ in the PATH.
151
+ def which( program )
152
+ ENV['PATH'].split(/:/).
153
+ collect {|dir| Pathname.new(dir) + program }.
154
+ find {|path| path.exist? && path.executable? }
155
+ end
156
+
157
+
158
+ ### Create a string that contains the ANSI codes specified and return it
159
+ def ansi_code( *attributes )
160
+ attributes.flatten!
161
+ attributes.collect! {|at| at.to_s }
162
+ # $deferr.puts "Returning ansicode for TERM = %p: %p" %
163
+ # [ ENV['TERM'], attributes ]
164
+ return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
165
+ attributes = ANSI_ATTRIBUTES.values_at( *attributes ).compact.join(';')
166
+
167
+ # $deferr.puts " attr is: %p" % [attributes]
168
+ if attributes.empty?
169
+ return ''
170
+ else
171
+ return "\e[%sm" % attributes
172
+ end
173
+ end
174
+
175
+
176
+ ### Colorize the given +string+ with the specified +attributes+ and return it, handling
177
+ ### line-endings, color reset, etc.
178
+ def colorize( *args )
179
+ string = ''
180
+
181
+ if block_given?
182
+ string = yield
183
+ else
184
+ string = args.shift
185
+ end
186
+
187
+ ending = string[/(\s)$/] || ''
188
+ string = string.rstrip
189
+
190
+ return ansi_code( args.flatten ) + string + ansi_code( 'reset' ) + ending
191
+ end
192
+
193
+
194
+ ### Output the specified <tt>msg</tt> as an ANSI-colored error message
195
+ ### (white on red).
196
+ def error_message( msg, details='' )
197
+ $deferr.puts colorize( 'bold', 'white', 'on_red' ) { msg } + details
198
+ end
199
+ alias :error :error_message
200
+
201
+
202
+ ### Highlight and embed a prompt control character in the given +string+ and return it.
203
+ def make_prompt_string( string )
204
+ return CLEAR_CURRENT_LINE + colorize( 'bold', 'green' ) { string + ' ' }
205
+ end
206
+
207
+
208
+ ### Output the specified <tt>prompt_string</tt> as a prompt (in green) and
209
+ ### return the user's input with leading and trailing spaces removed. If a
210
+ ### test is provided, the prompt will repeat until the test returns true.
211
+ ### An optional failure message can also be passed in.
212
+ def prompt( prompt_string, failure_msg="Try again." ) # :yields: response
213
+ prompt_string.chomp!
214
+ prompt_string << ":" unless /\W$/.match( prompt_string )
215
+ response = nil
216
+
217
+ begin
218
+ prompt = make_prompt_string( prompt_string )
219
+ response = Readline.readline( prompt ) || ''
220
+ response.strip!
221
+ if block_given? && ! yield( response )
222
+ error_message( failure_msg + "\n\n" )
223
+ response = nil
224
+ end
225
+ end while response.nil?
226
+
227
+ return response
228
+ end
229
+
230
+
231
+ ### Prompt the user with the given <tt>prompt_string</tt> via #prompt,
232
+ ### substituting the given <tt>default</tt> if the user doesn't input
233
+ ### anything. If a test is provided, the prompt will repeat until the test
234
+ ### returns true. An optional failure message can also be passed in.
235
+ def prompt_with_default( prompt_string, default, failure_msg="Try again." )
236
+ response = nil
237
+
238
+ begin
239
+ default ||= '~'
240
+ response = prompt( "%s [%s]" % [ prompt_string, default ] )
241
+ response = default.to_s if !response.nil? && response.empty?
242
+
243
+ trace "Validating reponse %p" % [ response ]
244
+
245
+ # the block is a validator. We need to make sure that the user didn't
246
+ # enter '~', because if they did, it's nil and we should move on. If
247
+ # they didn't, then call the block.
248
+ if block_given? && response != '~' && ! yield( response )
249
+ error_message( failure_msg + "\n\n" )
250
+ response = nil
251
+ end
252
+ end while response.nil?
253
+
254
+ return nil if response == '~'
255
+ return response
256
+ end
257
+
258
+
259
+ ### Prompt for an array of values
260
+ def prompt_for_multiple_values( label, default=nil )
261
+ $stderr.puts( MULTILINE_PROMPT % [label] )
262
+ if default
263
+ $stderr.puts "Enter a single blank line to keep the default:\n %p" % [ default ]
264
+ end
265
+
266
+ results = []
267
+ result = nil
268
+
269
+ begin
270
+ result = Readline.readline( make_prompt_string("> ") )
271
+ if result.nil? || result.empty?
272
+ results << default if default && results.empty?
273
+ else
274
+ results << result
275
+ end
276
+ end until result.nil? || result.empty?
277
+
278
+ return results.flatten
279
+ end
280
+
281
+
282
+ ### Turn echo and masking of input on/off. Based on similar code in
283
+ ### Ruby-Password by Ian Macdonald <ian@caliban.org>.
284
+ def noecho( masked=false )
285
+ require 'termios'
286
+
287
+ rval = nil
288
+ term = Termios.getattr( $stdin )
289
+
290
+ begin
291
+ term.c_lflag &= ~Termios::ECHO
292
+ term.c_lflag &= ~Termios::ICANON if masked
293
+
294
+ rval = yield
295
+ ensure
296
+ term.c_lflag |= ( Termios::ECHO | Termios::ICANON )
297
+ Termios.setattr( $stdin, Termios::TCSANOW, term )
298
+ end
299
+
300
+ return rval
301
+ end
302
+
303
+
304
+ ### Prompt the user for her password, turning off echo if the 'termios' module is
305
+ ### available.
306
+ def prompt_for_password( prompt="Password: " )
307
+ return noecho( true ) do
308
+ $stderr.print( prompt )
309
+ ($stdin.gets || '').chomp
310
+ end
311
+ end
312
+
313
+
314
+ ### Display a description of a potentially-dangerous task, and prompt
315
+ ### for confirmation. If the user answers with anything that begins
316
+ ### with 'y', yield to the block, else raise with an error.
317
+ def ask_for_confirmation( description )
318
+ puts description
319
+
320
+ answer = prompt_with_default( "Continue?", 'n' ) do |input|
321
+ input =~ /^[yn]/i
322
+ end
323
+
324
+ case answer
325
+ when /^y/i
326
+ yield
327
+ else
328
+ error "Aborted."
329
+ fail
330
+ end
331
+ end
332
+
333
+
334
+ ### Search line-by-line in the specified +file+ for the given +regexp+, returning the
335
+ ### first match, or nil if no match was found. If the +regexp+ has any capture groups,
336
+ ### those will be returned in an Array, else the whole matching line is returned.
337
+ def find_pattern_in_file( regexp, file )
338
+ rval = nil
339
+
340
+ File.open( file, 'r' ).each do |line|
341
+ if (( match = regexp.match(line) ))
342
+ rval = match.captures.empty? ? match[0] : match.captures
343
+ break
344
+ end
345
+ end
346
+
347
+ return rval
348
+ end
349
+
350
+
351
+ ### Get a list of the file or files to run rspec on.
352
+ def rspec_files
353
+ if ENV['class']
354
+ classname = ENV['class']
355
+ spec_file = SPECSDIR + "#{classname}_spec.rb"
356
+ raise "Can't find the spec file for the class '#{classname}'" unless spec_file.exist?
357
+ return [ spec_file ]
358
+ else
359
+ return SPEC_FILES
360
+ end
361
+ end
362
+
363
+
364
+ ### Invoke the user's editor on the given +filename+ and return the exit code
365
+ ### from doing so.
366
+ def edit( filename )
367
+ editor = ENV['EDITOR'] || ENV['VISUAL'] || DEFAULT_EDITOR
368
+ system editor, filename
369
+ unless $?.success?
370
+ fail "Editor exited uncleanly."
371
+ end
372
+ end
373
+
374
+
375
+ ### Extract all the non Rake-target arguments from ARGV and return them.
376
+ def get_target_args
377
+ args = ARGV.reject {|arg| Rake::Task.task_defined?(arg) }
378
+ return args
379
+ end
380
+
381
+
382
+