reap 4.3.4 → 4.4.0

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