rubytree 1.0.2 → 2.0.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.
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