rubytree 1.0.0 → 1.0.2

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