reap 4.3.4 → 4.4.0

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