roll 0.8.0

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