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