Develop and Download Open Source Software

Browse CVS Repository

Contents of /exerb/exerb/setup.rb

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


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

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26