axtro-actionwebservice 2.3.5.1.20101118142125

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/CHANGELOG +335 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +381 -0
  4. data/Rakefile +184 -0
  5. data/TODO +32 -0
  6. data/examples/googlesearch/README +143 -0
  7. data/examples/googlesearch/autoloading/google_search_api.rb +51 -0
  8. data/examples/googlesearch/autoloading/google_search_controller.rb +58 -0
  9. data/examples/googlesearch/delegated/google_search_service.rb +109 -0
  10. data/examples/googlesearch/delegated/search_controller.rb +8 -0
  11. data/examples/googlesearch/direct/google_search_api.rb +51 -0
  12. data/examples/googlesearch/direct/search_controller.rb +59 -0
  13. data/examples/metaWeblog/README +17 -0
  14. data/examples/metaWeblog/apis/blogger_api.rb +61 -0
  15. data/examples/metaWeblog/apis/blogger_service.rb +35 -0
  16. data/examples/metaWeblog/apis/meta_weblog_api.rb +68 -0
  17. data/examples/metaWeblog/apis/meta_weblog_service.rb +49 -0
  18. data/examples/metaWeblog/controllers/xmlrpc_controller.rb +17 -0
  19. data/generators/web_service/USAGE +28 -0
  20. data/generators/web_service/templates/api_definition.rb +6 -0
  21. data/generators/web_service/templates/controller.rb +9 -0
  22. data/generators/web_service/templates/functional_test.rb +20 -0
  23. data/generators/web_service/web_service_generator.rb +30 -0
  24. data/lib/action_web_service.rb +61 -0
  25. data/lib/action_web_service/acts_as_web_service.rb +26 -0
  26. data/lib/action_web_service/api.rb +298 -0
  27. data/lib/action_web_service/base.rb +39 -0
  28. data/lib/action_web_service/casting.rb +160 -0
  29. data/lib/action_web_service/client.rb +4 -0
  30. data/lib/action_web_service/client/base.rb +29 -0
  31. data/lib/action_web_service/client/soap_client.rb +114 -0
  32. data/lib/action_web_service/client/xmlrpc_client.rb +59 -0
  33. data/lib/action_web_service/container.rb +4 -0
  34. data/lib/action_web_service/container/action_controller_container.rb +94 -0
  35. data/lib/action_web_service/container/delegated_container.rb +87 -0
  36. data/lib/action_web_service/container/direct_container.rb +70 -0
  37. data/lib/action_web_service/dispatcher.rb +3 -0
  38. data/lib/action_web_service/dispatcher/abstract.rb +209 -0
  39. data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +397 -0
  40. data/lib/action_web_service/invocation.rb +203 -0
  41. data/lib/action_web_service/protocol.rb +5 -0
  42. data/lib/action_web_service/protocol/abstract.rb +113 -0
  43. data/lib/action_web_service/protocol/discovery.rb +38 -0
  44. data/lib/action_web_service/protocol/soap_protocol.rb +177 -0
  45. data/lib/action_web_service/protocol/soap_protocol/marshaler.rb +243 -0
  46. data/lib/action_web_service/protocol/soap_protocol/marshaler.rb~ +243 -0
  47. data/lib/action_web_service/protocol/xmlrpc_protocol.rb +124 -0
  48. data/lib/action_web_service/scaffolding.rb +282 -0
  49. data/lib/action_web_service/simple.rb +54 -0
  50. data/lib/action_web_service/string_to_datetime_for_soap.rb +17 -0
  51. data/lib/action_web_service/struct.rb +69 -0
  52. data/lib/action_web_service/support/class_inheritable_options.rb +27 -0
  53. data/lib/action_web_service/support/signature_types.rb +262 -0
  54. data/lib/action_web_service/templates/scaffolds/layout.html.erb +65 -0
  55. data/lib/action_web_service/templates/scaffolds/methods.html.erb +6 -0
  56. data/lib/action_web_service/templates/scaffolds/parameters.html.erb +29 -0
  57. data/lib/action_web_service/templates/scaffolds/result.html.erb +30 -0
  58. data/lib/action_web_service/test_invoke.rb +111 -0
  59. data/lib/action_web_service/version.rb +11 -0
  60. data/lib/action_web_service/version.rb~ +10 -0
  61. data/lib/actionwebservice.rb +2 -0
  62. data/setup.rb +1380 -0
  63. data/test/abstract_client.rb +185 -0
  64. data/test/abstract_dispatcher.rb +550 -0
  65. data/test/abstract_unit.rb +44 -0
  66. data/test/api_test.rb +103 -0
  67. data/test/apis/auto_load_api.rb +4 -0
  68. data/test/apis/broken_auto_load_api.rb +3 -0
  69. data/test/base_test.rb +43 -0
  70. data/test/casting_test.rb +96 -0
  71. data/test/client_soap_test.rb +157 -0
  72. data/test/client_xmlrpc_test.rb +155 -0
  73. data/test/container_test.rb +76 -0
  74. data/test/dispatcher_action_controller_soap_test.rb +147 -0
  75. data/test/dispatcher_action_controller_xmlrpc_test.rb +60 -0
  76. data/test/fixtures/db_definitions/mysql.sql +8 -0
  77. data/test/fixtures/db_definitions/sqlite3.sql +8 -0
  78. data/test/fixtures/users.yml +12 -0
  79. data/test/gencov +3 -0
  80. data/test/invocation_test.rb +187 -0
  81. data/test/run +6 -0
  82. data/test/scaffolded_controller_test.rb +148 -0
  83. data/test/struct_test.rb +85 -0
  84. data/test/test_invoke_test.rb +114 -0
  85. metadata +167 -0
@@ -0,0 +1,29 @@
1
+ <h4>Method Invocation Details for <em><%= @scaffold_service %>#<%= @scaffold_method.public_name %></em></h4>
2
+
3
+ <% form_tag(:action => @scaffold_action_name + '_submit') do -%>
4
+ <%= hidden_field_tag "service", @scaffold_service.name %>
5
+ <%= hidden_field_tag "method", @scaffold_method.public_name %>
6
+
7
+ <p>
8
+ <label for="protocol">Protocol:</label><br />
9
+ <%= select_tag 'protocol', options_for_select([['SOAP', 'soap'], ['XML-RPC', 'xmlrpc']], params['protocol']) %>
10
+ </p>
11
+
12
+ <% if @scaffold_method.expects %>
13
+
14
+ <strong>Method Parameters:</strong><br />
15
+ <% @scaffold_method.expects.each_with_index do |type, i| %>
16
+ <p>
17
+ <label for="method_params[<%= i %>]"><%= method_parameter_label(type.name, type) %> </label><br />
18
+ <%= method_parameter_input_fields(@scaffold_method, type, "method_params", i) %>
19
+ </p>
20
+ <% end %>
21
+
22
+ <% end %>
23
+
24
+ <%= submit_tag "Invoke" %>
25
+ <% end -%>
26
+
27
+ <p>
28
+ <%= link_to "Back", :action => @scaffold_action_name %>
29
+ </p>
@@ -0,0 +1,30 @@
1
+ <h4>Method Invocation Result for <em><%= @scaffold_service %>#<%= @scaffold_method.public_name %></em></h4>
2
+
3
+ <p>
4
+ Invocation took <tt><%= '%f' % @method_elapsed %></tt> seconds
5
+ </p>
6
+
7
+ <p>
8
+ <strong>Return Value:</strong><br />
9
+ <pre>
10
+ <%= h @method_return_value.inspect %>
11
+ </pre>
12
+ </p>
13
+
14
+ <p>
15
+ <strong>Request XML:</strong><br />
16
+ <pre>
17
+ <%= h @method_request_xml %>
18
+ </pre>
19
+ </p>
20
+
21
+ <p>
22
+ <strong>Response XML:</strong><br />
23
+ <pre>
24
+ <%= h @method_response_xml %>
25
+ </pre>
26
+ </p>
27
+
28
+ <p>
29
+ <%= link_to "Back", :action => @scaffold_action_name + '_method_params', :method => @scaffold_method.public_name, :service => @scaffold_service.name %>
30
+ </p>
@@ -0,0 +1,111 @@
1
+ # encoding: UTF-8
2
+ require 'test/unit'
3
+
4
+ module Test # :nodoc:
5
+ module Unit # :nodoc:
6
+ class TestCase # :nodoc:
7
+ private
8
+ # invoke the specified API method
9
+ def invoke_direct(method_name, *args)
10
+ prepare_request('api', 'api', method_name, *args)
11
+ @controller.process(@request, @response)
12
+ decode_rpc_response
13
+ end
14
+ alias_method :invoke, :invoke_direct
15
+
16
+ # invoke the specified API method on the specified service
17
+ def invoke_delegated(service_name, method_name, *args)
18
+ prepare_request(service_name.to_s, service_name, method_name, *args)
19
+ @controller.process(@request, @response)
20
+ decode_rpc_response
21
+ end
22
+
23
+ # invoke the specified layered API method on the correct service
24
+ def invoke_layered(service_name, method_name, *args)
25
+ prepare_request('api', service_name, method_name, *args)
26
+ @controller.process(@request, @response)
27
+ decode_rpc_response
28
+ end
29
+
30
+ # ---------------------- internal ---------------------------
31
+
32
+ def prepare_request(action, service_name, api_method_name, *args)
33
+ @request.recycle!
34
+ @request.request_parameters['action'] = action
35
+ @request.env['REQUEST_METHOD'] = 'POST'
36
+ @request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
37
+ @request.env['RAW_POST_DATA'] = encode_rpc_call(service_name, api_method_name, *args)
38
+ case protocol
39
+ when ActionWebService::Protocol::Soap::SoapProtocol
40
+ soap_action = "/#{@controller.controller_name}/#{service_name}/#{public_method_name(service_name, api_method_name)}"
41
+ @request.env['HTTP_SOAPACTION'] = soap_action
42
+ when ActionWebService::Protocol::XmlRpc::XmlRpcProtocol
43
+ @request.env.delete('HTTP_SOAPACTION')
44
+ end
45
+ end
46
+
47
+ def encode_rpc_call(service_name, api_method_name, *args)
48
+ case @controller.web_service_dispatching_mode
49
+ when :direct
50
+ api = @controller.class.web_service_api
51
+ when :delegated, :layered
52
+ api = @controller.web_service_object(service_name.to_sym).class.web_service_api
53
+ end
54
+ protocol.register_api(api)
55
+ method = api.api_methods[api_method_name.to_sym]
56
+ raise ArgumentError, "wrong number of arguments for rpc call (#{args.length} for #{method.expects.length})" if method && method.expects && args.length != method.expects.length
57
+ protocol.encode_request(public_method_name(service_name, api_method_name), args.dup, method.expects)
58
+ end
59
+
60
+ def decode_rpc_response
61
+ public_method_name, return_value = protocol.decode_response(@response.body)
62
+ exception = is_exception?(return_value)
63
+ raise exception if exception
64
+ return_value
65
+ end
66
+
67
+ def public_method_name(service_name, api_method_name)
68
+ public_name = service_api(service_name).public_api_method_name(api_method_name)
69
+ if @controller.web_service_dispatching_mode == :layered && protocol.is_a?(ActionWebService::Protocol::XmlRpc::XmlRpcProtocol)
70
+ '%s.%s' % [service_name.to_s, public_name]
71
+ else
72
+ public_name
73
+ end
74
+ end
75
+
76
+ def service_api(service_name)
77
+ case @controller.web_service_dispatching_mode
78
+ when :direct
79
+ @controller.class.web_service_api
80
+ when :delegated, :layered
81
+ @controller.web_service_object(service_name.to_sym).class.web_service_api
82
+ end
83
+ end
84
+
85
+ def protocol
86
+ if @protocol.nil?
87
+ @protocol ||= ActionWebService::Protocol::Soap::SoapProtocol.create(@controller)
88
+ else
89
+ case @protocol
90
+ when :xmlrpc
91
+ @protocol = ActionWebService::Protocol::XmlRpc::XmlRpcProtocol.create(@controller)
92
+ when :soap
93
+ @protocol = ActionWebService::Protocol::Soap::SoapProtocol.create(@controller)
94
+ else
95
+ @protocol
96
+ end
97
+ end
98
+ end
99
+
100
+ def is_exception?(obj)
101
+ case protocol
102
+ when :soap, ActionWebService::Protocol::Soap::SoapProtocol
103
+ (obj.respond_to?(:detail) && obj.detail.respond_to?(:cause) && \
104
+ obj.detail.cause.is_a?(Exception)) ? obj.detail.cause : nil
105
+ when :xmlrpc, ActionWebService::Protocol::XmlRpc::XmlRpcProtocol
106
+ obj.is_a?(XMLRPC::FaultException) ? obj : nil
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: UTF-8
2
+ module ActionWebService
3
+ module VERSION #:nodoc:
4
+ MAJOR = 2
5
+ MINOR = 3
6
+ TINY = 5
7
+ BUILD = 1
8
+
9
+ STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: UTF-8
2
+ module ActionWebService
3
+ module VERSION #:nodoc:
4
+ MAJOR = 2
5
+ MINOR = 3
6
+ TINY = 5
7
+
8
+ STRING = [MAJOR, MINOR, TINY].join('.')
9
+ end
10
+ end
@@ -0,0 +1,2 @@
1
+ # encoding: UTF-8
2
+ require 'action_web_service'
@@ -0,0 +1,1380 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # setup.rb
4
+ #
5
+ # Copyright (c) 2000-2004 Minero Aoki
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject to
13
+ # the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+ #
26
+ # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
27
+ # with permission of Minero Aoki.
28
+
29
+ #
30
+
31
+ unless Enumerable.method_defined?(:map) # Ruby 1.4.6
32
+ module Enumerable
33
+ alias map collect
34
+ end
35
+ end
36
+
37
+ unless File.respond_to?(:read) # Ruby 1.6
38
+ def File.read(fname)
39
+ open(fname) {|f|
40
+ return f.read
41
+ }
42
+ end
43
+ end
44
+
45
+ def File.binread(fname)
46
+ open(fname, 'rb') {|f|
47
+ return f.read
48
+ }
49
+ end
50
+
51
+ # for corrupted windows stat(2)
52
+ def File.dir?(path)
53
+ File.directory?((path[-1,1] == '/') ? path : path + '/')
54
+ end
55
+
56
+
57
+ class SetupError < StandardError; end
58
+
59
+ def setup_rb_error(msg)
60
+ raise SetupError, msg
61
+ end
62
+
63
+ #
64
+ # Config
65
+ #
66
+
67
+ if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
68
+ ARGV.delete(arg)
69
+ require arg.split(/=/, 2)[1]
70
+ $".push 'rbconfig.rb'
71
+ else
72
+ require 'rbconfig'
73
+ end
74
+
75
+ def multipackage_install?
76
+ FileTest.directory?(File.dirname($0) + '/packages')
77
+ end
78
+
79
+
80
+ class ConfigItem
81
+ def initialize(name, template, default, desc)
82
+ @name = name.freeze
83
+ @template = template
84
+ @value = default
85
+ @default = default.dup.freeze
86
+ @description = desc
87
+ end
88
+
89
+ attr_reader :name
90
+ attr_reader :description
91
+
92
+ attr_accessor :default
93
+ alias help_default default
94
+
95
+ def help_opt
96
+ "--#{@name}=#{@template}"
97
+ end
98
+
99
+ def value
100
+ @value
101
+ end
102
+
103
+ def eval(table)
104
+ @value.gsub(%r<\$([^/]+)>) { table[$1] }
105
+ end
106
+
107
+ def set(val)
108
+ @value = check(val)
109
+ end
110
+
111
+ private
112
+
113
+ def check(val)
114
+ setup_rb_error "config: --#{name} requires argument" unless val
115
+ val
116
+ end
117
+ end
118
+
119
+ class BoolItem < ConfigItem
120
+ def config_type
121
+ 'bool'
122
+ end
123
+
124
+ def help_opt
125
+ "--#{@name}"
126
+ end
127
+
128
+ private
129
+
130
+ def check(val)
131
+ return 'yes' unless val
132
+ unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val
133
+ setup_rb_error "config: --#{@name} accepts only yes/no for argument"
134
+ end
135
+ (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no'
136
+ end
137
+ end
138
+
139
+ class PathItem < ConfigItem
140
+ def config_type
141
+ 'path'
142
+ end
143
+
144
+ private
145
+
146
+ def check(path)
147
+ setup_rb_error "config: --#{@name} requires argument" unless path
148
+ path[0,1] == '$' ? path : File.expand_path(path)
149
+ end
150
+ end
151
+
152
+ class ProgramItem < ConfigItem
153
+ def config_type
154
+ 'program'
155
+ end
156
+ end
157
+
158
+ class SelectItem < ConfigItem
159
+ def initialize(name, template, default, desc)
160
+ super
161
+ @ok = template.split('/')
162
+ end
163
+
164
+ def config_type
165
+ 'select'
166
+ end
167
+
168
+ private
169
+
170
+ def check(val)
171
+ unless @ok.include?(val.strip)
172
+ setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
173
+ end
174
+ val.strip
175
+ end
176
+ end
177
+
178
+ class PackageSelectionItem < ConfigItem
179
+ def initialize(name, template, default, help_default, desc)
180
+ super name, template, default, desc
181
+ @help_default = help_default
182
+ end
183
+
184
+ attr_reader :help_default
185
+
186
+ def config_type
187
+ 'package'
188
+ end
189
+
190
+ private
191
+
192
+ def check(val)
193
+ unless File.dir?("packages/#{val}")
194
+ setup_rb_error "config: no such package: #{val}"
195
+ end
196
+ val
197
+ end
198
+ end
199
+
200
+ class ConfigTable_class
201
+
202
+ def initialize(items)
203
+ @items = items
204
+ @table = {}
205
+ items.each do |i|
206
+ @table[i.name] = i
207
+ end
208
+ ALIASES.each do |ali, name|
209
+ @table[ali] = @table[name]
210
+ end
211
+ end
212
+
213
+ include Enumerable
214
+
215
+ def each(&block)
216
+ @items.each(&block)
217
+ end
218
+
219
+ def key?(name)
220
+ @table.key?(name)
221
+ end
222
+
223
+ def lookup(name)
224
+ @table[name] or raise ArgumentError, "no such config item: #{name}"
225
+ end
226
+
227
+ def add(item)
228
+ @items.push item
229
+ @table[item.name] = item
230
+ end
231
+
232
+ def remove(name)
233
+ item = lookup(name)
234
+ @items.delete_if {|i| i.name == name }
235
+ @table.delete_if {|name, i| i.name == name }
236
+ item
237
+ end
238
+
239
+ def new
240
+ dup()
241
+ end
242
+
243
+ def savefile
244
+ '.config'
245
+ end
246
+
247
+ def load
248
+ begin
249
+ t = dup()
250
+ File.foreach(savefile()) do |line|
251
+ k, v = *line.split(/=/, 2)
252
+ t[k] = v.strip
253
+ end
254
+ t
255
+ rescue Errno::ENOENT
256
+ setup_rb_error $!.message + "#{File.basename($0)} config first"
257
+ end
258
+ end
259
+
260
+ def save
261
+ @items.each {|i| i.value }
262
+ File.open(savefile(), 'w') {|f|
263
+ @items.each do |i|
264
+ f.printf "%s=%s\n", i.name, i.value if i.value
265
+ end
266
+ }
267
+ end
268
+
269
+ def [](key)
270
+ lookup(key).eval(self)
271
+ end
272
+
273
+ def []=(key, val)
274
+ lookup(key).set val
275
+ end
276
+
277
+ end
278
+
279
+ c = ::Config::CONFIG
280
+
281
+ rubypath = c['bindir'] + '/' + c['ruby_install_name']
282
+
283
+ major = c['MAJOR'].to_i
284
+ minor = c['MINOR'].to_i
285
+ teeny = c['TEENY'].to_i
286
+ version = "#{major}.#{minor}"
287
+
288
+ # ruby ver. >= 1.4.4?
289
+ newpath_p = ((major >= 2) or
290
+ ((major == 1) and
291
+ ((minor >= 5) or
292
+ ((minor == 4) and (teeny >= 4)))))
293
+
294
+ if c['rubylibdir']
295
+ # V < 1.6.3
296
+ _stdruby = c['rubylibdir']
297
+ _siteruby = c['sitedir']
298
+ _siterubyver = c['sitelibdir']
299
+ _siterubyverarch = c['sitearchdir']
300
+ elsif newpath_p
301
+ # 1.4.4 <= V <= 1.6.3
302
+ _stdruby = "$prefix/lib/ruby/#{version}"
303
+ _siteruby = c['sitedir']
304
+ _siterubyver = "$siteruby/#{version}"
305
+ _siterubyverarch = "$siterubyver/#{c['arch']}"
306
+ else
307
+ # V < 1.4.4
308
+ _stdruby = "$prefix/lib/ruby/#{version}"
309
+ _siteruby = "$prefix/lib/ruby/#{version}/site_ruby"
310
+ _siterubyver = _siteruby
311
+ _siterubyverarch = "$siterubyver/#{c['arch']}"
312
+ end
313
+ libdir = '-* dummy libdir *-'
314
+ stdruby = '-* dummy rubylibdir *-'
315
+ siteruby = '-* dummy site_ruby *-'
316
+ siterubyver = '-* dummy site_ruby version *-'
317
+ parameterize = lambda {|path|
318
+ path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\
319
+ .sub(/\A#{Regexp.quote(libdir)}/, '$libdir')\
320
+ .sub(/\A#{Regexp.quote(stdruby)}/, '$stdruby')\
321
+ .sub(/\A#{Regexp.quote(siteruby)}/, '$siteruby')\
322
+ .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver')
323
+ }
324
+ libdir = parameterize.call(c['libdir'])
325
+ stdruby = parameterize.call(_stdruby)
326
+ siteruby = parameterize.call(_siteruby)
327
+ siterubyver = parameterize.call(_siterubyver)
328
+ siterubyverarch = parameterize.call(_siterubyverarch)
329
+
330
+ if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
331
+ makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
332
+ else
333
+ makeprog = 'make'
334
+ end
335
+
336
+ common_conf = [
337
+ PathItem.new('prefix', 'path', c['prefix'],
338
+ 'path prefix of target environment'),
339
+ PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
340
+ 'the directory for commands'),
341
+ PathItem.new('libdir', 'path', libdir,
342
+ 'the directory for libraries'),
343
+ PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
344
+ 'the directory for shared data'),
345
+ PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
346
+ 'the directory for man pages'),
347
+ PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
348
+ 'the directory for man pages'),
349
+ PathItem.new('stdruby', 'path', stdruby,
350
+ 'the directory for standard ruby libraries'),
351
+ PathItem.new('siteruby', 'path', siteruby,
352
+ 'the directory for version-independent aux ruby libraries'),
353
+ PathItem.new('siterubyver', 'path', siterubyver,
354
+ 'the directory for aux ruby libraries'),
355
+ PathItem.new('siterubyverarch', 'path', siterubyverarch,
356
+ 'the directory for aux ruby binaries'),
357
+ PathItem.new('rbdir', 'path', '$siterubyver',
358
+ 'the directory for ruby scripts'),
359
+ PathItem.new('sodir', 'path', '$siterubyverarch',
360
+ 'the directory for ruby extentions'),
361
+ PathItem.new('rubypath', 'path', rubypath,
362
+ 'the path to set to #! line'),
363
+ ProgramItem.new('rubyprog', 'name', rubypath,
364
+ 'the ruby program using for installation'),
365
+ ProgramItem.new('makeprog', 'name', makeprog,
366
+ 'the make program to compile ruby extentions'),
367
+ SelectItem.new('shebang', 'all/ruby/never', 'ruby',
368
+ 'shebang line (#!) editing mode'),
369
+ BoolItem.new('without-ext', 'yes/no', 'no',
370
+ 'does not compile/install ruby extentions')
371
+ ]
372
+ class ConfigTable_class # open again
373
+ ALIASES = {
374
+ 'std-ruby' => 'stdruby',
375
+ 'site-ruby-common' => 'siteruby', # For backward compatibility
376
+ 'site-ruby' => 'siterubyver', # For backward compatibility
377
+ 'bin-dir' => 'bindir',
378
+ 'bin-dir' => 'bindir',
379
+ 'rb-dir' => 'rbdir',
380
+ 'so-dir' => 'sodir',
381
+ 'data-dir' => 'datadir',
382
+ 'ruby-path' => 'rubypath',
383
+ 'ruby-prog' => 'rubyprog',
384
+ 'ruby' => 'rubyprog',
385
+ 'make-prog' => 'makeprog',
386
+ 'make' => 'makeprog'
387
+ }
388
+ end
389
+ multipackage_conf = [
390
+ PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
391
+ 'package names that you want to install'),
392
+ PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
393
+ 'package names that you do not want to install')
394
+ ]
395
+ if multipackage_install?
396
+ ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf)
397
+ else
398
+ ConfigTable = ConfigTable_class.new(common_conf)
399
+ end
400
+
401
+
402
+ module MetaConfigAPI
403
+
404
+ def eval_file_ifexist(fname)
405
+ instance_eval File.read(fname), fname, 1 if File.file?(fname)
406
+ end
407
+
408
+ def config_names
409
+ ConfigTable.map {|i| i.name }
410
+ end
411
+
412
+ def config?(name)
413
+ ConfigTable.key?(name)
414
+ end
415
+
416
+ def bool_config?(name)
417
+ ConfigTable.lookup(name).config_type == 'bool'
418
+ end
419
+
420
+ def path_config?(name)
421
+ ConfigTable.lookup(name).config_type == 'path'
422
+ end
423
+
424
+ def value_config?(name)
425
+ case ConfigTable.lookup(name).config_type
426
+ when 'bool', 'path'
427
+ true
428
+ else
429
+ false
430
+ end
431
+ end
432
+
433
+ def add_config(item)
434
+ ConfigTable.add item
435
+ end
436
+
437
+ def add_bool_config(name, default, desc)
438
+ ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
439
+ end
440
+
441
+ def add_path_config(name, default, desc)
442
+ ConfigTable.add PathItem.new(name, 'path', default, desc)
443
+ end
444
+
445
+ def set_config_default(name, default)
446
+ ConfigTable.lookup(name).default = default
447
+ end
448
+
449
+ def remove_config(name)
450
+ ConfigTable.remove(name)
451
+ end
452
+
453
+ end
454
+
455
+
456
+ #
457
+ # File Operations
458
+ #
459
+
460
+ module FileOperations
461
+
462
+ def mkdir_p(dirname, prefix = nil)
463
+ dirname = prefix + File.expand_path(dirname) if prefix
464
+ $stderr.puts "mkdir -p #{dirname}" if verbose?
465
+ return if no_harm?
466
+
467
+ # does not check '/'... it's too abnormal case
468
+ dirs = File.expand_path(dirname).split(%r<(?=/)>)
469
+ if /\A[a-z]:\z/i =~ dirs[0]
470
+ disk = dirs.shift
471
+ dirs[0] = disk + dirs[0]
472
+ end
473
+ dirs.each_index do |idx|
474
+ path = dirs[0..idx].join('')
475
+ Dir.mkdir path unless File.dir?(path)
476
+ end
477
+ end
478
+
479
+ def rm_f(fname)
480
+ $stderr.puts "rm -f #{fname}" if verbose?
481
+ return if no_harm?
482
+
483
+ if File.exist?(fname) or File.symlink?(fname)
484
+ File.chmod 0777, fname
485
+ File.unlink fname
486
+ end
487
+ end
488
+
489
+ def rm_rf(dn)
490
+ $stderr.puts "rm -rf #{dn}" if verbose?
491
+ return if no_harm?
492
+
493
+ Dir.chdir dn
494
+ Dir.foreach('.') do |fn|
495
+ next if fn == '.'
496
+ next if fn == '..'
497
+ if File.dir?(fn)
498
+ verbose_off {
499
+ rm_rf fn
500
+ }
501
+ else
502
+ verbose_off {
503
+ rm_f fn
504
+ }
505
+ end
506
+ end
507
+ Dir.chdir '..'
508
+ Dir.rmdir dn
509
+ end
510
+
511
+ def move_file(src, dest)
512
+ File.unlink dest if File.exist?(dest)
513
+ begin
514
+ File.rename src, dest
515
+ rescue
516
+ File.open(dest, 'wb') {|f| f.write File.binread(src) }
517
+ File.chmod File.stat(src).mode, dest
518
+ File.unlink src
519
+ end
520
+ end
521
+
522
+ def install(from, dest, mode, prefix = nil)
523
+ $stderr.puts "install #{from} #{dest}" if verbose?
524
+ return if no_harm?
525
+
526
+ realdest = prefix ? prefix + File.expand_path(dest) : dest
527
+ realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
528
+ str = File.binread(from)
529
+ if diff?(str, realdest)
530
+ verbose_off {
531
+ rm_f realdest if File.exist?(realdest)
532
+ }
533
+ File.open(realdest, 'wb') {|f|
534
+ f.write str
535
+ }
536
+ File.chmod mode, realdest
537
+
538
+ File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
539
+ if prefix
540
+ f.puts realdest.sub(prefix, '')
541
+ else
542
+ f.puts realdest
543
+ end
544
+ }
545
+ end
546
+ end
547
+
548
+ def diff?(new_content, path)
549
+ return true unless File.exist?(path)
550
+ new_content != File.binread(path)
551
+ end
552
+
553
+ def command(str)
554
+ $stderr.puts str if verbose?
555
+ system str or raise RuntimeError, "'system #{str}' failed"
556
+ end
557
+
558
+ def ruby(str)
559
+ command config('rubyprog') + ' ' + str
560
+ end
561
+
562
+ def make(task = '')
563
+ command config('makeprog') + ' ' + task
564
+ end
565
+
566
+ def extdir?(dir)
567
+ File.exist?(dir + '/MANIFEST')
568
+ end
569
+
570
+ def all_files_in(dirname)
571
+ Dir.open(dirname) {|d|
572
+ return d.select {|ent| File.file?("#{dirname}/#{ent}") }
573
+ }
574
+ end
575
+
576
+ REJECT_DIRS = %w(
577
+ CVS SCCS RCS CVS.adm .svn
578
+ )
579
+
580
+ def all_dirs_in(dirname)
581
+ Dir.open(dirname) {|d|
582
+ return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS
583
+ }
584
+ end
585
+
586
+ end
587
+
588
+
589
+ #
590
+ # Main Installer
591
+ #
592
+
593
+ module HookUtils
594
+
595
+ def run_hook(name)
596
+ try_run_hook "#{curr_srcdir()}/#{name}" or
597
+ try_run_hook "#{curr_srcdir()}/#{name}.rb"
598
+ end
599
+
600
+ def try_run_hook(fname)
601
+ return false unless File.file?(fname)
602
+ begin
603
+ instance_eval File.read(fname), fname, 1
604
+ rescue
605
+ setup_rb_error "hook #{fname} failed:\n" + $!.message
606
+ end
607
+ true
608
+ end
609
+
610
+ end
611
+
612
+
613
+ module HookScriptAPI
614
+
615
+ def get_config(key)
616
+ @config[key]
617
+ end
618
+
619
+ alias config get_config
620
+
621
+ def set_config(key, val)
622
+ @config[key] = val
623
+ end
624
+
625
+ #
626
+ # srcdir/objdir (works only in the package directory)
627
+ #
628
+
629
+ #abstract srcdir_root
630
+ #abstract objdir_root
631
+ #abstract relpath
632
+
633
+ def curr_srcdir
634
+ "#{srcdir_root()}/#{relpath()}"
635
+ end
636
+
637
+ def curr_objdir
638
+ "#{objdir_root()}/#{relpath()}"
639
+ end
640
+
641
+ def srcfile(path)
642
+ "#{curr_srcdir()}/#{path}"
643
+ end
644
+
645
+ def srcexist?(path)
646
+ File.exist?(srcfile(path))
647
+ end
648
+
649
+ def srcdirectory?(path)
650
+ File.dir?(srcfile(path))
651
+ end
652
+
653
+ def srcfile?(path)
654
+ File.file? srcfile(path)
655
+ end
656
+
657
+ def srcentries(path = '.')
658
+ Dir.open("#{curr_srcdir()}/#{path}") {|d|
659
+ return d.to_a - %w(. ..)
660
+ }
661
+ end
662
+
663
+ def srcfiles(path = '.')
664
+ srcentries(path).select {|fname|
665
+ File.file?(File.join(curr_srcdir(), path, fname))
666
+ }
667
+ end
668
+
669
+ def srcdirectories(path = '.')
670
+ srcentries(path).select {|fname|
671
+ File.dir?(File.join(curr_srcdir(), path, fname))
672
+ }
673
+ end
674
+
675
+ end
676
+
677
+
678
+ class ToplevelInstaller
679
+
680
+ Version = '3.3.1'
681
+ Copyright = 'Copyright (c) 2000-2004 Minero Aoki'
682
+
683
+ TASKS = [
684
+ [ 'all', 'do config, setup, then install' ],
685
+ [ 'config', 'saves your configurations' ],
686
+ [ 'show', 'shows current configuration' ],
687
+ [ 'setup', 'compiles ruby extentions and others' ],
688
+ [ 'install', 'installs files' ],
689
+ [ 'clean', "does `make clean' for each extention" ],
690
+ [ 'distclean',"does `make distclean' for each extention" ]
691
+ ]
692
+
693
+ def ToplevelInstaller.invoke
694
+ instance().invoke
695
+ end
696
+
697
+ @singleton = nil
698
+
699
+ def ToplevelInstaller.instance
700
+ @singleton ||= new(File.dirname($0))
701
+ @singleton
702
+ end
703
+
704
+ include MetaConfigAPI
705
+
706
+ def initialize(ardir_root)
707
+ @config = nil
708
+ @options = { 'verbose' => true }
709
+ @ardir = File.expand_path(ardir_root)
710
+ end
711
+
712
+ def inspect
713
+ "#<#{self.class} #{__id__()}>"
714
+ end
715
+
716
+ def invoke
717
+ run_metaconfigs
718
+ case task = parsearg_global()
719
+ when nil, 'all'
720
+ @config = load_config('config')
721
+ parsearg_config
722
+ init_installers
723
+ exec_config
724
+ exec_setup
725
+ exec_install
726
+ else
727
+ @config = load_config(task)
728
+ __send__ "parsearg_#{task}"
729
+ init_installers
730
+ __send__ "exec_#{task}"
731
+ end
732
+ end
733
+
734
+ def run_metaconfigs
735
+ eval_file_ifexist "#{@ardir}/metaconfig"
736
+ end
737
+
738
+ def load_config(task)
739
+ case task
740
+ when 'config'
741
+ ConfigTable.new
742
+ when 'clean', 'distclean'
743
+ if File.exist?(ConfigTable.savefile)
744
+ then ConfigTable.load
745
+ else ConfigTable.new
746
+ end
747
+ else
748
+ ConfigTable.load
749
+ end
750
+ end
751
+
752
+ def init_installers
753
+ @installer = Installer.new(@config, @options, @ardir, File.expand_path('.'))
754
+ end
755
+
756
+ #
757
+ # Hook Script API bases
758
+ #
759
+
760
+ def srcdir_root
761
+ @ardir
762
+ end
763
+
764
+ def objdir_root
765
+ '.'
766
+ end
767
+
768
+ def relpath
769
+ '.'
770
+ end
771
+
772
+ #
773
+ # Option Parsing
774
+ #
775
+
776
+ def parsearg_global
777
+ valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/
778
+
779
+ while arg = ARGV.shift
780
+ case arg
781
+ when /\A\w+\z/
782
+ setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg
783
+ return arg
784
+
785
+ when '-q', '--quiet'
786
+ @options['verbose'] = false
787
+
788
+ when '--verbose'
789
+ @options['verbose'] = true
790
+
791
+ when '-h', '--help'
792
+ print_usage $stdout
793
+ exit 0
794
+
795
+ when '-v', '--version'
796
+ puts "#{File.basename($0)} version #{Version}"
797
+ exit 0
798
+
799
+ when '--copyright'
800
+ puts Copyright
801
+ exit 0
802
+
803
+ else
804
+ setup_rb_error "unknown global option '#{arg}'"
805
+ end
806
+ end
807
+
808
+ nil
809
+ end
810
+
811
+
812
+ def parsearg_no_options
813
+ unless ARGV.empty?
814
+ setup_rb_error "#{task}: unknown options: #{ARGV.join ' '}"
815
+ end
816
+ end
817
+
818
+ alias parsearg_show parsearg_no_options
819
+ alias parsearg_setup parsearg_no_options
820
+ alias parsearg_clean parsearg_no_options
821
+ alias parsearg_distclean parsearg_no_options
822
+
823
+ def parsearg_config
824
+ re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/
825
+ @options['config-opt'] = []
826
+
827
+ while i = ARGV.shift
828
+ if /\A--?\z/ =~ i
829
+ @options['config-opt'] = ARGV.dup
830
+ break
831
+ end
832
+ m = re.match(i) or setup_rb_error "config: unknown option #{i}"
833
+ name, value = *m.to_a[1,2]
834
+ @config[name] = value
835
+ end
836
+ end
837
+
838
+ def parsearg_install
839
+ @options['no-harm'] = false
840
+ @options['install-prefix'] = ''
841
+ while a = ARGV.shift
842
+ case a
843
+ when /\A--no-harm\z/
844
+ @options['no-harm'] = true
845
+ when /\A--prefix=(.*)\z/
846
+ path = $1
847
+ path = File.expand_path(path) unless path[0,1] == '/'
848
+ @options['install-prefix'] = path
849
+ else
850
+ setup_rb_error "install: unknown option #{a}"
851
+ end
852
+ end
853
+ end
854
+
855
+ def print_usage(out)
856
+ out.puts 'Typical Installation Procedure:'
857
+ out.puts " $ ruby #{File.basename $0} config"
858
+ out.puts " $ ruby #{File.basename $0} setup"
859
+ out.puts " # ruby #{File.basename $0} install (may require root privilege)"
860
+ out.puts
861
+ out.puts 'Detailed Usage:'
862
+ out.puts " ruby #{File.basename $0} <global option>"
863
+ out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
864
+
865
+ fmt = " %-24s %s\n"
866
+ out.puts
867
+ out.puts 'Global options:'
868
+ out.printf fmt, '-q,--quiet', 'suppress message outputs'
869
+ out.printf fmt, ' --verbose', 'output messages verbosely'
870
+ out.printf fmt, '-h,--help', 'print this message'
871
+ out.printf fmt, '-v,--version', 'print version and quit'
872
+ out.printf fmt, ' --copyright', 'print copyright and quit'
873
+ out.puts
874
+ out.puts 'Tasks:'
875
+ TASKS.each do |name, desc|
876
+ out.printf fmt, name, desc
877
+ end
878
+
879
+ fmt = " %-24s %s [%s]\n"
880
+ out.puts
881
+ out.puts 'Options for CONFIG or ALL:'
882
+ ConfigTable.each do |item|
883
+ out.printf fmt, item.help_opt, item.description, item.help_default
884
+ end
885
+ out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
886
+ out.puts
887
+ out.puts 'Options for INSTALL:'
888
+ out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
889
+ out.printf fmt, '--prefix=path', 'install path prefix', '$prefix'
890
+ out.puts
891
+ end
892
+
893
+ #
894
+ # Task Handlers
895
+ #
896
+
897
+ def exec_config
898
+ @installer.exec_config
899
+ @config.save # must be final
900
+ end
901
+
902
+ def exec_setup
903
+ @installer.exec_setup
904
+ end
905
+
906
+ def exec_install
907
+ @installer.exec_install
908
+ end
909
+
910
+ def exec_show
911
+ ConfigTable.each do |i|
912
+ printf "%-20s %s\n", i.name, i.value
913
+ end
914
+ end
915
+
916
+ def exec_clean
917
+ @installer.exec_clean
918
+ end
919
+
920
+ def exec_distclean
921
+ @installer.exec_distclean
922
+ end
923
+
924
+ end
925
+
926
+
927
+ class ToplevelInstallerMulti < ToplevelInstaller
928
+
929
+ include HookUtils
930
+ include HookScriptAPI
931
+ include FileOperations
932
+
933
+ def initialize(ardir)
934
+ super
935
+ @packages = all_dirs_in("#{@ardir}/packages")
936
+ raise 'no package exists' if @packages.empty?
937
+ end
938
+
939
+ def run_metaconfigs
940
+ eval_file_ifexist "#{@ardir}/metaconfig"
941
+ @packages.each do |name|
942
+ eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig"
943
+ end
944
+ end
945
+
946
+ def init_installers
947
+ @installers = {}
948
+ @packages.each do |pack|
949
+ @installers[pack] = Installer.new(@config, @options,
950
+ "#{@ardir}/packages/#{pack}",
951
+ "packages/#{pack}")
952
+ end
953
+
954
+ with = extract_selection(config('with'))
955
+ without = extract_selection(config('without'))
956
+ @selected = @installers.keys.select {|name|
957
+ (with.empty? or with.include?(name)) \
958
+ and not without.include?(name)
959
+ }
960
+ end
961
+
962
+ def extract_selection(list)
963
+ a = list.split(/,/)
964
+ a.each do |name|
965
+ setup_rb_error "no such package: #{name}" unless @installers.key?(name)
966
+ end
967
+ a
968
+ end
969
+
970
+ def print_usage(f)
971
+ super
972
+ f.puts 'Included packages:'
973
+ f.puts ' ' + @packages.sort.join(' ')
974
+ f.puts
975
+ end
976
+
977
+ #
978
+ # multi-package metaconfig API
979
+ #
980
+
981
+ attr_reader :packages
982
+
983
+ def declare_packages(list)
984
+ raise 'package list is empty' if list.empty?
985
+ list.each do |name|
986
+ raise "directory packages/#{name} does not exist"\
987
+ unless File.dir?("#{@ardir}/packages/#{name}")
988
+ end
989
+ @packages = list
990
+ end
991
+
992
+ #
993
+ # Task Handlers
994
+ #
995
+
996
+ def exec_config
997
+ run_hook 'pre-config'
998
+ each_selected_installers {|inst| inst.exec_config }
999
+ run_hook 'post-config'
1000
+ @config.save # must be final
1001
+ end
1002
+
1003
+ def exec_setup
1004
+ run_hook 'pre-setup'
1005
+ each_selected_installers {|inst| inst.exec_setup }
1006
+ run_hook 'post-setup'
1007
+ end
1008
+
1009
+ def exec_install
1010
+ run_hook 'pre-install'
1011
+ each_selected_installers {|inst| inst.exec_install }
1012
+ run_hook 'post-install'
1013
+ end
1014
+
1015
+ def exec_clean
1016
+ rm_f ConfigTable.savefile
1017
+ run_hook 'pre-clean'
1018
+ each_selected_installers {|inst| inst.exec_clean }
1019
+ run_hook 'post-clean'
1020
+ end
1021
+
1022
+ def exec_distclean
1023
+ rm_f ConfigTable.savefile
1024
+ run_hook 'pre-distclean'
1025
+ each_selected_installers {|inst| inst.exec_distclean }
1026
+ run_hook 'post-distclean'
1027
+ end
1028
+
1029
+ #
1030
+ # lib
1031
+ #
1032
+
1033
+ def each_selected_installers
1034
+ Dir.mkdir 'packages' unless File.dir?('packages')
1035
+ @selected.each do |pack|
1036
+ $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose']
1037
+ Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
1038
+ Dir.chdir "packages/#{pack}"
1039
+ yield @installers[pack]
1040
+ Dir.chdir '../..'
1041
+ end
1042
+ end
1043
+
1044
+ def verbose?
1045
+ @options['verbose']
1046
+ end
1047
+
1048
+ def no_harm?
1049
+ @options['no-harm']
1050
+ end
1051
+
1052
+ end
1053
+
1054
+
1055
+ class Installer
1056
+
1057
+ FILETYPES = %w( bin lib ext data )
1058
+
1059
+ include HookScriptAPI
1060
+ include HookUtils
1061
+ include FileOperations
1062
+
1063
+ def initialize(config, opt, srcroot, objroot)
1064
+ @config = config
1065
+ @options = opt
1066
+ @srcdir = File.expand_path(srcroot)
1067
+ @objdir = File.expand_path(objroot)
1068
+ @currdir = '.'
1069
+ end
1070
+
1071
+ def inspect
1072
+ "#<#{self.class} #{File.basename(@srcdir)}>"
1073
+ end
1074
+
1075
+ #
1076
+ # Hook Script API base methods
1077
+ #
1078
+
1079
+ def srcdir_root
1080
+ @srcdir
1081
+ end
1082
+
1083
+ def objdir_root
1084
+ @objdir
1085
+ end
1086
+
1087
+ def relpath
1088
+ @currdir
1089
+ end
1090
+
1091
+ #
1092
+ # configs/options
1093
+ #
1094
+
1095
+ def no_harm?
1096
+ @options['no-harm']
1097
+ end
1098
+
1099
+ def verbose?
1100
+ @options['verbose']
1101
+ end
1102
+
1103
+ def verbose_off
1104
+ begin
1105
+ save, @options['verbose'] = @options['verbose'], false
1106
+ yield
1107
+ ensure
1108
+ @options['verbose'] = save
1109
+ end
1110
+ end
1111
+
1112
+ #
1113
+ # TASK config
1114
+ #
1115
+
1116
+ def exec_config
1117
+ exec_task_traverse 'config'
1118
+ end
1119
+
1120
+ def config_dir_bin(rel)
1121
+ end
1122
+
1123
+ def config_dir_lib(rel)
1124
+ end
1125
+
1126
+ def config_dir_ext(rel)
1127
+ extconf if extdir?(curr_srcdir())
1128
+ end
1129
+
1130
+ def extconf
1131
+ opt = @options['config-opt'].join(' ')
1132
+ command "#{config('rubyprog')} #{curr_srcdir()}/extconf.rb #{opt}"
1133
+ end
1134
+
1135
+ def config_dir_data(rel)
1136
+ end
1137
+
1138
+ #
1139
+ # TASK setup
1140
+ #
1141
+
1142
+ def exec_setup
1143
+ exec_task_traverse 'setup'
1144
+ end
1145
+
1146
+ def setup_dir_bin(rel)
1147
+ all_files_in(curr_srcdir()).each do |fname|
1148
+ adjust_shebang "#{curr_srcdir()}/#{fname}"
1149
+ end
1150
+ end
1151
+
1152
+ def adjust_shebang(path)
1153
+ return if no_harm?
1154
+ tmpfile = File.basename(path) + '.tmp'
1155
+ begin
1156
+ File.open(path, 'rb') {|r|
1157
+ first = r.gets
1158
+ return unless File.basename(config('rubypath')) == 'ruby'
1159
+ return unless File.basename(first.sub(/\A\#!/, '').split[0]) == 'ruby'
1160
+ $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose?
1161
+ File.open(tmpfile, 'wb') {|w|
1162
+ w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath'))
1163
+ w.write r.read
1164
+ }
1165
+ move_file tmpfile, File.basename(path)
1166
+ }
1167
+ ensure
1168
+ File.unlink tmpfile if File.exist?(tmpfile)
1169
+ end
1170
+ end
1171
+
1172
+ def setup_dir_lib(rel)
1173
+ end
1174
+
1175
+ def setup_dir_ext(rel)
1176
+ make if extdir?(curr_srcdir())
1177
+ end
1178
+
1179
+ def setup_dir_data(rel)
1180
+ end
1181
+
1182
+ #
1183
+ # TASK install
1184
+ #
1185
+
1186
+ def exec_install
1187
+ rm_f 'InstalledFiles'
1188
+ exec_task_traverse 'install'
1189
+ end
1190
+
1191
+ def install_dir_bin(rel)
1192
+ install_files collect_filenames_auto(), "#{config('bindir')}/#{rel}", 0755
1193
+ end
1194
+
1195
+ def install_dir_lib(rel)
1196
+ install_files ruby_scripts(), "#{config('rbdir')}/#{rel}", 0644
1197
+ end
1198
+
1199
+ def install_dir_ext(rel)
1200
+ return unless extdir?(curr_srcdir())
1201
+ install_files ruby_extentions('.'),
1202
+ "#{config('sodir')}/#{File.dirname(rel)}",
1203
+ 0555
1204
+ end
1205
+
1206
+ def install_dir_data(rel)
1207
+ install_files collect_filenames_auto(), "#{config('datadir')}/#{rel}", 0644
1208
+ end
1209
+
1210
+ def install_files(list, dest, mode)
1211
+ mkdir_p dest, @options['install-prefix']
1212
+ list.each do |fname|
1213
+ install fname, dest, mode, @options['install-prefix']
1214
+ end
1215
+ end
1216
+
1217
+ def ruby_scripts
1218
+ collect_filenames_auto().select {|n| /\.rb\z/ =~ n }
1219
+ end
1220
+
1221
+ # picked up many entries from cvs-1.11.1/src/ignore.c
1222
+ reject_patterns = %w(
1223
+ core RCSLOG tags TAGS .make.state
1224
+ .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1225
+ *~ *.old *.bak *.BAK *.orig *.rej _$* *$
1226
+
1227
+ *.org *.in .*
1228
+ )
1229
+ mapping = {
1230
+ '.' => '\.',
1231
+ '$' => '\$',
1232
+ '#' => '\#',
1233
+ '*' => '.*'
1234
+ }
1235
+ REJECT_PATTERNS = Regexp.new('\A(?:' +
1236
+ reject_patterns.map {|pat|
1237
+ pat.gsub(/[\.\$\#\*]/) {|ch| mapping[ch] }
1238
+ }.join('|') +
1239
+ ')\z')
1240
+
1241
+ def collect_filenames_auto
1242
+ mapdir((existfiles() - hookfiles()).reject {|fname|
1243
+ REJECT_PATTERNS =~ fname
1244
+ })
1245
+ end
1246
+
1247
+ def existfiles
1248
+ all_files_in(curr_srcdir()) | all_files_in('.')
1249
+ end
1250
+
1251
+ def hookfiles
1252
+ %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
1253
+ %w( config setup install clean ).map {|t| sprintf(fmt, t) }
1254
+ }.flatten
1255
+ end
1256
+
1257
+ def mapdir(filelist)
1258
+ filelist.map {|fname|
1259
+ if File.exist?(fname) # objdir
1260
+ fname
1261
+ else # srcdir
1262
+ File.join(curr_srcdir(), fname)
1263
+ end
1264
+ }
1265
+ end
1266
+
1267
+ def ruby_extentions(dir)
1268
+ Dir.open(dir) {|d|
1269
+ ents = d.select {|fname| /\.#{::Config::CONFIG['DLEXT']}\z/ =~ fname }
1270
+ if ents.empty?
1271
+ setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
1272
+ end
1273
+ return ents
1274
+ }
1275
+ end
1276
+
1277
+ #
1278
+ # TASK clean
1279
+ #
1280
+
1281
+ def exec_clean
1282
+ exec_task_traverse 'clean'
1283
+ rm_f ConfigTable.savefile
1284
+ rm_f 'InstalledFiles'
1285
+ end
1286
+
1287
+ def clean_dir_bin(rel)
1288
+ end
1289
+
1290
+ def clean_dir_lib(rel)
1291
+ end
1292
+
1293
+ def clean_dir_ext(rel)
1294
+ return unless extdir?(curr_srcdir())
1295
+ make 'clean' if File.file?('Makefile')
1296
+ end
1297
+
1298
+ def clean_dir_data(rel)
1299
+ end
1300
+
1301
+ #
1302
+ # TASK distclean
1303
+ #
1304
+
1305
+ def exec_distclean
1306
+ exec_task_traverse 'distclean'
1307
+ rm_f ConfigTable.savefile
1308
+ rm_f 'InstalledFiles'
1309
+ end
1310
+
1311
+ def distclean_dir_bin(rel)
1312
+ end
1313
+
1314
+ def distclean_dir_lib(rel)
1315
+ end
1316
+
1317
+ def distclean_dir_ext(rel)
1318
+ return unless extdir?(curr_srcdir())
1319
+ make 'distclean' if File.file?('Makefile')
1320
+ end
1321
+
1322
+ #
1323
+ # lib
1324
+ #
1325
+
1326
+ def exec_task_traverse(task)
1327
+ run_hook "pre-#{task}"
1328
+ FILETYPES.each do |type|
1329
+ if config('without-ext') == 'yes' and type == 'ext'
1330
+ $stderr.puts 'skipping ext/* by user option' if verbose?
1331
+ next
1332
+ end
1333
+ traverse task, type, "#{task}_dir_#{type}"
1334
+ end
1335
+ run_hook "post-#{task}"
1336
+ end
1337
+
1338
+ def traverse(task, rel, mid)
1339
+ dive_into(rel) {
1340
+ run_hook "pre-#{task}"
1341
+ __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
1342
+ all_dirs_in(curr_srcdir()).each do |d|
1343
+ traverse task, "#{rel}/#{d}", mid
1344
+ end
1345
+ run_hook "post-#{task}"
1346
+ }
1347
+ end
1348
+
1349
+ def dive_into(rel)
1350
+ return unless File.dir?("#{@srcdir}/#{rel}")
1351
+
1352
+ dir = File.basename(rel)
1353
+ Dir.mkdir dir unless File.dir?(dir)
1354
+ prevdir = Dir.pwd
1355
+ Dir.chdir dir
1356
+ $stderr.puts '---> ' + rel if verbose?
1357
+ @currdir = rel
1358
+ yield
1359
+ Dir.chdir prevdir
1360
+ $stderr.puts '<--- ' + rel if verbose?
1361
+ @currdir = File.dirname(rel)
1362
+ end
1363
+
1364
+ end
1365
+
1366
+
1367
+ if $0 == __FILE__
1368
+ begin
1369
+ if multipackage_install?
1370
+ ToplevelInstallerMulti.invoke
1371
+ else
1372
+ ToplevelInstaller.invoke
1373
+ end
1374
+ rescue SetupError
1375
+ raise if $DEBUG
1376
+ $stderr.puts $!.message
1377
+ $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
1378
+ exit 1
1379
+ end
1380
+ end