kingpong-bitwise_string_ops 0.1.2

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