rubytree 1.0.2 → 2.0.0

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