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