4 # Copyright (c) 2000-2005 Minero Aoki
6 # This program is free software.
7 # You can distribute/modify this program under the terms of
8 # the GNU LGPL, Lesser General Public License version 2.1.
11 unless Enumerable.method_defined?(:map) # Ruby 1.4.6
17 unless File.respond_to?(:read) # Ruby 1.6
25 unless Errno.const_defined?(:ENOTEMPTY) # Windows?
28 # We do not raise this exception, implementation is not needed.
33 def File.binread(fname)
34 open(fname, 'rb') {|f|
39 # for corrupted Windows' stat(2)
41 File.directory?((path[-1,1] == '/') ? path : path + '/')
49 def initialize(rbconfig)
60 attr_accessor :install_prefix
61 attr_accessor :config_opt
76 lookup(key).resolve(self)
84 @items.map {|i| i.name }
96 @table[name] or setup_rb_error "no such config item: #{name}"
101 @table[item.name] = item
106 @items.delete_if {|i| i.name == name }
107 @table.delete_if {|name, i| i.name == name }
111 def load_script(path, inst = nil)
113 MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
123 File.foreach(savefile()) do |line|
124 k, v = *line.split(/=/, 2)
128 setup_rb_error $!.message + "\n#{File.basename($0)} config first"
133 @items.each {|i| i.value }
134 File.open(savefile(), 'w') {|f|
136 f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
141 def load_standard_entries
142 standard_entries(@rbconfig).each do |ent|
147 def standard_entries(rbconfig)
150 rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
152 major = c['MAJOR'].to_i
153 minor = c['MINOR'].to_i
154 teeny = c['TEENY'].to_i
155 version = "#{major}.#{minor}"
157 # ruby ver. >= 1.4.4?
158 newpath_p = ((major >= 2) or
161 ((minor == 4) and (teeny >= 4)))))
165 libruby = "#{c['prefix']}/lib/ruby"
166 librubyver = c['rubylibdir']
167 librubyverarch = c['archdir']
168 siteruby = c['sitedir']
169 siterubyver = c['sitelibdir']
170 siterubyverarch = c['sitearchdir']
172 # 1.4.4 <= V <= 1.6.3
173 libruby = "#{c['prefix']}/lib/ruby"
174 librubyver = "#{c['prefix']}/lib/ruby/#{version}"
175 librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
176 siteruby = c['sitedir']
177 siterubyver = "$siteruby/#{version}"
178 siterubyverarch = "$siterubyver/#{c['arch']}"
181 libruby = "#{c['prefix']}/lib/ruby"
182 librubyver = "#{c['prefix']}/lib/ruby/#{version}"
183 librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
184 siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
185 siterubyver = siteruby
186 siterubyverarch = "$siterubyver/#{c['arch']}"
188 parameterize = lambda {|path|
189 path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
192 if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
193 makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
199 ExecItem.new('installdirs', 'std/site/home',
200 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
204 table['rbdir'] = '$librubyver'
205 table['sodir'] = '$librubyverarch'
207 table['rbdir'] = '$siterubyver'
208 table['sodir'] = '$siterubyverarch'
210 setup_rb_error '$HOME was not set' unless ENV['HOME']
211 table['prefix'] = ENV['HOME']
212 table['rbdir'] = '$libdir/ruby'
213 table['sodir'] = '$libdir/ruby'
216 PathItem.new('prefix', 'path', c['prefix'],
217 'path prefix of target environment'),
218 PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
219 'the directory for commands'),
220 PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
221 'the directory for libraries'),
222 PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
223 'the directory for shared data'),
224 PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
225 'the directory for man pages'),
226 PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
227 'the directory for system configuration files'),
228 PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
229 'the directory for local state data'),
230 PathItem.new('libruby', 'path', parameterize.call(libruby),
231 'the directory for ruby libraries'),
232 PathItem.new('librubyver', 'path', parameterize.call(librubyver),
233 'the directory for standard ruby libraries'),
234 PathItem.new('librubyverarch', 'path', parameterize.call(librubyverarch),
235 'the directory for standard ruby extensions'),
236 PathItem.new('siteruby', 'path', parameterize.call(siteruby),
237 'the directory for version-independent aux ruby libraries'),
238 PathItem.new('siterubyver', 'path', parameterize.call(siterubyver),
239 'the directory for aux ruby libraries'),
240 PathItem.new('siterubyverarch', 'path', parameterize.call(siterubyverarch),
241 'the directory for aux ruby binaries'),
242 PathItem.new('rbdir', 'path', '$siterubyver',
243 'the directory for ruby scripts'),
244 PathItem.new('sodir', 'path', '$siterubyverarch',
245 'the directory for ruby extentions'),
246 PathItem.new('rubypath', 'path', rubypath,
247 'the path to set to #! line'),
248 ProgramItem.new('rubyprog', 'name', rubypath,
249 'the ruby program using for installation'),
250 ProgramItem.new('makeprog', 'name', makeprog,
251 'the make program to compile ruby extentions'),
252 SelectItem.new('shebang', 'all/ruby/never', 'ruby',
253 'shebang line (#!) editing mode'),
254 BoolItem.new('without-ext', 'yes/no', 'no',
255 'does not compile/install ruby extentions')
258 private :standard_entries
260 def load_multipackage_entries
261 multipackage_entries().each do |ent|
266 def multipackage_entries
268 PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
269 'package names that you want to install'),
270 PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
271 'package names that you do not want to install')
274 private :multipackage_entries
277 'std-ruby' => 'librubyver',
278 'stdruby' => 'librubyver',
279 'rubylibdir' => 'librubyver',
280 'archdir' => 'librubyverarch',
281 'site-ruby-common' => 'siteruby', # For backward compatibility
282 'site-ruby' => 'siterubyver', # For backward compatibility
283 'bin-dir' => 'bindir',
284 'bin-dir' => 'bindir',
287 'data-dir' => 'datadir',
288 'ruby-path' => 'rubypath',
289 'ruby-prog' => 'rubyprog',
290 'ruby' => 'rubyprog',
291 'make-prog' => 'makeprog',
296 ALIASES.each do |ali, name|
297 @table[ali] = @table[name]
301 @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
305 m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
313 def value_config?(name)
318 def initialize(name, template, default, desc)
327 attr_reader :description
329 attr_accessor :default
330 alias help_default default
333 "--#{@name}=#{@template}"
345 @value.gsub(%r<\$([^/]+)>) { table[$1] }
355 setup_rb_error "config: --#{name} requires argument" unless val
360 class BoolItem < Item
372 return 'yes' unless val
374 when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
375 when /\An(o)?\z/i, /\Af(alse)\z/i then 'no'
377 setup_rb_error "config: --#{@name} accepts only yes/no for argument"
382 class PathItem < Item
390 setup_rb_error "config: --#{@name} requires argument" unless path
391 path[0,1] == '$' ? path : File.expand_path(path)
395 class ProgramItem < Item
401 class SelectItem < Item
402 def initialize(name, selection, default, desc)
404 @ok = selection.split('/')
414 unless @ok.include?(val.strip)
415 setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
421 class ExecItem < Item
422 def initialize(name, selection, desc, &block)
423 super name, selection, nil, desc
424 @ok = selection.split('/')
437 setup_rb_error "$#{name()} wrongly used as option value"
442 def evaluate(val, table)
443 v = val.strip.downcase
444 unless @ok.include?(v)
445 setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
447 @action.call v, table
451 class PackageSelectionItem < Item
452 def initialize(name, template, default, help_default, desc)
453 super name, template, default, desc
454 @help_default = help_default
457 attr_reader :help_default
466 unless File.dir?("packages/#{val}")
467 setup_rb_error "config: no such package: #{val}"
473 class MetaConfigEnvironment
474 def initialize(config, installer)
476 @installer = installer
487 def bool_config?(name)
488 @config.lookup(name).config_type == 'bool'
491 def path_config?(name)
492 @config.lookup(name).config_type == 'path'
495 def value_config?(name)
496 @config.lookup(name).config_type != 'exec'
503 def add_bool_config(name, default, desc)
504 @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
507 def add_path_config(name, default, desc)
508 @config.add PathItem.new(name, 'path', default, desc)
511 def set_config_default(name, default)
512 @config.lookup(name).default = default
515 def remove_config(name)
519 # For only multipackage
521 raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
525 # For only multipackage
526 def declare_packages(list)
527 raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
528 @installer.packages = list
532 end # class ConfigTable
535 # This module requires: #verbose?, #no_harm?
536 module FileOperations
538 def mkdir_p(dirname, prefix = nil)
539 dirname = prefix + File.expand_path(dirname) if prefix
540 $stderr.puts "mkdir -p #{dirname}" if verbose?
543 # Does not check '/', it's too abnormal.
544 dirs = File.expand_path(dirname).split(%r<(?=/)>)
545 if /\A[a-z]:\z/i =~ dirs[0]
547 dirs[0] = disk + dirs[0]
549 dirs.each_index do |idx|
550 path = dirs[0..idx].join('')
551 Dir.mkdir path unless File.dir?(path)
556 $stderr.puts "rm -f #{path}" if verbose?
558 force_remove_file path
562 $stderr.puts "rm -rf #{path}" if verbose?
567 def remove_tree(path)
568 if File.symlink?(path)
570 elsif File.dir?(path)
573 force_remove_file path
577 def remove_tree0(path)
578 Dir.foreach(path) do |ent|
581 entpath = "#{path}/#{ent}"
582 if File.symlink?(entpath)
584 elsif File.dir?(entpath)
587 force_remove_file entpath
592 rescue Errno::ENOTEMPTY
593 # directory may not be empty
597 def move_file(src, dest)
598 force_remove_file dest
600 File.rename src, dest
602 File.open(dest, 'wb') {|f|
603 f.write File.binread(src)
605 File.chmod File.stat(src).mode, dest
610 def force_remove_file(path)
617 def remove_file(path)
618 File.chmod 0777, path
622 def install(from, dest, mode, prefix = nil)
623 $stderr.puts "install #{from} #{dest}" if verbose?
626 realdest = prefix ? prefix + File.expand_path(dest) : dest
627 realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
628 str = File.binread(from)
629 if diff?(str, realdest)
631 rm_f realdest if File.exist?(realdest)
633 File.open(realdest, 'wb') {|f|
636 File.chmod mode, realdest
638 File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
640 f.puts realdest.sub(prefix, '')
648 def diff?(new_content, path)
649 return true unless File.exist?(path)
650 new_content != File.binread(path)
654 $stderr.puts args.join(' ') if verbose?
655 system(*args) or raise RuntimeError,
656 "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
660 command config('rubyprog'), *args
664 command(*[config('makeprog'), task].compact)
668 File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
673 return d.select {|ent| File.file?("#{dir}/#{ent}") }
677 DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
679 def directories_of(dir)
681 return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
688 # This module requires: #srcdir_root, #objdir_root, #relpath
695 alias config get_config
697 # obsolete: use metaconfig to change configuration
698 def set_config(key, val)
703 # srcdir/objdir (works only in the package directory)
707 "#{srcdir_root()}/#{relpath()}"
711 "#{objdir_root()}/#{relpath()}"
715 "#{curr_srcdir()}/#{path}"
719 File.exist?(srcfile(path))
722 def srcdirectory?(path)
723 File.dir?(srcfile(path))
727 File.file?(srcfile(path))
730 def srcentries(path = '.')
731 Dir.open("#{curr_srcdir()}/#{path}") {|d|
732 return d.to_a - %w(. ..)
736 def srcfiles(path = '.')
737 srcentries(path).select {|fname|
738 File.file?(File.join(curr_srcdir(), path, fname))
742 def srcdirectories(path = '.')
743 srcentries(path).select {|fname|
744 File.dir?(File.join(curr_srcdir(), path, fname))
751 class ToplevelInstaller
754 Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
757 [ 'all', 'do config, setup, then install' ],
758 [ 'config', 'saves your configurations' ],
759 [ 'show', 'shows current configuration' ],
760 [ 'setup', 'compiles ruby extentions and others' ],
761 [ 'install', 'installs files' ],
762 [ 'test', 'run all tests in test/' ],
763 [ 'clean', "does `make clean' for each extention" ],
764 [ 'distclean',"does `make distclean' for each extention" ]
767 def ToplevelInstaller.invoke
768 config = ConfigTable.new(load_rbconfig())
769 config.load_standard_entries
770 config.load_multipackage_entries if multipackage?
772 klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
773 klass.new(File.dirname($0), config).invoke
776 def ToplevelInstaller.multipackage?
777 File.dir?(File.dirname($0) + '/packages')
780 def ToplevelInstaller.load_rbconfig
781 if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
783 load File.expand_path(arg.split(/=/, 2)[1])
784 $".push 'rbconfig.rb'
791 def initialize(ardir_root, config)
792 @ardir = File.expand_path(ardir_root)
803 "#<#{self.class} #{__id__()}>"
808 case task = parsearg_global()
817 when 'config', 'test'
819 when 'clean', 'distclean'
820 @config.load_savefile if File.exist?(@config.savefile)
822 @config.load_savefile
824 __send__ "parsearg_#{task}"
826 __send__ "exec_#{task}"
831 @config.load_script "#{@ardir}/metaconfig"
835 @installer = Installer.new(@config, @ardir, File.expand_path('.'))
839 # Hook Script API bases
859 while arg = ARGV.shift
862 setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
865 @config.verbose = false
867 @config.verbose = true
872 puts "#{File.basename($0)} version #{Version}"
878 setup_rb_error "unknown global option '#{arg}'"
889 @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
892 def parsearg_no_options
894 task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
895 setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
899 alias parsearg_show parsearg_no_options
900 alias parsearg_setup parsearg_no_options
901 alias parsearg_test parsearg_no_options
902 alias parsearg_clean parsearg_no_options
903 alias parsearg_distclean parsearg_no_options
908 @config.config_opt = []
911 @config.config_opt = ARGV.dup
914 name, value = *@config.parse_opt(i)
915 if @config.value_config?(name)
916 @config[name] = value
918 evalopt.push [name, value]
922 evalopt.each do |name, value|
923 @config.lookup(name).evaluate value, @config
925 # Check if configuration is valid
927 @config[n] if @config.value_config?(n)
932 @config.no_harm = false
933 @config.install_prefix = ''
937 @config.no_harm = true
939 path = a.split(/=/, 2)[1]
940 path = File.expand_path(path) unless path[0,1] == '/'
941 @config.install_prefix = path
943 setup_rb_error "install: unknown option #{a}"
949 out.puts 'Typical Installation Procedure:'
950 out.puts " $ ruby #{File.basename $0} config"
951 out.puts " $ ruby #{File.basename $0} setup"
952 out.puts " # ruby #{File.basename $0} install (may require root privilege)"
954 out.puts 'Detailed Usage:'
955 out.puts " ruby #{File.basename $0} <global option>"
956 out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
960 out.puts 'Global options:'
961 out.printf fmt, '-q,--quiet', 'suppress message outputs'
962 out.printf fmt, ' --verbose', 'output messages verbosely'
963 out.printf fmt, ' --help', 'print this message'
964 out.printf fmt, ' --version', 'print version and quit'
965 out.printf fmt, ' --copyright', 'print copyright and quit'
968 TASKS.each do |name, desc|
969 out.printf fmt, name, desc
972 fmt = " %-24s %s [%s]\n"
974 out.puts 'Options for CONFIG or ALL:'
975 @config.each do |item|
976 out.printf fmt, item.help_opt, item.description, item.help_default
978 out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
980 out.puts 'Options for INSTALL:'
981 out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
982 out.printf fmt, '--prefix=path', 'install path prefix', ''
991 @installer.exec_config
992 @config.save # must be final
996 @installer.exec_setup
1000 @installer.exec_install
1004 @installer.exec_test
1009 printf "%-20s %s\n", i.name, i.value if i.value?
1014 @installer.exec_clean
1018 @installer.exec_distclean
1021 end # class ToplevelInstaller
1024 class ToplevelInstallerMulti < ToplevelInstaller
1026 include FileOperations
1028 def initialize(ardir_root, config)
1030 @packages = directories_of("#{@ardir}/packages")
1031 raise 'no package exists' if @packages.empty?
1032 @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
1036 @config.load_script "#{@ardir}/metaconfig", self
1037 @packages.each do |name|
1038 @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
1042 attr_reader :packages
1045 raise 'package list is empty' if list.empty?
1047 raise "directory packages/#{name} does not exist"\
1048 unless File.dir?("#{@ardir}/packages/#{name}")
1055 @packages.each do |pack|
1056 @installers[pack] = Installer.new(@config,
1057 "#{@ardir}/packages/#{pack}",
1060 with = extract_selection(config('with'))
1061 without = extract_selection(config('without'))
1062 @selected = @installers.keys.select {|name|
1063 (with.empty? or with.include?(name)) \
1064 and not without.include?(name)
1068 def extract_selection(list)
1071 setup_rb_error "no such package: #{name}" unless @installers.key?(name)
1078 f.puts 'Inluded packages:'
1079 f.puts ' ' + @packages.sort.join(' ')
1088 run_hook 'pre-config'
1089 each_selected_installers {|inst| inst.exec_config }
1090 run_hook 'post-config'
1091 @config.save # must be final
1095 run_hook 'pre-setup'
1096 each_selected_installers {|inst| inst.exec_setup }
1097 run_hook 'post-setup'
1101 run_hook 'pre-install'
1102 each_selected_installers {|inst| inst.exec_install }
1103 run_hook 'post-install'
1108 each_selected_installers {|inst| inst.exec_test }
1109 run_hook 'post-test'
1113 rm_f @config.savefile
1114 run_hook 'pre-clean'
1115 each_selected_installers {|inst| inst.exec_clean }
1116 run_hook 'post-clean'
1120 rm_f @config.savefile
1121 run_hook 'pre-distclean'
1122 each_selected_installers {|inst| inst.exec_distclean }
1123 run_hook 'post-distclean'
1130 def each_selected_installers
1131 Dir.mkdir 'packages' unless File.dir?('packages')
1132 @selected.each do |pack|
1133 $stderr.puts "Processing the package `#{pack}' ..." if verbose?
1134 Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
1135 Dir.chdir "packages/#{pack}"
1136 yield @installers[pack]
1142 @root_installer.run_hook id
1145 # module FileOperations requires this
1150 # module FileOperations requires this
1155 end # class ToplevelInstallerMulti
1160 FILETYPES = %w( bin lib ext data conf man )
1162 include FileOperations
1163 include HookScriptAPI
1165 def initialize(config, srcroot, objroot)
1167 @srcdir = File.expand_path(srcroot)
1168 @objdir = File.expand_path(objroot)
1173 "#<#{self.class} #{File.basename(@srcdir)}>"
1180 # Hook Script API base methods
1199 # module FileOperations requires this
1204 # module FileOperations requires this
1211 save, @config.verbose = @config.verbose?, false
1214 @config.verbose = save
1223 exec_task_traverse 'config'
1226 alias config_dir_bin noop
1227 alias config_dir_lib noop
1229 def config_dir_ext(rel)
1230 extconf if extdir?(curr_srcdir())
1233 alias config_dir_data noop
1234 alias config_dir_conf noop
1235 alias config_dir_man noop
1238 ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
1246 exec_task_traverse 'setup'
1249 def setup_dir_bin(rel)
1250 files_of(curr_srcdir()).each do |fname|
1251 update_shebang_line "#{curr_srcdir()}/#{fname}"
1255 alias setup_dir_lib noop
1257 def setup_dir_ext(rel)
1258 make if extdir?(curr_srcdir())
1261 alias setup_dir_data noop
1262 alias setup_dir_conf noop
1263 alias setup_dir_man noop
1265 def update_shebang_line(path)
1267 return if config('shebang') == 'never'
1268 old = Shebang.load(path)
1270 $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1
1271 new = new_shebang(old)
1272 return if new.to_s == old.to_s
1274 return unless config('shebang') == 'all'
1275 new = Shebang.new(config('rubypath'))
1277 $stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
1278 open_atomic_writer(path) {|output|
1279 File.open(path, 'rb') {|f|
1280 f.gets if old # discard
1281 output.puts new.to_s
1287 def new_shebang(old)
1288 if /\Aruby/ =~ File.basename(old.cmd)
1289 Shebang.new(config('rubypath'), old.args)
1290 elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
1291 Shebang.new(config('rubypath'), old.args[1..-1])
1293 return old unless config('shebang') == 'all'
1294 Shebang.new(config('rubypath'))
1298 def open_atomic_writer(path, &block)
1299 tmpfile = File.basename(path) + '.tmp'
1301 File.open(tmpfile, 'wb', &block)
1302 File.rename tmpfile, File.basename(path)
1304 File.unlink tmpfile if File.exist?(tmpfile)
1309 def Shebang.load(path)
1311 File.open(path) {|f|
1314 return nil unless /\A#!/ =~ line
1318 def Shebang.parse(line)
1319 cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
1323 def initialize(cmd, args = [])
1332 "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
1341 rm_f 'InstalledFiles'
1342 exec_task_traverse 'install'
1345 def install_dir_bin(rel)
1346 install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
1349 def install_dir_lib(rel)
1350 install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
1353 def install_dir_ext(rel)
1354 return unless extdir?(curr_srcdir())
1355 install_files rubyextentions('.'),
1356 "#{config('sodir')}/#{File.dirname(rel)}",
1360 def install_dir_data(rel)
1361 install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
1364 def install_dir_conf(rel)
1365 # FIXME: should not remove current config files
1366 # (rename previous file to .old/.org)
1367 install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
1370 def install_dir_man(rel)
1371 install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
1374 def install_files(list, dest, mode)
1375 mkdir_p dest, @config.install_prefix
1376 list.each do |fname|
1377 install fname, dest, mode, @config.install_prefix
1382 glob_reject(%w(*.y *.output), targetfiles())
1385 def rubyextentions(dir)
1386 ents = glob_select("*.#{@config.dllext}", targetfiles())
1388 setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
1394 mapdir(existfiles() - hookfiles())
1401 else "#{curr_srcdir()}/#{ent}" # srcdir
1406 # picked up many entries from cvs-1.11.1/src/ignore.c
1408 core RCSLOG tags TAGS .make.state
1409 .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1410 *~ *.old *.bak *.BAK *.orig *.rej _$* *$
1416 glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
1420 %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
1421 %w( config setup install clean ).map {|t| sprintf(fmt, t) }
1425 def glob_select(pat, ents)
1426 re = globs2re([pat])
1427 ents.select {|ent| re =~ ent }
1430 def glob_reject(pats, ents)
1432 ents.reject {|ent| re =~ ent }
1444 pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
1455 unless File.directory?('test')
1456 $stderr.puts 'no test in this package' if verbose?
1459 $stderr.puts 'Running tests...' if verbose?
1463 setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.'
1465 runner = Test::Unit::AutoRunner.new(true)
1466 runner.to_run << TESTDIR
1475 exec_task_traverse 'clean'
1476 rm_f @config.savefile
1477 rm_f 'InstalledFiles'
1480 alias clean_dir_bin noop
1481 alias clean_dir_lib noop
1482 alias clean_dir_data noop
1483 alias clean_dir_conf noop
1484 alias clean_dir_man noop
1486 def clean_dir_ext(rel)
1487 return unless extdir?(curr_srcdir())
1488 make 'clean' if File.file?('Makefile')
1496 exec_task_traverse 'distclean'
1497 rm_f @config.savefile
1498 rm_f 'InstalledFiles'
1501 alias distclean_dir_bin noop
1502 alias distclean_dir_lib noop
1504 def distclean_dir_ext(rel)
1505 return unless extdir?(curr_srcdir())
1506 make 'distclean' if File.file?('Makefile')
1509 alias distclean_dir_data noop
1510 alias distclean_dir_conf noop
1511 alias distclean_dir_man noop
1517 def exec_task_traverse(task)
1518 run_hook "pre-#{task}"
1519 FILETYPES.each do |type|
1520 if type == 'ext' and config('without-ext') == 'yes'
1521 $stderr.puts 'skipping ext/* by user option' if verbose?
1524 traverse task, type, "#{task}_dir_#{type}"
1526 run_hook "post-#{task}"
1529 def traverse(task, rel, mid)
1531 run_hook "pre-#{task}"
1532 __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
1533 directories_of(curr_srcdir()).each do |d|
1534 traverse task, "#{rel}/#{d}", mid
1536 run_hook "post-#{task}"
1541 return unless File.dir?("#{@srcdir}/#{rel}")
1543 dir = File.basename(rel)
1544 Dir.mkdir dir unless File.dir?(dir)
1547 $stderr.puts '---> ' + rel if verbose?
1551 $stderr.puts '<--- ' + rel if verbose?
1552 @currdir = File.dirname(rel)
1556 path = [ "#{curr_srcdir()}/#{id}",
1557 "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
1560 instance_eval File.read(path), path, 1
1563 setup_rb_error "hook #{path} failed:\n" + $!.message
1567 end # class Installer
1570 class SetupError < StandardError; end
1572 def setup_rb_error(msg)
1573 raise SetupError, msg
1578 ToplevelInstaller.invoke
1581 $stderr.puts $!.message
1582 $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."