4 # Copyright (c) 2000-2004 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 def File.binread(fname)
26 open(fname, 'rb') {|f|
31 # for corrupted windows stat(2)
33 File.directory?((path[-1,1] == '/') ? path : path + '/')
37 class SetupError < StandardError; end
39 def setup_rb_error(msg)
47 if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
49 require arg.split(/=/, 2)[1]
55 def multipackage_install?
56 FileTest.directory?(File.dirname($0) + '/packages')
61 def initialize(name, template, default, desc)
65 @default = default.dup.freeze
70 attr_reader :description
72 attr_accessor :default
73 alias help_default default
76 "--#{@name}=#{@template}"
84 @value.gsub(%r<\$([^/]+)>) { table[$1] }
94 setup_rb_error "config: --#{name} requires argument" unless val
99 class BoolItem < ConfigItem
111 return 'yes' unless val
112 unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val
113 setup_rb_error "config: --#{@name} accepts only yes/no for argument"
115 (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no'
119 class PathItem < ConfigItem
127 setup_rb_error "config: --#{@name} requires argument" unless path
128 path[0,1] == '$' ? path : File.expand_path(path)
132 class ProgramItem < ConfigItem
138 class SelectItem < ConfigItem
139 def initialize(name, template, default, desc)
141 @ok = template.split('/')
151 unless @ok.include?(val.strip)
152 setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
158 class PackageSelectionItem < ConfigItem
159 def initialize(name, template, default, help_default, desc)
160 super name, template, default, desc
161 @help_default = help_default
164 attr_reader :help_default
173 unless File.dir?("packages/#{val}")
174 setup_rb_error "config: no such package: #{val}"
180 class ConfigTable_class
182 def initialize(items)
188 ALIASES.each do |ali, name|
189 @table[ali] = @table[name]
204 @table[name] or raise ArgumentError, "no such config item: #{name}"
209 @table[item.name] = item
214 @items.delete_if {|i| i.name == name }
215 @table.delete_if {|name, i| i.name == name }
230 File.foreach(savefile()) do |line|
231 k, v = *line.split(/=/, 2)
236 setup_rb_error $!.message + "#{File.basename($0)} config first"
241 @items.each {|i| i.value }
242 File.open(savefile(), 'w') {|f|
244 f.printf "%s=%s\n", i.name, i.value if i.value
250 lookup(key).eval(self)
261 rubypath = c['bindir'] + '/' + c['ruby_install_name']
263 major = c['MAJOR'].to_i
264 minor = c['MINOR'].to_i
265 teeny = c['TEENY'].to_i
266 version = "#{major}.#{minor}"
268 # ruby ver. >= 1.4.4?
269 newpath_p = ((major >= 2) or
272 ((minor == 4) and (teeny >= 4)))))
276 _stdruby = c['rubylibdir']
277 _siteruby = c['sitedir']
278 _siterubyver = c['sitelibdir']
279 _siterubyverarch = c['sitearchdir']
281 # 1.4.4 <= V <= 1.6.3
282 _stdruby = "$prefix/lib/ruby/#{version}"
283 _siteruby = c['sitedir']
284 _siterubyver = "$siteruby/#{version}"
285 _siterubyverarch = "$siterubyver/#{c['arch']}"
288 _stdruby = "$prefix/lib/ruby/#{version}"
289 _siteruby = "$prefix/lib/ruby/#{version}/site_ruby"
290 _siterubyver = _siteruby
291 _siterubyverarch = "$siterubyver/#{c['arch']}"
293 libdir = '-* dummy libdir *-'
294 stdruby = '-* dummy rubylibdir *-'
295 siteruby = '-* dummy site_ruby *-'
296 siterubyver = '-* dummy site_ruby version *-'
297 parameterize = lambda {|path|
298 path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\
299 .sub(/\A#{Regexp.quote(libdir)}/, '$libdir')\
300 .sub(/\A#{Regexp.quote(stdruby)}/, '$stdruby')\
301 .sub(/\A#{Regexp.quote(siteruby)}/, '$siteruby')\
302 .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver')
304 libdir = parameterize.call(c['libdir'])
305 stdruby = parameterize.call(_stdruby)
306 siteruby = parameterize.call(_siteruby)
307 siterubyver = parameterize.call(_siterubyver)
308 siterubyverarch = parameterize.call(_siterubyverarch)
310 if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
311 makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
317 PathItem.new('prefix', 'path', c['prefix'],
318 'path prefix of target environment'),
319 PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
320 'the directory for commands'),
321 PathItem.new('libdir', 'path', libdir,
322 'the directory for libraries'),
323 PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
324 'the directory for shared data'),
325 PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
326 'the directory for man pages'),
327 PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
328 'the directory for man pages'),
329 PathItem.new('stdruby', 'path', stdruby,
330 'the directory for standard ruby libraries'),
331 PathItem.new('siteruby', 'path', siteruby,
332 'the directory for version-independent aux ruby libraries'),
333 PathItem.new('siterubyver', 'path', siterubyver,
334 'the directory for aux ruby libraries'),
335 PathItem.new('siterubyverarch', 'path', siterubyverarch,
336 'the directory for aux ruby binaries'),
337 PathItem.new('rbdir', 'path', '$siterubyver',
338 'the directory for ruby scripts'),
339 PathItem.new('sodir', 'path', '$siterubyverarch',
340 'the directory for ruby extentions'),
341 PathItem.new('rubypath', 'path', rubypath,
342 'the path to set to #! line'),
343 ProgramItem.new('rubyprog', 'name', rubypath,
344 'the ruby program using for installation'),
345 ProgramItem.new('makeprog', 'name', makeprog,
346 'the make program to compile ruby extentions'),
347 SelectItem.new('shebang', 'all/ruby/never', 'ruby',
348 'shebang line (#!) editing mode'),
349 BoolItem.new('without-ext', 'yes/no', 'no',
350 'does not compile/install ruby extentions')
352 class ConfigTable_class # open again
354 'std-ruby' => 'stdruby',
355 'site-ruby-common' => 'siteruby', # For backward compatibility
356 'site-ruby' => 'siterubyver', # For backward compatibility
357 'bin-dir' => 'bindir',
358 'bin-dir' => 'bindir',
361 'data-dir' => 'datadir',
362 'ruby-path' => 'rubypath',
363 'ruby-prog' => 'rubyprog',
364 'ruby' => 'rubyprog',
365 'make-prog' => 'makeprog',
369 multipackage_conf = [
370 PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
371 'package names that you want to install'),
372 PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
373 'package names that you do not want to install')
375 if multipackage_install?
376 ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf)
378 ConfigTable = ConfigTable_class.new(common_conf)
384 def eval_file_ifexist(fname)
385 instance_eval File.read(fname), fname, 1 if File.file?(fname)
389 ConfigTable.map {|i| i.name }
393 ConfigTable.key?(name)
396 def bool_config?(name)
397 ConfigTable.lookup(name).config_type == 'bool'
400 def path_config?(name)
401 ConfigTable.lookup(name).config_type == 'path'
404 def value_config?(name)
405 case ConfigTable.lookup(name).config_type
417 def add_bool_config(name, default, desc)
418 ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
421 def add_path_config(name, default, desc)
422 ConfigTable.add PathItem.new(name, 'path', default, desc)
425 def set_config_default(name, default)
426 ConfigTable.lookup(name).default = default
429 def remove_config(name)
430 ConfigTable.remove(name)
440 module FileOperations
442 def mkdir_p(dirname, prefix = nil)
443 dirname = prefix + File.expand_path(dirname) if prefix
444 $stderr.puts "mkdir -p #{dirname}" if verbose?
447 # does not check '/'... it's too abnormal case
448 dirs = File.expand_path(dirname).split(%r<(?=/)>)
449 if /\A[a-z]:\z/i =~ dirs[0]
451 dirs[0] = disk + dirs[0]
453 dirs.each_index do |idx|
454 path = dirs[0..idx].join('')
455 Dir.mkdir path unless File.dir?(path)
460 $stderr.puts "rm -f #{fname}" if verbose?
463 if File.exist?(fname) or File.symlink?(fname)
464 File.chmod 0777, fname
470 $stderr.puts "rm -rf #{dn}" if verbose?
474 Dir.foreach('.') do |fn|
491 def move_file(src, dest)
492 File.unlink dest if File.exist?(dest)
494 File.rename src, dest
496 File.open(dest, 'wb') {|f| f.write File.binread(src) }
497 File.chmod File.stat(src).mode, dest
502 def install(from, dest, mode, prefix = nil)
503 $stderr.puts "install #{from} #{dest}" if verbose?
506 realdest = prefix ? prefix + File.expand_path(dest) : dest
507 realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
508 str = File.binread(from)
509 if diff?(str, realdest)
511 rm_f realdest if File.exist?(realdest)
513 File.open(realdest, 'wb') {|f|
516 File.chmod mode, realdest
518 File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
520 f.puts realdest.sub(prefix, '')
528 def diff?(new_content, path)
529 return true unless File.exist?(path)
530 new_content != File.binread(path)
534 $stderr.puts str if verbose?
535 system str or raise RuntimeError, "'system #{str}' failed"
539 command config('rubyprog') + ' ' + str
543 command config('makeprog') + ' ' + task
547 File.exist?(dir + '/MANIFEST')
550 def all_files_in(dirname)
551 Dir.open(dirname) {|d|
552 return d.select {|ent| File.file?("#{dirname}/#{ent}") }
557 CVS SCCS RCS CVS.adm .svn
560 def all_dirs_in(dirname)
561 Dir.open(dirname) {|d|
562 return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS
576 try_run_hook "#{curr_srcdir()}/#{name}" or
577 try_run_hook "#{curr_srcdir()}/#{name}.rb"
580 def try_run_hook(fname)
581 return false unless File.file?(fname)
583 instance_eval File.read(fname), fname, 1
585 setup_rb_error "hook #{fname} failed:\n" + $!.message
599 alias config get_config
601 def set_config(key, val)
606 # srcdir/objdir (works only in the package directory)
609 #abstract srcdir_root
610 #abstract objdir_root
614 "#{srcdir_root()}/#{relpath()}"
618 "#{objdir_root()}/#{relpath()}"
622 "#{curr_srcdir()}/#{path}"
626 File.exist?(srcfile(path))
629 def srcdirectory?(path)
630 File.dir?(srcfile(path))
634 File.file? srcfile(path)
637 def srcentries(path = '.')
638 Dir.open("#{curr_srcdir()}/#{path}") {|d|
639 return d.to_a - %w(. ..)
643 def srcfiles(path = '.')
644 srcentries(path).select {|fname|
645 File.file?(File.join(curr_srcdir(), path, fname))
649 def srcdirectories(path = '.')
650 srcentries(path).select {|fname|
651 File.dir?(File.join(curr_srcdir(), path, fname))
658 class ToplevelInstaller
661 Copyright = 'Copyright (c) 2000-2004 Minero Aoki'
664 [ 'all', 'do config, setup, then install' ],
665 [ 'config', 'saves your configurations' ],
666 [ 'show', 'shows current configuration' ],
667 [ 'setup', 'compiles ruby extentions and others' ],
668 [ 'install', 'installs files' ],
669 [ 'clean', "does `make clean' for each extention" ],
670 [ 'distclean',"does `make distclean' for each extention" ]
673 def ToplevelInstaller.invoke
679 def ToplevelInstaller.instance
680 @singleton ||= new(File.dirname($0))
684 include MetaConfigAPI
686 def initialize(ardir_root)
688 @options = { 'verbose' => true }
689 @ardir = File.expand_path(ardir_root)
693 "#<#{self.class} #{__id__()}>"
698 case task = parsearg_global()
700 @config = load_config('config')
707 @config = load_config(task)
708 __send__ "parsearg_#{task}"
710 __send__ "exec_#{task}"
715 eval_file_ifexist "#{@ardir}/metaconfig"
718 def load_config(task)
722 when 'clean', 'distclean'
723 if File.exist?(ConfigTable.savefile)
724 then ConfigTable.load
733 @installer = Installer.new(@config, @options, @ardir, File.expand_path('.'))
737 # Hook Script API bases
757 valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/
759 while arg = ARGV.shift
762 setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg
766 @options['verbose'] = false
769 @options['verbose'] = true
775 when '-v', '--version'
776 puts "#{File.basename($0)} version #{Version}"
784 setup_rb_error "unknown global option '#{arg}'"
792 def parsearg_no_options
794 setup_rb_error "#{task}: unknown options: #{ARGV.join ' '}"
798 alias parsearg_show parsearg_no_options
799 alias parsearg_setup parsearg_no_options
800 alias parsearg_clean parsearg_no_options
801 alias parsearg_distclean parsearg_no_options
804 re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/
805 @options['config-opt'] = []
809 @options['config-opt'] = ARGV.dup
812 m = re.match(i) or setup_rb_error "config: unknown option #{i}"
813 name, value = *m.to_a[1,2]
814 @config[name] = value
819 @options['no-harm'] = false
820 @options['install-prefix'] = ''
824 @options['no-harm'] = true
825 when /\A--prefix=(.*)\z/
827 path = File.expand_path(path) unless path[0,1] == '/'
828 @options['install-prefix'] = path
830 setup_rb_error "install: unknown option #{a}"
836 out.puts 'Typical Installation Procedure:'
837 out.puts " $ ruby #{File.basename $0} config"
838 out.puts " $ ruby #{File.basename $0} setup"
839 out.puts " # ruby #{File.basename $0} install (may require root privilege)"
841 out.puts 'Detailed Usage:'
842 out.puts " ruby #{File.basename $0} <global option>"
843 out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
847 out.puts 'Global options:'
848 out.printf fmt, '-q,--quiet', 'suppress message outputs'
849 out.printf fmt, ' --verbose', 'output messages verbosely'
850 out.printf fmt, '-h,--help', 'print this message'
851 out.printf fmt, '-v,--version', 'print version and quit'
852 out.printf fmt, ' --copyright', 'print copyright and quit'
855 TASKS.each do |name, desc|
856 out.printf fmt, name, desc
859 fmt = " %-24s %s [%s]\n"
861 out.puts 'Options for CONFIG or ALL:'
862 ConfigTable.each do |item|
863 out.printf fmt, item.help_opt, item.description, item.help_default
865 out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
867 out.puts 'Options for INSTALL:'
868 out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
869 out.printf fmt, '--prefix=path', 'install path prefix', '$prefix'
878 @installer.exec_config
879 @config.save # must be final
883 @installer.exec_setup
887 @installer.exec_install
891 ConfigTable.each do |i|
892 printf "%-20s %s\n", i.name, i.value
897 @installer.exec_clean
901 @installer.exec_distclean
907 class ToplevelInstallerMulti < ToplevelInstaller
910 include HookScriptAPI
911 include FileOperations
913 def initialize(ardir)
915 @packages = all_dirs_in("#{@ardir}/packages")
916 raise 'no package exists' if @packages.empty?
920 eval_file_ifexist "#{@ardir}/metaconfig"
921 @packages.each do |name|
922 eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig"
928 @packages.each do |pack|
929 @installers[pack] = Installer.new(@config, @options,
930 "#{@ardir}/packages/#{pack}",
934 with = extract_selection(config('with'))
935 without = extract_selection(config('without'))
936 @selected = @installers.keys.select {|name|
937 (with.empty? or with.include?(name)) \
938 and not without.include?(name)
942 def extract_selection(list)
945 setup_rb_error "no such package: #{name}" unless @installers.key?(name)
952 f.puts 'Inluded packages:'
953 f.puts ' ' + @packages.sort.join(' ')
958 # multi-package metaconfig API
961 attr_reader :packages
963 def declare_packages(list)
964 raise 'package list is empty' if list.empty?
966 raise "directory packages/#{name} does not exist"\
967 unless File.dir?("#{@ardir}/packages/#{name}")
977 run_hook 'pre-config'
978 each_selected_installers {|inst| inst.exec_config }
979 run_hook 'post-config'
980 @config.save # must be final
985 each_selected_installers {|inst| inst.exec_setup }
986 run_hook 'post-setup'
990 run_hook 'pre-install'
991 each_selected_installers {|inst| inst.exec_install }
992 run_hook 'post-install'
996 rm_f ConfigTable.savefile
998 each_selected_installers {|inst| inst.exec_clean }
999 run_hook 'post-clean'
1003 rm_f ConfigTable.savefile
1004 run_hook 'pre-distclean'
1005 each_selected_installers {|inst| inst.exec_distclean }
1006 run_hook 'post-distclean'
1013 def each_selected_installers
1014 Dir.mkdir 'packages' unless File.dir?('packages')
1015 @selected.each do |pack|
1016 $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose']
1017 Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
1018 Dir.chdir "packages/#{pack}"
1019 yield @installers[pack]
1037 FILETYPES = %w( bin lib ext data )
1039 include HookScriptAPI
1041 include FileOperations
1043 def initialize(config, opt, srcroot, objroot)
1046 @srcdir = File.expand_path(srcroot)
1047 @objdir = File.expand_path(objroot)
1052 "#<#{self.class} #{File.basename(@srcdir)}>"
1056 # Hook Script API base methods
1085 save, @options['verbose'] = @options['verbose'], false
1088 @options['verbose'] = save
1097 exec_task_traverse 'config'
1100 def config_dir_bin(rel)
1103 def config_dir_lib(rel)
1106 def config_dir_ext(rel)
1107 extconf if extdir?(curr_srcdir())
1111 opt = @options['config-opt'].join(' ')
1112 command "#{config('rubyprog')} #{curr_srcdir()}/extconf.rb #{opt}"
1115 def config_dir_data(rel)
1123 exec_task_traverse 'setup'
1126 def setup_dir_bin(rel)
1127 all_files_in(curr_srcdir()).each do |fname|
1128 adjust_shebang "#{curr_srcdir()}/#{fname}"
1132 def adjust_shebang(path)
1134 tmpfile = File.basename(path) + '.tmp'
1136 File.open(path, 'rb') {|r|
1138 return unless File.basename(config('rubypath')) == 'ruby'
1139 return unless File.basename(first.sub(/\A\#!/, '').split[0]) == 'ruby'
1140 $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose?
1141 File.open(tmpfile, 'wb') {|w|
1142 w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath'))
1145 move_file tmpfile, File.basename(path)
1148 File.unlink tmpfile if File.exist?(tmpfile)
1152 def setup_dir_lib(rel)
1155 def setup_dir_ext(rel)
1156 make if extdir?(curr_srcdir())
1159 def setup_dir_data(rel)
1167 rm_f 'InstalledFiles'
1168 exec_task_traverse 'install'
1171 def install_dir_bin(rel)
1172 install_files collect_filenames_auto(), "#{config('bindir')}/#{rel}", 0755
1175 def install_dir_lib(rel)
1176 install_files ruby_scripts(), "#{config('rbdir')}/#{rel}", 0644
1179 def install_dir_ext(rel)
1180 return unless extdir?(curr_srcdir())
1181 install_files ruby_extentions('.'),
1182 "#{config('sodir')}/#{File.dirname(rel)}",
1186 def install_dir_data(rel)
1187 install_files collect_filenames_auto(), "#{config('datadir')}/#{rel}", 0644
1190 def install_files(list, dest, mode)
1191 mkdir_p dest, @options['install-prefix']
1192 list.each do |fname|
1193 install fname, dest, mode, @options['install-prefix']
1198 collect_filenames_auto().select {|n| /\.rb\z/ =~ n }
1201 # picked up many entries from cvs-1.11.1/src/ignore.c
1202 reject_patterns = %w(
1203 core RCSLOG tags TAGS .make.state
1204 .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1205 *~ *.old *.bak *.BAK *.orig *.rej _$* *$
1215 REJECT_PATTERNS = Regexp.new('\A(?:' +
1216 reject_patterns.map {|pat|
1217 pat.gsub(/[\.\$\#\*]/) {|ch| mapping[ch] }
1221 def collect_filenames_auto
1222 mapdir((existfiles() - hookfiles()).reject {|fname|
1223 REJECT_PATTERNS =~ fname
1228 all_files_in(curr_srcdir()) | all_files_in('.')
1232 %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
1233 %w( config setup install clean ).map {|t| sprintf(fmt, t) }
1237 def mapdir(filelist)
1238 filelist.map {|fname|
1239 if File.exist?(fname) # objdir
1242 File.join(curr_srcdir(), fname)
1247 def ruby_extentions(dir)
1249 ents = d.select {|fname| /\.#{::Config::CONFIG['DLEXT']}\z/ =~ fname }
1251 setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
1262 exec_task_traverse 'clean'
1263 rm_f ConfigTable.savefile
1264 rm_f 'InstalledFiles'
1267 def clean_dir_bin(rel)
1270 def clean_dir_lib(rel)
1273 def clean_dir_ext(rel)
1274 return unless extdir?(curr_srcdir())
1275 make 'clean' if File.file?('Makefile')
1278 def clean_dir_data(rel)
1286 exec_task_traverse 'distclean'
1287 rm_f ConfigTable.savefile
1288 rm_f 'InstalledFiles'
1291 def distclean_dir_bin(rel)
1294 def distclean_dir_lib(rel)
1297 def distclean_dir_ext(rel)
1298 return unless extdir?(curr_srcdir())
1299 make 'distclean' if File.file?('Makefile')
1306 def exec_task_traverse(task)
1307 run_hook "pre-#{task}"
1308 FILETYPES.each do |type|
1309 if config('without-ext') == 'yes' and type == 'ext'
1310 $stderr.puts 'skipping ext/* by user option' if verbose?
1313 traverse task, type, "#{task}_dir_#{type}"
1315 run_hook "post-#{task}"
1318 def traverse(task, rel, mid)
1320 run_hook "pre-#{task}"
1321 __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
1322 all_dirs_in(curr_srcdir()).each do |d|
1323 traverse task, "#{rel}/#{d}", mid
1325 run_hook "post-#{task}"
1330 return unless File.dir?("#{@srcdir}/#{rel}")
1332 dir = File.basename(rel)
1333 Dir.mkdir dir unless File.dir?(dir)
1336 $stderr.puts '---> ' + rel if verbose?
1340 $stderr.puts '<--- ' + rel if verbose?
1341 @currdir = File.dirname(rel)
1349 if multipackage_install?
1350 ToplevelInstallerMulti.invoke
1352 ToplevelInstaller.invoke
1356 $stderr.puts $!.message
1357 $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."