axtro-actionwebservice 2.3.5.1.20101118142125

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.
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