proutils 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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