]> git.pld-linux.org Git - packages/amrita.git/blame - setup.rb
- up to 3.3.1
[packages/amrita.git] / setup.rb
CommitLineData
acbc6b09 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
a2eb2574 8# the GNU LGPL, Lesser General Public License version 2.1.
acbc6b09 9#
10
a2eb2574 11unless Enumerable.method_defined?(:map) # Ruby 1.4.6
acbc6b09 12 module Enumerable
13 alias map collect
14 end
15end
16
a2eb2574 17unless File.respond_to?(:read) # Ruby 1.6
acbc6b09 18 def File.read(fname)
19 open(fname) {|f|
20 return f.read
21 }
22 end
23end
24
acbc6b09 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
a2eb2574 36
37class SetupError < StandardError; end
38
39def setup_rb_error(msg)
40 raise SetupError, msg
41end
42
acbc6b09 43#
44# Config
45#
46
a2eb2574 47if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
acbc6b09 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
a2eb2574 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
acbc6b09 68
a2eb2574 69 attr_reader :name
70 attr_reader :description
acbc6b09 71
a2eb2574 72 attr_accessor :default
73 alias help_default default
acbc6b09 74
a2eb2574 75 def help_opt
76 "--#{@name}=#{@template}"
77 end
acbc6b09 78
a2eb2574 79 def value
80 @value
81 end
acbc6b09 82
a2eb2574 83 def eval(table)
84 @value.gsub(%r<\$([^/]+)>) { table[$1] }
85 end
86
87 def set(val)
88 @value = check(val)
acbc6b09 89 end
90
a2eb2574 91 private
acbc6b09 92
a2eb2574 93 def check(val)
94 setup_rb_error "config: --#{name} requires argument" unless val
95 val
acbc6b09 96 end
a2eb2574 97end
acbc6b09 98
a2eb2574 99class BoolItem < ConfigItem
100 def config_type
101 'bool'
acbc6b09 102 end
103
a2eb2574 104 def help_opt
105 "--#{@name}"
acbc6b09 106 end
107
a2eb2574 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'
acbc6b09 116 end
a2eb2574 117end
acbc6b09 118
a2eb2574 119class PathItem < ConfigItem
120 def config_type
121 'path'
acbc6b09 122 end
123
a2eb2574 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)
acbc6b09 129 end
a2eb2574 130end
acbc6b09 131
a2eb2574 132class ProgramItem < ConfigItem
133 def config_type
134 'program'
acbc6b09 135 end
a2eb2574 136end
acbc6b09 137
a2eb2574 138class SelectItem < ConfigItem
139 def initialize(name, template, default, desc)
140 super
141 @ok = template.split('/')
acbc6b09 142 end
143
a2eb2574 144 def config_type
145 'select'
acbc6b09 146 end
147
a2eb2574 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
acbc6b09 155 end
a2eb2574 156end
acbc6b09 157
a2eb2574 158class PackageSelectionItem < ConfigItem
159 def initialize(name, template, default, help_default, desc)
160 super name, template, default, desc
161 @help_default = help_default
acbc6b09 162 end
163
a2eb2574 164 attr_reader :help_default
acbc6b09 165
a2eb2574 166 def config_type
167 'package'
acbc6b09 168 end
169
a2eb2574 170 private
acbc6b09 171
a2eb2574 172 def check(val)
173 unless File.dir?("packages/#{val}")
174 setup_rb_error "config: no such package: #{val}"
175 end
176 val
acbc6b09 177 end
a2eb2574 178end
179
180class ConfigTable_class
acbc6b09 181
a2eb2574 182 def initialize(items)
183 @items = items
acbc6b09 184 @table = {}
a2eb2574 185 items.each do |i|
186 @table[i.name] = i
187 end
188 ALIASES.each do |ali, name|
189 @table[ali] = @table[name]
acbc6b09 190 end
191 end
192
a2eb2574 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"
acbc6b09 237 end
238 end
239
240 def save
a2eb2574 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
acbc6b09 245 end
246 }
247 end
248
acbc6b09 249 def [](key)
a2eb2574 250 lookup(key).eval(self)
acbc6b09 251 end
252
a2eb2574 253 def []=(key, val)
254 lookup(key).set val
acbc6b09 255 end
256
a2eb2574 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
acbc6b09 315
a2eb2574 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)
acbc6b09 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
a2eb2574 389 ConfigTable.map {|i| i.name }
acbc6b09 390 end
391
392 def config?(name)
a2eb2574 393 ConfigTable.key?(name)
acbc6b09 394 end
395
396 def bool_config?(name)
a2eb2574 397 ConfigTable.lookup(name).config_type == 'bool'
acbc6b09 398 end
399
400 def path_config?(name)
a2eb2574 401 ConfigTable.lookup(name).config_type == 'path'
acbc6b09 402 end
403
a2eb2574 404 def value_config?(name)
405 case ConfigTable.lookup(name).config_type
406 when 'bool', 'path'
407 true
408 else
409 false
410 end
acbc6b09 411 end
412
a2eb2574 413 def add_config(item)
414 ConfigTable.add item
acbc6b09 415 end
416
417 def add_bool_config(name, default, desc)
a2eb2574 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)
acbc6b09 423 end
424
425 def set_config_default(name, default)
a2eb2574 426 ConfigTable.lookup(name).default = default
acbc6b09 427 end
428
429 def remove_config(name)
a2eb2574 430 ConfigTable.remove(name)
acbc6b09 431 end
432
433end
434
a2eb2574 435
acbc6b09 436#
437# File Operations
438#
439
440module FileOperations
441
442 def mkdir_p(dirname, prefix = nil)
a2eb2574 443 dirname = prefix + File.expand_path(dirname) if prefix
acbc6b09 444 $stderr.puts "mkdir -p #{dirname}" if verbose?
445 return if no_harm?
446
447 # does not check '/'... it's too abnormal case
a2eb2574 448 dirs = File.expand_path(dirname).split(%r<(?=/)>)
acbc6b09 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
a2eb2574 506 realdest = prefix ? prefix + File.expand_path(dest) : dest
acbc6b09 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)
a2eb2574 539 command config('rubyprog') + ' ' + str
acbc6b09 540 end
541
542 def make(task = '')
a2eb2574 543 command config('makeprog') + ' ' + task
acbc6b09 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(
a2eb2574 557 CVS SCCS RCS CVS.adm .svn
acbc6b09 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
a2eb2574 568
acbc6b09 569#
570# Main Installer
571#
572
acbc6b09 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
a2eb2574 585 setup_rb_error "hook #{fname} failed:\n" + $!.message
acbc6b09 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
a2eb2574 660 Version = '3.3.1'
acbc6b09 661 Copyright = 'Copyright (c) 2000-2004 Minero Aoki'
662
663 TASKS = [
a2eb2574 664 [ 'all', 'do config, setup, then install' ],
acbc6b09 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
a2eb2574 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
acbc6b09 712 end
a2eb2574 713
acbc6b09 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'
a2eb2574 723 if File.exist?(ConfigTable.savefile)
acbc6b09 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/
a2eb2574 762 setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg
acbc6b09 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
a2eb2574 784 setup_rb_error "unknown global option '#{arg}'"
acbc6b09 785 end
786 end
787
a2eb2574 788 nil
acbc6b09 789 end
790
791
792 def parsearg_no_options
a2eb2574 793 unless ARGV.empty?
794 setup_rb_error "#{task}: unknown options: #{ARGV.join ' '}"
795 end
acbc6b09 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
a2eb2574 804 re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/
acbc6b09 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
a2eb2574 812 m = re.match(i) or setup_rb_error "config: unknown option #{i}"
813 name, value = *m.to_a[1,2]
acbc6b09 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
a2eb2574 830 setup_rb_error "install: unknown option #{a}"
acbc6b09 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
a2eb2574 845 fmt = " %-24s %s\n"
acbc6b09 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'
acbc6b09 853 out.puts
854 out.puts 'Tasks:'
855 TASKS.each do |name, desc|
a2eb2574 856 out.printf fmt, name, desc
acbc6b09 857 end
858
a2eb2574 859 fmt = " %-24s %s [%s]\n"
acbc6b09 860 out.puts
a2eb2574 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
acbc6b09 864 end
a2eb2574 865 out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
acbc6b09 866 out.puts
a2eb2574 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'
acbc6b09 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
a2eb2574 891 ConfigTable.each do |i|
892 printf "%-20s %s\n", i.name, i.value
acbc6b09 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|
a2eb2574 945 setup_rb_error "no such package: #{name}" unless @installers.key?(name)
acbc6b09 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
a2eb2574 996 rm_f ConfigTable.savefile
acbc6b09 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
a2eb2574 1003 rm_f ConfigTable.savefile
acbc6b09 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 #
a2eb2574 1056 # Hook Script API base methods
acbc6b09 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(' ')
a2eb2574 1112 command "#{config('rubyprog')} #{curr_srcdir()}/extconf.rb #{opt}"
acbc6b09 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
acbc6b09 1132 def adjust_shebang(path)
1133 return if no_harm?
acbc6b09 1134 tmpfile = File.basename(path) + '.tmp'
1135 begin
1136 File.open(path, 'rb') {|r|
a2eb2574 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?
acbc6b09 1141 File.open(tmpfile, 'wb') {|w|
a2eb2574 1142 w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath'))
acbc6b09 1143 w.write r.read
1144 }
a2eb2574 1145 move_file tmpfile, File.basename(path)
acbc6b09 1146 }
acbc6b09 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
a2eb2574 1167 rm_f 'InstalledFiles'
acbc6b09 1168 exec_task_traverse 'install'
1169 end
1170
1171 def install_dir_bin(rel)
a2eb2574 1172 install_files collect_filenames_auto(), "#{config('bindir')}/#{rel}", 0755
acbc6b09 1173 end
1174
1175 def install_dir_lib(rel)
a2eb2574 1176 install_files ruby_scripts(), "#{config('rbdir')}/#{rel}", 0644
acbc6b09 1177 end
1178
1179 def install_dir_ext(rel)
1180 return unless extdir?(curr_srcdir())
1181 install_files ruby_extentions('.'),
a2eb2574 1182 "#{config('sodir')}/#{File.dirname(rel)}",
acbc6b09 1183 0555
1184 end
1185
1186 def install_dir_data(rel)
a2eb2574 1187 install_files collect_filenames_auto(), "#{config('datadir')}/#{rel}", 0644
acbc6b09 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)
acbc6b09 1248 Dir.open(dir) {|d|
a2eb2574 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
acbc6b09 1254 }
1255 end
1256
1257 #
1258 # TASK clean
1259 #
1260
1261 def exec_clean
1262 exec_task_traverse 'clean'
a2eb2574 1263 rm_f ConfigTable.savefile
acbc6b09 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'
a2eb2574 1287 rm_f ConfigTable.savefile
acbc6b09 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
a2eb2574 1354 rescue SetupError
acbc6b09 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.392863 seconds and 4 git commands to generate.