pluginfactory 1.0.5 → 1.0.6
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.
- data/ChangeLog +286 -70
- data/Rakefile +35 -20
- data/lib/pluginfactory.rb +2 -1
- data/rake/documentation.rb +71 -0
- data/rake/helpers.rb +318 -311
- data/rake/hg.rb +15 -1
- data/rake/manual.rb +5 -5
- data/rake/packaging.rb +14 -35
- data/rake/publishing.rb +18 -62
- metadata +14 -8
- data/rake/rdoc.rb +0 -30
- data/rake/win32.rb +0 -190
data/lib/pluginfactory.rb
CHANGED
@@ -0,0 +1,71 @@
|
|
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
|
+
|
17
|
+
# Prefer YARD, fallback to RDoc
|
18
|
+
begin
|
19
|
+
require 'yard'
|
20
|
+
require 'yard/rake/yardoc_task'
|
21
|
+
|
22
|
+
# Undo the lazy-assed monkeypatch yard/globals.rb installs and
|
23
|
+
# re-install them as mixins as they should have been from the
|
24
|
+
# start
|
25
|
+
# <metamonkeypatch>
|
26
|
+
class Object
|
27
|
+
remove_method :log
|
28
|
+
remove_method :P
|
29
|
+
end
|
30
|
+
|
31
|
+
module YardGlobals
|
32
|
+
def P(namespace, name = nil)
|
33
|
+
namespace, name = nil, namespace if name.nil?
|
34
|
+
YARD::Registry.resolve(namespace, name, false, true)
|
35
|
+
end
|
36
|
+
|
37
|
+
def log
|
38
|
+
YARD::Logger.instance
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class YARD::CLI::Base; include YardGlobals; end
|
43
|
+
class YARD::Parser::SourceParser; extend YardGlobals; include YardGlobals; end
|
44
|
+
class YARD::Parser::CParser; include YardGlobals; end
|
45
|
+
class YARD::CodeObjects::Base; include YardGlobals; end
|
46
|
+
class YARD::Handlers::Base; include YardGlobals; end
|
47
|
+
class YARD::Serializers::Base; include YardGlobals; end
|
48
|
+
module YARD::Templates::Helpers::ModuleHelper; include YardGlobals; end
|
49
|
+
# </metamonkeypatch>
|
50
|
+
|
51
|
+
YARD_OPTIONS = [] unless defined?( YARD_OPTIONS )
|
52
|
+
|
53
|
+
YARD::Rake::YardocTask.new( :apidocs ) do |task|
|
54
|
+
task.files = DOCFILES
|
55
|
+
task.options = YARD_OPTIONS
|
56
|
+
end
|
57
|
+
rescue LoadError
|
58
|
+
require 'rdoc/task'
|
59
|
+
|
60
|
+
desc "Build API documentation in #{DOCDIR}"
|
61
|
+
RDoc::Task.new( :apidocs ) do |task|
|
62
|
+
task.main = "README"
|
63
|
+
task.rdoc_files.include( DOCFILES )
|
64
|
+
task.rdoc_dir = API_DOCSDIR
|
65
|
+
task.options = RDOC_OPTIONS
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Need the DOCFILES to exist to build the API docs
|
70
|
+
task :apidocs => DOCFILES
|
71
|
+
|
data/rake/helpers.rb
CHANGED
@@ -19,416 +19,423 @@ rescue LoadError
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
+
###############
|
58
|
+
module_function
|
59
|
+
###############
|
60
|
+
|
61
|
+
### Output a logging message
|
62
|
+
def log( *msg )
|
63
|
+
output = colorize( msg.flatten.join(' '), 'cyan' )
|
64
|
+
$stderr.puts( output )
|
65
|
+
end
|
61
66
|
|
62
67
|
|
63
|
-
### Output a logging message if tracing is on
|
64
|
-
def trace( *msg )
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
68
|
+
### Output a logging message if tracing is on
|
69
|
+
def trace( *msg )
|
70
|
+
return unless $trace
|
71
|
+
output = colorize( msg.flatten.join(' '), 'yellow' )
|
72
|
+
$stderr.puts( output )
|
73
|
+
end
|
69
74
|
|
70
75
|
|
71
|
-
### Return the specified args as a string, quoting any that have a space.
|
72
|
-
def quotelist( *args )
|
73
|
-
|
74
|
-
end
|
76
|
+
### Return the specified args as a string, quoting any that have a space.
|
77
|
+
def quotelist( *args )
|
78
|
+
return args.flatten.collect {|part| part =~ /\s/ ? part.inspect : part}
|
79
|
+
end
|
75
80
|
|
76
81
|
|
77
|
-
### Run the specified command +cmd+ with system(), failing if the execution
|
78
|
-
### fails.
|
79
|
-
def run( *cmd )
|
80
|
-
|
82
|
+
### Run the specified command +cmd+ with system(), failing if the execution
|
83
|
+
### fails.
|
84
|
+
def run( *cmd )
|
85
|
+
cmd.flatten!
|
81
86
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
+
if cmd.length > 1
|
88
|
+
trace( quotelist(*cmd) )
|
89
|
+
else
|
90
|
+
trace( cmd )
|
91
|
+
end
|
87
92
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
93
|
+
if $dryrun
|
94
|
+
$stderr.puts "(dry run mode)"
|
95
|
+
else
|
96
|
+
system( *cmd )
|
97
|
+
unless $?.success?
|
98
|
+
fail "Command failed: [%s]" % [cmd.join(' ')]
|
99
|
+
end
|
94
100
|
end
|
95
101
|
end
|
96
|
-
end
|
97
102
|
|
98
103
|
|
99
|
-
### Run the given +cmd+ with the specified +args+ without interpolation by the shell and
|
100
|
-
### return anything written to its STDOUT.
|
101
|
-
def read_command_output( cmd, *args )
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end
|
104
|
+
### Run the given +cmd+ with the specified +args+ without interpolation by the shell and
|
105
|
+
### return anything written to its STDOUT.
|
106
|
+
def read_command_output( cmd, *args )
|
107
|
+
trace "Reading output from: %s" % [ cmd, quotelist(cmd, *args) ]
|
108
|
+
output = IO.read( '|-' ) or exec cmd, *args
|
109
|
+
return output
|
110
|
+
end
|
106
111
|
|
107
112
|
|
108
|
-
### Run a subordinate Rake process with the same options and the specified +targets+.
|
109
|
-
def rake( *targets )
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
end
|
113
|
+
### Run a subordinate Rake process with the same options and the specified +targets+.
|
114
|
+
def rake( *targets )
|
115
|
+
opts = ARGV.select {|arg| arg[0,1] == '-' }
|
116
|
+
args = opts + targets.map {|t| t.to_s }
|
117
|
+
run 'rake', '-N', *args
|
118
|
+
end
|
114
119
|
|
115
120
|
|
116
|
-
### Open a pipe to a process running the given +cmd+ and call the given block with it.
|
117
|
-
def pipeto( *cmd )
|
118
|
-
|
121
|
+
### Open a pipe to a process running the given +cmd+ and call the given block with it.
|
122
|
+
def pipeto( *cmd )
|
123
|
+
$DEBUG = true
|
119
124
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
125
|
+
cmd.flatten!
|
126
|
+
log( "Opening a pipe to: ", cmd.collect {|part| part =~ /\s/ ? part.inspect : part} )
|
127
|
+
if $dryrun
|
128
|
+
$stderr.puts "(dry run mode)"
|
129
|
+
else
|
130
|
+
open( '|-', 'w+' ) do |io|
|
126
131
|
|
127
|
-
|
128
|
-
|
129
|
-
|
132
|
+
# Parent
|
133
|
+
if io
|
134
|
+
yield( io )
|
130
135
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
136
|
+
# Child
|
137
|
+
else
|
138
|
+
exec( *cmd )
|
139
|
+
fail "Command failed: [%s]" % [cmd.join(' ')]
|
140
|
+
end
|
135
141
|
end
|
136
142
|
end
|
137
143
|
end
|
138
|
-
end
|
139
144
|
|
140
145
|
|
141
|
-
### Download the file at +sourceuri+ via HTTP and write it to +targetfile+.
|
142
|
-
def download( sourceuri, targetfile=nil )
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
+
### Download the file at +sourceuri+ via HTTP and write it to +targetfile+.
|
147
|
+
def download( sourceuri, targetfile=nil )
|
148
|
+
oldsync = $stdout.sync
|
149
|
+
$stdout.sync = true
|
150
|
+
require 'open-uri'
|
146
151
|
|
147
|
-
|
152
|
+
targetpath = Pathname.new( targetfile )
|
148
153
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
154
|
+
log "Downloading %s to %s" % [sourceuri, targetfile]
|
155
|
+
trace " connecting..."
|
156
|
+
ifh = open( sourceuri ) do |ifh|
|
157
|
+
trace " connected..."
|
158
|
+
targetpath.open( File::WRONLY|File::TRUNC|File::CREAT, 0644 ) do |ofh|
|
159
|
+
log "Downloading..."
|
160
|
+
buf = ''
|
156
161
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
162
|
+
while ifh.read( 16384, buf )
|
163
|
+
until buf.empty?
|
164
|
+
bytes = ofh.write( buf )
|
165
|
+
buf.slice!( 0, bytes )
|
166
|
+
end
|
161
167
|
end
|
168
|
+
|
169
|
+
log "Done."
|
162
170
|
end
|
163
171
|
|
164
|
-
log "Done."
|
165
172
|
end
|
166
173
|
|
174
|
+
return targetpath
|
175
|
+
ensure
|
176
|
+
$stdout.sync = oldsync
|
167
177
|
end
|
168
178
|
|
169
|
-
return targetpath
|
170
|
-
ensure
|
171
|
-
$stdout.sync = oldsync
|
172
|
-
end
|
173
179
|
|
180
|
+
### Return the fully-qualified path to the specified +program+ in the PATH.
|
181
|
+
def which( program )
|
182
|
+
return nil unless ENV['PATH']
|
183
|
+
ENV['PATH'].split(/:/).
|
184
|
+
collect {|dir| Pathname.new(dir) + program }.
|
185
|
+
find {|path| path.exist? && path.executable? }
|
186
|
+
end
|
174
187
|
|
175
|
-
### Return the fully-qualified path to the specified +program+ in the PATH.
|
176
|
-
def which( program )
|
177
|
-
ENV['PATH'].split(/:/).
|
178
|
-
collect {|dir| Pathname.new(dir) + program }.
|
179
|
-
find {|path| path.exist? && path.executable? }
|
180
|
-
end
|
181
188
|
|
189
|
+
### Create a string that contains the ANSI codes specified and return it
|
190
|
+
def ansi_code( *attributes )
|
191
|
+
attributes.flatten!
|
192
|
+
attributes.collect! {|at| at.to_s }
|
193
|
+
# $stderr.puts "Returning ansicode for TERM = %p: %p" %
|
194
|
+
# [ ENV['TERM'], attributes ]
|
195
|
+
return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
|
196
|
+
attributes = ANSI_ATTRIBUTES.values_at( *attributes ).compact.join(';')
|
182
197
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
|
190
|
-
attributes = ANSI_ATTRIBUTES.values_at( *attributes ).compact.join(';')
|
191
|
-
|
192
|
-
# $stderr.puts " attr is: %p" % [attributes]
|
193
|
-
if attributes.empty?
|
194
|
-
return ''
|
195
|
-
else
|
196
|
-
return "\e[%sm" % attributes
|
198
|
+
# $stderr.puts " attr is: %p" % [attributes]
|
199
|
+
if attributes.empty?
|
200
|
+
return ''
|
201
|
+
else
|
202
|
+
return "\e[%sm" % attributes
|
203
|
+
end
|
197
204
|
end
|
198
|
-
end
|
199
205
|
|
200
206
|
|
201
|
-
### Colorize the given +string+ with the specified +attributes+ and return it, handling
|
202
|
-
### line-endings, color reset, etc.
|
203
|
-
def colorize( *args )
|
204
|
-
|
207
|
+
### Colorize the given +string+ with the specified +attributes+ and return it, handling
|
208
|
+
### line-endings, color reset, etc.
|
209
|
+
def colorize( *args )
|
210
|
+
string = ''
|
205
211
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
212
|
+
if block_given?
|
213
|
+
string = yield
|
214
|
+
else
|
215
|
+
string = args.shift
|
216
|
+
end
|
217
|
+
|
218
|
+
ending = string[/(\s)$/] || ''
|
219
|
+
string = string.rstrip
|
220
|
+
|
221
|
+
return ansi_code( args.flatten ) + string + ansi_code( 'reset' ) + ending
|
210
222
|
end
|
211
223
|
|
212
|
-
ending = string[/(\s)$/] || ''
|
213
|
-
string = string.rstrip
|
214
224
|
|
215
|
-
|
216
|
-
|
225
|
+
### Output the specified <tt>msg</tt> as an ANSI-colored error message
|
226
|
+
### (white on red).
|
227
|
+
def error_message( msg, details='' )
|
228
|
+
$stderr.puts colorize( 'bold', 'white', 'on_red' ) { msg } + details
|
229
|
+
end
|
230
|
+
alias :error :error_message
|
217
231
|
|
218
232
|
|
219
|
-
###
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
end
|
224
|
-
alias :error :error_message
|
233
|
+
### Highlight and embed a prompt control character in the given +string+ and return it.
|
234
|
+
def make_prompt_string( string )
|
235
|
+
return CLEAR_CURRENT_LINE + colorize( 'bold', 'green' ) { string + ' ' }
|
236
|
+
end
|
225
237
|
|
226
238
|
|
227
|
-
###
|
228
|
-
|
229
|
-
|
230
|
-
|
239
|
+
### Output the specified <tt>prompt_string</tt> as a prompt (in green) and
|
240
|
+
### return the user's input with leading and trailing spaces removed. If a
|
241
|
+
### test is provided, the prompt will repeat until the test returns true.
|
242
|
+
### An optional failure message can also be passed in.
|
243
|
+
def prompt( prompt_string, failure_msg="Try again." ) # :yields: response
|
244
|
+
prompt_string.chomp!
|
245
|
+
prompt_string << ":" unless /\W$/.match( prompt_string )
|
246
|
+
response = nil
|
247
|
+
|
248
|
+
begin
|
249
|
+
prompt = make_prompt_string( prompt_string )
|
250
|
+
response = readline( prompt ) || ''
|
251
|
+
response.strip!
|
252
|
+
if block_given? && ! yield( response )
|
253
|
+
error_message( failure_msg + "\n\n" )
|
254
|
+
response = nil
|
255
|
+
end
|
256
|
+
end while response.nil?
|
231
257
|
|
258
|
+
return response
|
259
|
+
end
|
232
260
|
|
233
|
-
### Output the specified <tt>prompt_string</tt> as a prompt (in green) and
|
234
|
-
### return the user's input with leading and trailing spaces removed. If a
|
235
|
-
### test is provided, the prompt will repeat until the test returns true.
|
236
|
-
### An optional failure message can also be passed in.
|
237
|
-
def prompt( prompt_string, failure_msg="Try again." ) # :yields: response
|
238
|
-
prompt_string.chomp!
|
239
|
-
prompt_string << ":" unless /\W$/.match( prompt_string )
|
240
|
-
response = nil
|
241
|
-
|
242
|
-
begin
|
243
|
-
prompt = make_prompt_string( prompt_string )
|
244
|
-
response = readline( prompt ) || ''
|
245
|
-
response.strip!
|
246
|
-
if block_given? && ! yield( response )
|
247
|
-
error_message( failure_msg + "\n\n" )
|
248
|
-
response = nil
|
249
|
-
end
|
250
|
-
end while response.nil?
|
251
261
|
|
252
|
-
|
253
|
-
|
262
|
+
### Prompt the user with the given <tt>prompt_string</tt> via #prompt,
|
263
|
+
### substituting the given <tt>default</tt> if the user doesn't input
|
264
|
+
### anything. If a test is provided, the prompt will repeat until the test
|
265
|
+
### returns true. An optional failure message can also be passed in.
|
266
|
+
def prompt_with_default( prompt_string, default, failure_msg="Try again." )
|
267
|
+
response = nil
|
254
268
|
|
269
|
+
begin
|
270
|
+
default ||= '~'
|
271
|
+
response = prompt( "%s [%s]" % [ prompt_string, default ] )
|
272
|
+
response = default.to_s if !response.nil? && response.empty?
|
255
273
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
274
|
+
trace "Validating response %p" % [ response ]
|
275
|
+
|
276
|
+
# the block is a validator. We need to make sure that the user didn't
|
277
|
+
# enter '~', because if they did, it's nil and we should move on. If
|
278
|
+
# they didn't, then call the block.
|
279
|
+
if block_given? && response != '~' && ! yield( response )
|
280
|
+
error_message( failure_msg + "\n\n" )
|
281
|
+
response = nil
|
282
|
+
end
|
283
|
+
end while response.nil?
|
262
284
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
response = default.to_s if !response.nil? && response.empty?
|
285
|
+
return nil if response == '~'
|
286
|
+
return response
|
287
|
+
end
|
267
288
|
|
268
|
-
trace "Validating response %p" % [ response ]
|
269
289
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
response = nil
|
290
|
+
### Prompt for an array of values
|
291
|
+
def prompt_for_multiple_values( label, default=nil )
|
292
|
+
$stderr.puts( MULTILINE_PROMPT % [label] )
|
293
|
+
if default
|
294
|
+
$stderr.puts "Enter a single blank line to keep the default:\n %p" % [ default ]
|
276
295
|
end
|
277
|
-
end while response.nil?
|
278
296
|
|
279
|
-
|
280
|
-
|
281
|
-
end
|
297
|
+
results = []
|
298
|
+
result = nil
|
282
299
|
|
300
|
+
begin
|
301
|
+
result = readline( make_prompt_string("> ") )
|
302
|
+
if result.nil? || result.empty?
|
303
|
+
results << default if default && results.empty?
|
304
|
+
else
|
305
|
+
results << result
|
306
|
+
end
|
307
|
+
end until result.nil? || result.empty?
|
283
308
|
|
284
|
-
|
285
|
-
def prompt_for_multiple_values( label, default=nil )
|
286
|
-
$stderr.puts( MULTILINE_PROMPT % [label] )
|
287
|
-
if default
|
288
|
-
$stderr.puts "Enter a single blank line to keep the default:\n %p" % [ default ]
|
309
|
+
return results.flatten
|
289
310
|
end
|
290
311
|
|
291
|
-
results = []
|
292
|
-
result = nil
|
293
|
-
|
294
|
-
begin
|
295
|
-
result = readline( make_prompt_string("> ") )
|
296
|
-
if result.nil? || result.empty?
|
297
|
-
results << default if default && results.empty?
|
298
|
-
else
|
299
|
-
results << result
|
300
|
-
end
|
301
|
-
end until result.nil? || result.empty?
|
302
312
|
|
303
|
-
|
304
|
-
|
313
|
+
### Turn echo and masking of input on/off.
|
314
|
+
def noecho( masked=false )
|
315
|
+
require 'termios'
|
305
316
|
|
317
|
+
rval = nil
|
318
|
+
term = Termios.getattr( $stdin )
|
306
319
|
|
307
|
-
|
308
|
-
|
309
|
-
|
320
|
+
begin
|
321
|
+
newt = term.dup
|
322
|
+
newt.c_lflag &= ~Termios::ECHO
|
323
|
+
newt.c_lflag &= ~Termios::ICANON if masked
|
310
324
|
|
311
|
-
|
312
|
-
term = Termios.getattr( $stdin )
|
325
|
+
Termios.tcsetattr( $stdin, Termios::TCSANOW, newt )
|
313
326
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
Termios.tcsetattr( $stdin, Termios::TCSANOW, newt )
|
327
|
+
rval = yield
|
328
|
+
ensure
|
329
|
+
Termios.tcsetattr( $stdin, Termios::TCSANOW, term )
|
330
|
+
end
|
320
331
|
|
321
|
-
rval
|
322
|
-
ensure
|
323
|
-
Termios.tcsetattr( $stdin, Termios::TCSANOW, term )
|
332
|
+
return rval
|
324
333
|
end
|
325
334
|
|
326
|
-
return rval
|
327
|
-
end
|
328
|
-
|
329
335
|
|
330
|
-
### Prompt the user for her password, turning off echo if the 'termios' module is
|
331
|
-
### available.
|
332
|
-
def prompt_for_password( prompt="Password: " )
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
+
### Prompt the user for her password, turning off echo if the 'termios' module is
|
337
|
+
### available.
|
338
|
+
def prompt_for_password( prompt="Password: " )
|
339
|
+
return noecho( true ) do
|
340
|
+
$stderr.print( prompt )
|
341
|
+
($stdin.gets || '').chomp
|
342
|
+
end
|
336
343
|
end
|
337
|
-
end
|
338
344
|
|
339
345
|
|
340
|
-
### Display a description of a potentially-dangerous task, and prompt
|
341
|
-
### for confirmation. If the user answers with anything that begins
|
342
|
-
### with 'y', yield to the block. If +abort_on_decline+ is +true+,
|
343
|
-
### any non-'y' answer will fail with an error message.
|
344
|
-
def ask_for_confirmation( description, abort_on_decline=true )
|
345
|
-
|
346
|
+
### Display a description of a potentially-dangerous task, and prompt
|
347
|
+
### for confirmation. If the user answers with anything that begins
|
348
|
+
### with 'y', yield to the block. If +abort_on_decline+ is +true+,
|
349
|
+
### any non-'y' answer will fail with an error message.
|
350
|
+
def ask_for_confirmation( description, abort_on_decline=true )
|
351
|
+
puts description
|
346
352
|
|
347
|
-
|
348
|
-
|
349
|
-
|
353
|
+
answer = prompt_with_default( "Continue?", 'n' ) do |input|
|
354
|
+
input =~ /^[yn]/i
|
355
|
+
end
|
350
356
|
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
+
if answer =~ /^y/i
|
358
|
+
return yield
|
359
|
+
elsif abort_on_decline
|
360
|
+
error "Aborted."
|
361
|
+
fail
|
362
|
+
end
|
357
363
|
|
358
|
-
|
359
|
-
end
|
360
|
-
alias :prompt_for_confirmation :ask_for_confirmation
|
364
|
+
return false
|
365
|
+
end
|
366
|
+
alias :prompt_for_confirmation :ask_for_confirmation
|
361
367
|
|
362
368
|
|
363
|
-
### Search line-by-line in the specified +file+ for the given +regexp+, returning the
|
364
|
-
### first match, or nil if no match was found. If the +regexp+ has any capture groups,
|
365
|
-
### those will be returned in an Array, else the whole matching line is returned.
|
366
|
-
def find_pattern_in_file( regexp, file )
|
367
|
-
|
369
|
+
### Search line-by-line in the specified +file+ for the given +regexp+, returning the
|
370
|
+
### first match, or nil if no match was found. If the +regexp+ has any capture groups,
|
371
|
+
### those will be returned in an Array, else the whole matching line is returned.
|
372
|
+
def find_pattern_in_file( regexp, file )
|
373
|
+
rval = nil
|
368
374
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
375
|
+
File.open( file, 'r' ).each do |line|
|
376
|
+
if (( match = regexp.match(line) ))
|
377
|
+
rval = match.captures.empty? ? match[0] : match.captures
|
378
|
+
break
|
379
|
+
end
|
373
380
|
end
|
381
|
+
|
382
|
+
return rval
|
374
383
|
end
|
375
384
|
|
376
|
-
return rval
|
377
|
-
end
|
378
385
|
|
386
|
+
### Search line-by-line in the output of the specified +cmd+ for the given +regexp+,
|
387
|
+
### returning the first match, or nil if no match was found. If the +regexp+ has any
|
388
|
+
### capture groups, those will be returned in an Array, else the whole matching line
|
389
|
+
### is returned.
|
390
|
+
def find_pattern_in_pipe( regexp, *cmd )
|
391
|
+
output = []
|
379
392
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
### is returned.
|
384
|
-
def find_pattern_in_pipe( regexp, *cmd )
|
385
|
-
output = []
|
393
|
+
log( cmd.collect {|part| part =~ /\s/ ? part.inspect : part} )
|
394
|
+
Open3.popen3( *cmd ) do |stdin, stdout, stderr|
|
395
|
+
stdin.close
|
386
396
|
|
387
|
-
|
388
|
-
|
389
|
-
|
397
|
+
output << stdout.gets until stdout.eof?
|
398
|
+
output << stderr.gets until stderr.eof?
|
399
|
+
end
|
390
400
|
|
391
|
-
output
|
392
|
-
|
401
|
+
result = output.find { |line| regexp.match(line) }
|
402
|
+
return $1 || result
|
393
403
|
end
|
394
404
|
|
395
|
-
result = output.find { |line| regexp.match(line) }
|
396
|
-
return $1 || result
|
397
|
-
end
|
398
|
-
|
399
405
|
|
400
|
-
### Invoke the user's editor on the given +filename+ and return the exit code
|
401
|
-
### from doing so.
|
402
|
-
def edit( filename )
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
406
|
+
### Invoke the user's editor on the given +filename+ and return the exit code
|
407
|
+
### from doing so.
|
408
|
+
def edit( filename )
|
409
|
+
editor = ENV['EDITOR'] || ENV['VISUAL'] || DEFAULT_EDITOR
|
410
|
+
system editor, filename
|
411
|
+
unless $?.success? || editor =~ /vim/i
|
412
|
+
fail "Editor exited uncleanly."
|
413
|
+
end
|
407
414
|
end
|
408
|
-
end
|
409
415
|
|
410
416
|
|
411
|
-
### Extract all the non Rake-target arguments from ARGV and return them.
|
412
|
-
def get_target_args
|
413
|
-
|
414
|
-
|
415
|
-
end
|
417
|
+
### Extract all the non Rake-target arguments from ARGV and return them.
|
418
|
+
def get_target_args
|
419
|
+
args = ARGV.reject {|arg| arg =~ /^-/ || Rake::Task.task_defined?(arg) }
|
420
|
+
return args
|
421
|
+
end
|
416
422
|
|
417
423
|
|
418
|
-
### Log a subdirectory change, execute a block, and exit the subdirectory
|
419
|
-
def in_subdirectory( subdir )
|
420
|
-
|
424
|
+
### Log a subdirectory change, execute a block, and exit the subdirectory
|
425
|
+
def in_subdirectory( subdir )
|
426
|
+
block = Proc.new
|
421
427
|
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
end
|
428
|
+
log "Entering #{subdir}"
|
429
|
+
Dir.chdir( subdir, &block )
|
430
|
+
log "Leaving #{subdir}"
|
431
|
+
end
|
426
432
|
|
427
433
|
|
428
|
-
### Make an easily-comparable version vector out of +ver+ and return it.
|
429
|
-
def vvec( ver )
|
430
|
-
|
431
|
-
end
|
434
|
+
### Make an easily-comparable version vector out of +ver+ and return it.
|
435
|
+
def vvec( ver )
|
436
|
+
return ver.split('.').collect {|char| char.to_i }.pack('N*')
|
437
|
+
end
|
432
438
|
|
439
|
+
end # module Rakefile::Helpers
|
433
440
|
|
434
441
|
|