genx4r 0.04

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
1
+ require 'rubygems'
2
+
3
+ spec = Gem::Specification.new do |s|
4
+ s.name = 'genx4r'
5
+ s.version = '0.04'
6
+ s.summary = <<-EOF
7
+ GenX4r is a Ruby wrapper around the GenX library, which allows you to
8
+ programatically generate correct, cannonical XML output.
9
+ EOF
10
+ s.description = <<-EOF
11
+ GenX4r is a Ruby wrapper around the GenX library, which allows you to
12
+ programatically generate correct, cannonical XML output.
13
+ EOF
14
+
15
+ s.files = Dir.glob("**/*").delete_if { |item| item.include?(".svn") }
16
+
17
+ s.extensions << "ext/genx4r/extconf.rb"
18
+
19
+ s.require_path = 'lib' # Use these for libraries.
20
+ s.autorequire = 'genx4r'
21
+
22
+ s.has_rdoc = false
23
+ s.test_suite_file = "test/basics.rb"
24
+
25
+ s.author = "Garrett Rooney"
26
+ s.email = "rooneg@electricjellyfish.net"
27
+ s.homepage = "http://genx4r.rubyforge.org"
28
+ s.rubyforge_project = "genx4r"
29
+ end
@@ -0,0 +1,1346 @@
1
+ #
2
+ # setup.rb
3
+ #
4
+ # Copyright (c) 2000-2004 Minero Aoki
5
+ #
6
+ # This program is free software.
7
+ # You can distribute/modify this program under the terms of
8
+ # the GNU Lesser General Public License version 2.1.
9
+ #
10
+
11
+ #
12
+ # For backward compatibility
13
+ #
14
+
15
+ unless Enumerable.method_defined?(:map)
16
+ module Enumerable
17
+ alias map collect
18
+ end
19
+ end
20
+
21
+ unless Enumerable.method_defined?(:detect)
22
+ module Enumerable
23
+ alias detect find
24
+ end
25
+ end
26
+
27
+ unless Enumerable.method_defined?(:select)
28
+ module Enumerable
29
+ alias select find_all
30
+ end
31
+ end
32
+
33
+ unless Enumerable.method_defined?(:reject)
34
+ module Enumerable
35
+ def reject
36
+ result = []
37
+ each do |i|
38
+ result.push i unless yield(i)
39
+ end
40
+ result
41
+ end
42
+ end
43
+ end
44
+
45
+ unless Enumerable.method_defined?(:inject)
46
+ module Enumerable
47
+ def inject(result)
48
+ each do |i|
49
+ result = yield(result, i)
50
+ end
51
+ result
52
+ end
53
+ end
54
+ end
55
+
56
+ unless Enumerable.method_defined?(:any?)
57
+ module Enumerable
58
+ def any?
59
+ each do |i|
60
+ return true if yield(i)
61
+ end
62
+ false
63
+ end
64
+ end
65
+ end
66
+
67
+ unless File.respond_to?(:read)
68
+ def File.read(fname)
69
+ open(fname) {|f|
70
+ return f.read
71
+ }
72
+ end
73
+ end
74
+
75
+ #
76
+ # Application independent utilities
77
+ #
78
+
79
+ def File.binread(fname)
80
+ open(fname, 'rb') {|f|
81
+ return f.read
82
+ }
83
+ end
84
+
85
+ # for corrupted windows stat(2)
86
+ def File.dir?(path)
87
+ File.directory?((path[-1,1] == '/') ? path : path + '/')
88
+ end
89
+
90
+ #
91
+ # Config
92
+ #
93
+
94
+ if arg = ARGV.detect{|arg| /\A--rbconfig=/ =~ arg }
95
+ ARGV.delete(arg)
96
+ require arg.split(/=/, 2)[1]
97
+ $".push 'rbconfig.rb'
98
+ else
99
+ require 'rbconfig'
100
+ end
101
+
102
+ def multipackage_install?
103
+ FileTest.directory?(File.dirname($0) + '/packages')
104
+ end
105
+
106
+
107
+ class ConfigTable
108
+
109
+ c = ::Config::CONFIG
110
+
111
+ rubypath = c['bindir'] + '/' + c['ruby_install_name']
112
+
113
+ major = c['MAJOR'].to_i
114
+ minor = c['MINOR'].to_i
115
+ teeny = c['TEENY'].to_i
116
+ version = "#{major}.#{minor}"
117
+
118
+ # ruby ver. >= 1.4.4?
119
+ newpath_p = ((major >= 2) or
120
+ ((major == 1) and
121
+ ((minor >= 5) or
122
+ ((minor == 4) and (teeny >= 4)))))
123
+
124
+ subprefix = lambda {|path|
125
+ path.sub(/\A#{Regexp.quote(c['prefix'])}/o, '$prefix')
126
+ }
127
+
128
+ if c['rubylibdir']
129
+ # V < 1.6.3
130
+ stdruby = subprefix.call(c['rubylibdir'])
131
+ siteruby = subprefix.call(c['sitedir'])
132
+ versite = subprefix.call(c['sitelibdir'])
133
+ sodir = subprefix.call(c['sitearchdir'])
134
+ elsif newpath_p
135
+ # 1.4.4 <= V <= 1.6.3
136
+ stdruby = "$prefix/lib/ruby/#{version}"
137
+ siteruby = subprefix.call(c['sitedir'])
138
+ versite = siteruby + '/' + version
139
+ sodir = "$site-ruby/#{c['arch']}"
140
+ else
141
+ # V < 1.4.4
142
+ stdruby = "$prefix/lib/ruby/#{version}"
143
+ siteruby = "$prefix/lib/ruby/#{version}/site_ruby"
144
+ versite = siteruby
145
+ sodir = "$site-ruby/#{c['arch']}"
146
+ end
147
+
148
+ if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
149
+ makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
150
+ else
151
+ makeprog = 'make'
152
+ end
153
+
154
+ common_descripters = [
155
+ [ 'prefix', [ c['prefix'],
156
+ 'path',
157
+ 'path prefix of target environment' ] ],
158
+ [ 'std-ruby', [ stdruby,
159
+ 'path',
160
+ 'the directory for standard ruby libraries' ] ],
161
+ [ 'site-ruby-common', [ siteruby,
162
+ 'path',
163
+ 'the directory for version-independent non-standard ruby libraries' ] ],
164
+ [ 'site-ruby', [ versite,
165
+ 'path',
166
+ 'the directory for non-standard ruby libraries' ] ],
167
+ [ 'bin-dir', [ '$prefix/bin',
168
+ 'path',
169
+ 'the directory for commands' ] ],
170
+ [ 'rb-dir', [ '$site-ruby',
171
+ 'path',
172
+ 'the directory for ruby scripts' ] ],
173
+ [ 'so-dir', [ sodir,
174
+ 'path',
175
+ 'the directory for ruby extentions' ] ],
176
+ [ 'data-dir', [ '$prefix/share',
177
+ 'path',
178
+ 'the directory for shared data' ] ],
179
+ [ 'ruby-path', [ rubypath,
180
+ 'path',
181
+ 'path to set to #! line' ] ],
182
+ [ 'ruby-prog', [ rubypath,
183
+ 'name',
184
+ 'the ruby program using for installation' ] ],
185
+ [ 'make-prog', [ makeprog,
186
+ 'name',
187
+ 'the make program to compile ruby extentions' ] ],
188
+ [ 'without-ext', [ 'no',
189
+ 'yes/no',
190
+ 'does not compile/install ruby extentions' ] ]
191
+ ]
192
+ multipackage_descripters = [
193
+ [ 'with', [ '',
194
+ 'name,name...',
195
+ 'package names that you want to install',
196
+ 'ALL' ] ],
197
+ [ 'without', [ '',
198
+ 'name,name...',
199
+ 'package names that you do not want to install',
200
+ 'NONE' ] ]
201
+ ]
202
+ if multipackage_install?
203
+ DESCRIPTER = common_descripters + multipackage_descripters
204
+ else
205
+ DESCRIPTER = common_descripters
206
+ end
207
+
208
+ SAVE_FILE = 'config.save'
209
+
210
+ def ConfigTable.each_name(&block)
211
+ keys().each(&block)
212
+ end
213
+
214
+ def ConfigTable.keys
215
+ DESCRIPTER.map {|name, *dummy| name }
216
+ end
217
+
218
+ def ConfigTable.each_definition(&block)
219
+ DESCRIPTER.each(&block)
220
+ end
221
+
222
+ def ConfigTable.get_entry(name)
223
+ name, ent = DESCRIPTER.assoc(name)
224
+ ent
225
+ end
226
+
227
+ def ConfigTable.get_entry!(name)
228
+ get_entry(name) or raise ArgumentError, "no such config: #{name}"
229
+ end
230
+
231
+ def ConfigTable.add_entry(name, vals)
232
+ ConfigTable::DESCRIPTER.push [name,vals]
233
+ end
234
+
235
+ def ConfigTable.remove_entry(name)
236
+ get_entry(name) or raise ArgumentError, "no such config: #{name}"
237
+ DESCRIPTER.delete_if {|n, arr| n == name }
238
+ end
239
+
240
+ def ConfigTable.config_key?(name)
241
+ get_entry(name) ? true : false
242
+ end
243
+
244
+ def ConfigTable.bool_config?(name)
245
+ ent = get_entry(name) or return false
246
+ ent[1] == 'yes/no'
247
+ end
248
+
249
+ def ConfigTable.value_config?(name)
250
+ ent = get_entry(name) or return false
251
+ ent[1] != 'yes/no'
252
+ end
253
+
254
+ def ConfigTable.path_config?(name)
255
+ ent = get_entry(name) or return false
256
+ ent[1] == 'path'
257
+ end
258
+
259
+
260
+ class << self
261
+ alias newobj new
262
+ end
263
+
264
+ def ConfigTable.new
265
+ c = newobj()
266
+ c.initialize_from_table
267
+ c
268
+ end
269
+
270
+ def ConfigTable.load
271
+ c = newobj()
272
+ c.initialize_from_file
273
+ c
274
+ end
275
+
276
+ def initialize_from_table
277
+ @table = {}
278
+ DESCRIPTER.each do |k, (default, vname, desc, default2)|
279
+ @table[k] = default
280
+ end
281
+ end
282
+
283
+ def initialize_from_file
284
+ raise InstallError, "#{File.basename $0} config first"\
285
+ unless File.file?(SAVE_FILE)
286
+ @table = {}
287
+ File.foreach(SAVE_FILE) do |line|
288
+ k, v = line.split(/=/, 2)
289
+ @table[k] = v.strip
290
+ end
291
+ end
292
+
293
+ def save
294
+ File.open(SAVE_FILE, 'w') {|f|
295
+ @table.each do |k, v|
296
+ f.printf "%s=%s\n", k, v if v
297
+ end
298
+ }
299
+ end
300
+
301
+ def []=(k, v)
302
+ raise InstallError, "unknown config option #{k}"\
303
+ unless ConfigTable.config_key?(k)
304
+ @table[k] = v
305
+ end
306
+
307
+ def [](key)
308
+ return nil unless @table[key]
309
+ @table[key].gsub(%r<\$([^/]+)>) { self[$1] }
310
+ end
311
+
312
+ def set_raw(key, val)
313
+ @table[key] = val
314
+ end
315
+
316
+ def get_raw(key)
317
+ @table[key]
318
+ end
319
+
320
+ end
321
+
322
+
323
+ module MetaConfigAPI
324
+
325
+ def eval_file_ifexist(fname)
326
+ instance_eval File.read(fname), fname, 1 if File.file?(fname)
327
+ end
328
+
329
+ def config_names
330
+ ConfigTable.keys
331
+ end
332
+
333
+ def config?(name)
334
+ ConfigTable.config_key?(name)
335
+ end
336
+
337
+ def bool_config?(name)
338
+ ConfigTable.bool_config?(name)
339
+ end
340
+
341
+ def value_config?(name)
342
+ ConfigTable.value_config?(name)
343
+ end
344
+
345
+ def path_config?(name)
346
+ ConfigTable.path_config?(name)
347
+ end
348
+
349
+ def add_config(name, argname, default, desc)
350
+ ConfigTable.add_entry name,[default,argname,desc]
351
+ end
352
+
353
+ def add_path_config(name, default, desc)
354
+ add_config name, 'path', default, desc
355
+ end
356
+
357
+ def add_bool_config(name, default, desc)
358
+ add_config name, 'yes/no', default ? 'yes' : 'no', desc
359
+ end
360
+
361
+ def set_config_default(name, default)
362
+ if bool_config?(name)
363
+ ConfigTable.get_entry!(name)[0] = (default ? 'yes' : 'no')
364
+ else
365
+ ConfigTable.get_entry!(name)[0] = default
366
+ end
367
+ end
368
+
369
+ def remove_config(name)
370
+ ent = ConfigTable.get_entry(name)
371
+ ConfigTable.remove_entry name
372
+ ent
373
+ end
374
+
375
+ end
376
+
377
+ #
378
+ # File Operations
379
+ #
380
+
381
+ module FileOperations
382
+
383
+ def mkdir_p(dirname, prefix = nil)
384
+ dirname = prefix + dirname if prefix
385
+ $stderr.puts "mkdir -p #{dirname}" if verbose?
386
+ return if no_harm?
387
+
388
+ # does not check '/'... it's too abnormal case
389
+ dirs = dirname.split(%r<(?=/)>)
390
+ if /\A[a-z]:\z/i =~ dirs[0]
391
+ disk = dirs.shift
392
+ dirs[0] = disk + dirs[0]
393
+ end
394
+ dirs.each_index do |idx|
395
+ path = dirs[0..idx].join('')
396
+ Dir.mkdir path unless File.dir?(path)
397
+ end
398
+ end
399
+
400
+ def rm_f(fname)
401
+ $stderr.puts "rm -f #{fname}" if verbose?
402
+ return if no_harm?
403
+
404
+ if File.exist?(fname) or File.symlink?(fname)
405
+ File.chmod 0777, fname
406
+ File.unlink fname
407
+ end
408
+ end
409
+
410
+ def rm_rf(dn)
411
+ $stderr.puts "rm -rf #{dn}" if verbose?
412
+ return if no_harm?
413
+
414
+ Dir.chdir dn
415
+ Dir.foreach('.') do |fn|
416
+ next if fn == '.'
417
+ next if fn == '..'
418
+ if File.dir?(fn)
419
+ verbose_off {
420
+ rm_rf fn
421
+ }
422
+ else
423
+ verbose_off {
424
+ rm_f fn
425
+ }
426
+ end
427
+ end
428
+ Dir.chdir '..'
429
+ Dir.rmdir dn
430
+ end
431
+
432
+ def move_file(src, dest)
433
+ File.unlink dest if File.exist?(dest)
434
+ begin
435
+ File.rename src, dest
436
+ rescue
437
+ File.open(dest, 'wb') {|f| f.write File.binread(src) }
438
+ File.chmod File.stat(src).mode, dest
439
+ File.unlink src
440
+ end
441
+ end
442
+
443
+ def install(from, dest, mode, prefix = nil)
444
+ $stderr.puts "install #{from} #{dest}" if verbose?
445
+ return if no_harm?
446
+
447
+ realdest = prefix + dest if prefix
448
+ realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
449
+ str = File.binread(from)
450
+ if diff?(str, realdest)
451
+ verbose_off {
452
+ rm_f realdest if File.exist?(realdest)
453
+ }
454
+ File.open(realdest, 'wb') {|f|
455
+ f.write str
456
+ }
457
+ File.chmod mode, realdest
458
+
459
+ File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
460
+ if prefix
461
+ f.puts realdest.sub(prefix, '')
462
+ else
463
+ f.puts realdest
464
+ end
465
+ }
466
+ end
467
+ end
468
+
469
+ def diff?(new_content, path)
470
+ return true unless File.exist?(path)
471
+ new_content != File.binread(path)
472
+ end
473
+
474
+ def command(str)
475
+ $stderr.puts str if verbose?
476
+ system str or raise RuntimeError, "'system #{str}' failed"
477
+ end
478
+
479
+ def ruby(str)
480
+ command config('ruby-prog') + ' ' + str
481
+ end
482
+
483
+ def make(task = '')
484
+ command config('make-prog') + ' ' + task
485
+ end
486
+
487
+ def extdir?(dir)
488
+ File.exist?(dir + '/MANIFEST')
489
+ end
490
+
491
+ def all_files_in(dirname)
492
+ Dir.open(dirname) {|d|
493
+ return d.select {|ent| File.file?("#{dirname}/#{ent}") }
494
+ }
495
+ end
496
+
497
+ REJECT_DIRS = %w(
498
+ CVS SCCS RCS CVS.adm .svn
499
+ )
500
+
501
+ def all_dirs_in(dirname)
502
+ Dir.open(dirname) {|d|
503
+ return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS
504
+ }
505
+ end
506
+
507
+ end
508
+
509
+ #
510
+ # Main Installer
511
+ #
512
+
513
+ class InstallError < StandardError; end
514
+
515
+
516
+ module HookUtils
517
+
518
+ def run_hook(name)
519
+ try_run_hook "#{curr_srcdir()}/#{name}" or
520
+ try_run_hook "#{curr_srcdir()}/#{name}.rb"
521
+ end
522
+
523
+ def try_run_hook(fname)
524
+ return false unless File.file?(fname)
525
+ begin
526
+ instance_eval File.read(fname), fname, 1
527
+ rescue
528
+ raise InstallError, "hook #{fname} failed:\n" + $!.message
529
+ end
530
+ true
531
+ end
532
+
533
+ end
534
+
535
+
536
+ module HookScriptAPI
537
+
538
+ def get_config(key)
539
+ @config[key]
540
+ end
541
+
542
+ alias config get_config
543
+
544
+ def set_config(key, val)
545
+ @config[key] = val
546
+ end
547
+
548
+ #
549
+ # srcdir/objdir (works only in the package directory)
550
+ #
551
+
552
+ #abstract srcdir_root
553
+ #abstract objdir_root
554
+ #abstract relpath
555
+
556
+ def curr_srcdir
557
+ "#{srcdir_root()}/#{relpath()}"
558
+ end
559
+
560
+ def curr_objdir
561
+ "#{objdir_root()}/#{relpath()}"
562
+ end
563
+
564
+ def srcfile(path)
565
+ "#{curr_srcdir()}/#{path}"
566
+ end
567
+
568
+ def srcexist?(path)
569
+ File.exist?(srcfile(path))
570
+ end
571
+
572
+ def srcdirectory?(path)
573
+ File.dir?(srcfile(path))
574
+ end
575
+
576
+ def srcfile?(path)
577
+ File.file? srcfile(path)
578
+ end
579
+
580
+ def srcentries(path = '.')
581
+ Dir.open("#{curr_srcdir()}/#{path}") {|d|
582
+ return d.to_a - %w(. ..)
583
+ }
584
+ end
585
+
586
+ def srcfiles(path = '.')
587
+ srcentries(path).select {|fname|
588
+ File.file?(File.join(curr_srcdir(), path, fname))
589
+ }
590
+ end
591
+
592
+ def srcdirectories(path = '.')
593
+ srcentries(path).select {|fname|
594
+ File.dir?(File.join(curr_srcdir(), path, fname))
595
+ }
596
+ end
597
+
598
+ end
599
+
600
+
601
+ class ToplevelInstaller
602
+
603
+ Version = '3.2.4'
604
+ Copyright = 'Copyright (c) 2000-2004 Minero Aoki'
605
+
606
+ TASKS = [
607
+ [ 'config', 'saves your configurations' ],
608
+ [ 'show', 'shows current configuration' ],
609
+ [ 'setup', 'compiles ruby extentions and others' ],
610
+ [ 'install', 'installs files' ],
611
+ [ 'clean', "does `make clean' for each extention" ],
612
+ [ 'distclean',"does `make distclean' for each extention" ],
613
+ [ 'check', "runs unit tests" ]
614
+ ]
615
+
616
+ def ToplevelInstaller.invoke
617
+ instance().invoke
618
+ end
619
+
620
+ @singleton = nil
621
+
622
+ def ToplevelInstaller.instance
623
+ @singleton ||= new(File.dirname($0))
624
+ @singleton
625
+ end
626
+
627
+ include MetaConfigAPI
628
+
629
+ def initialize(ardir_root)
630
+ @config = nil
631
+ @options = { 'verbose' => true }
632
+ @ardir = File.expand_path(ardir_root)
633
+ end
634
+
635
+ def inspect
636
+ "#<#{self.class} #{__id__()}>"
637
+ end
638
+
639
+ def invoke
640
+ run_metaconfigs
641
+ task = parsearg_global()
642
+ @config = load_config(task)
643
+ __send__ "parsearg_#{task}"
644
+ init_installers
645
+ __send__ "exec_#{task}"
646
+ end
647
+
648
+ def run_metaconfigs
649
+ eval_file_ifexist "#{@ardir}/metaconfig"
650
+ end
651
+
652
+ def load_config(task)
653
+ case task
654
+ when 'config'
655
+ ConfigTable.new
656
+ when 'clean', 'distclean'
657
+ if File.exist?('config.save')
658
+ then ConfigTable.load
659
+ else ConfigTable.new
660
+ end
661
+ else
662
+ ConfigTable.load
663
+ end
664
+ end
665
+
666
+ def init_installers
667
+ @installer = Installer.new(@config, @options, @ardir, File.expand_path('.'))
668
+ end
669
+
670
+ #
671
+ # Hook Script API bases
672
+ #
673
+
674
+ def srcdir_root
675
+ @ardir
676
+ end
677
+
678
+ def objdir_root
679
+ '.'
680
+ end
681
+
682
+ def relpath
683
+ '.'
684
+ end
685
+
686
+ #
687
+ # Option Parsing
688
+ #
689
+
690
+ def parsearg_global
691
+ valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/
692
+
693
+ while arg = ARGV.shift
694
+ case arg
695
+ when /\A\w+\z/
696
+ raise InstallError, "invalid task: #{arg}" unless valid_task =~ arg
697
+ return arg
698
+
699
+ when '-q', '--quiet'
700
+ @options['verbose'] = false
701
+
702
+ when '--verbose'
703
+ @options['verbose'] = true
704
+
705
+ when '-h', '--help'
706
+ print_usage $stdout
707
+ exit 0
708
+
709
+ when '-v', '--version'
710
+ puts "#{File.basename($0)} version #{Version}"
711
+ exit 0
712
+
713
+ when '--copyright'
714
+ puts Copyright
715
+ exit 0
716
+
717
+ else
718
+ raise InstallError, "unknown global option '#{arg}'"
719
+ end
720
+ end
721
+
722
+ raise InstallError, <<EOS
723
+ No task or global option given.
724
+ Typical installation procedure is:
725
+ $ ruby #{File.basename($0)} config
726
+ $ ruby #{File.basename($0)} setup
727
+ $ ruby #{File.basename($0)} check
728
+ # ruby #{File.basename($0)} install (may require root privilege)
729
+ EOS
730
+ end
731
+
732
+
733
+ def parsearg_no_options
734
+ raise InstallError, "#{task}: unknown options: #{ARGV.join ' '}"\
735
+ unless ARGV.empty?
736
+ end
737
+
738
+ alias parsearg_show parsearg_no_options
739
+ alias parsearg_setup parsearg_no_options
740
+ alias parsearg_clean parsearg_no_options
741
+ alias parsearg_distclean parsearg_no_options
742
+ alias parsearg_check parsearg_no_options
743
+
744
+ def parsearg_config
745
+ re = /\A--(#{ConfigTable.keys.join '|'})(?:=(.*))?\z/
746
+ @options['config-opt'] = []
747
+
748
+ while i = ARGV.shift
749
+ if /\A--?\z/ =~ i
750
+ @options['config-opt'] = ARGV.dup
751
+ break
752
+ end
753
+ m = re.match(i) or raise InstallError, "config: unknown option #{i}"
754
+ name, value = m.to_a[1,2]
755
+ if value
756
+ if ConfigTable.bool_config?(name)
757
+ raise InstallError, "config: --#{name} allows only yes/no for argument"\
758
+ unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ value
759
+ value = (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no'
760
+ end
761
+ else
762
+ raise InstallError, "config: --#{name} requires argument"\
763
+ unless ConfigTable.bool_config?(name)
764
+ value = 'yes'
765
+ end
766
+ @config[name] = value
767
+ end
768
+ end
769
+
770
+ def parsearg_install
771
+ @options['no-harm'] = false
772
+ @options['install-prefix'] = ''
773
+ while a = ARGV.shift
774
+ case a
775
+ when /\A--no-harm\z/
776
+ @options['no-harm'] = true
777
+ when /\A--prefix=(.*)\z/
778
+ path = $1
779
+ path = File.expand_path(path) unless path[0,1] == '/'
780
+ @options['install-prefix'] = path
781
+ else
782
+ raise InstallError, "install: unknown option #{a}"
783
+ end
784
+ end
785
+ end
786
+
787
+ def print_usage(out)
788
+ out.puts 'Typical Installation Procedure:'
789
+ out.puts " $ ruby #{File.basename $0} config"
790
+ out.puts " $ ruby #{File.basename $0} setup"
791
+ out.puts " $ ruby #{File.basename $0} check"
792
+ out.puts " # ruby #{File.basename $0} install (may require root privilege)"
793
+ out.puts
794
+ out.puts 'Detailed Usage:'
795
+ out.puts " ruby #{File.basename $0} <global option>"
796
+ out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
797
+
798
+ fmt = " %-20s %s\n"
799
+ out.puts
800
+ out.puts 'Global options:'
801
+ out.printf fmt, '-q,--quiet', 'suppress message outputs'
802
+ out.printf fmt, ' --verbose', 'output messages verbosely'
803
+ out.printf fmt, '-h,--help', 'print this message'
804
+ out.printf fmt, '-v,--version', 'print version and quit'
805
+ out.printf fmt, ' --copyright', 'print copyright and quit'
806
+
807
+ out.puts
808
+ out.puts 'Tasks:'
809
+ TASKS.each do |name, desc|
810
+ out.printf " %-10s %s\n", name, desc
811
+ end
812
+
813
+ out.puts
814
+ out.puts 'Options for config:'
815
+ ConfigTable.each_definition do |name, (default, arg, desc, default2)|
816
+ out.printf " %-20s %s [%s]\n",
817
+ '--'+ name + (ConfigTable.bool_config?(name) ? '' : '='+arg),
818
+ desc,
819
+ default2 || default
820
+ end
821
+ out.printf " %-20s %s [%s]\n",
822
+ '--rbconfig=path', 'your rbconfig.rb to load', "running ruby's"
823
+
824
+ out.puts
825
+ out.puts 'Options for install:'
826
+ out.printf " %-20s %s [%s]\n",
827
+ '--no-harm', 'only display what to do if given', 'off'
828
+ out.printf " %-20s %s [%s]\n",
829
+ '--prefix', 'install path prefix', '$prefix'
830
+
831
+ out.puts
832
+ end
833
+
834
+ #
835
+ # Task Handlers
836
+ #
837
+
838
+ def exec_config
839
+ @installer.exec_config
840
+ @config.save # must be final
841
+ end
842
+
843
+ def exec_setup
844
+ @installer.exec_setup
845
+ end
846
+
847
+ def exec_install
848
+ @installer.exec_install
849
+ end
850
+
851
+ def exec_show
852
+ ConfigTable.each_name do |k|
853
+ v = @config.get_raw(k)
854
+ if not v or v.empty?
855
+ v = '(not specified)'
856
+ end
857
+ printf "%-10s %s\n", k, v
858
+ end
859
+ end
860
+
861
+ def exec_clean
862
+ @installer.exec_clean
863
+ end
864
+
865
+ def exec_distclean
866
+ @installer.exec_distclean
867
+ end
868
+
869
+ def exec_check
870
+ require 'test/unit'
871
+
872
+ Dir["test/*.rb"].each do |file|
873
+ begin
874
+ load file
875
+ rescue Exception => ex
876
+ puts "Error in #{file}: #{ex.message}"
877
+ end
878
+ end
879
+ end
880
+ end
881
+
882
+
883
+ class ToplevelInstallerMulti < ToplevelInstaller
884
+
885
+ include HookUtils
886
+ include HookScriptAPI
887
+ include FileOperations
888
+
889
+ def initialize(ardir)
890
+ super
891
+ @packages = all_dirs_in("#{@ardir}/packages")
892
+ raise 'no package exists' if @packages.empty?
893
+ end
894
+
895
+ def run_metaconfigs
896
+ eval_file_ifexist "#{@ardir}/metaconfig"
897
+ @packages.each do |name|
898
+ eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig"
899
+ end
900
+ end
901
+
902
+ def init_installers
903
+ @installers = {}
904
+ @packages.each do |pack|
905
+ @installers[pack] = Installer.new(@config, @options,
906
+ "#{@ardir}/packages/#{pack}",
907
+ "packages/#{pack}")
908
+ end
909
+
910
+ with = extract_selection(config('with'))
911
+ without = extract_selection(config('without'))
912
+ @selected = @installers.keys.select {|name|
913
+ (with.empty? or with.include?(name)) \
914
+ and not without.include?(name)
915
+ }
916
+ end
917
+
918
+ def extract_selection(list)
919
+ a = list.split(/,/)
920
+ a.each do |name|
921
+ raise InstallError, "no such package: #{name}" \
922
+ unless @installers.key?(name)
923
+ end
924
+ a
925
+ end
926
+
927
+ def print_usage(f)
928
+ super
929
+ f.puts 'Inluded packages:'
930
+ f.puts ' ' + @packages.sort.join(' ')
931
+ f.puts
932
+ end
933
+
934
+ #
935
+ # multi-package metaconfig API
936
+ #
937
+
938
+ attr_reader :packages
939
+
940
+ def declare_packages(list)
941
+ raise 'package list is empty' if list.empty?
942
+ list.each do |name|
943
+ raise "directory packages/#{name} does not exist"\
944
+ unless File.dir?("#{@ardir}/packages/#{name}")
945
+ end
946
+ @packages = list
947
+ end
948
+
949
+ #
950
+ # Task Handlers
951
+ #
952
+
953
+ def exec_config
954
+ run_hook 'pre-config'
955
+ each_selected_installers {|inst| inst.exec_config }
956
+ run_hook 'post-config'
957
+ @config.save # must be final
958
+ end
959
+
960
+ def exec_setup
961
+ run_hook 'pre-setup'
962
+ each_selected_installers {|inst| inst.exec_setup }
963
+ run_hook 'post-setup'
964
+ end
965
+
966
+ def exec_install
967
+ run_hook 'pre-install'
968
+ each_selected_installers {|inst| inst.exec_install }
969
+ run_hook 'post-install'
970
+ end
971
+
972
+ def exec_clean
973
+ rm_f 'config.save'
974
+ run_hook 'pre-clean'
975
+ each_selected_installers {|inst| inst.exec_clean }
976
+ run_hook 'post-clean'
977
+ end
978
+
979
+ def exec_distclean
980
+ rm_f 'config.save'
981
+ run_hook 'pre-distclean'
982
+ each_selected_installers {|inst| inst.exec_distclean }
983
+ run_hook 'post-distclean'
984
+ end
985
+
986
+ #
987
+ # lib
988
+ #
989
+
990
+ def each_selected_installers
991
+ Dir.mkdir 'packages' unless File.dir?('packages')
992
+ @selected.each do |pack|
993
+ $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose']
994
+ Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
995
+ Dir.chdir "packages/#{pack}"
996
+ yield @installers[pack]
997
+ Dir.chdir '../..'
998
+ end
999
+ end
1000
+
1001
+ def verbose?
1002
+ @options['verbose']
1003
+ end
1004
+
1005
+ def no_harm?
1006
+ @options['no-harm']
1007
+ end
1008
+
1009
+ end
1010
+
1011
+
1012
+ class Installer
1013
+
1014
+ FILETYPES = %w( bin lib ext data )
1015
+
1016
+ include HookScriptAPI
1017
+ include HookUtils
1018
+ include FileOperations
1019
+
1020
+ def initialize(config, opt, srcroot, objroot)
1021
+ @config = config
1022
+ @options = opt
1023
+ @srcdir = File.expand_path(srcroot)
1024
+ @objdir = File.expand_path(objroot)
1025
+ @currdir = '.'
1026
+ end
1027
+
1028
+ def inspect
1029
+ "#<#{self.class} #{File.basename(@srcdir)}>"
1030
+ end
1031
+
1032
+ #
1033
+ # Hook Script API bases
1034
+ #
1035
+
1036
+ def srcdir_root
1037
+ @srcdir
1038
+ end
1039
+
1040
+ def objdir_root
1041
+ @objdir
1042
+ end
1043
+
1044
+ def relpath
1045
+ @currdir
1046
+ end
1047
+
1048
+ #
1049
+ # configs/options
1050
+ #
1051
+
1052
+ def no_harm?
1053
+ @options['no-harm']
1054
+ end
1055
+
1056
+ def verbose?
1057
+ @options['verbose']
1058
+ end
1059
+
1060
+ def verbose_off
1061
+ begin
1062
+ save, @options['verbose'] = @options['verbose'], false
1063
+ yield
1064
+ ensure
1065
+ @options['verbose'] = save
1066
+ end
1067
+ end
1068
+
1069
+ #
1070
+ # TASK config
1071
+ #
1072
+
1073
+ def exec_config
1074
+ exec_task_traverse 'config'
1075
+ end
1076
+
1077
+ def config_dir_bin(rel)
1078
+ end
1079
+
1080
+ def config_dir_lib(rel)
1081
+ end
1082
+
1083
+ def config_dir_ext(rel)
1084
+ extconf if extdir?(curr_srcdir())
1085
+ end
1086
+
1087
+ def extconf
1088
+ opt = @options['config-opt'].join(' ')
1089
+ command "#{config('ruby-prog')} #{curr_srcdir()}/extconf.rb #{opt}"
1090
+ end
1091
+
1092
+ def config_dir_data(rel)
1093
+ end
1094
+
1095
+ #
1096
+ # TASK setup
1097
+ #
1098
+
1099
+ def exec_setup
1100
+ exec_task_traverse 'setup'
1101
+ end
1102
+
1103
+ def setup_dir_bin(rel)
1104
+ all_files_in(curr_srcdir()).each do |fname|
1105
+ adjust_shebang "#{curr_srcdir()}/#{fname}"
1106
+ end
1107
+ end
1108
+
1109
+ # modify: #!/usr/bin/ruby
1110
+ # modify: #! /usr/bin/ruby
1111
+ # modify: #!ruby
1112
+ # not modify: #!/usr/bin/env ruby
1113
+ SHEBANG_RE = /\A\#!\s*\S*ruby\S*/
1114
+
1115
+ def adjust_shebang(path)
1116
+ return if no_harm?
1117
+
1118
+ tmpfile = File.basename(path) + '.tmp'
1119
+ begin
1120
+ File.open(path, 'rb') {|r|
1121
+ File.open(tmpfile, 'wb') {|w|
1122
+ first = r.gets
1123
+ return unless SHEBANG_RE =~ first
1124
+
1125
+ $stderr.puts "adjusting shebang: #{File.basename path}" if verbose?
1126
+ w.print first.sub(SHEBANG_RE, '#!' + config('ruby-path'))
1127
+ w.write r.read
1128
+ }
1129
+ }
1130
+ move_file tmpfile, File.basename(path)
1131
+ ensure
1132
+ File.unlink tmpfile if File.exist?(tmpfile)
1133
+ end
1134
+ end
1135
+
1136
+ def setup_dir_lib(rel)
1137
+ end
1138
+
1139
+ def setup_dir_ext(rel)
1140
+ make if extdir?(curr_srcdir())
1141
+ end
1142
+
1143
+ def setup_dir_data(rel)
1144
+ end
1145
+
1146
+ #
1147
+ # TASK install
1148
+ #
1149
+
1150
+ def exec_install
1151
+ exec_task_traverse 'install'
1152
+ end
1153
+
1154
+ def install_dir_bin(rel)
1155
+ install_files collect_filenames_auto(), "#{config('bin-dir')}/#{rel}", 0755
1156
+ end
1157
+
1158
+ def install_dir_lib(rel)
1159
+ install_files ruby_scripts(), "#{config('rb-dir')}/#{rel}", 0644
1160
+ end
1161
+
1162
+ def install_dir_ext(rel)
1163
+ return unless extdir?(curr_srcdir())
1164
+ install_files ruby_extentions('.'),
1165
+ "#{config('so-dir')}/#{File.dirname(rel)}",
1166
+ 0555
1167
+ end
1168
+
1169
+ def install_dir_data(rel)
1170
+ install_files collect_filenames_auto(), "#{config('data-dir')}/#{rel}", 0644
1171
+ end
1172
+
1173
+ def install_files(list, dest, mode)
1174
+ mkdir_p dest, @options['install-prefix']
1175
+ list.each do |fname|
1176
+ install fname, dest, mode, @options['install-prefix']
1177
+ end
1178
+ end
1179
+
1180
+ def ruby_scripts
1181
+ collect_filenames_auto().select {|n| /\.rb\z/ =~ n }
1182
+ end
1183
+
1184
+ # picked up many entries from cvs-1.11.1/src/ignore.c
1185
+ reject_patterns = %w(
1186
+ core RCSLOG tags TAGS .make.state
1187
+ .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1188
+ *~ *.old *.bak *.BAK *.orig *.rej _$* *$
1189
+
1190
+ *.org *.in .*
1191
+ )
1192
+ mapping = {
1193
+ '.' => '\.',
1194
+ '$' => '\$',
1195
+ '#' => '\#',
1196
+ '*' => '.*'
1197
+ }
1198
+ REJECT_PATTERNS = Regexp.new('\A(?:' +
1199
+ reject_patterns.map {|pat|
1200
+ pat.gsub(/[\.\$\#\*]/) {|ch| mapping[ch] }
1201
+ }.join('|') +
1202
+ ')\z')
1203
+
1204
+ def collect_filenames_auto
1205
+ mapdir((existfiles() - hookfiles()).reject {|fname|
1206
+ REJECT_PATTERNS =~ fname
1207
+ })
1208
+ end
1209
+
1210
+ def existfiles
1211
+ all_files_in(curr_srcdir()) | all_files_in('.')
1212
+ end
1213
+
1214
+ def hookfiles
1215
+ %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
1216
+ %w( config setup install clean ).map {|t| sprintf(fmt, t) }
1217
+ }.flatten
1218
+ end
1219
+
1220
+ def mapdir(filelist)
1221
+ filelist.map {|fname|
1222
+ if File.exist?(fname) # objdir
1223
+ fname
1224
+ else # srcdir
1225
+ File.join(curr_srcdir(), fname)
1226
+ end
1227
+ }
1228
+ end
1229
+
1230
+ def ruby_extentions(dir)
1231
+ _ruby_extentions(dir) or
1232
+ raise InstallError, "no ruby extention exists: 'ruby #{$0} setup' first"
1233
+ end
1234
+
1235
+ DLEXT = /\.#{ ::Config::CONFIG['DLEXT'] }\z/
1236
+
1237
+ def _ruby_extentions(dir)
1238
+ Dir.open(dir) {|d|
1239
+ return d.select {|fname| DLEXT =~ fname }
1240
+ }
1241
+ end
1242
+
1243
+ #
1244
+ # TASK clean
1245
+ #
1246
+
1247
+ def exec_clean
1248
+ exec_task_traverse 'clean'
1249
+ rm_f 'config.save'
1250
+ rm_f 'InstalledFiles'
1251
+ end
1252
+
1253
+ def clean_dir_bin(rel)
1254
+ end
1255
+
1256
+ def clean_dir_lib(rel)
1257
+ end
1258
+
1259
+ def clean_dir_ext(rel)
1260
+ return unless extdir?(curr_srcdir())
1261
+ make 'clean' if File.file?('Makefile')
1262
+ end
1263
+
1264
+ def clean_dir_data(rel)
1265
+ end
1266
+
1267
+ #
1268
+ # TASK distclean
1269
+ #
1270
+
1271
+ def exec_distclean
1272
+ exec_task_traverse 'distclean'
1273
+ rm_f 'config.save'
1274
+ rm_f 'InstalledFiles'
1275
+ end
1276
+
1277
+ def distclean_dir_bin(rel)
1278
+ end
1279
+
1280
+ def distclean_dir_lib(rel)
1281
+ end
1282
+
1283
+ def distclean_dir_ext(rel)
1284
+ return unless extdir?(curr_srcdir())
1285
+ make 'distclean' if File.file?('Makefile')
1286
+ end
1287
+
1288
+ #
1289
+ # lib
1290
+ #
1291
+
1292
+ def exec_task_traverse(task)
1293
+ run_hook "pre-#{task}"
1294
+ FILETYPES.each do |type|
1295
+ if config('without-ext') == 'yes' and type == 'ext'
1296
+ $stderr.puts 'skipping ext/* by user option' if verbose?
1297
+ next
1298
+ end
1299
+ traverse task, type, "#{task}_dir_#{type}"
1300
+ end
1301
+ run_hook "post-#{task}"
1302
+ end
1303
+
1304
+ def traverse(task, rel, mid)
1305
+ dive_into(rel) {
1306
+ run_hook "pre-#{task}"
1307
+ __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
1308
+ all_dirs_in(curr_srcdir()).each do |d|
1309
+ traverse task, "#{rel}/#{d}", mid
1310
+ end
1311
+ run_hook "post-#{task}"
1312
+ }
1313
+ end
1314
+
1315
+ def dive_into(rel)
1316
+ return unless File.dir?("#{@srcdir}/#{rel}")
1317
+
1318
+ dir = File.basename(rel)
1319
+ Dir.mkdir dir unless File.dir?(dir)
1320
+ prevdir = Dir.pwd
1321
+ Dir.chdir dir
1322
+ $stderr.puts '---> ' + rel if verbose?
1323
+ @currdir = rel
1324
+ yield
1325
+ Dir.chdir prevdir
1326
+ $stderr.puts '<--- ' + rel if verbose?
1327
+ @currdir = File.dirname(rel)
1328
+ end
1329
+
1330
+ end
1331
+
1332
+
1333
+ if $0 == __FILE__
1334
+ begin
1335
+ if multipackage_install?
1336
+ ToplevelInstallerMulti.invoke
1337
+ else
1338
+ ToplevelInstaller.invoke
1339
+ end
1340
+ rescue
1341
+ raise if $DEBUG
1342
+ $stderr.puts $!.message
1343
+ $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
1344
+ exit 1
1345
+ end
1346
+ end