5 # Copyright (c) 2000-2005 Minero Aoki
7 # This program is free software.
8 # You can distribute/modify this program under the terms of
9 # the GNU LGPL, Lesser General Public License version 2.1.
12 unless Enumerable.method_defined?(:map) # Ruby 1.4.6
18 unless File.respond_to?(:read) # Ruby 1.6
20 open(fname) { |f| return f.read }
24 unless Errno.const_defined?(:ENOTEMPTY) # Windows?
27 # We do not raise this exception, implementation is not needed.
32 def File.binread(fname)
33 open(fname, 'rb') { |f| return f.read }
36 # for corrupted Windows' stat(2)
38 File.directory?((path[-1,1] == '/') ? path : path + '/')
46 def initialize(rbconfig)
57 attr_accessor :install_prefix
58 attr_accessor :config_opt
73 lookup(key).resolve(self)
81 @items.map { |i| i.name }
93 @table[name] or setup_rb_error "no such config item: #{name}"
98 @table[item.name] = item
103 @items.delete_if { |i| i.name == name }
104 @table.delete_if { |name, i| i.name == name }
108 def load_script(path, inst = nil)
110 MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
120 File.foreach(savefile()) do |line|
121 k, v = *line.split(/=/, 2)
125 setup_rb_error $!.message + "\n#{File.basename($PROGRAM_NAME)} config first"
130 @items.each { |i| i.value }
131 File.open(savefile(), 'w') { |f|
133 f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
138 def load_standard_entries
139 standard_entries(@rbconfig).each do |ent|
144 def standard_entries(rbconfig)
147 rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
149 major = c['MAJOR'].to_i
150 minor = c['MINOR'].to_i
151 teeny = c['TEENY'].to_i
152 version = "#{major}.#{minor}"
154 # ruby ver. >= 1.4.4?
155 newpath_p = ((major >= 2) or
158 ((minor == 4) and (teeny >= 4)))))
162 libruby = "#{c['prefix']}/lib/ruby"
163 librubyver = c['rubylibdir']
164 librubyverarch = c['archdir']
165 siteruby = c['sitedir']
166 siterubyver = c['sitelibdir']
167 siterubyverarch = c['sitearchdir']
169 # 1.4.4 <= V <= 1.6.3
170 libruby = "#{c['prefix']}/lib/ruby"
171 librubyver = "#{c['prefix']}/lib/ruby/#{version}"
172 librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
173 siteruby = c['sitedir']
174 siterubyver = "$siteruby/#{version}"
175 siterubyverarch = "$siterubyver/#{c['arch']}"
178 libruby = "#{c['prefix']}/lib/ruby"
179 librubyver = "#{c['prefix']}/lib/ruby/#{version}"
180 librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
181 siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
182 siterubyver = siteruby
183 siterubyverarch = "$siterubyver/#{c['arch']}"
185 parameterize = lambda { |path|
186 path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
189 if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
190 makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
196 ExecItem.new('installdirs', 'std/site/home',
197 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
201 table['rbdir'] = '$librubyver'
202 table['sodir'] = '$librubyverarch'
204 table['rbdir'] = '$siterubyver'
205 table['sodir'] = '$siterubyverarch'
207 setup_rb_error '$HOME was not set' unless ENV['HOME']
208 table['prefix'] = ENV['HOME']
209 table['rbdir'] = '$libdir/ruby'
210 table['sodir'] = '$libdir/ruby'
213 PathItem.new('prefix', 'path', c['prefix'],
214 'path prefix of target environment'),
215 PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
216 'the directory for commands'),
217 PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
218 'the directory for libraries'),
219 PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
220 'the directory for shared data'),
221 PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
222 'the directory for man pages'),
223 PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
224 'the directory for system configuration files'),
225 PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
226 'the directory for local state data'),
227 PathItem.new('libruby', 'path', libruby,
228 'the directory for ruby libraries'),
229 PathItem.new('librubyver', 'path', librubyver,
230 'the directory for standard ruby libraries'),
231 PathItem.new('librubyverarch', 'path', librubyverarch,
232 'the directory for standard ruby extensions'),
233 PathItem.new('siteruby', 'path', siteruby,
234 'the directory for version-independent aux ruby libraries'),
235 PathItem.new('siterubyver', 'path', siterubyver,
236 'the directory for aux ruby libraries'),
237 PathItem.new('siterubyverarch', 'path', siterubyverarch,
238 'the directory for aux ruby binaries'),
239 PathItem.new('rbdir', 'path', '$siterubyver',
240 'the directory for ruby scripts'),
241 PathItem.new('sodir', 'path', '$siterubyverarch',
242 'the directory for ruby extensions'),
243 PathItem.new('rubypath', 'path', rubypath,
244 'the path to set to #! line'),
245 ProgramItem.new('rubyprog', 'name', rubypath,
246 'the ruby program using for installation'),
247 ProgramItem.new('makeprog', 'name', makeprog,
248 'the make program to compile ruby extensions'),
249 SelectItem.new('shebang', 'all/ruby/never', 'never',
250 'shebang line (#!) editing mode'),
251 BoolItem.new('without-ext', 'yes/no', 'no',
252 'does not compile/install ruby extensions')
255 private :standard_entries
257 def load_multipackage_entries
258 multipackage_entries().each do |ent|
263 def multipackage_entries
265 PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
266 'package names that you want to install'),
267 PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
268 'package names that you do not want to install')
271 private :multipackage_entries
274 'std-ruby' => 'librubyver',
275 'stdruby' => 'librubyver',
276 'rubylibdir' => 'librubyver',
277 'archdir' => 'librubyverarch',
278 'site-ruby-common' => 'siteruby', # For backward compatibility
279 'site-ruby' => 'siterubyver', # For backward compatibility
280 'bin-dir' => 'bindir',
283 'data-dir' => 'datadir',
284 'ruby-path' => 'rubypath',
285 'ruby-prog' => 'rubyprog',
286 'ruby' => 'rubyprog',
287 'make-prog' => 'makeprog',
292 ALIASES.each do |ali, name|
293 @table[ali] = @table[name]
297 @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
301 m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
309 def value_config?(name)
314 def initialize(name, template, default, desc)
323 attr_reader :description
325 attr_accessor :default
326 alias help_default default
329 "--#{@name}=#{@template}"
341 @value.gsub(%r<\$([^/]+)>) { table[$1] }
351 setup_rb_error "config: --#{name} requires argument" unless val
356 class BoolItem < Item
368 return 'yes' unless val
370 when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
371 when /\An(o)?\z/i, /\Af(alse)\z/i then 'no'
373 setup_rb_error "config: --#{@name} accepts only yes/no for argument"
378 class PathItem < Item
386 setup_rb_error "config: --#{@name} requires argument" unless path
387 path[0,1] == '$' ? path : File.expand_path(path)
391 class ProgramItem < Item
397 class SelectItem < Item
398 def initialize(name, selection, default, desc)
400 @ok = selection.split('/')
410 unless @ok.include?(val.strip)
411 setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
417 class ExecItem < Item
418 def initialize(name, selection, desc, &block)
419 super name, selection, nil, desc
420 @ok = selection.split('/')
433 setup_rb_error "$#{name()} wrongly used as option value"
438 def evaluate(val, table)
439 v = val.strip.downcase
440 unless @ok.include?(v)
441 setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
443 @action.call v, table
447 class PackageSelectionItem < Item
448 def initialize(name, template, default, help_default, desc)
449 super name, template, default, desc
450 @help_default = help_default
453 attr_reader :help_default
462 unless File.dir?("packages/#{val}")
463 setup_rb_error "config: no such package: #{val}"
469 class MetaConfigEnvironment
470 def initialize(config, installer)
472 @installer = installer
483 def bool_config?(name)
484 @config.lookup(name).config_type == 'bool'
487 def path_config?(name)
488 @config.lookup(name).config_type == 'path'
491 def value_config?(name)
492 @config.lookup(name).config_type != 'exec'
499 def add_bool_config(name, default, desc)
500 @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
503 def add_path_config(name, default, desc)
504 @config.add PathItem.new(name, 'path', default, desc)
507 def set_config_default(name, default)
508 @config.lookup(name).default = default
511 def remove_config(name)
515 # For only multipackage
517 raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
521 # For only multipackage
522 def declare_packages(list)
523 raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
524 @installer.packages = list
528 end # class ConfigTable
531 # This module requires: #verbose?, #no_harm?
532 module FileOperations
534 def mkdir_p(dirname, prefix = nil)
535 dirname = prefix + File.expand_path(dirname) if prefix
536 $stderr.puts "mkdir -p #{dirname}" if verbose?
539 # Does not check '/', it's too abnormal.
540 dirs = File.expand_path(dirname).split(%r<(?=/)>)
541 if /\A[a-z]:\z/i =~ dirs[0]
543 dirs[0] = disk + dirs[0]
545 dirs.each_index do |idx|
546 path = dirs[0..idx].join('')
547 Dir.mkdir path unless File.dir?(path)
552 $stderr.puts "rm -f #{path}" if verbose?
554 force_remove_file path
558 $stderr.puts "rm -rf #{path}" if verbose?
563 def remove_tree(path)
564 if File.symlink?(path)
566 elsif File.dir?(path)
569 force_remove_file path
573 def remove_tree0(path)
574 Dir.foreach(path) do |ent|
578 entpath = "#{path}/#{ent}"
579 if File.symlink?(entpath)
581 elsif File.dir?(entpath)
584 force_remove_file entpath
589 rescue Errno::ENOTEMPTY
590 # directory may not be empty
594 def move_file(src, dest)
595 force_remove_file dest
597 File.rename src, dest
599 File.open(dest, 'wb') { |f| f.write File.binread(src) }
600 File.chmod File.stat(src).mode, dest
605 def force_remove_file(path)
612 def remove_file(path)
613 File.chmod 0777, path
617 def install(from, dest, mode, prefix = nil)
618 $stderr.puts "install #{from} #{dest}" if verbose?
621 realdest = prefix ? prefix + File.expand_path(dest) : dest
622 realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
623 str = File.binread(from)
624 if diff?(str, realdest)
625 verbose_off { rm_f realdest if File.exist?(realdest) }
626 File.open(realdest, 'wb') { |f| f.write str }
627 File.chmod mode, realdest
629 File.open("#{objdir_root()}/InstalledFiles", 'a') do |f|
631 f.puts realdest.sub(prefix, '')
639 def diff?(new_content, path)
640 return true unless File.exist?(path)
642 new_content != File.binread(path)
646 $stderr.puts args.join(' ') if verbose?
647 system(*args) or raise RuntimeError,
648 "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
652 command config('rubyprog'), *args
656 command(*[config('makeprog'), task].compact)
660 File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
664 Dir.open(dir) { |d| return d.select { |ent| File.file?("#{dir}/#{ent}") } }
667 DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
669 def directories_of(dir)
670 Dir.open(dir) { |d| return d.select { |ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT }
675 # This module requires: #srcdir_root, #objdir_root, #relpath
682 alias config get_config
684 # obsolete: use metaconfig to change configuration
685 def set_config(key, val)
690 # srcdir/objdir (works only in the package directory)
694 "#{srcdir_root()}/#{relpath()}"
698 "#{objdir_root()}/#{relpath()}"
702 "#{curr_srcdir()}/#{path}"
706 File.exist?(srcfile(path))
709 def srcdirectory?(path)
710 File.dir?(srcfile(path))
714 File.file?(srcfile(path))
717 def srcentries(path = '.')
718 Dir.open("#{curr_srcdir()}/#{path}") { |d| return d.to_a - %w(. ..) }
721 def srcfiles(path = '.')
722 srcentries(path).select { |fname| File.file?(File.join(curr_srcdir(), path, fname)) }
725 def srcdirectories(path = '.')
726 srcentries(path).select { |fname| File.dir?(File.join(curr_srcdir(), path, fname)) }
731 class ToplevelInstaller
734 Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
737 ['all', 'do config, setup, then install'],
738 ['config', 'saves your configurations'],
739 ['show', 'shows current configuration'],
740 ['setup', 'compiles ruby extensions and others'],
741 ['install', 'installs files'],
742 ['test', 'run all tests in test/'],
743 ['clean', "does `make clean' for each extension"],
744 ['distclean', "does `make distclean' for each extension"]
747 def ToplevelInstaller.invoke
748 config = ConfigTable.new(load_rbconfig())
749 config.load_standard_entries
750 config.load_multipackage_entries if multipackage?
752 klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
753 klass.new(File.dirname($PROGRAM_NAME), config).invoke
756 def ToplevelInstaller.multipackage?
757 File.dir?("#{File.dirname($PROGRAM_NAME)}/packages")
760 def ToplevelInstaller.load_rbconfig
761 if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
763 load File.expand_path(arg.split(/=/, 2)[1])
764 $LOADED_FEATURES.push 'rbconfig.rb'
771 def initialize(ardir_root, config)
772 @ardir = File.expand_path(ardir_root)
783 "#<#{self.class} #{__id__()}>"
788 case task = parsearg_global()
797 when 'config', 'test'
799 when 'clean', 'distclean'
800 @config.load_savefile if File.exist?(@config.savefile)
802 @config.load_savefile
804 __send__ "parsearg_#{task}"
806 __send__ "exec_#{task}"
811 @config.load_script "#{@ardir}/metaconfig"
815 @installer = Installer.new(@config, @ardir, File.expand_path('.'))
819 # Hook Script API bases
839 while (arg = ARGV.shift)
842 setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
845 @config.verbose = false
847 @config.verbose = true
852 puts "#{File.basename($PROGRAM_NAME)} version #{Version}"
858 setup_rb_error "unknown global option '#{arg}'"
869 @valid_task_re ||= /\A(?:#{TASKS.map { |task,desc| task }.join('|')})\z/
872 def parsearg_no_options
874 task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
875 setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
879 alias parsearg_show parsearg_no_options
880 alias parsearg_setup parsearg_no_options
881 alias parsearg_test parsearg_no_options
882 alias parsearg_clean parsearg_no_options
883 alias parsearg_distclean parsearg_no_options
888 @config.config_opt = []
889 while (i = ARGV.shift)
891 @config.config_opt = ARGV.dup
894 name, value = *@config.parse_opt(i)
895 if @config.value_config?(name)
896 @config[name] = value
898 evalopt.push [name, value]
902 evalopt.each do |name, value|
903 @config.lookup(name).evaluate value, @config
905 # Check if configuration is valid
907 @config[n] if @config.value_config?(n)
912 @config.no_harm = false
913 @config.install_prefix = ''
914 while (a = ARGV.shift)
917 @config.no_harm = true
919 path = a.split(/=/, 2)[1]
920 path = File.expand_path(path) unless path[0,1] == '/'
921 @config.install_prefix = path
923 setup_rb_error "install: unknown option #{a}"
929 out.puts 'Typical Installation Procedure:'
930 out.puts " $ ruby #{File.basename $PROGRAM_NAME} config"
931 out.puts " $ ruby #{File.basename $PROGRAM_NAME} setup"
932 out.puts " # ruby #{File.basename $PROGRAM_NAME} install (may require root privilege)"
934 out.puts 'Detailed Usage:'
935 out.puts " ruby #{File.basename $PROGRAM_NAME} <global option>"
936 out.puts " ruby #{File.basename $PROGRAM_NAME} [<global options>] <task> [<task options>]"
940 out.puts 'Global options:'
941 out.printf fmt, '-q,--quiet', 'suppress message outputs'
942 out.printf fmt, ' --verbose', 'output messages verbosely'
943 out.printf fmt, ' --help', 'print this message'
944 out.printf fmt, ' --version', 'print version and quit'
945 out.printf fmt, ' --copyright', 'print copyright and quit'
948 TASKS.each do |name, desc|
949 out.printf fmt, name, desc
952 fmt = " %-24s %s [%s]\n"
954 out.puts 'Options for CONFIG or ALL:'
955 @config.each do |item|
956 out.printf fmt, item.help_opt, item.description, item.help_default
958 out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
960 out.puts 'Options for INSTALL:'
961 out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
962 out.printf fmt, '--prefix=path', 'install path prefix', ''
971 @installer.exec_config
972 @config.save # must be final
976 @installer.exec_setup
980 @installer.exec_install
989 printf "%-20s %s\n", i.name, i.value if i.value?
994 @installer.exec_clean
998 @installer.exec_distclean
1000 end # class ToplevelInstaller
1003 class ToplevelInstallerMulti < ToplevelInstaller
1005 include FileOperations
1007 def initialize(ardir_root, config)
1009 @packages = directories_of("#{@ardir}/packages")
1010 raise 'no package exists' if @packages.empty?
1012 @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
1016 @config.load_script "#{@ardir}/metaconfig", self
1017 @packages.each do |name|
1018 @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
1022 attr_reader :packages
1025 raise 'package list is empty' if list.empty?
1028 raise "directory packages/#{name} does not exist"\
1029 unless File.dir?("#{@ardir}/packages/#{name}")
1036 @packages.each do |pack|
1037 @installers[pack] = Installer.new(@config,
1038 "#{@ardir}/packages/#{pack}",
1041 with = extract_selection(config('with'))
1042 without = extract_selection(config('without'))
1043 @selected = @installers.keys.select do |name|
1044 (with.empty? or with.include?(name)) and not without.include?(name)
1048 def extract_selection(list)
1051 setup_rb_error "no such package: #{name}" unless @installers.key?(name)
1058 f.puts 'Inluded packages:'
1059 f.puts ' ' + @packages.sort.join(' ')
1068 run_hook 'pre-config'
1069 each_selected_installers {|inst| inst.exec_config }
1070 run_hook 'post-config'
1071 @config.save # must be final
1075 run_hook 'pre-setup'
1076 each_selected_installers {|inst| inst.exec_setup }
1077 run_hook 'post-setup'
1081 run_hook 'pre-install'
1082 each_selected_installers {|inst| inst.exec_install }
1083 run_hook 'post-install'
1088 each_selected_installers {|inst| inst.exec_test }
1089 run_hook 'post-test'
1093 rm_f @config.savefile
1094 run_hook 'pre-clean'
1095 each_selected_installers {|inst| inst.exec_clean }
1096 run_hook 'post-clean'
1100 rm_f @config.savefile
1101 run_hook 'pre-distclean'
1102 each_selected_installers {|inst| inst.exec_distclean }
1103 run_hook 'post-distclean'
1110 def each_selected_installers
1111 Dir.mkdir 'packages' unless File.dir?('packages')
1112 @selected.each do |pack|
1113 $stderr.puts "Processing the package `#{pack}' ..." if verbose?
1114 Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
1115 Dir.chdir "packages/#{pack}"
1116 yield @installers[pack]
1122 @root_installer.run_hook id
1125 # module FileOperations requires this
1130 # module FileOperations requires this
1134 end # class ToplevelInstallerMulti
1139 FILETYPES = %w( bin lib ext data conf man )
1141 include FileOperations
1142 include HookScriptAPI
1144 def initialize(config, srcroot, objroot)
1146 @srcdir = File.expand_path(srcroot)
1147 @objdir = File.expand_path(objroot)
1152 "#<#{self.class} #{File.basename(@srcdir)}>"
1159 # Hook Script API base methods
1178 # module FileOperations requires this
1183 # module FileOperations requires this
1190 save, @config.verbose = @config.verbose?, false
1193 @config.verbose = save
1202 exec_task_traverse 'config'
1205 alias config_dir_bin noop
1206 alias config_dir_lib noop
1208 def config_dir_ext(rel)
1209 extconf if extdir?(curr_srcdir())
1212 alias config_dir_data noop
1213 alias config_dir_conf noop
1214 alias config_dir_man noop
1217 ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
1225 exec_task_traverse 'setup'
1228 def setup_dir_bin(rel)
1229 files_of(curr_srcdir()).each do |fname|
1230 update_shebang_line "#{curr_srcdir()}/#{fname}"
1234 alias setup_dir_lib noop
1236 def setup_dir_ext(rel)
1237 make if extdir?(curr_srcdir())
1240 alias setup_dir_data noop
1241 alias setup_dir_conf noop
1242 alias setup_dir_man noop
1244 def update_shebang_line(path)
1246 return if config('shebang') == 'never'
1248 old = Shebang.load(path)
1250 $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
1251 new = new_shebang(old)
1252 return if new.to_s == old.to_s
1254 return unless config('shebang') == 'all'
1256 new = Shebang.new(config('rubypath'))
1258 $stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
1259 open_atomic_writer(path) do |output|
1260 File.open(path, 'rb') do |f|
1261 f.gets if old # discard
1262 output.puts new.to_s
1268 def new_shebang(old)
1269 if /\Aruby/ =~ File.basename(old.cmd)
1270 Shebang.new(config('rubypath'), old.args)
1271 elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
1272 Shebang.new(config('rubypath'), old.args[1..-1])
1274 return old unless config('shebang') == 'all'
1276 Shebang.new(config('rubypath'))
1280 def open_atomic_writer(path, &block)
1281 tmpfile = "#{File.basename(path)}.tmp"
1283 File.open(tmpfile, 'wb', &block)
1284 File.rename tmpfile, File.basename(path)
1286 File.unlink tmpfile if File.exist?(tmpfile)
1291 def Shebang.load(path)
1293 File.open(path) { |f| line = f.gets }
1294 return nil unless /\A#!/ =~ line
1299 def Shebang.parse(line)
1300 cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
1304 def initialize(cmd, args = [])
1313 "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
1322 rm_f 'InstalledFiles'
1323 exec_task_traverse 'install'
1326 def install_dir_bin(rel)
1327 install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
1330 def install_dir_lib(rel)
1331 install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
1334 def install_dir_ext(rel)
1335 return unless extdir?(curr_srcdir())
1336 install_files rubyextensions('.'),
1337 "#{config('sodir')}/#{File.dirname(rel)}",
1341 def install_dir_data(rel)
1342 install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
1345 def install_dir_conf(rel)
1346 # FIXME: should not remove current config files
1347 # (rename previous file to .old/.org)
1348 install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
1351 def install_dir_man(rel)
1352 install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
1355 def install_files(list, dest, mode)
1356 mkdir_p dest, @config.install_prefix
1357 list.each do |fname|
1358 install fname, dest, mode, @config.install_prefix
1363 glob_reject(%w(*.y *.output), targetfiles())
1366 def rubyextensions(dir)
1367 ents = glob_select("*.#{@config.dllext}", targetfiles())
1369 setup_rb_error "no ruby extension exists: 'ruby #{$PROGRAM_NAME} setup' first"
1375 mapdir(existfiles() - hookfiles())
1382 else "#{curr_srcdir()}/#{ent}" # srcdir
1387 # picked up many entries from cvs-1.11.1/src/ignore.c
1389 core RCSLOG tags TAGS .make.state
1390 .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1391 *~ *.old *.bak *.BAK *.orig *.rej _$* *$
1397 glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
1401 %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map { |fmt|
1402 %w( config setup install clean ).map {|t| sprintf(fmt, t) }
1406 def glob_select(pat, ents)
1407 re = globs2re([pat])
1408 ents.select { |ent| re =~ ent }
1411 def glob_reject(pats, ents)
1413 ents.reject { |ent| re =~ ent }
1425 pats.map { |pat| pat.gsub(/[\.\$\#\*]/) { |ch| GLOB2REGEX[ch] } }.join('|')
1436 unless File.directory?('test')
1437 $stderr.puts 'no test in this package' if verbose?
1440 $stderr.puts 'Running tests...' if verbose?
1444 setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.'
1446 runner = Test::Unit::AutoRunner.new(true)
1447 runner.to_run << TESTDIR
1456 exec_task_traverse 'clean'
1457 rm_f @config.savefile
1458 rm_f 'InstalledFiles'
1461 alias clean_dir_bin noop
1462 alias clean_dir_lib noop
1463 alias clean_dir_data noop
1464 alias clean_dir_conf noop
1465 alias clean_dir_man noop
1467 def clean_dir_ext(rel)
1468 return unless extdir?(curr_srcdir())
1469 make 'clean' if File.file?('Makefile')
1477 exec_task_traverse 'distclean'
1478 rm_f @config.savefile
1479 rm_f 'InstalledFiles'
1482 alias distclean_dir_bin noop
1483 alias distclean_dir_lib noop
1485 def distclean_dir_ext(rel)
1486 return unless extdir?(curr_srcdir())
1487 make 'distclean' if File.file?('Makefile')
1490 alias distclean_dir_data noop
1491 alias distclean_dir_conf noop
1492 alias distclean_dir_man noop
1498 def exec_task_traverse(task)
1499 run_hook "pre-#{task}"
1500 FILETYPES.each do |type|
1501 if type == 'ext' and config('without-ext') == 'yes'
1502 $stderr.puts 'skipping ext/* by user option' if verbose?
1505 traverse task, type, "#{task}_dir_#{type}"
1507 run_hook "post-#{task}"
1510 def traverse(task, rel, mid)
1512 run_hook "pre-#{task}"
1513 __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
1514 directories_of(curr_srcdir()).each do |d|
1515 traverse task, "#{rel}/#{d}", mid
1517 run_hook "post-#{task}"
1522 return unless File.dir?("#{@srcdir}/#{rel}")
1524 dir = File.basename(rel)
1525 Dir.mkdir dir unless File.dir?(dir)
1528 $stderr.puts "---> #{rel}" if verbose?
1532 $stderr.puts "<--- #{rel}" if verbose?
1533 @currdir = File.dirname(rel)
1537 path = [ "#{curr_srcdir()}/#{id}",
1538 "#{curr_srcdir()}/#{id}.rb" ].detect { |cand| File.file?(cand) }
1542 instance_eval File.read(path), path, 1
1546 setup_rb_error "hook #{path} failed:\n" + $!.message
1549 end # class Installer
1552 class SetupError < StandardError; end
1554 def setup_rb_error(msg)
1555 raise SetupError, msg
1558 if $PROGRAM_NAME == __FILE__
1560 ToplevelInstaller.invoke
1564 $stderr.puts $!.message
1565 $stderr.puts "Try 'ruby #{$PROGRAM_NAME} --help' for detailed usage."