4 # Copyright (c) 2000-2004 Minero Aoki
6 # Permission is hereby granted, free of charge, to any person obtaining
7 # a copy of this software and associated documentation files (the
8 # "Software"), to deal in the Software without restriction, including
9 # without limitation the rights to use, copy, modify, merge, publish,
10 # distribute, sublicense, and/or sell copies of the Software, and to
11 # permit persons to whom the Software is furnished to do so, subject to
12 # the following conditions:
14 # The above copyright notice and this permission notice shall be
15 # included in all copies or substantial portions of the Software.
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
26 # with permission of Minero Aoki.
30 unless Enumerable.method_defined?(:map) # Ruby 1.4.6
36 unless File.respond_to?(:read) # Ruby 1.6
44 def File.binread(fname)
45 open(fname, 'rb') {|f|
50 # for corrupted windows stat(2)
52 File.directory?((path[-1,1] == '/') ? path : path + '/')
56 class SetupError < StandardError; end
58 def setup_rb_error(msg)
66 if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
68 require arg.split(/=/, 2)[1]
74 def multipackage_install?
75 FileTest.directory?(File.dirname($0) + '/packages')
80 def initialize(name, template, default, desc)
84 @default = default.dup.freeze
89 attr_reader :description
91 attr_accessor :default
92 alias help_default default
95 "--#{@name}=#{@template}"
103 @value.gsub(%r<\$([^/]+)>) { table[$1] }
113 setup_rb_error "config: --#{name} requires argument" unless val
118 class BoolItem < ConfigItem
130 return 'yes' unless val
131 unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val
132 setup_rb_error "config: --#{@name} accepts only yes/no for argument"
134 (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no'
138 class PathItem < ConfigItem
146 setup_rb_error "config: --#{@name} requires argument" unless path
147 path[0,1] == '$' ? path : File.expand_path(path)
151 class ProgramItem < ConfigItem
157 class SelectItem < ConfigItem
158 def initialize(name, template, default, desc)
160 @ok = template.split('/')
170 unless @ok.include?(val.strip)
171 setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
177 class PackageSelectionItem < ConfigItem
178 def initialize(name, template, default, help_default, desc)
179 super name, template, default, desc
180 @help_default = help_default
183 attr_reader :help_default
192 unless File.dir?("packages/#{val}")
193 setup_rb_error "config: no such package: #{val}"
199 class ConfigTable_class
201 def initialize(items)
207 ALIASES.each do |ali, name|
208 @table[ali] = @table[name]
223 @table[name] or raise ArgumentError, "no such config item: #{name}"
228 @table[item.name] = item
233 @items.delete_if {|i| i.name == name }
234 @table.delete_if {|name, i| i.name == name }
249 File.foreach(savefile()) do |line|
250 k, v = *line.split(/=/, 2)
255 setup_rb_error $!.message + "#{File.basename($0)} config first"
260 @items.each {|i| i.value }
261 File.open(savefile(), 'w') {|f|
263 f.printf "%s=%s\n", i.name, i.value if i.value
269 lookup(key).eval(self)
280 rubypath = c['bindir'] + '/' + c['ruby_install_name']
282 major = c['MAJOR'].to_i
283 minor = c['MINOR'].to_i
284 teeny = c['TEENY'].to_i
285 version = "#{major}.#{minor}"
287 # ruby ver. >= 1.4.4?
288 newpath_p = ((major >= 2) or
291 ((minor == 4) and (teeny >= 4)))))
295 _stdruby = c['rubylibdir']
296 _siteruby = c['sitedir']
297 _siterubyver = c['sitelibdir']
298 _siterubyverarch = c['sitearchdir']
300 # 1.4.4 <= V <= 1.6.3
301 _stdruby = "$prefix/lib/ruby/#{version}"
302 _siteruby = c['sitedir']
303 _siterubyver = "$siteruby/#{version}"
304 _siterubyverarch = "$siterubyver/#{c['arch']}"
307 _stdruby = "$prefix/lib/ruby/#{version}"
308 _siteruby = "$prefix/lib/ruby/#{version}/site_ruby"
309 _siterubyver = _siteruby
310 _siterubyverarch = "$siterubyver/#{c['arch']}"
312 libdir = '-* dummy libdir *-'
313 stdruby = '-* dummy rubylibdir *-'
314 siteruby = '-* dummy site_ruby *-'
315 siterubyver = '-* dummy site_ruby version *-'
316 parameterize = lambda {|path|
317 path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\
318 .sub(/\A#{Regexp.quote(libdir)}/, '$libdir')\
319 .sub(/\A#{Regexp.quote(stdruby)}/, '$stdruby')\
320 .sub(/\A#{Regexp.quote(siteruby)}/, '$siteruby')\
321 .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver')
323 libdir = parameterize.call(c['libdir'])
324 stdruby = parameterize.call(_stdruby)
325 siteruby = parameterize.call(_siteruby)
326 siterubyver = parameterize.call(_siterubyver)
327 siterubyverarch = parameterize.call(_siterubyverarch)
329 if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
330 makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
336 PathItem.new('prefix', 'path', c['prefix'],
337 'path prefix of target environment'),
338 PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
339 'the directory for commands'),
340 PathItem.new('libdir', 'path', libdir,
341 'the directory for libraries'),
342 PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
343 'the directory for shared data'),
344 PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
345 'the directory for man pages'),
346 PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
347 'the directory for man pages'),
348 PathItem.new('stdruby', 'path', stdruby,
349 'the directory for standard ruby libraries'),
350 PathItem.new('siteruby', 'path', siteruby,
351 'the directory for version-independent aux ruby libraries'),
352 PathItem.new('siterubyver', 'path', siterubyver,
353 'the directory for aux ruby libraries'),
354 PathItem.new('siterubyverarch', 'path', siterubyverarch,
355 'the directory for aux ruby binaries'),
356 PathItem.new('rbdir', 'path', '$siterubyver',
357 'the directory for ruby scripts'),
358 PathItem.new('sodir', 'path', '$siterubyverarch',
359 'the directory for ruby extentions'),
360 PathItem.new('rubypath', 'path', rubypath,
361 'the path to set to #! line'),
362 ProgramItem.new('rubyprog', 'name', rubypath,
363 'the ruby program using for installation'),
364 ProgramItem.new('makeprog', 'name', makeprog,
365 'the make program to compile ruby extentions'),
366 SelectItem.new('shebang', 'all/ruby/never', 'ruby',
367 'shebang line (#!) editing mode'),
368 BoolItem.new('without-ext', 'yes/no', 'no',
369 'does not compile/install ruby extentions')
371 class ConfigTable_class # open again
373 'std-ruby' => 'stdruby',
374 'site-ruby-common' => 'siteruby', # For backward compatibility
375 'site-ruby' => 'siterubyver', # For backward compatibility
376 'bin-dir' => 'bindir',
377 'bin-dir' => 'bindir',
380 'data-dir' => 'datadir',
381 'ruby-path' => 'rubypath',
382 'ruby-prog' => 'rubyprog',
383 'ruby' => 'rubyprog',
384 'make-prog' => 'makeprog',
388 multipackage_conf = [
389 PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
390 'package names that you want to install'),
391 PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
392 'package names that you do not want to install')
394 if multipackage_install?
395 ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf)
397 ConfigTable = ConfigTable_class.new(common_conf)
403 def eval_file_ifexist(fname)
404 instance_eval File.read(fname), fname, 1 if File.file?(fname)
408 ConfigTable.map {|i| i.name }
412 ConfigTable.key?(name)
415 def bool_config?(name)
416 ConfigTable.lookup(name).config_type == 'bool'
419 def path_config?(name)
420 ConfigTable.lookup(name).config_type == 'path'
423 def value_config?(name)
424 case ConfigTable.lookup(name).config_type
436 def add_bool_config(name, default, desc)
437 ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
440 def add_path_config(name, default, desc)
441 ConfigTable.add PathItem.new(name, 'path', default, desc)
444 def set_config_default(name, default)
445 ConfigTable.lookup(name).default = default
448 def remove_config(name)
449 ConfigTable.remove(name)
459 module FileOperations
461 def mkdir_p(dirname, prefix = nil)
462 dirname = prefix + File.expand_path(dirname) if prefix
463 $stderr.puts "mkdir -p #{dirname}" if verbose?
466 # does not check '/'... it's too abnormal case
467 dirs = File.expand_path(dirname).split(%r<(?=/)>)
468 if /\A[a-z]:\z/i =~ dirs[0]
470 dirs[0] = disk + dirs[0]
472 dirs.each_index do |idx|
473 path = dirs[0..idx].join('')
474 Dir.mkdir path unless File.dir?(path)
479 $stderr.puts "rm -f #{fname}" if verbose?
482 if File.exist?(fname) or File.symlink?(fname)
483 File.chmod 0777, fname
489 $stderr.puts "rm -rf #{dn}" if verbose?
493 Dir.foreach('.') do |fn|
510 def move_file(src, dest)
511 File.unlink dest if File.exist?(dest)
513 File.rename src, dest
515 File.open(dest, 'wb') {|f| f.write File.binread(src) }
516 File.chmod File.stat(src).mode, dest
521 def install(from, dest, mode, prefix = nil)
522 $stderr.puts "install #{from} #{dest}" if verbose?
525 realdest = prefix ? prefix + File.expand_path(dest) : dest
526 realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
527 str = File.binread(from)
528 if diff?(str, realdest)
530 rm_f realdest if File.exist?(realdest)
532 File.open(realdest, 'wb') {|f|
535 File.chmod mode, realdest
537 File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
539 f.puts realdest.sub(prefix, '')
547 def diff?(new_content, path)
548 return true unless File.exist?(path)
549 new_content != File.binread(path)
553 $stderr.puts str if verbose?
554 system str or raise RuntimeError, "'system #{str}' failed"
558 command config('rubyprog') + ' ' + str
562 command config('makeprog') + ' ' + task
566 File.exist?(dir + '/MANIFEST')
569 def all_files_in(dirname)
570 Dir.open(dirname) {|d|
571 return d.select {|ent| File.file?("#{dirname}/#{ent}") }
576 CVS SCCS RCS CVS.adm .svn
579 def all_dirs_in(dirname)
580 Dir.open(dirname) {|d|
581 return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS
595 try_run_hook "#{curr_srcdir()}/#{name}" or
596 try_run_hook "#{curr_srcdir()}/#{name}.rb"
599 def try_run_hook(fname)
600 return false unless File.file?(fname)
602 instance_eval File.read(fname), fname, 1
604 setup_rb_error "hook #{fname} failed:\n" + $!.message
618 alias config get_config
620 def set_config(key, val)
625 # srcdir/objdir (works only in the package directory)
628 #abstract srcdir_root
629 #abstract objdir_root
633 "#{srcdir_root()}/#{relpath()}"
637 "#{objdir_root()}/#{relpath()}"
641 "#{curr_srcdir()}/#{path}"
645 File.exist?(srcfile(path))
648 def srcdirectory?(path)
649 File.dir?(srcfile(path))
653 File.file? srcfile(path)
656 def srcentries(path = '.')
657 Dir.open("#{curr_srcdir()}/#{path}") {|d|
658 return d.to_a - %w(. ..)
662 def srcfiles(path = '.')
663 srcentries(path).select {|fname|
664 File.file?(File.join(curr_srcdir(), path, fname))
668 def srcdirectories(path = '.')
669 srcentries(path).select {|fname|
670 File.dir?(File.join(curr_srcdir(), path, fname))
677 class ToplevelInstaller
680 Copyright = 'Copyright (c) 2000-2004 Minero Aoki'
683 [ 'all', 'do config, setup, then install' ],
684 [ 'config', 'saves your configurations' ],
685 [ 'show', 'shows current configuration' ],
686 [ 'setup', 'compiles ruby extentions and others' ],
687 [ 'install', 'installs files' ],
688 [ 'clean', "does `make clean' for each extention" ],
689 [ 'distclean',"does `make distclean' for each extention" ]
692 def ToplevelInstaller.invoke
698 def ToplevelInstaller.instance
699 @singleton ||= new(File.dirname($0))
703 include MetaConfigAPI
705 def initialize(ardir_root)
707 @options = { 'verbose' => true }
708 @ardir = File.expand_path(ardir_root)
712 "#<#{self.class} #{__id__()}>"
717 case task = parsearg_global()
719 @config = load_config('config')
726 @config = load_config(task)
727 __send__ "parsearg_#{task}"
729 __send__ "exec_#{task}"
734 eval_file_ifexist "#{@ardir}/metaconfig"
737 def load_config(task)
741 when 'clean', 'distclean'
742 if File.exist?(ConfigTable.savefile)
743 then ConfigTable.load
752 @installer = Installer.new(@config, @options, @ardir, File.expand_path('.'))
756 # Hook Script API bases
776 valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/
778 while arg = ARGV.shift
781 setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg
785 @options['verbose'] = false
788 @options['verbose'] = true
794 when '-v', '--version'
795 puts "#{File.basename($0)} version #{Version}"
803 setup_rb_error "unknown global option '#{arg}'"
811 def parsearg_no_options
813 setup_rb_error "#{task}: unknown options: #{ARGV.join ' '}"
817 alias parsearg_show parsearg_no_options
818 alias parsearg_setup parsearg_no_options
819 alias parsearg_clean parsearg_no_options
820 alias parsearg_distclean parsearg_no_options
823 re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/
824 @options['config-opt'] = []
828 @options['config-opt'] = ARGV.dup
831 m = re.match(i) or setup_rb_error "config: unknown option #{i}"
832 name, value = *m.to_a[1,2]
833 @config[name] = value
838 @options['no-harm'] = false
839 @options['install-prefix'] = ''
843 @options['no-harm'] = true
844 when /\A--prefix=(.*)\z/
846 path = File.expand_path(path) unless path[0,1] == '/'
847 @options['install-prefix'] = path
849 setup_rb_error "install: unknown option #{a}"
855 out.puts 'Typical Installation Procedure:'
856 out.puts " $ ruby #{File.basename $0} config"
857 out.puts " $ ruby #{File.basename $0} setup"
858 out.puts " # ruby #{File.basename $0} install (may require root privilege)"
860 out.puts 'Detailed Usage:'
861 out.puts " ruby #{File.basename $0} <global option>"
862 out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
866 out.puts 'Global options:'
867 out.printf fmt, '-q,--quiet', 'suppress message outputs'
868 out.printf fmt, ' --verbose', 'output messages verbosely'
869 out.printf fmt, '-h,--help', 'print this message'
870 out.printf fmt, '-v,--version', 'print version and quit'
871 out.printf fmt, ' --copyright', 'print copyright and quit'
874 TASKS.each do |name, desc|
875 out.printf fmt, name, desc
878 fmt = " %-24s %s [%s]\n"
880 out.puts 'Options for CONFIG or ALL:'
881 ConfigTable.each do |item|
882 out.printf fmt, item.help_opt, item.description, item.help_default
884 out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
886 out.puts 'Options for INSTALL:'
887 out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
888 out.printf fmt, '--prefix=path', 'install path prefix', '$prefix'
897 @installer.exec_config
898 @config.save # must be final
902 @installer.exec_setup
906 @installer.exec_install
910 ConfigTable.each do |i|
911 printf "%-20s %s\n", i.name, i.value
916 @installer.exec_clean
920 @installer.exec_distclean
926 class ToplevelInstallerMulti < ToplevelInstaller
929 include HookScriptAPI
930 include FileOperations
932 def initialize(ardir)
934 @packages = all_dirs_in("#{@ardir}/packages")
935 raise 'no package exists' if @packages.empty?
939 eval_file_ifexist "#{@ardir}/metaconfig"
940 @packages.each do |name|
941 eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig"
947 @packages.each do |pack|
948 @installers[pack] = Installer.new(@config, @options,
949 "#{@ardir}/packages/#{pack}",
953 with = extract_selection(config('with'))
954 without = extract_selection(config('without'))
955 @selected = @installers.keys.select {|name|
956 (with.empty? or with.include?(name)) \
957 and not without.include?(name)
961 def extract_selection(list)
964 setup_rb_error "no such package: #{name}" unless @installers.key?(name)
971 f.puts 'Inluded packages:'
972 f.puts ' ' + @packages.sort.join(' ')
977 # multi-package metaconfig API
980 attr_reader :packages
982 def declare_packages(list)
983 raise 'package list is empty' if list.empty?
985 raise "directory packages/#{name} does not exist"\
986 unless File.dir?("#{@ardir}/packages/#{name}")
996 run_hook 'pre-config'
997 each_selected_installers {|inst| inst.exec_config }
998 run_hook 'post-config'
999 @config.save # must be final
1003 run_hook 'pre-setup'
1004 each_selected_installers {|inst| inst.exec_setup }
1005 run_hook 'post-setup'
1009 run_hook 'pre-install'
1010 each_selected_installers {|inst| inst.exec_install }
1011 run_hook 'post-install'
1015 rm_f ConfigTable.savefile
1016 run_hook 'pre-clean'
1017 each_selected_installers {|inst| inst.exec_clean }
1018 run_hook 'post-clean'
1022 rm_f ConfigTable.savefile
1023 run_hook 'pre-distclean'
1024 each_selected_installers {|inst| inst.exec_distclean }
1025 run_hook 'post-distclean'
1032 def each_selected_installers
1033 Dir.mkdir 'packages' unless File.dir?('packages')
1034 @selected.each do |pack|
1035 $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose']
1036 Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
1037 Dir.chdir "packages/#{pack}"
1038 yield @installers[pack]
1056 FILETYPES = %w( bin lib ext data )
1058 include HookScriptAPI
1060 include FileOperations
1062 def initialize(config, opt, srcroot, objroot)
1065 @srcdir = File.expand_path(srcroot)
1066 @objdir = File.expand_path(objroot)
1071 "#<#{self.class} #{File.basename(@srcdir)}>"
1075 # Hook Script API base methods
1104 save, @options['verbose'] = @options['verbose'], false
1107 @options['verbose'] = save
1116 exec_task_traverse 'config'
1119 def config_dir_bin(rel)
1122 def config_dir_lib(rel)
1125 def config_dir_ext(rel)
1126 extconf if extdir?(curr_srcdir())
1130 opt = @options['config-opt'].join(' ')
1131 command "#{config('rubyprog')} #{curr_srcdir()}/extconf.rb #{opt}"
1134 def config_dir_data(rel)
1142 exec_task_traverse 'setup'
1145 def setup_dir_bin(rel)
1146 all_files_in(curr_srcdir()).each do |fname|
1147 adjust_shebang "#{curr_srcdir()}/#{fname}"
1151 def adjust_shebang(path)
1153 tmpfile = File.basename(path) + '.tmp'
1155 File.open(path, 'rb') {|r|
1157 return unless File.basename(config('rubypath')) == 'ruby'
1158 return unless File.basename(first.sub(/\A\#!/, '').split[0]) == 'ruby'
1159 $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose?
1160 File.open(tmpfile, 'wb') {|w|
1161 w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath'))
1164 move_file tmpfile, File.basename(path)
1167 File.unlink tmpfile if File.exist?(tmpfile)
1171 def setup_dir_lib(rel)
1174 def setup_dir_ext(rel)
1175 make if extdir?(curr_srcdir())
1178 def setup_dir_data(rel)
1186 rm_f 'InstalledFiles'
1187 exec_task_traverse 'install'
1190 def install_dir_bin(rel)
1191 install_files collect_filenames_auto(), "#{config('bindir')}/#{rel}", 0755
1194 def install_dir_lib(rel)
1195 install_files ruby_scripts(), "#{config('rbdir')}/#{rel}", 0644
1198 def install_dir_ext(rel)
1199 return unless extdir?(curr_srcdir())
1200 install_files ruby_extentions('.'),
1201 "#{config('sodir')}/#{File.dirname(rel)}",
1205 def install_dir_data(rel)
1206 install_files collect_filenames_auto(), "#{config('datadir')}/#{rel}", 0644
1209 def install_files(list, dest, mode)
1210 mkdir_p dest, @options['install-prefix']
1211 list.each do |fname|
1212 install fname, dest, mode, @options['install-prefix']
1217 collect_filenames_auto().select {|n| /\.rb\z/ =~ n }
1220 # picked up many entries from cvs-1.11.1/src/ignore.c
1221 reject_patterns = %w(
1222 core RCSLOG tags TAGS .make.state
1223 .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1224 *~ *.old *.bak *.BAK *.orig *.rej _$* *$
1234 REJECT_PATTERNS = Regexp.new('\A(?:' +
1235 reject_patterns.map {|pat|
1236 pat.gsub(/[\.\$\#\*]/) {|ch| mapping[ch] }
1240 def collect_filenames_auto
1241 mapdir((existfiles() - hookfiles()).reject {|fname|
1242 REJECT_PATTERNS =~ fname
1247 all_files_in(curr_srcdir()) | all_files_in('.')
1251 %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
1252 %w( config setup install clean ).map {|t| sprintf(fmt, t) }
1256 def mapdir(filelist)
1257 filelist.map {|fname|
1258 if File.exist?(fname) # objdir
1261 File.join(curr_srcdir(), fname)
1266 def ruby_extentions(dir)
1268 ents = d.select {|fname| /\.#{::Config::CONFIG['DLEXT']}\z/ =~ fname }
1270 setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
1281 exec_task_traverse 'clean'
1282 rm_f ConfigTable.savefile
1283 rm_f 'InstalledFiles'
1286 def clean_dir_bin(rel)
1289 def clean_dir_lib(rel)
1292 def clean_dir_ext(rel)
1293 return unless extdir?(curr_srcdir())
1294 make 'clean' if File.file?('Makefile')
1297 def clean_dir_data(rel)
1305 exec_task_traverse 'distclean'
1306 rm_f ConfigTable.savefile
1307 rm_f 'InstalledFiles'
1310 def distclean_dir_bin(rel)
1313 def distclean_dir_lib(rel)
1316 def distclean_dir_ext(rel)
1317 return unless extdir?(curr_srcdir())
1318 make 'distclean' if File.file?('Makefile')
1325 def exec_task_traverse(task)
1326 run_hook "pre-#{task}"
1327 FILETYPES.each do |type|
1328 if config('without-ext') == 'yes' and type == 'ext'
1329 $stderr.puts 'skipping ext/* by user option' if verbose?
1332 traverse task, type, "#{task}_dir_#{type}"
1334 run_hook "post-#{task}"
1337 def traverse(task, rel, mid)
1339 run_hook "pre-#{task}"
1340 __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
1341 all_dirs_in(curr_srcdir()).each do |d|
1342 traverse task, "#{rel}/#{d}", mid
1344 run_hook "post-#{task}"
1349 return unless File.dir?("#{@srcdir}/#{rel}")
1351 dir = File.basename(rel)
1352 Dir.mkdir dir unless File.dir?(dir)
1355 $stderr.puts '---> ' + rel if verbose?
1359 $stderr.puts '<--- ' + rel if verbose?
1360 @currdir = File.dirname(rel)
1368 if multipackage_install?
1369 ToplevelInstallerMulti.invoke
1371 ToplevelInstaller.invoke
1375 $stderr.puts $!.message
1376 $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."