reap 6.0.0 → 6.0.1

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.
@@ -0,0 +1,1558 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # setup.rb
5
+ #
6
+ # Copyright (c) 2000-2005 Minero Aoki
7
+ #
8
+ # This program is free software.
9
+ # You can distribute/modify this program under the terms of
10
+ # the GNU LGPL, Lesser General Public License version 2.1.
11
+ #
12
+
13
+ unless Enumerable.method_defined?(:map) # Ruby 1.4.6
14
+ module Enumerable
15
+ alias map collect
16
+ end
17
+ end
18
+
19
+ unless File.respond_to?(:read) # Ruby 1.6
20
+ def File.read(fname)
21
+ open(fname) {|f|
22
+ return f.read
23
+ }
24
+ end
25
+ end
26
+
27
+ unless Errno.const_defined?(:ENOTEMPTY) # Windows?
28
+ module Errno
29
+ class ENOTEMPTY
30
+ # We do not raise this exception, implementation is not needed.
31
+ end
32
+ end
33
+ end
34
+
35
+ def File.binread(fname)
36
+ open(fname, 'rb') {|f|
37
+ return f.read
38
+ }
39
+ end
40
+
41
+ # for corrupted Windows' stat(2)
42
+ def File.dir?(path)
43
+ File.directory?((path[-1,1] == '/') ? path : path + '/')
44
+ end
45
+
46
+
47
+ class ConfigTable
48
+
49
+ include Enumerable
50
+
51
+ def initialize(rbconfig)
52
+ @rbconfig = rbconfig
53
+ @items = []
54
+ @table = {}
55
+ # options
56
+ @install_prefix = nil
57
+ @config_opt = nil
58
+ @verbose = true
59
+ @no_harm = false
60
+ @libsrc_pattern = '*.rb' # THIS IS NOT GOOD!!!
61
+ end
62
+
63
+ attr_accessor :install_prefix
64
+ attr_accessor :config_opt
65
+
66
+ attr_writer :verbose
67
+
68
+ def verbose?
69
+ @verbose
70
+ end
71
+
72
+ attr_writer :no_harm
73
+
74
+ def no_harm?
75
+ @no_harm
76
+ end
77
+
78
+ attr_accessor :libsrc_pattern
79
+
80
+ def [](key)
81
+ lookup(key).resolve(self)
82
+ end
83
+
84
+ def []=(key, val)
85
+ lookup(key).set val
86
+ end
87
+
88
+ def names
89
+ @items.map {|i| i.name }
90
+ end
91
+
92
+ def each(&block)
93
+ @items.each(&block)
94
+ end
95
+
96
+ def key?(name)
97
+ @table.key?(name)
98
+ end
99
+
100
+ def lookup(name)
101
+ @table[name] or setup_rb_error "no such config item: #{name}"
102
+ end
103
+
104
+ def add(item)
105
+ @items.push item
106
+ @table[item.name] = item
107
+ end
108
+
109
+ def remove(name)
110
+ item = lookup(name)
111
+ @items.delete_if {|i| i.name == name }
112
+ @table.delete_if {|name, i| i.name == name }
113
+ item
114
+ end
115
+
116
+ def load_script(path, inst = nil)
117
+ if File.file?(path)
118
+ MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
119
+ end
120
+ end
121
+
122
+ def savefile
123
+ '.config'
124
+ end
125
+
126
+ def load_savefile
127
+ begin
128
+ File.foreach(savefile()) do |line|
129
+ k, v = *line.split(/=/, 2)
130
+ self[k] = v.strip
131
+ end
132
+ rescue Errno::ENOENT
133
+ setup_rb_error $!.message + "\n#{File.basename($0)} config first"
134
+ end
135
+ end
136
+
137
+ def save
138
+ @items.each {|i| i.value }
139
+ File.open(savefile(), 'w') {|f|
140
+ @items.each do |i|
141
+ f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
142
+ end
143
+ }
144
+ end
145
+
146
+ def load_standard_entries
147
+ standard_entries(@rbconfig).each do |ent|
148
+ add ent
149
+ end
150
+ end
151
+
152
+ def standard_entries(rbconfig)
153
+ c = rbconfig
154
+
155
+ rubypath = c['bindir'] + '/' + c['ruby_install_name']
156
+
157
+ major = c['MAJOR'].to_i
158
+ minor = c['MINOR'].to_i
159
+ teeny = c['TEENY'].to_i
160
+ version = "#{major}.#{minor}"
161
+
162
+ # ruby ver. >= 1.4.4?
163
+ newpath_p = ((major >= 2) or
164
+ ((major == 1) and
165
+ ((minor >= 5) or
166
+ ((minor == 4) and (teeny >= 4)))))
167
+
168
+ if c['rubylibdir']
169
+ # V > 1.6.3
170
+ libruby = "#{c['prefix']}/lib/ruby"
171
+ librubyver = c['rubylibdir']
172
+ librubyverarch = c['archdir']
173
+ siteruby = c['sitedir']
174
+ siterubyver = c['sitelibdir']
175
+ siterubyverarch = c['sitearchdir']
176
+ elsif newpath_p
177
+ # 1.4.4 <= V <= 1.6.3
178
+ libruby = "#{c['prefix']}/lib/ruby"
179
+ librubyver = "#{c['prefix']}/lib/ruby/#{version}"
180
+ librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
181
+ siteruby = c['sitedir']
182
+ siterubyver = "$siteruby/#{version}"
183
+ siterubyverarch = "$siterubyver/#{c['arch']}"
184
+ else
185
+ # V < 1.4.4
186
+ libruby = "#{c['prefix']}/lib/ruby"
187
+ librubyver = "#{c['prefix']}/lib/ruby/#{version}"
188
+ librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
189
+ siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
190
+ siterubyver = siteruby
191
+ siterubyverarch = "$siterubyver/#{c['arch']}"
192
+ end
193
+ parameterize = lambda {|path|
194
+ path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
195
+ }
196
+
197
+ if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
198
+ makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
199
+ else
200
+ makeprog = 'make'
201
+ end
202
+
203
+ [
204
+ ExecItem.new('installdirs', 'std/site/home',
205
+ 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
206
+ {|val, table|
207
+ case val
208
+ when 'std'
209
+ table['rbdir'] = '$librubyver'
210
+ table['sodir'] = '$librubyverarch'
211
+ when 'site'
212
+ table['rbdir'] = '$siterubyver'
213
+ table['sodir'] = '$siterubyverarch'
214
+ when 'home'
215
+ setup_rb_error '$HOME was not set' unless ENV['HOME']
216
+ table['prefix'] = ENV['HOME']
217
+ table['rbdir'] = '$libdir/ruby'
218
+ table['sodir'] = '$libdir/ruby'
219
+ end
220
+ },
221
+ PathItem.new('prefix', 'path', c['prefix'],
222
+ 'path prefix of target environment'),
223
+ PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
224
+ 'the directory for commands'),
225
+ PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
226
+ 'the directory for libraries'),
227
+ PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
228
+ 'the directory for shared data'),
229
+ PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
230
+ 'the directory for man pages'),
231
+ PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
232
+ 'the directory for system configuration files'),
233
+ PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
234
+ 'the directory for local state data'),
235
+ PathItem.new('libruby', 'path', libruby,
236
+ 'the directory for ruby libraries'),
237
+ PathItem.new('librubyver', 'path', librubyver,
238
+ 'the directory for standard ruby libraries'),
239
+ PathItem.new('librubyverarch', 'path', librubyverarch,
240
+ 'the directory for standard ruby extensions'),
241
+ PathItem.new('siteruby', 'path', siteruby,
242
+ 'the directory for version-independent aux ruby libraries'),
243
+ PathItem.new('siterubyver', 'path', siterubyver,
244
+ 'the directory for aux ruby libraries'),
245
+ PathItem.new('siterubyverarch', 'path', siterubyverarch,
246
+ 'the directory for aux ruby binaries'),
247
+ PathItem.new('rbdir', 'path', '$siterubyver',
248
+ 'the directory for ruby scripts'),
249
+ PathItem.new('sodir', 'path', '$siterubyverarch',
250
+ 'the directory for ruby extentions'),
251
+ PathItem.new('rubypath', 'path', rubypath,
252
+ 'the path to set to #! line'),
253
+ ProgramItem.new('rubyprog', 'name', rubypath,
254
+ 'the ruby program using for installation'),
255
+ ProgramItem.new('makeprog', 'name', makeprog,
256
+ 'the make program to compile ruby extentions'),
257
+ SelectItem.new('shebang', 'all/ruby/never', 'ruby',
258
+ 'shebang line (#!) editing mode'),
259
+ BoolItem.new('without-ext', 'yes/no', 'no',
260
+ 'does not compile/install ruby extentions')
261
+ ]
262
+ end
263
+ private :standard_entries
264
+
265
+ def load_multipackage_entries
266
+ multipackage_entries().each do |ent|
267
+ add ent
268
+ end
269
+ end
270
+
271
+ def multipackage_entries
272
+ [
273
+ PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
274
+ 'package names that you want to install'),
275
+ PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
276
+ 'package names that you do not want to install')
277
+ ]
278
+ end
279
+ private :multipackage_entries
280
+
281
+ ALIASES = {
282
+ 'std-ruby' => 'librubyver',
283
+ 'stdruby' => 'librubyver',
284
+ 'rubylibdir' => 'librubyver',
285
+ 'archdir' => 'librubyverarch',
286
+ 'site-ruby-common' => 'siteruby', # For backward compatibility
287
+ 'site-ruby' => 'siterubyver', # For backward compatibility
288
+ 'bin-dir' => 'bindir',
289
+ 'bin-dir' => 'bindir',
290
+ 'rb-dir' => 'rbdir',
291
+ 'so-dir' => 'sodir',
292
+ 'data-dir' => 'datadir',
293
+ 'ruby-path' => 'rubypath',
294
+ 'ruby-prog' => 'rubyprog',
295
+ 'ruby' => 'rubyprog',
296
+ 'make-prog' => 'makeprog',
297
+ 'make' => 'makeprog'
298
+ }
299
+
300
+ def fixup
301
+ ALIASES.each do |ali, name|
302
+ @table[ali] = @table[name]
303
+ end
304
+ @items.freeze
305
+ @table.freeze
306
+ @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
307
+ end
308
+
309
+ def parse_opt(opt)
310
+ m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
311
+ m.to_a[1,2]
312
+ end
313
+
314
+ def dllext
315
+ @rbconfig['DLEXT']
316
+ end
317
+
318
+ def value_config?(name)
319
+ lookup(name).value?
320
+ end
321
+
322
+ class Item
323
+ def initialize(name, template, default, desc)
324
+ @name = name.freeze
325
+ @template = template
326
+ @value = default
327
+ @default = default
328
+ @description = desc
329
+ end
330
+
331
+ attr_reader :name
332
+ attr_reader :description
333
+
334
+ attr_accessor :default
335
+ alias help_default default
336
+
337
+ def help_opt
338
+ "--#{@name}=#{@template}"
339
+ end
340
+
341
+ def value?
342
+ true
343
+ end
344
+
345
+ def value
346
+ @value
347
+ end
348
+
349
+ def resolve(table)
350
+ @value.gsub(%r<\$([^/]+)>) { table[$1] }
351
+ end
352
+
353
+ def set(val)
354
+ @value = check(val)
355
+ end
356
+
357
+ private
358
+
359
+ def check(val)
360
+ setup_rb_error "config: --#{name} requires argument" unless val
361
+ val
362
+ end
363
+ end
364
+
365
+ class BoolItem < Item
366
+ def config_type
367
+ 'bool'
368
+ end
369
+
370
+ def help_opt
371
+ "--#{@name}"
372
+ end
373
+
374
+ private
375
+
376
+ def check(val)
377
+ return 'yes' unless val
378
+ unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val
379
+ setup_rb_error "config: --#{@name} accepts only yes/no for argument"
380
+ end
381
+ (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no'
382
+ end
383
+ end
384
+
385
+ class PathItem < Item
386
+ def config_type
387
+ 'path'
388
+ end
389
+
390
+ private
391
+
392
+ def check(path)
393
+ setup_rb_error "config: --#{@name} requires argument" unless path
394
+ path[0,1] == '$' ? path : File.expand_path(path)
395
+ end
396
+ end
397
+
398
+ class ProgramItem < Item
399
+ def config_type
400
+ 'program'
401
+ end
402
+ end
403
+
404
+ class SelectItem < Item
405
+ def initialize(name, selection, default, desc)
406
+ super
407
+ @ok = selection.split('/')
408
+ end
409
+
410
+ def config_type
411
+ 'select'
412
+ end
413
+
414
+ private
415
+
416
+ def check(val)
417
+ unless @ok.include?(val.strip)
418
+ setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
419
+ end
420
+ val.strip
421
+ end
422
+ end
423
+
424
+ class ExecItem < Item
425
+ def initialize(name, selection, desc, &block)
426
+ super name, selection, nil, desc
427
+ @ok = selection.split('/')
428
+ @action = block
429
+ end
430
+
431
+ def config_type
432
+ 'exec'
433
+ end
434
+
435
+ def value?
436
+ false
437
+ end
438
+
439
+ def resolve(table)
440
+ setup_rb_error "$#{name()} wrongly used as option value"
441
+ end
442
+
443
+ undef set
444
+
445
+ def evaluate(val, table)
446
+ v = val.strip.downcase
447
+ unless @ok.include?(v)
448
+ setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
449
+ end
450
+ @action.call v, table
451
+ end
452
+ end
453
+
454
+ class PackageSelectionItem < Item
455
+ def initialize(name, template, default, help_default, desc)
456
+ super name, template, default, desc
457
+ @help_default = help_default
458
+ end
459
+
460
+ attr_reader :help_default
461
+
462
+ def config_type
463
+ 'package'
464
+ end
465
+
466
+ private
467
+
468
+ def check(val)
469
+ unless File.dir?("packages/#{val}")
470
+ setup_rb_error "config: no such package: #{val}"
471
+ end
472
+ val
473
+ end
474
+ end
475
+
476
+ class MetaConfigEnvironment
477
+ def intiailize(config, installer)
478
+ @config = config
479
+ @installer = installer
480
+ end
481
+
482
+ def config_names
483
+ @config.names
484
+ end
485
+
486
+ def config?(name)
487
+ @config.key?(name)
488
+ end
489
+
490
+ def bool_config?(name)
491
+ @config.lookup(name).config_type == 'bool'
492
+ end
493
+
494
+ def path_config?(name)
495
+ @config.lookup(name).config_type == 'path'
496
+ end
497
+
498
+ def value_config?(name)
499
+ @config.lookup(name).config_type != 'exec'
500
+ end
501
+
502
+ def add_config(item)
503
+ @config.add item
504
+ end
505
+
506
+ def add_bool_config(name, default, desc)
507
+ @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
508
+ end
509
+
510
+ def add_path_config(name, default, desc)
511
+ @config.add PathItem.new(name, 'path', default, desc)
512
+ end
513
+
514
+ def set_config_default(name, default)
515
+ @config.lookup(name).default = default
516
+ end
517
+
518
+ def remove_config(name)
519
+ @config.remove(name)
520
+ end
521
+
522
+ # For only multipackage
523
+ def packages
524
+ raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
525
+ @installer.packages
526
+ end
527
+
528
+ # For only multipackage
529
+ def declare_packages(list)
530
+ raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
531
+ @installer.packages = list
532
+ end
533
+ end
534
+
535
+ end # class ConfigTable
536
+
537
+
538
+ # This module requires: #verbose?, #no_harm?
539
+ module FileOperations
540
+
541
+ def mkdir_p(dirname, prefix = nil)
542
+ dirname = prefix + File.expand_path(dirname) if prefix
543
+ $stderr.puts "mkdir -p #{dirname}" if verbose?
544
+ return if no_harm?
545
+
546
+ # Does not check '/', it's too abnormal.
547
+ dirs = File.expand_path(dirname).split(%r<(?=/)>)
548
+ if /\A[a-z]:\z/i =~ dirs[0]
549
+ disk = dirs.shift
550
+ dirs[0] = disk + dirs[0]
551
+ end
552
+ dirs.each_index do |idx|
553
+ path = dirs[0..idx].join('')
554
+ Dir.mkdir path unless File.dir?(path)
555
+ end
556
+ end
557
+
558
+ def rm_f(path)
559
+ $stderr.puts "rm -f #{path}" if verbose?
560
+ return if no_harm?
561
+ force_remove_file path
562
+ end
563
+
564
+ def rm_rf(path)
565
+ $stderr.puts "rm -rf #{path}" if verbose?
566
+ return if no_harm?
567
+ remove_tree path
568
+ end
569
+
570
+ def remove_tree(path)
571
+ if File.symlink?(path)
572
+ remove_file path
573
+ elsif File.dir?(path)
574
+ remove_tree0 path
575
+ else
576
+ force_remove_file path
577
+ end
578
+ end
579
+
580
+ def remove_tree0(path)
581
+ Dir.foreach(path) do |ent|
582
+ next if ent == '.'
583
+ next if ent == '..'
584
+ entpath = "#{path}/#{ent}"
585
+ if File.symlink?(entpath)
586
+ remove_file entpath
587
+ elsif File.dir?(entpath)
588
+ remove_tree0 entpath
589
+ else
590
+ force_remove_file entpath
591
+ end
592
+ end
593
+ begin
594
+ Dir.rmdir path
595
+ rescue Errno::ENOTEMPTY
596
+ # directory may not be empty
597
+ end
598
+ end
599
+
600
+ def move_file(src, dest)
601
+ force_remove_file dest
602
+ begin
603
+ File.rename src, dest
604
+ rescue
605
+ File.open(dest, 'wb') {|f|
606
+ f.write File.binread(src)
607
+ }
608
+ File.chmod File.stat(src).mode, dest
609
+ File.unlink src
610
+ end
611
+ end
612
+
613
+ def force_remove_file(path)
614
+ begin
615
+ remove_file path
616
+ rescue
617
+ end
618
+ end
619
+
620
+ def remove_file(path)
621
+ File.chmod 0777, path
622
+ File.unlink path
623
+ end
624
+
625
+ def install(from, dest, mode, prefix = nil)
626
+ $stderr.puts "install #{from} #{dest}" if verbose?
627
+ return if no_harm?
628
+
629
+ realdest = prefix ? prefix + File.expand_path(dest) : dest
630
+ realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
631
+ str = File.binread(from)
632
+ if diff?(str, realdest)
633
+ verbose_off {
634
+ rm_f realdest if File.exist?(realdest)
635
+ }
636
+ File.open(realdest, 'wb') {|f|
637
+ f.write str
638
+ }
639
+ File.chmod mode, realdest
640
+ # 0777
641
+ File.open("#{objdir_root()}/InstalledFiles", 'a', 0777) {|f|
642
+ if prefix
643
+ f.puts realdest.sub(prefix, '')
644
+ else
645
+ f.puts realdest
646
+ end
647
+ }
648
+ end
649
+ end
650
+
651
+ def diff?(new_content, path)
652
+ return true unless File.exist?(path)
653
+ new_content != File.binread(path)
654
+ end
655
+
656
+ def command(*args)
657
+ $stderr.puts args.join(' ') if verbose?
658
+ system(*args) or raise RuntimeError,
659
+ "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
660
+ end
661
+
662
+ def ruby(*args)
663
+ command config('rubyprog'), *args
664
+ end
665
+
666
+ def make(task = nil)
667
+ command(*[config('makeprog'), task].compact)
668
+ end
669
+
670
+ def extdir?(dir)
671
+ File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
672
+ end
673
+
674
+ def files_of(dir)
675
+ Dir.open(dir) {|d|
676
+ return d.select {|ent| File.file?("#{dir}/#{ent}") }
677
+ }
678
+ end
679
+
680
+ DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
681
+
682
+ def directories_of(dir)
683
+ Dir.open(dir) {|d|
684
+ return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
685
+ }
686
+ end
687
+
688
+ end
689
+
690
+
691
+ # This module requires: #srcdir_root, #objdir_root, #relpath
692
+ module HookScriptAPI
693
+
694
+ def get_config(key)
695
+ @config[key]
696
+ end
697
+
698
+ alias config get_config
699
+
700
+ # obsolete: use metaconfig to change configuration
701
+ def set_config(key, val)
702
+ @config[key] = val
703
+ end
704
+
705
+ #
706
+ # srcdir/objdir (works only in the package directory)
707
+ #
708
+
709
+ def curr_srcdir
710
+ "#{srcdir_root()}/#{relpath()}"
711
+ end
712
+
713
+ def curr_objdir
714
+ "#{objdir_root()}/#{relpath()}"
715
+ end
716
+
717
+ def srcfile(path)
718
+ "#{curr_srcdir()}/#{path}"
719
+ end
720
+
721
+ def srcexist?(path)
722
+ File.exist?(srcfile(path))
723
+ end
724
+
725
+ def srcdirectory?(path)
726
+ File.dir?(srcfile(path))
727
+ end
728
+
729
+ def srcfile?(path)
730
+ File.file?(srcfile(path))
731
+ end
732
+
733
+ def srcentries(path = '.')
734
+ Dir.open("#{curr_srcdir()}/#{path}") {|d|
735
+ return d.to_a - %w(. ..)
736
+ }
737
+ end
738
+
739
+ def srcfiles(path = '.')
740
+ srcentries(path).select {|fname|
741
+ File.file?(File.join(curr_srcdir(), path, fname))
742
+ }
743
+ end
744
+
745
+ def srcdirectories(path = '.')
746
+ srcentries(path).select {|fname|
747
+ File.dir?(File.join(curr_srcdir(), path, fname))
748
+ }
749
+ end
750
+
751
+ end
752
+
753
+
754
+ class ToplevelInstaller
755
+
756
+ Version = '3.4.0'
757
+ Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
758
+
759
+ TASKS = [
760
+ [ 'all', 'do config, setup, then install' ],
761
+ [ 'config', 'saves your configurations' ],
762
+ [ 'show', 'shows current configuration' ],
763
+ [ 'setup', 'compiles ruby extentions and others' ],
764
+ [ 'install', 'installs files' ],
765
+ [ 'test', 'run all tests in test/' ],
766
+ [ 'clean', "does `make clean' for each extention" ],
767
+ [ 'distclean',"does `make distclean' for each extention" ]
768
+ ]
769
+
770
+ def ToplevelInstaller.invoke
771
+ config = ConfigTable.new(load_rbconfig())
772
+ config.load_standard_entries
773
+ config.load_multipackage_entries if multipackage?
774
+ config.fixup
775
+ klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
776
+ #klass.new(File.dirname($setup_pwd), config).invoke
777
+ klass.new($setup_pwd, config).invoke
778
+ end
779
+
780
+ def ToplevelInstaller.multipackage?
781
+ #File.dir?(File.dirname($setup_pwd) + '/packages')
782
+ File.dir?($setup_pwd + '/packages')
783
+ end
784
+
785
+ def ToplevelInstaller.load_rbconfig
786
+ if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
787
+ ARGV.delete(arg)
788
+ load File.expand_path(arg.split(/=/, 2)[1])
789
+ $".push 'rbconfig.rb'
790
+ else
791
+ require 'rbconfig'
792
+ end
793
+ ::Config::CONFIG
794
+ end
795
+
796
+ def initialize(ardir_root, config)
797
+ @ardir = File.expand_path(ardir_root)
798
+ @config = config
799
+ # cache
800
+ @valid_task_re = nil
801
+ end
802
+
803
+ def config(key)
804
+ @config[key]
805
+ end
806
+
807
+ def inspect
808
+ "#<#{self.class} #{__id__()}>"
809
+ end
810
+
811
+ def invoke
812
+ run_metaconfigs
813
+ case task = parsearg_global()
814
+ when nil, 'all'
815
+ parsearg_config
816
+ init_installers
817
+ exec_config
818
+ exec_setup
819
+ exec_install
820
+ else
821
+ case task
822
+ when 'config', 'test'
823
+ ;
824
+ when 'clean', 'distclean'
825
+ @config.load_savefile if File.exist?(@config.savefile)
826
+ else
827
+ @config.load_savefile
828
+ end
829
+ __send__ "parsearg_#{task}"
830
+ init_installers
831
+ __send__ "exec_#{task}"
832
+ end
833
+ end
834
+
835
+ def run_metaconfigs
836
+ @config.load_script "#{@ardir}/metaconfig"
837
+ end
838
+
839
+ def init_installers
840
+ @installer = Installer.new(@config, @ardir, File.expand_path('.'))
841
+ end
842
+
843
+ #
844
+ # Hook Script API bases
845
+ #
846
+
847
+ def srcdir_root
848
+ @ardir
849
+ end
850
+
851
+ def objdir_root
852
+ '.'
853
+ end
854
+
855
+ def relpath
856
+ '.'
857
+ end
858
+
859
+ #
860
+ # Option Parsing
861
+ #
862
+
863
+ def parsearg_global
864
+ while arg = ARGV.shift
865
+ case arg
866
+ when /\A\w+\z/
867
+ setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
868
+ return arg
869
+ when '-q', '--quiet'
870
+ @config.verbose = false
871
+ when '--verbose'
872
+ @config.verbose = true
873
+ when '--help'
874
+ print_usage $stdout
875
+ exit 0
876
+ #when '--version'
877
+ # puts "#{File.basename($setup_pwd)} version #{Version}"
878
+ # exit 0
879
+ when '--copyright'
880
+ puts Copyright
881
+ exit 0
882
+ else
883
+ setup_rb_error "unknown global option '#{arg}'"
884
+ end
885
+ end
886
+ nil
887
+ end
888
+
889
+ def valid_task?(t)
890
+ valid_task_re() =~ t
891
+ end
892
+
893
+ def valid_task_re
894
+ @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
895
+ end
896
+
897
+ def parsearg_no_options
898
+ unless ARGV.empty?
899
+ setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
900
+ end
901
+ end
902
+
903
+ alias parsearg_show parsearg_no_options
904
+ alias parsearg_setup parsearg_no_options
905
+ alias parsearg_test parsearg_no_options
906
+ alias parsearg_clean parsearg_no_options
907
+ alias parsearg_distclean parsearg_no_options
908
+
909
+ def parsearg_config
910
+ evalopt = []
911
+ set = []
912
+ @config.config_opt = []
913
+ while i = ARGV.shift
914
+ if /\A--?\z/ =~ i
915
+ @config.config_opt = ARGV.dup
916
+ break
917
+ end
918
+ name, value = *@config.parse_opt(i)
919
+ if @config.value_config?(name)
920
+ @config[name] = value
921
+ else
922
+ evalopt.push [name, value]
923
+ end
924
+ set.push name
925
+ end
926
+ evalopt.each do |name, value|
927
+ @config.lookup(name).evaluate value, @config
928
+ end
929
+ # Check if configuration is valid
930
+ set.each do |n|
931
+ @config[n] if @config.value_config?(n)
932
+ end
933
+ end
934
+
935
+ def parsearg_install
936
+ @config.no_harm = false
937
+ @config.install_prefix = ''
938
+ while a = ARGV.shift
939
+ case a
940
+ when '--no-harm'
941
+ @config.no_harm = true
942
+ when /\A--prefix=/
943
+ path = a.split(/=/, 2)[1]
944
+ path = File.expand_path(path) unless path[0,1] == '/'
945
+ @config.install_prefix = path
946
+ else
947
+ setup_rb_error "install: unknown option #{a}"
948
+ end
949
+ end
950
+ end
951
+
952
+ def print_usage(out)
953
+ out.puts 'Typical Installation Procedure:'
954
+ out.puts " $ ruby #{File.basename $0} config"
955
+ out.puts " $ ruby #{File.basename $0} setup"
956
+ out.puts " # ruby #{File.basename $0} install (may require root privilege)"
957
+ out.puts
958
+ out.puts 'Detailed Usage:'
959
+ out.puts " ruby #{File.basename $0} <global option>"
960
+ out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
961
+
962
+ fmt = " %-24s %s\n"
963
+ out.puts
964
+ out.puts 'Global options:'
965
+ out.printf fmt, '-q,--quiet', 'suppress message outputs'
966
+ out.printf fmt, ' --verbose', 'output messages verbosely'
967
+ out.printf fmt, ' --help', 'print this message'
968
+ out.printf fmt, ' --version', 'print version and quit'
969
+ out.printf fmt, ' --copyright', 'print copyright and quit'
970
+ out.puts
971
+ out.puts 'Tasks:'
972
+ TASKS.each do |name, desc|
973
+ out.printf fmt, name, desc
974
+ end
975
+
976
+ fmt = " %-24s %s [%s]\n"
977
+ out.puts
978
+ out.puts 'Options for CONFIG or ALL:'
979
+ @config.each do |item|
980
+ out.printf fmt, item.help_opt, item.description, item.help_default
981
+ end
982
+ out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
983
+ out.puts
984
+ out.puts 'Options for INSTALL:'
985
+ out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
986
+ out.printf fmt, '--prefix=path', 'install path prefix', ''
987
+ out.puts
988
+ end
989
+
990
+ #
991
+ # Task Handlers
992
+ #
993
+
994
+ def exec_config
995
+ @installer.exec_config
996
+ @config.save # must be final
997
+ end
998
+
999
+ def exec_setup
1000
+ @installer.exec_setup
1001
+ end
1002
+
1003
+ def exec_install
1004
+ @installer.exec_install
1005
+ end
1006
+
1007
+ def exec_test
1008
+ @installer.exec_test
1009
+ end
1010
+
1011
+ def exec_show
1012
+ @config.each do |i|
1013
+ printf "%-20s %s\n", i.name, i.value if i.value?
1014
+ end
1015
+ end
1016
+
1017
+ def exec_clean
1018
+ @installer.exec_clean
1019
+ end
1020
+
1021
+ def exec_distclean
1022
+ @installer.exec_distclean
1023
+ end
1024
+
1025
+ end # class ToplevelInstaller
1026
+
1027
+
1028
+ class ToplevelInstallerMulti < ToplevelInstaller
1029
+
1030
+ include FileOperations
1031
+
1032
+ def initialize(ardir_root, config)
1033
+ super
1034
+ @packages = directories_of("#{@ardir}/packages")
1035
+ raise 'no package exists' if @packages.empty?
1036
+ @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
1037
+ end
1038
+
1039
+ def run_metaconfigs
1040
+ @config.load_script "#{@ardir}/metaconfig", self
1041
+ @packages.each do |name|
1042
+ @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
1043
+ end
1044
+ end
1045
+
1046
+ attr_reader :packages
1047
+
1048
+ def packages=(list)
1049
+ raise 'package list is empty' if list.empty?
1050
+ list.each do |name|
1051
+ raise "directory packages/#{name} does not exist"\
1052
+ unless File.dir?("#{@ardir}/packages/#{name}")
1053
+ end
1054
+ @packages = list
1055
+ end
1056
+
1057
+ def init_installers
1058
+ @installers = {}
1059
+ @packages.each do |pack|
1060
+ @installers[pack] = Installer.new(@config,
1061
+ "#{@ardir}/packages/#{pack}",
1062
+ "packages/#{pack}")
1063
+ end
1064
+ with = extract_selection(config('with'))
1065
+ without = extract_selection(config('without'))
1066
+ @selected = @installers.keys.select {|name|
1067
+ (with.empty? or with.include?(name)) \
1068
+ and not without.include?(name)
1069
+ }
1070
+ end
1071
+
1072
+ def extract_selection(list)
1073
+ a = list.split(/,/)
1074
+ a.each do |name|
1075
+ setup_rb_error "no such package: #{name}" unless @installers.key?(name)
1076
+ end
1077
+ a
1078
+ end
1079
+
1080
+ def print_usage(f)
1081
+ super
1082
+ f.puts 'Inluded packages:'
1083
+ f.puts ' ' + @packages.sort.join(' ')
1084
+ f.puts
1085
+ end
1086
+
1087
+ #
1088
+ # Task Handlers
1089
+ #
1090
+
1091
+ def exec_config
1092
+ run_hook 'pre-config'
1093
+ each_selected_installers {|inst| inst.exec_config }
1094
+ run_hook 'post-config'
1095
+ @config.save # must be final
1096
+ end
1097
+
1098
+ def exec_setup
1099
+ run_hook 'pre-setup'
1100
+ each_selected_installers {|inst| inst.exec_setup }
1101
+ run_hook 'post-setup'
1102
+ end
1103
+
1104
+ def exec_install
1105
+ run_hook 'pre-install'
1106
+ each_selected_installers {|inst| inst.exec_install }
1107
+ run_hook 'post-install'
1108
+ end
1109
+
1110
+ def exec_test
1111
+ run_hook 'pre-test'
1112
+ each_selected_installers {|inst| inst.exec_test }
1113
+ run_hook 'post-test'
1114
+ end
1115
+
1116
+ def exec_clean
1117
+ rm_f @config.savefile
1118
+ run_hook 'pre-clean'
1119
+ each_selected_installers {|inst| inst.exec_clean }
1120
+ run_hook 'post-clean'
1121
+ end
1122
+
1123
+ def exec_distclean
1124
+ rm_f @config.savefile
1125
+ run_hook 'pre-distclean'
1126
+ each_selected_installers {|inst| inst.exec_distclean }
1127
+ run_hook 'post-distclean'
1128
+ end
1129
+
1130
+ #
1131
+ # lib
1132
+ #
1133
+
1134
+ def each_selected_installers
1135
+ Dir.mkdir 'packages' unless File.dir?('packages')
1136
+ @selected.each do |pack|
1137
+ $stderr.puts "Processing the package `#{pack}' ..." if verbose?
1138
+ Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
1139
+ Dir.chdir "packages/#{pack}"
1140
+ yield @installers[pack]
1141
+ Dir.chdir '../..'
1142
+ end
1143
+ end
1144
+
1145
+ def run_hook(id)
1146
+ @root_installer.run_hook id
1147
+ end
1148
+
1149
+ # module FileOperations requires this
1150
+ def verbose?
1151
+ @config.verbose?
1152
+ end
1153
+
1154
+ # module FileOperations requires this
1155
+ def no_harm?
1156
+ @config.no_harm?
1157
+ end
1158
+
1159
+ end # class ToplevelInstallerMulti
1160
+
1161
+
1162
+ class Installer
1163
+
1164
+ FILETYPES = %w( bin lib ext data conf man )
1165
+
1166
+ include FileOperations
1167
+ include HookScriptAPI
1168
+
1169
+ def initialize(config, srcroot, objroot)
1170
+ @config = config
1171
+ @srcdir = File.expand_path(srcroot)
1172
+ @objdir = File.expand_path(objroot)
1173
+ @currdir = '.'
1174
+ end
1175
+
1176
+ def inspect
1177
+ "#<#{self.class} #{File.basename(@srcdir)}>"
1178
+ end
1179
+
1180
+ #
1181
+ # Hook Script API base methods
1182
+ #
1183
+
1184
+ def srcdir_root
1185
+ @srcdir
1186
+ end
1187
+
1188
+ def objdir_root
1189
+ @objdir
1190
+ end
1191
+
1192
+ def relpath
1193
+ @currdir
1194
+ end
1195
+
1196
+ #
1197
+ # Config Access
1198
+ #
1199
+
1200
+ # module FileOperations requires this
1201
+ def verbose?
1202
+ @config.verbose?
1203
+ end
1204
+
1205
+ # module FileOperations requires this
1206
+ def no_harm?
1207
+ @config.no_harm?
1208
+ end
1209
+
1210
+ def verbose_off
1211
+ begin
1212
+ save, @config.verbose = @config.verbose?, false
1213
+ yield
1214
+ ensure
1215
+ @config.verbose = save
1216
+ end
1217
+ end
1218
+
1219
+ #
1220
+ # TASK config
1221
+ #
1222
+
1223
+ def exec_config
1224
+ exec_task_traverse 'config'
1225
+ end
1226
+
1227
+ def config_dir_bin(rel)
1228
+ end
1229
+
1230
+ def config_dir_lib(rel)
1231
+ end
1232
+
1233
+ def config_dir_man(rel)
1234
+ end
1235
+
1236
+ def config_dir_ext(rel)
1237
+ extconf if extdir?(curr_srcdir())
1238
+ end
1239
+
1240
+ def extconf
1241
+ ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
1242
+ end
1243
+
1244
+ def config_dir_data(rel)
1245
+ end
1246
+
1247
+ def config_dir_conf(rel)
1248
+ end
1249
+
1250
+ #
1251
+ # TASK setup
1252
+ #
1253
+
1254
+ def exec_setup
1255
+ exec_task_traverse 'setup'
1256
+ end
1257
+
1258
+ def setup_dir_bin(rel)
1259
+ files_of(curr_srcdir()).each do |fname|
1260
+ adjust_shebang "#{curr_srcdir()}/#{fname}"
1261
+ end
1262
+ end
1263
+
1264
+ def adjust_shebang(path)
1265
+ return if no_harm?
1266
+ tmpfile = File.basename(path) + '.tmp'
1267
+ begin
1268
+ File.open(path, 'rb') {|r|
1269
+ first = r.gets
1270
+ return unless File.basename(first.sub(/\A\#!/, '').split[0].to_s) == 'ruby'
1271
+ $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose?
1272
+ File.open(tmpfile, 'wb') {|w|
1273
+ w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath'))
1274
+ w.write r.read
1275
+ }
1276
+ }
1277
+ move_file tmpfile, File.basename(path)
1278
+ ensure
1279
+ File.unlink tmpfile if File.exist?(tmpfile)
1280
+ end
1281
+ end
1282
+
1283
+ def setup_dir_lib(rel)
1284
+ end
1285
+
1286
+ def setup_dir_man(rel)
1287
+ end
1288
+
1289
+ def setup_dir_ext(rel)
1290
+ make if extdir?(curr_srcdir())
1291
+ end
1292
+
1293
+ def setup_dir_data(rel)
1294
+ end
1295
+
1296
+ def setup_dir_conf(rel)
1297
+ end
1298
+
1299
+ #
1300
+ # TASK install
1301
+ #
1302
+
1303
+ def exec_install
1304
+ rm_f 'InstalledFiles'
1305
+ exec_task_traverse 'install'
1306
+ end
1307
+
1308
+ def install_dir_bin(rel)
1309
+ install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
1310
+ end
1311
+
1312
+ def install_dir_lib(rel)
1313
+ p rubyscripts(), "#{config('rbdir')}/#{rel}", 0644
1314
+ install_files rubyscripts(), "#{config('rbdir')}/#{rel}", 0644
1315
+ end
1316
+
1317
+ def install_dir_ext(rel)
1318
+ return unless extdir?(curr_srcdir())
1319
+ install_files rubyextentions('.'),
1320
+ "#{config('sodir')}/#{File.dirname(rel)}",
1321
+ 0555
1322
+ end
1323
+
1324
+ def install_dir_data(rel)
1325
+ install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
1326
+ end
1327
+
1328
+ def install_dir_conf(rel)
1329
+ # FIXME: should not remove current config files
1330
+ # (rename previous file to .old/.org)
1331
+ install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
1332
+ end
1333
+
1334
+ def install_dir_man(rel)
1335
+ install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
1336
+ end
1337
+
1338
+ def install_files(list, dest, mode)
1339
+ mkdir_p dest, @config.install_prefix
1340
+ list.each do |fname|
1341
+ install fname, dest, mode, @config.install_prefix
1342
+ end
1343
+ end
1344
+
1345
+ def rubyscripts
1346
+ glob_select(@config.libsrc_pattern, targetfiles())
1347
+ end
1348
+
1349
+ def rubyextentions(dir)
1350
+ ents = glob_select("*.#{@config.dllext}", targetfiles())
1351
+ if ents.empty?
1352
+ setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
1353
+ end
1354
+ ents
1355
+ end
1356
+
1357
+ def targetfiles
1358
+ mapdir(existfiles() - hookfiles())
1359
+ end
1360
+
1361
+ def mapdir(ents)
1362
+ ents.map {|ent|
1363
+ if File.exist?(ent)
1364
+ then ent # objdir
1365
+ else "#{curr_srcdir()}/#{ent}" # srcdir
1366
+ end
1367
+ }
1368
+ end
1369
+
1370
+ # picked up many entries from cvs-1.11.1/src/ignore.c
1371
+ JUNK_FILES = %w(
1372
+ core RCSLOG tags TAGS .make.state
1373
+ .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1374
+ *~ *.old *.bak *.BAK *.orig *.rej _$* *$
1375
+
1376
+ *.org *.in .*
1377
+ )
1378
+
1379
+ def existfiles
1380
+ glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
1381
+ end
1382
+
1383
+ def hookfiles
1384
+ %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
1385
+ %w( config setup install clean ).map {|t| sprintf(fmt, t) }
1386
+ }.flatten
1387
+ end
1388
+
1389
+ def glob_select(pat, ents)
1390
+ re = globs2re([pat])
1391
+ ents.select {|ent| re =~ ent }
1392
+ end
1393
+
1394
+ def glob_reject(pats, ents)
1395
+ re = globs2re(pats)
1396
+ ents.reject {|ent| re =~ ent }
1397
+ end
1398
+
1399
+ GLOB2REGEX = {
1400
+ '.' => '\.',
1401
+ '$' => '\$',
1402
+ '#' => '\#',
1403
+ '*' => '.*'
1404
+ }
1405
+
1406
+ def globs2re(pats)
1407
+ /\A(?:#{
1408
+ pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
1409
+ })\z/
1410
+ end
1411
+
1412
+ #
1413
+ # TASK test
1414
+ #
1415
+
1416
+ TESTDIR = 'test'
1417
+
1418
+ def exec_test
1419
+ unless File.directory?('test')
1420
+ $stderr.puts 'no test in this package' if verbose?
1421
+ return
1422
+ end
1423
+ $stderr.puts 'Running tests...' if verbose?
1424
+ require 'test/unit'
1425
+ runner = Test::Unit::AutoRunner.new(true)
1426
+ runner.to_run << TESTDIR
1427
+ runner.run
1428
+ end
1429
+
1430
+ #
1431
+ # TASK clean
1432
+ #
1433
+
1434
+ def exec_clean
1435
+ exec_task_traverse 'clean'
1436
+ rm_f @config.savefile
1437
+ rm_f 'InstalledFiles'
1438
+ end
1439
+
1440
+ def clean_dir_bin(rel)
1441
+ end
1442
+
1443
+ def clean_dir_lib(rel)
1444
+ end
1445
+
1446
+ def clean_dir_ext(rel)
1447
+ return unless extdir?(curr_srcdir())
1448
+ make 'clean' if File.file?('Makefile')
1449
+ end
1450
+
1451
+ def clean_dir_data(rel)
1452
+ end
1453
+
1454
+ def clean_dir_conf(rel)
1455
+ end
1456
+
1457
+ #
1458
+ # TASK distclean
1459
+ #
1460
+
1461
+ def exec_distclean
1462
+ exec_task_traverse 'distclean'
1463
+ rm_f @config.savefile
1464
+ rm_f 'InstalledFiles'
1465
+ end
1466
+
1467
+ def distclean_dir_bin(rel)
1468
+ end
1469
+
1470
+ def distclean_dir_lib(rel)
1471
+ end
1472
+
1473
+ def distclean_dir_ext(rel)
1474
+ return unless extdir?(curr_srcdir())
1475
+ make 'distclean' if File.file?('Makefile')
1476
+ end
1477
+
1478
+ def distclean_dir_data(rel)
1479
+ end
1480
+
1481
+ def distclean_dir_conf(rel)
1482
+ end
1483
+
1484
+ #
1485
+ # lib
1486
+ #
1487
+
1488
+ def exec_task_traverse(task)
1489
+ run_hook "pre-#{task}"
1490
+ FILETYPES.each do |type|
1491
+ if config('without-ext') == 'yes' and type == 'ext'
1492
+ $stderr.puts 'skipping ext/* by user option' if verbose?
1493
+ next
1494
+ end
1495
+ traverse task, type, "#{task}_dir_#{type}"
1496
+ end
1497
+ run_hook "post-#{task}"
1498
+ end
1499
+
1500
+ def traverse(task, rel, mid)
1501
+ dive_into(rel) {
1502
+ run_hook "pre-#{task}"
1503
+ __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
1504
+ directories_of(curr_srcdir()).each do |d|
1505
+ traverse task, "#{rel}/#{d}", mid
1506
+ end
1507
+ run_hook "post-#{task}"
1508
+ }
1509
+ end
1510
+
1511
+ def dive_into(rel)
1512
+ return unless File.dir?("#{@srcdir}/#{rel}")
1513
+
1514
+ dir = File.basename(rel)
1515
+ Dir.mkdir dir unless File.dir?(dir)
1516
+ prevdir = Dir.pwd
1517
+ Dir.chdir dir
1518
+ $stderr.puts '---> ' + rel if verbose?
1519
+ @currdir = rel
1520
+ yield
1521
+ Dir.chdir prevdir
1522
+ $stderr.puts '<--- ' + rel if verbose?
1523
+ @currdir = File.dirname(rel)
1524
+ end
1525
+
1526
+ def run_hook(id)
1527
+ path = [ "#{curr_srcdir()}/#{id}",
1528
+ "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
1529
+ return unless path
1530
+ begin
1531
+ instance_eval File.read(path), path, 1
1532
+ rescue
1533
+ raise if $DEBUG
1534
+ setup_rb_error "hook #{path} failed:\n" + $!.message
1535
+ end
1536
+ end
1537
+
1538
+ end # class Installer
1539
+
1540
+
1541
+ class SetupError < StandardError; end
1542
+
1543
+ def setup_rb_error(msg)
1544
+ raise SetupError, msg
1545
+ end
1546
+
1547
+ =begin
1548
+ if $0 == __FILE__
1549
+ begin
1550
+ ToplevelInstaller.invoke
1551
+ rescue SetupError
1552
+ raise if $DEBUG
1553
+ $stderr.puts $!.message
1554
+ $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
1555
+ exit 1
1556
+ end
1557
+ end
1558
+ =end