rubyjedi-actionwebservice 2.3.5.20100615120735

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