proutils 0.3.0

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