pg 0.9.0-x86-mswin32 → 0.11.0pre229-x86-mswin32

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/ext/pg.h CHANGED
@@ -1,3 +1,6 @@
1
+ #ifndef PG_H_C98VS4AD
2
+ #define PG_H_C98VS4AD
3
+
1
4
  #include <stdio.h>
2
5
  #include <stdlib.h>
3
6
  #include <sys/types.h>
@@ -47,3 +50,4 @@ __declspec(dllexport)
47
50
  #endif
48
51
  void Init_pg_ext(void);
49
52
 
53
+ #endif /* end of include guard: PG_H_C98VS4AD */
Binary file
Binary file
data/lib/pg.rb CHANGED
@@ -1,11 +1,16 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # Load the correct version if it's a Windows binary gem
4
- if RUBY_PLATFORM =~/(mswin|mingw)/i
5
- major_minor = RUBY_VERSION[ /^(\d+\.\d+)/ ] or
6
- raise "Oops, can't extract the major/minor version from #{RUBY_VERSION.dump}"
7
- require "#{major_minor}/pg_ext"
8
- else
3
+ begin
9
4
  require 'pg_ext'
5
+ rescue LoadError => err
6
+ # If it's a Windows binary gem, try the <major>.<minor> subdirectory
7
+ if RUBY_PLATFORM =~/(mswin|mingw)/i
8
+ major_minor = RUBY_VERSION[ /^(\d+\.\d+)/ ] or
9
+ raise "Oops, can't extract the major/minor version from #{RUBY_VERSION.dump}"
10
+ require "#{major_minor}/pg_ext"
11
+ else
12
+ raise
13
+ end
14
+
10
15
  end
11
16
 
@@ -0,0 +1,123 @@
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,4 +1,5 @@
1
1
  # encoding: utf-8
2
+
2
3
  #####################################################################
3
4
  ### G L O B A L H E L P E R F U N C T I O N S
4
5
  #####################################################################
@@ -6,7 +7,6 @@
6
7
 
7
8
  require 'pathname'
8
9
  require 'uri'
9
- require 'open3'
10
10
 
11
11
  begin
12
12
  require 'readline'
@@ -19,417 +19,484 @@ rescue LoadError
19
19
  end
20
20
  end
21
21
 
22
- # Set some ANSI escape code constants (Shamelessly stolen from Perl's
23
- # Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
24
- ANSI_ATTRIBUTES = {
25
- 'clear' => 0,
26
- 'reset' => 0,
27
- 'bold' => 1,
28
- 'dark' => 2,
29
- 'underline' => 4,
30
- 'underscore' => 4,
31
- 'blink' => 5,
32
- 'reverse' => 7,
33
- 'concealed' => 8,
34
-
35
- 'black' => 30, 'on_black' => 40,
36
- 'red' => 31, 'on_red' => 41,
37
- 'green' => 32, 'on_green' => 42,
38
- 'yellow' => 33, 'on_yellow' => 43,
39
- 'blue' => 34, 'on_blue' => 44,
40
- 'magenta' => 35, 'on_magenta' => 45,
41
- 'cyan' => 36, 'on_cyan' => 46,
42
- 'white' => 37, 'on_white' => 47
43
- }
44
-
45
-
46
- MULTILINE_PROMPT = <<-'EOF'
47
- Enter one or more values for '%s'.
48
- A blank line finishes input.
49
- EOF
50
-
51
-
52
- CLEAR_TO_EOL = "\e[K"
53
- CLEAR_CURRENT_LINE = "\e[2K"
54
-
55
-
56
- ### Output a logging message
57
- def log( *msg )
58
- output = colorize( msg.flatten.join(' '), 'cyan' )
59
- $stderr.puts( output )
60
- end
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,
61
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
+ }
62
45
 
63
- ### Output a logging message if tracing is on
64
- def trace( *msg )
65
- return unless $trace
66
- output = colorize( msg.flatten.join(' '), 'yellow' )
67
- $stderr.puts( output )
68
- end
69
46
 
47
+ MULTILINE_PROMPT = <<-'EOF'
48
+ Enter one or more values for '%s'.
49
+ A blank line finishes input.
50
+ EOF
70
51
 
71
- ### Return the specified args as a string, quoting any that have a space.
72
- def quotelist( *args )
73
- return args.flatten.collect {|part| part =~ /\s/ ? part.inspect : part}
74
- end
75
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
76
77
 
77
- ### Run the specified command +cmd+ with system(), failing if the execution
78
- ### fails.
79
- def run( *cmd )
80
- cmd.flatten!
81
78
 
82
- if cmd.length > 1
83
- trace( quotelist(*cmd) )
84
- else
85
- trace( cmd )
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}
86
82
  end
87
83
 
88
- if $dryrun
89
- $stderr.puts "(dry run mode)"
90
- else
91
- system( *cmd )
92
- unless $?.success?
93
- fail "Command failed: [%s]" % [cmd.join(' ')]
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
94
103
  end
95
104
  end
96
- end
97
105
 
98
106
 
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
- trace "Reading output from: %s" % [ cmd, quotelist(cmd, *args) ]
103
- output = IO.read( '|-' ) or exec cmd, *args
104
- return output
105
- end
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
106
114
 
107
115
 
108
- ### Run a subordinate Rake process with the same options and the specified +targets+.
109
- def rake( *targets )
110
- opts = ARGV.select {|arg| arg[0,1] == '-' }
111
- args = opts + targets.map {|t| t.to_s }
112
- run 'rake', '-N', *args
113
- end
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
114
122
 
115
123
 
116
- ### Open a pipe to a process running the given +cmd+ and call the given block with it.
117
- def pipeto( *cmd )
118
- $DEBUG = true
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
119
127
 
120
- cmd.flatten!
121
- log( "Opening a pipe to: ", cmd.collect {|part| part =~ /\s/ ? part.inspect : part} )
122
- if $dryrun
123
- $stderr.puts "(dry run mode)"
124
- else
125
- open( '|-', 'w+' ) do |io|
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|
126
134
 
127
- # Parent
128
- if io
129
- yield( io )
135
+ # Parent
136
+ if io
137
+ yield( io )
130
138
 
131
- # Child
132
- else
133
- exec( *cmd )
134
- fail "Command failed: [%s]" % [cmd.join(' ')]
139
+ # Child
140
+ else
141
+ exec( *cmd )
142
+ fail "Command failed: [%s]" % [cmd.join(' ')]
143
+ end
135
144
  end
136
145
  end
137
146
  end
138
- end
139
147
 
140
148
 
141
- ### Download the file at +sourceuri+ via HTTP and write it to +targetfile+.
142
- def download( sourceuri, targetfile=nil )
143
- oldsync = $stdout.sync
144
- $stdout.sync = true
145
- require 'open-uri'
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'
146
154
 
147
- targetpath = Pathname.new( targetfile )
155
+ targetpath = Pathname.new( targetfile )
148
156
 
149
- log "Downloading %s to %s" % [sourceuri, targetfile]
150
- trace " connecting..."
151
- ifh = open( sourceuri ) do |ifh|
152
- trace " connected..."
153
- targetpath.open( File::WRONLY|File::TRUNC|File::CREAT, 0644 ) do |ofh|
154
- log "Downloading..."
155
- buf = ''
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 = ''
156
164
 
157
- while ifh.read( 16384, buf )
158
- until buf.empty?
159
- bytes = ofh.write( buf )
160
- buf.slice!( 0, bytes )
165
+ while ifh.read( 16384, buf )
166
+ until buf.empty?
167
+ bytes = ofh.write( buf )
168
+ buf.slice!( 0, bytes )
169
+ end
161
170
  end
171
+
172
+ log "Done."
162
173
  end
163
174
 
164
- log "Done."
165
175
  end
166
176
 
177
+ return targetpath
178
+ ensure
179
+ $stdout.sync = oldsync
167
180
  end
168
181
 
169
- return targetpath
170
- ensure
171
- $stdout.sync = oldsync
172
- end
173
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
174
190
 
175
- ### Return the fully-qualified path to the specified +program+ in the PATH.
176
- def which( program )
177
- return nil unless ENV['PATH']
178
- ENV['PATH'].split(/:/).
179
- collect {|dir| Pathname.new(dir) + program }.
180
- find {|path| path.exist? && path.executable? }
181
- end
182
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(';')
183
200
 
184
- ### Create a string that contains the ANSI codes specified and return it
185
- def ansi_code( *attributes )
186
- attributes.flatten!
187
- attributes.collect! {|at| at.to_s }
188
- # $stderr.puts "Returning ansicode for TERM = %p: %p" %
189
- # [ ENV['TERM'], attributes ]
190
- return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
191
- attributes = ANSI_ATTRIBUTES.values_at( *attributes ).compact.join(';')
192
-
193
- # $stderr.puts " attr is: %p" % [attributes]
194
- if attributes.empty?
195
- return ''
196
- else
197
- return "\e[%sm" % attributes
201
+ # $stderr.puts " attr is: %p" % [attributes]
202
+ if attributes.empty?
203
+ return ''
204
+ else
205
+ return "\e[%sm" % attributes
206
+ end
198
207
  end
199
- end
200
208
 
201
209
 
202
- ### Colorize the given +string+ with the specified +attributes+ and return it, handling
203
- ### line-endings, color reset, etc.
204
- def colorize( *args )
205
- string = ''
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
206
223
 
207
- if block_given?
208
- string = yield
209
- else
210
- string = args.shift
224
+ return ansi_code( args.flatten ) + string + ansi_code( 'reset' ) + ending
211
225
  end
212
226
 
213
- ending = string[/(\s)$/] || ''
214
- string = string.rstrip
215
227
 
216
- return ansi_code( args.flatten ) + string + ansi_code( 'reset' ) + ending
217
- end
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
218
234
 
219
235
 
220
- ### Output the specified <tt>msg</tt> as an ANSI-colored error message
221
- ### (white on red).
222
- def error_message( msg, details='' )
223
- $stderr.puts colorize( 'bold', 'white', 'on_red' ) { msg } + details
224
- end
225
- alias :error :error_message
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
226
240
 
227
241
 
228
- ### Highlight and embed a prompt control character in the given +string+ and return it.
229
- def make_prompt_string( string )
230
- return CLEAR_CURRENT_LINE + colorize( 'bold', 'green' ) { string + ' ' }
231
- end
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?
232
260
 
261
+ return response
262
+ end
233
263
 
234
- ### Output the specified <tt>prompt_string</tt> as a prompt (in green) and
235
- ### return the user's input with leading and trailing spaces removed. If a
236
- ### test is provided, the prompt will repeat until the test returns true.
237
- ### An optional failure message can also be passed in.
238
- def prompt( prompt_string, failure_msg="Try again." ) # :yields: response
239
- prompt_string.chomp!
240
- prompt_string << ":" unless /\W$/.match( prompt_string )
241
- response = nil
242
-
243
- begin
244
- prompt = make_prompt_string( prompt_string )
245
- response = readline( prompt ) || ''
246
- response.strip!
247
- if block_given? && ! yield( response )
248
- error_message( failure_msg + "\n\n" )
249
- response = nil
250
- end
251
- end while response.nil?
252
264
 
253
- return response
254
- end
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
255
271
 
272
+ begin
273
+ default ||= '~'
274
+ response = prompt( "%s [%s]" % [ prompt_string, default ] )
275
+ response = default.to_s if !response.nil? && response.empty?
256
276
 
257
- ### Prompt the user with the given <tt>prompt_string</tt> via #prompt,
258
- ### substituting the given <tt>default</tt> if the user doesn't input
259
- ### anything. If a test is provided, the prompt will repeat until the test
260
- ### returns true. An optional failure message can also be passed in.
261
- def prompt_with_default( prompt_string, default, failure_msg="Try again." )
262
- response = nil
277
+ trace "Validating response %p" % [ response ]
263
278
 
264
- begin
265
- default ||= '~'
266
- response = prompt( "%s [%s]" % [ prompt_string, default ] )
267
- response = default.to_s if !response.nil? && response.empty?
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?
268
287
 
269
- trace "Validating response %p" % [ response ]
288
+ return nil if response == '~'
289
+ return response
290
+ end
270
291
 
271
- # the block is a validator. We need to make sure that the user didn't
272
- # enter '~', because if they did, it's nil and we should move on. If
273
- # they didn't, then call the block.
274
- if block_given? && response != '~' && ! yield( response )
275
- error_message( failure_msg + "\n\n" )
276
- response = nil
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 ]
277
298
  end
278
- end while response.nil?
279
299
 
280
- return nil if response == '~'
281
- return response
282
- end
300
+ results = []
301
+ result = nil
283
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?
284
311
 
285
- ### Prompt for an array of values
286
- def prompt_for_multiple_values( label, default=nil )
287
- $stderr.puts( MULTILINE_PROMPT % [label] )
288
- if default
289
- $stderr.puts "Enter a single blank line to keep the default:\n %p" % [ default ]
312
+ return results.flatten
290
313
  end
291
314
 
292
- results = []
293
- result = nil
294
315
 
295
- begin
296
- result = readline( make_prompt_string("> ") )
297
- if result.nil? || result.empty?
298
- results << default if default && results.empty?
299
- else
300
- results << result
301
- end
302
- end until result.nil? || result.empty?
316
+ ### Turn echo and masking of input on/off.
317
+ def noecho( masked=false )
318
+ require 'termios'
303
319
 
304
- return results.flatten
305
- end
320
+ rval = nil
321
+ term = Termios.getattr( $stdin )
306
322
 
323
+ begin
324
+ newt = term.dup
325
+ newt.c_lflag &= ~Termios::ECHO
326
+ newt.c_lflag &= ~Termios::ICANON if masked
307
327
 
308
- ### Turn echo and masking of input on/off.
309
- def noecho( masked=false )
310
- require 'termios'
328
+ Termios.tcsetattr( $stdin, Termios::TCSANOW, newt )
311
329
 
312
- rval = nil
313
- term = Termios.getattr( $stdin )
330
+ rval = yield
331
+ ensure
332
+ Termios.tcsetattr( $stdin, Termios::TCSANOW, term )
333
+ end
314
334
 
315
- begin
316
- newt = term.dup
317
- newt.c_lflag &= ~Termios::ECHO
318
- newt.c_lflag &= ~Termios::ICANON if masked
335
+ return rval
336
+ end
319
337
 
320
- Termios.tcsetattr( $stdin, Termios::TCSANOW, newt )
321
338
 
322
- rval = yield
323
- ensure
324
- Termios.tcsetattr( $stdin, Termios::TCSANOW, term )
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
325
346
  end
326
347
 
327
- return rval
328
- end
329
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
330
366
 
331
- ### Prompt the user for her password, turning off echo if the 'termios' module is
332
- ### available.
333
- def prompt_for_password( prompt="Password: " )
334
- return noecho( true ) do
335
- $stderr.print( prompt )
336
- ($stdin.gets || '').chomp
367
+ return false
337
368
  end
338
- end
369
+ alias :prompt_for_confirmation :ask_for_confirmation
339
370
 
340
371
 
341
- ### Display a description of a potentially-dangerous task, and prompt
342
- ### for confirmation. If the user answers with anything that begins
343
- ### with 'y', yield to the block. If +abort_on_decline+ is +true+,
344
- ### any non-'y' answer will fail with an error message.
345
- def ask_for_confirmation( description, abort_on_decline=true )
346
- puts description
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
347
377
 
348
- answer = prompt_with_default( "Continue?", 'n' ) do |input|
349
- input =~ /^[yn]/i
350
- end
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
351
384
 
352
- if answer =~ /^y/i
353
- return yield
354
- elsif abort_on_decline
355
- error "Aborted."
356
- fail
385
+ return rval
357
386
  end
358
387
 
359
- return false
360
- end
361
- alias :prompt_for_confirmation :ask_for_confirmation
362
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 = []
363
396
 
364
- ### Search line-by-line in the specified +file+ for the given +regexp+, returning the
365
- ### first match, or nil if no match was found. If the +regexp+ has any capture groups,
366
- ### those will be returned in an Array, else the whole matching line is returned.
367
- def find_pattern_in_file( regexp, file )
368
- rval = nil
397
+ log( cmd.collect {|part| part =~ /\s/ ? part.inspect : part} )
398
+ Open3.popen3( *cmd ) do |stdin, stdout, stderr|
399
+ stdin.close
369
400
 
370
- File.open( file, 'r' ).each do |line|
371
- if (( match = regexp.match(line) ))
372
- rval = match.captures.empty? ? match[0] : match.captures
373
- break
401
+ output << stdout.gets until stdout.eof?
402
+ output << stderr.gets until stderr.eof?
374
403
  end
375
- end
376
404
 
377
- return rval
378
- end
405
+ result = output.find { |line| regexp.match(line) }
406
+ return $1 || result
407
+ end
379
408
 
380
409
 
381
- ### Search line-by-line in the output of the specified +cmd+ for the given +regexp+,
382
- ### returning the first match, or nil if no match was found. If the +regexp+ has any
383
- ### capture groups, those will be returned in an Array, else the whole matching line
384
- ### is returned.
385
- def find_pattern_in_pipe( regexp, *cmd )
386
- output = []
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
387
419
 
388
- log( cmd.collect {|part| part =~ /\s/ ? part.inspect : part} )
389
- Open3.popen3( *cmd ) do |stdin, stdout, stderr|
390
- stdin.close
391
420
 
392
- output << stdout.gets until stdout.eof?
393
- output << stderr.gets until stderr.eof?
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
394
425
  end
395
426
 
396
- result = output.find { |line| regexp.match(line) }
397
- return $1 || result
398
- end
399
427
 
428
+ ### Log a subdirectory change, execute a block, and exit the subdirectory
429
+ def in_subdirectory( subdir )
430
+ block = Proc.new
400
431
 
401
- ### Invoke the user's editor on the given +filename+ and return the exit code
402
- ### from doing so.
403
- def edit( filename )
404
- editor = ENV['EDITOR'] || ENV['VISUAL'] || DEFAULT_EDITOR
405
- system editor, filename
406
- unless $?.success? || editor =~ /vim/i
407
- fail "Editor exited uncleanly."
432
+ log "Entering #{subdir}"
433
+ Dir.chdir( subdir, &block )
434
+ log "Leaving #{subdir}"
408
435
  end
409
- end
410
436
 
411
437
 
412
- ### Extract all the non Rake-target arguments from ARGV and return them.
413
- def get_target_args
414
- args = ARGV.reject {|arg| arg =~ /^-/ || Rake::Task.task_defined?(arg) }
415
- return args
416
- end
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
417
442
 
418
443
 
419
- ### Log a subdirectory change, execute a block, and exit the subdirectory
420
- def in_subdirectory( subdir )
421
- block = Proc.new
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?
422
450
 
423
- log "Entering #{subdir}"
424
- Dir.chdir( subdir, &block )
425
- log "Leaving #{subdir}"
426
- end
451
+ reader = Archive::Tar::Reader.new( tarfile.to_s, TAR_OPTS )
427
452
 
453
+ mkdir_p( targetdir )
454
+ reader.each( true ) do |header, body|
455
+ path = targetdir + header[:path]
456
+ # trace "Header is: %p" % [ header ]
428
457
 
429
- ### Make an easily-comparable version vector out of +ver+ and return it.
430
- def vvec( ver )
431
- return ver.split('.').collect {|char| char.to_i }.pack('N*')
432
- end
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
433
499
 
500
+ end # module Rakefile::Helpers
434
501
 
435
502