[rubygems/rubygems] Use a constant empty tar header to avoid extra allocations
[ruby.git] / tool / rbinstall.rb
blob63f4beb94348614739c5685e145035e2ddac511b
1 #!./miniruby
3 # Used by the "make install" target to install Ruby.
4 # See common.mk for more details.
6 ENV["SDKROOT"] ||= "" if /darwin/ =~ RUBY_PLATFORM
8 begin
9   load "./rbconfig.rb"
10 rescue LoadError
11   CONFIG = Hash.new {""}
12 else
13   include RbConfig
14   $".unshift File.expand_path("./rbconfig.rb")
15 end
17 srcdir = File.expand_path('../..', __FILE__)
18 unless defined?(CROSS_COMPILING) and CROSS_COMPILING
19   $:.replace([srcdir+"/lib", Dir.pwd])
20 end
21 require 'fileutils'
22 require 'shellwords'
23 require 'optparse'
24 require 'optparse/shellwords'
25 require 'rubygems'
26 begin
27   require "zlib"
28 rescue LoadError
29   $" << "zlib.rb"
30 end
31 require_relative 'lib/path'
33 INDENT = " "*36
34 STDOUT.sync = true
35 File.umask(022)
37 def parse_args(argv = ARGV)
38   $mantype = 'doc'
39   $destdir = nil
40   $extout = nil
41   $make = 'make'
42   $mflags = []
43   $install = []
44   $installed = {}
45   $installed_list = nil
46   $exclude = []
47   $dryrun = false
48   $rdocdir = nil
49   $htmldir = nil
50   $data_mode = 0644
51   $prog_mode = 0755
52   $dir_mode = nil
53   $script_mode = nil
54   $strip = false
55   $debug_symbols = nil
56   $cmdtype = (if File::ALT_SEPARATOR == '\\'
57                 File.exist?("rubystub.exe") ? 'exe' : 'cmd'
58               end)
59   mflags = []
60   gnumake = false
61   opt = OptionParser.new
62   opt.on('-n', '--dry-run') {$dryrun = true}
63   opt.on('--dest-dir=DIR') {|dir| $destdir = dir}
64   opt.on('--extout=DIR') {|dir| $extout = (dir unless dir.empty?)}
65   opt.on('--ext-build-dir=DIR') {|v| $ext_build_dir = v }
66   opt.on('--make=COMMAND') {|make| $make = make}
67   opt.on('--mantype=MAN') {|man| $mantype = man}
68   opt.on('--make-flags=FLAGS', '--mflags', Shellwords) do |v|
69     if arg = v.first
70       arg.insert(0, '-') if /\A[^-][^=]*\Z/ =~ arg
71     end
72     $mflags.concat(v)
73   end
74   opt.on('-i', '--install=TYPE', $install_procs.keys) do |ins|
75     $install << ins
76   end
77   opt.on('-x', '--exclude=TYPE', $install_procs.keys) do |exc|
78     $exclude << exc
79   end
80   opt.on('--data-mode=OCTAL-MODE', OptionParser::OctalInteger) do |mode|
81     $data_mode = mode
82   end
83   opt.on('--prog-mode=OCTAL-MODE', OptionParser::OctalInteger) do |mode|
84     $prog_mode = mode
85   end
86   opt.on('--dir-mode=OCTAL-MODE', OptionParser::OctalInteger) do |mode|
87     $dir_mode = mode
88   end
89   opt.on('--script-mode=OCTAL-MODE', OptionParser::OctalInteger) do |mode|
90     $script_mode = mode
91   end
92   opt.on('--installed-list [FILENAME]') {|name| $installed_list = name}
93   opt.on('--rdoc-output [DIR]') {|dir| $rdocdir = dir}
94   opt.on('--html-output [DIR]') {|dir| $htmldir = dir}
95   opt.on('--cmd-type=TYPE', %w[cmd plain]) {|cmd| $cmdtype = (cmd unless cmd == 'plain')}
96   opt.on('--[no-]strip') {|strip| $strip = strip}
97   opt.on('--gnumake') {gnumake = true}
98   opt.on('--debug-symbols=SUFFIX', /\w+/) {|name| $debug_symbols = ".#{name}"}
100   unless $install_procs.empty?
101     w = (w = ENV["COLUMNS"] and (w = w.to_i) > 80) ? w - 30 : 50
102     opt.on("\n""Types for --install and --exclude:")
103     mesg = +" "
104     $install_procs.each_key do |t|
105       if mesg.size + t.size > w
106         opt.on(mesg)
107         mesg = +" "
108       end
109       mesg << " " << t.to_s
110     end
111     opt.on(mesg)
112   end
114   opt.order!(argv) do |v|
115     case v
116     when /\AINSTALL[-_]([-\w]+)=(.*)/
117       argv.unshift("--#{$1.tr('_', '-')}=#{$2}")
118     when /\A\w[-\w]*=/
119       mflags << v
120     when /\A\w[-\w+]*\z/
121       $install << v.intern
122     else
123       raise OptionParser::InvalidArgument, v
124     end
125   end rescue abort "#{$!.message}\n#{opt.help}"
127   unless defined?(RbConfig)
128     puts opt.help
129     exit
130   end
132   $make, *rest = Shellwords.shellwords($make)
133   $mflags.unshift(*rest) unless rest.empty?
134   $mflags.unshift(*mflags)
135   $mflags.reject! {|v| /\A-[OW]/ =~ v} if gnumake
137   def $mflags.set?(flag)
138     grep(/\A-(?!-).*#{flag.chr}/i) { return true }
139     false
140   end
141   def $mflags.defined?(var)
142     grep(/\A#{var}=(.*)/) {return block_given? ? yield($1) : $1}
143     false
144   end
146   if $mflags.set?(?n)
147     $dryrun = true
148   else
149     $mflags << '-n' if $dryrun
150   end
152   $destdir ||= $mflags.defined?("DESTDIR")
153   if $extout ||= $mflags.defined?("EXTOUT")
154     RbConfig.expand($extout)
155   end
157   $continue = $mflags.set?(?k)
159   if $installed_list ||= $mflags.defined?('INSTALLED_LIST')
160     RbConfig.expand($installed_list, RbConfig::CONFIG)
161     $installed_list = File.open($installed_list, "ab")
162     $installed_list.sync = true
163   end
165   $rdocdir ||= $mflags.defined?('RDOCOUT')
166   $htmldir ||= $mflags.defined?('HTMLOUT')
168   $dir_mode ||= $prog_mode | 0700
169   $script_mode ||= $prog_mode
170   if $ext_build_dir.nil?
171     raise OptionParser::MissingArgument.new("--ext-build-dir=DIR")
172   end
175 $install_procs = Hash.new {[]}
176 def install?(*types, &block)
177   unless types.delete(:nodefault)
178     $install_procs[:all] <<= block
179   end
180   types.each do |type|
181     $install_procs[type] <<= block
182   end
185 def strip_file(files)
186   if !defined?($strip_command) and (cmd = CONFIG["STRIP"])
187     case cmd
188     when "", "true", ":" then return
189     else $strip_command = Shellwords.shellwords(cmd)
190     end
191   elsif !$strip_command
192     return
193   end
194   system(*($strip_command + [files].flatten))
197 def install(src, dest, options = {})
198   options = options.clone
199   strip = options.delete(:strip)
200   options[:preserve] = true
201   srcs = Array(src).select {|s| !$installed[$made_dirs[dest] ? File.join(dest, s) : dest]}
202   return if srcs.empty?
203   src = srcs if Array === src
204   d = with_destdir(dest)
205   super(src, d, **options)
206   srcs.each {|s| $installed[$made_dirs[dest] ? File.join(dest, s) : dest] = true}
207   if strip
208     d = srcs.map {|s| File.join(d, File.basename(s))} if $made_dirs[dest]
209     strip_file(d)
210   end
211   if $installed_list
212     dest = srcs.map {|s| File.join(dest, File.basename(s))} if $made_dirs[dest]
213     $installed_list.puts dest
214   end
217 def ln_sf(src, dest)
218   super(src, with_destdir(dest))
219   $installed_list.puts dest if $installed_list
222 $made_dirs = {}
224 def dir_creating(dir)
225   $made_dirs.fetch(dir) do
226     $made_dirs[dir] = true
227     $installed_list.puts(File.join(dir, "")) if $installed_list
228     yield if defined?(yield)
229   end
232 def makedirs(dirs)
233   dirs = fu_list(dirs)
234   dirs.collect! do |dir|
235     realdir = with_destdir(dir)
236     realdir unless dir_creating(dir) {File.directory?(realdir)}
237   end.compact!
238   super(dirs, :mode => $dir_mode) unless dirs.empty?
241 FalseProc = proc {false}
242 def path_matcher(pat)
243   if pat and !pat.empty?
244     proc {|f| pat.any? {|n| File.fnmatch?(n, f)}}
245   else
246     FalseProc
247   end
250 def install_recursive(srcdir, dest, options = {})
251   opts = options.clone
252   noinst = opts.delete(:no_install)
253   glob = opts.delete(:glob) || "*"
254   maxdepth = opts.delete(:maxdepth)
255   subpath = (srcdir.size+1)..-1
256   prune = []
257   skip = []
258   if noinst
259     if Array === noinst
260       prune = noinst.grep(/#{File::SEPARATOR}/o).map!{|f| f.chomp(File::SEPARATOR)}
261       skip = noinst.grep(/\A[^#{File::SEPARATOR}]*\z/o)
262     else
263       if noinst.index(File::SEPARATOR)
264         prune = [noinst]
265       else
266         skip = [noinst]
267       end
268     end
269   end
270   skip |= %w"#*# *~ *.old *.bak *.orig *.rej *.diff *.patch *.core"
271   prune = path_matcher(prune)
272   skip = path_matcher(skip)
273   File.directory?(srcdir) or return rescue return
274   paths = [[srcdir, dest, 0]]
275   found = []
276   while file = paths.shift
277     found << file
278     file, d, dir = *file
279     if dir
280       depth = dir + 1
281       next if maxdepth and maxdepth < depth
282       files = []
283       Dir.foreach(file) do |f|
284         src = File.join(file, f)
285         d = File.join(dest, dir = src[subpath])
286         stat = File.lstat(src) rescue next
287         if stat.directory?
288           files << [src, d, depth] if maxdepth != depth and /\A\./ !~ f and !prune[dir]
289         elsif stat.symlink?
290           # skip
291         else
292           files << [src, d, false] if File.fnmatch?(glob, f, File::FNM_EXTGLOB) and !skip[f]
293         end
294       end
295       paths.insert(0, *files)
296     end
297   end
298   for src, d, dir in found
299     if dir
300       next
301       # makedirs(d)
302     else
303       makedirs(d[/.*(?=\/)/m])
304       if block_given?
305         yield src, d, opts
306       else
307         install src, d, opts
308       end
309     end
310   end
313 def open_for_install(path, mode)
314   data = File.binread(realpath = with_destdir(path)) rescue nil
315   newdata = yield
316   unless $dryrun
317     unless newdata == data
318       File.open(realpath, "wb", mode) {|f| f.write newdata}
319     end
320     File.chmod(mode, realpath)
321   end
322   $installed_list.puts path if $installed_list
325 def with_destdir(dir)
326   return dir if !$destdir or $destdir.empty?
327   dir = dir.sub(/\A\w:/, '') if File::PATH_SEPARATOR == ';'
328   $destdir + dir
331 def without_destdir(dir)
332   return dir if !$destdir or $destdir.empty?
333   dir.start_with?($destdir) ? dir[$destdir.size..-1] : dir
336 def prepare(mesg, basedir, subdirs=nil)
337   return unless basedir
338   case
339   when !subdirs
340     dirs = basedir
341   when subdirs.size == 0
342     subdirs = nil
343   when subdirs.size == 1
344     dirs = [basedir = File.join(basedir, subdirs)]
345     subdirs = nil
346   else
347     dirs = [basedir, *subdirs.collect {|dir| File.join(basedir, dir)}]
348   end
349   printf("%-*s%s%s\n", INDENT.size, "installing #{mesg}:", basedir,
350          (subdirs ? " (#{subdirs.join(', ')})" : ""))
351   makedirs(dirs)
354 def CONFIG.[](name, mandatory = false)
355   value = super(name)
356   if mandatory
357     raise "CONFIG['#{name}'] must be set" if !value or value.empty?
358   end
359   value
362 exeext = CONFIG["EXEEXT"]
364 ruby_install_name = CONFIG["ruby_install_name", true]
365 rubyw_install_name = CONFIG["rubyw_install_name"]
366 goruby_install_name = "go" + ruby_install_name
368 bindir = CONFIG["bindir", true]
369 if CONFIG["libdirname"] == "archlibdir"
370   libexecdir = MAKEFILE_CONFIG["archlibdir"].dup
371   unless libexecdir.sub!(/\$\(lib\K(?=dir\))/) {"exec"}
372     libexecdir = "$(libexecdir)/$(arch)"
373   end
374   archbindir = RbConfig.expand(libexecdir) + "/bin"
376 libdir = CONFIG[CONFIG.fetch("libdirname", "libdir"), true]
377 rubyhdrdir = CONFIG["rubyhdrdir", true]
378 archhdrdir = CONFIG["rubyarchhdrdir"] || (rubyhdrdir + "/" + CONFIG['arch'])
379 rubylibdir = CONFIG["rubylibdir", true]
380 archlibdir = CONFIG["rubyarchdir", true]
381 if CONFIG["sitedir"]
382   sitelibdir = CONFIG["sitelibdir"]
383   sitearchlibdir = CONFIG["sitearchdir"]
385 if CONFIG["vendordir"]
386   vendorlibdir = CONFIG["vendorlibdir"]
387   vendorarchlibdir = CONFIG["vendorarchdir"]
389 mandir = CONFIG["mandir", true]
390 docdir = CONFIG["docdir", true]
391 enable_shared = CONFIG["ENABLE_SHARED"] == 'yes'
392 dll = CONFIG["LIBRUBY_SO", enable_shared]
393 lib = CONFIG["LIBRUBY", true]
394 arc = CONFIG["LIBRUBY_A", true]
395 load_relative = CONFIG["LIBRUBY_RELATIVE"] == 'yes'
397 rdoc_noinst = %w[created.rid]
399 prolog_script = <<EOS
400 bindir="#{load_relative ? '${0%/*}' : bindir.gsub(/\"/, '\\\\"')}"
402 if CONFIG["LIBRUBY_RELATIVE"] != 'yes' and libpathenv = CONFIG["LIBPATHENV"]
403   pathsep = File::PATH_SEPARATOR
404   prolog_script << <<EOS
405 libdir="#{load_relative ? '$\{bindir%/bin\}/lib' : libdir.gsub(/\"/, '\\\\"')}"
406 export #{libpathenv}="$libdir${#{libpathenv}:+#{pathsep}$#{libpathenv}}"
409 prolog_script << %Q[exec "$bindir/#{ruby_install_name}" "-x" "$0" "$@"\n]
410 PROLOG_SCRIPT = {}
411 PROLOG_SCRIPT["exe"] = "#!#{bindir}/#{ruby_install_name}"
412 PROLOG_SCRIPT["cmd"] = <<EOS
413 :""||{ ""=> %q<-*- ruby -*-
414 @"%~dp0#{ruby_install_name}" -x "%~f0" %*
415 @exit /b %ERRORLEVEL%
416 };{ #\n#{prolog_script.gsub(/(?=\n)/, ' #')}>,\n}
418 PROLOG_SCRIPT.default = (load_relative || /\s/ =~ bindir) ?
419                           <<EOS : PROLOG_SCRIPT["exe"]
420 #!/bin/sh
421 # -*- ruby -*-
422 _=_\\
423 =begin
424 #{prolog_script.chomp}
425 =end
428 installer = Struct.new(:ruby_shebang, :ruby_bin, :ruby_install_name, :stub, :trans) do
429   def transform(name)
430     RbConfig.expand(trans[name])
431   end
434 $script_installer = Class.new(installer) do
435   ruby_shebang = File.join(bindir, ruby_install_name)
436   if File::ALT_SEPARATOR
437     ruby_bin = ruby_shebang.tr(File::SEPARATOR, File::ALT_SEPARATOR)
438   end
439   if trans = CONFIG["program_transform_name"]
440     exp = []
441     trans.gsub!(/\$\$/, '$')
442     trans.scan(%r[\G[\s;]*(/(?:\\.|[^/])*+/)?([sy])(\\?\W)((?:(?!\3)(?:\\.|.))*+)\3((?:(?!\3)(?:\\.|.))*+)\3([gi]*)]) do
443       |addr, cmd, sep, pat, rep, opt|
444       addr &&= Regexp.new(addr[/\A\/(.*)\/\z/, 1])
445       case cmd
446       when 's'
447         next if pat == '^' and rep.empty?
448         exp << [addr, (opt.include?('g') ? :gsub! : :sub!),
449                 Regexp.new(pat, opt.include?('i')), rep.gsub(/&/){'\&'}]
450       when 'y'
451         exp << [addr, :tr!, Regexp.quote(pat), rep]
452       end
453     end
454     trans = proc do |base|
455       exp.each {|addr, opt, pat, rep| base.__send__(opt, pat, rep) if !addr or addr =~ base}
456       base
457     end
458   elsif /ruby/ =~ ruby_install_name
459     trans = proc {|base| ruby_install_name.sub(/ruby/, base)}
460   else
461     trans = proc {|base| base}
462   end
464   def prolog(shebang)
465     shebang.sub!(/\r$/, '')
466     script = PROLOG_SCRIPT[$cmdtype]
467     shebang.sub!(/\A(\#!.*?ruby\b)?/) do
468       if script.end_with?("\n")
469         script + ($1 || "#!ruby\n")
470       else
471         $1 ? script : "#{script}\n"
472       end
473     end
474     shebang
475   end
477   def install(src, cmd)
478     cmd = cmd.sub(/[^\/]*\z/m) {|n| transform(n)}
480     shebang, body = File.open(src, "rb") do |f|
481       next f.gets, f.read
482     end
483     shebang or raise "empty file - #{src}"
484     shebang = prolog(shebang)
485     body.gsub!(/\r$/, '')
487     cmd << ".#{$cmdtype}" if $cmdtype
488     open_for_install(cmd, $script_mode) do
489       case $cmdtype
490       when "exe"
491         stub + shebang + body
492       else
493         shebang + body
494       end
495     end
496   end
498   def self.get_rubystub
499     stubfile = "rubystub.exe"
500     stub = File.open(stubfile, "rb") {|f| f.read} << "\n"
501   rescue => e
502     abort "No #{stubfile}: #{e}"
503   else
504     stub
505   end
507   def stub
508     super or self.stub = self.class.get_rubystub
509   end
511   break new(ruby_shebang, ruby_bin, ruby_install_name, nil, trans)
514 module RbInstall
515   def self.no_write(options = nil)
516     u = File.umask(0022)
517     if $dryrun
518       fu = ::Object.class_eval do
519         fu = remove_const(:FileUtils)
520         const_set(:FileUtils, fu::NoWrite)
521         fu
522       end
523       dir_mode = options.delete(:dir_mode) if options
524     end
525     yield
526   ensure
527     options[:dir_mode] = dir_mode if dir_mode
528     if fu
529       ::Object.class_eval do
530         remove_const(:FileUtils)
531         const_set(:FileUtils, fu)
532       end
533     end
534     File.umask(u)
535   end
537   module Specs
538     class FileCollector
539       def self.for(srcdir, type, gemspec)
540         relative_base = (File.dirname(gemspec) if gemspec.include?("/"))
541         const_get(type.capitalize).new(gemspec, srcdir, relative_base)
542       end
544       attr_reader :gemspec, :srcdir, :relative_base
545       def initialize(gemspec, srcdir, relative_base)
546         @gemspec = gemspec
547         @srcdir = srcdir
548         @relative_base = relative_base
549       end
551       def collect
552         requirable_features.sort
553       end
555       private
557       def features_from_makefile(makefile_path)
558         makefile = File.read(makefile_path)
560         name = makefile[/^TARGET[ \t]*=[ \t]*((?:.*\\\n)*.*)/, 1]
561         return [] if name.nil? || name.empty?
563         feature = makefile[/^DLLIB[ \t]*=[ \t]*((?:.*\\\n)*.*)/, 1]
564         feature = feature.sub("$(TARGET)", name)
566         target_prefix = makefile[/^target_prefix[ \t]*=[ \t]*((?:.*\\\n)*.*)/, 1]
567         feature = File.join(target_prefix.delete_prefix("/"), feature) unless target_prefix.empty?
569         Array(feature)
570       end
572       class Ext < self
573         def requirable_features
574           # install ext only when it's configured
575           return [] unless File.exist?(makefile_path)
577           ruby_features + ext_features
578         end
580         private
582         def ruby_features
583           Dir.glob("**/*.rb", base: "#{makefile_dir}/lib")
584         end
586         def ext_features
587           features_from_makefile(makefile_path)
588         end
590         def makefile_path
591           if File.exist?("#{makefile_dir}/Makefile")
592             "#{makefile_dir}/Makefile"
593           else
594             # for out-of-place build
595             "#{$ext_build_dir}/#{relative_base}/Makefile"
596           end
597         end
599         def makefile_dir
600           "#{root}/#{relative_base}"
601         end
603         def root
604           File.expand_path($ext_build_dir, srcdir)
605         end
606       end
608       class Lib < self
609         def requirable_features
610           ruby_features + ext_features
611         end
613         private
615         def ruby_features
616           gemname = File.basename(gemspec, ".gemspec")
617           base = relative_base || gemname
618           # for lib/net/net-smtp.gemspec
619           if m = /.*(?=-(.*)\z)/.match(gemname)
620             base = File.join(base, *m.to_a.select {|n| !base.include?(n)})
621           end
622           files = Dir.glob("#{base}{.rb,/**/*.rb}", base: root)
623           if !relative_base and files.empty? # no files at the toplevel
624             # pseudo gem like ruby2_keywords
625             files << "#{gemname}.rb"
626           end
628           case gemname
629           when "net-http"
630             files << "net/https.rb"
631           when "optparse"
632             files << "optionparser.rb"
633           end
635           files
636         end
638         def ext_features
639           loaded_gemspec = load_gemspec("#{root}/#{gemspec}")
640           extension = loaded_gemspec.extensions.first
641           return [] unless extension
643           extconf = File.expand_path(extension, srcdir)
644           ext_build_dir = File.dirname(extconf)
645           makefile_path = "#{ext_build_dir}/Makefile"
646           return [] unless File.exist?(makefile_path)
648           features_from_makefile(makefile_path)
649         end
651         def root
652           "#{srcdir}/lib"
653         end
654       end
655     end
656   end
658   class DirPackage
659     attr_reader :spec
661     attr_accessor :dir_mode
662     attr_accessor :prog_mode
663     attr_accessor :data_mode
665     def initialize(spec, dir_map = nil)
666       @spec = spec
667       @src_dir = File.dirname(@spec.loaded_from)
668       @dir_map = dir_map
669     end
671     def extract_files(destination_dir, pattern = "*")
672       return if @src_dir == destination_dir
673       File.chmod(0700, destination_dir) unless $dryrun
674       mode = pattern == File.join(spec.bindir, '*') ? prog_mode : data_mode
675       destdir = without_destdir(destination_dir)
676       if @dir_map
677         (dir_map = @dir_map.map {|k, v| Regexp.quote(k) unless k == v}).compact!
678         dir_map = %r{\A(?:#{dir_map.join('|')})(?=/)}
679       end
680       spec.files.each do |f|
681         next unless File.fnmatch(pattern, f)
682         src = File.join(@src_dir, dir_map =~ f ? "#{@dir_map[$&]}#{$'}" : f)
683         dest = File.join(destdir, f)
684         makedirs(dest[/.*(?=\/)/m])
685         install src, dest, :mode => mode
686       end
687       File.chmod(dir_mode, destination_dir) unless $dryrun
688     end
689   end
691   class UnpackedInstaller < Gem::Installer
692     def write_cache_file
693     end
695     def shebang(bin_file_name)
696       path = File.join(gem_dir, spec.bindir, bin_file_name)
697       first_line = File.open(path, "rb") {|file| file.gets}
698       $script_installer.prolog(first_line).chomp
699     end
701     def app_script_text(bin_file_name)
702       # move shell script part after comments generated by RubyGems.
703       super.sub(/\A
704         (\#!\/bin\/sh\n\#.*-\*-\s*ruby\s*-\*-.*\n)
705         ((?:.*\n)*?\#!.*ruby.*\n)
706         \#\n
707         ((?:\#.*\n)+)/x, '\1\3\2')
708     end
710     def check_executable_overwrite(filename)
711       return if @wrappers and same_bin_script?(filename, @bin_dir)
712       super
713     end
715     def same_bin_script?(filename, bindir)
716       path = File.join(bindir, formatted_program_filename(filename))
717       begin
718         return true if File.binread(path) == app_script_text(filename)
719       rescue
720       end
721       false
722     end
724     def write_spec
725       super unless $dryrun
726       $installed_list.puts(without_destdir(spec_file)) if $installed_list
727     end
729     def write_default_spec
730       super unless $dryrun
731       $installed_list.puts(without_destdir(default_spec_file)) if $installed_list
732     end
734     def install
735       spec.post_install_message = nil
736       dir_creating(without_destdir(gem_dir))
737       RbInstall.no_write(options) {super}
738     end
740     # Now build-ext builds all extensions including bundled gems.
741     def build_extensions
742     end
744     def generate_bin_script(filename, bindir)
745       return if same_bin_script?(filename, bindir)
746       name = formatted_program_filename(filename)
747       unless $dryrun
748         super
749         File.chmod($script_mode, File.join(bindir, name))
750       end
751       $installed_list.puts(File.join(without_destdir(bindir), name)) if $installed_list
752     end
754     def verify_gem_home # :nodoc:
755     end
757     def ensure_writable_dir(dir)
758       $made_dirs.fetch(d = without_destdir(dir)) do
759         $made_dirs[d] = true
760         super unless $dryrun
761         $installed_list.puts(d+"/") if $installed_list
762       end
763     end
764   end
767 def load_gemspec(file, base = nil)
768   file = File.realpath(file)
769   code = File.read(file, encoding: "utf-8:-")
771   files = []
772   Dir.glob("**/*", File::FNM_DOTMATCH, base: base) do |n|
773     case File.basename(n); when ".", ".."; next; end
774     next if File.directory?(File.join(base, n))
775     files << n.dump
776   end if base
777   code.gsub!(/(?:`git[^\`]*`|%x\[git[^\]]*\])\.split\([^\)]*\)/m) do
778     "[" + files.join(", ") + "]"
779   end
780   code.gsub!(/IO\.popen\(.*git.*?\)/) do
781     "[" + files.join(", ") + "] || itself"
782   end
784   spec = eval(code, binding, file)
785   unless Gem::Specification === spec
786     raise TypeError, "[#{file}] isn't a Gem::Specification (#{spec.class} instead)."
787   end
788   spec.loaded_from = base ? File.join(base, File.basename(file)) : file
789   spec.files.reject! {|n| n.end_with?(".gemspec") or n.start_with?(".git")}
790   spec.date = RUBY_RELEASE_DATE
792   spec
795 def install_default_gem(dir, srcdir, bindir)
796   gem_dir = Gem.default_dir
797   install_dir = with_destdir(gem_dir)
798   prepare "default gems from #{dir}", gem_dir
799   RbInstall.no_write do
800     makedirs(Gem.ensure_default_gem_subdirectories(install_dir, $dir_mode).map {|d| File.join(gem_dir, d)})
801   end
803   options = {
804     :install_dir => with_destdir(gem_dir),
805     :bin_dir => with_destdir(bindir),
806     :ignore_dependencies => true,
807     :dir_mode => $dir_mode,
808     :data_mode => $data_mode,
809     :prog_mode => $script_mode,
810     :wrappers => true,
811     :format_executable => true,
812     :install_as_default => true,
813   }
814   default_spec_dir = Gem.default_specifications_dir
816   base = "#{srcdir}/#{dir}"
817   gems = Dir.glob("**/*.gemspec", base: base).map {|src|
818     spec = load_gemspec("#{base}/#{src}")
819     file_collector = RbInstall::Specs::FileCollector.for(srcdir, dir, src)
820     files = file_collector.collect
821     if files.empty?
822       next
823     end
824     spec.files = files
825     spec
826   }
827   gems.compact.sort_by(&:name).each do |gemspec|
828     old_gemspecs = Dir[File.join(with_destdir(default_spec_dir), "#{gemspec.name}-*.gemspec")]
829     if old_gemspecs.size > 0
830       old_gemspecs.each {|spec| rm spec }
831     end
833     full_name = "#{gemspec.name}-#{gemspec.version}"
835     gemspec.loaded_from = File.join srcdir, gemspec.spec_name
837     package = RbInstall::DirPackage.new gemspec, {gemspec.bindir => 'libexec'}
838     ins = RbInstall::UnpackedInstaller.new(package, options)
839     puts "#{INDENT}#{gemspec.name} #{gemspec.version}"
840     ins.install
841   end
844 # :startdoc:
846 install?(:local, :arch, :bin, :'bin-arch') do
847   prepare "binary commands", (dest = archbindir || bindir)
849   def (bins = []).add(name)
850     push(name)
851     name
852   end
854   install bins.add(ruby_install_name+exeext), dest, :mode => $prog_mode, :strip => $strip
855   if rubyw_install_name and !rubyw_install_name.empty?
856     install bins.add(rubyw_install_name+exeext), dest, :mode => $prog_mode, :strip => $strip
857   end
858   # emcc produces ruby and ruby.wasm, the first is a JavaScript file of runtime support
859   # to load and execute the second .wasm file. Both are required to execute ruby
860   if RUBY_PLATFORM =~ /emscripten/ and File.exist? ruby_install_name+".wasm"
861     install bins.add(ruby_install_name+".wasm"), dest, :mode => $prog_mode, :strip => $strip
862   end
863   if File.exist? goruby_install_name+exeext
864     install bins.add(goruby_install_name+exeext), dest, :mode => $prog_mode, :strip => $strip
865   end
866   if enable_shared and dll != lib
867     install bins.add(dll), dest, :mode => $prog_mode, :strip => $strip
868   end
869   if archbindir
870     prepare "binary command links", bindir
871     relpath = Path.relative(archbindir, bindir)
872     bins.each do |f|
873       ln_sf(File.join(relpath, f), File.join(bindir, f))
874     end
875   end
878 install?(:local, :arch, :lib, :'lib-arch') do
879   prepare "base libraries", libdir
881   install lib, libdir, :mode => $prog_mode, :strip => $strip unless lib == arc
882   install arc, libdir, :mode => $data_mode unless CONFIG["INSTALL_STATIC_LIBRARY"] == "no"
883   if dll == lib and dll != arc
884     for link in CONFIG["LIBRUBY_ALIASES"].split - [File.basename(dll)]
885       ln_sf(dll, File.join(libdir, link))
886     end
887   end
889   prepare "arch files", archlibdir
890   install "rbconfig.rb", archlibdir, :mode => $data_mode
891   if CONFIG["ARCHFILE"]
892     for file in CONFIG["ARCHFILE"].split
893       install file, archlibdir, :mode => $data_mode
894     end
895   end
898 install?(:local, :arch, :data) do
899   pc = CONFIG["ruby_pc"]
900   if pc and File.file?(pc) and File.size?(pc)
901     prepare "pkgconfig data", pkgconfigdir = File.join(libdir, "pkgconfig")
902     install pc, pkgconfigdir, :mode => $data_mode
903     if (pkgconfig_base = CONFIG["libdir", true]) != libdir
904       prepare "pkgconfig data link", File.join(pkgconfig_base, "pkgconfig")
905       ln_sf(File.join("..", Path.relative(pkgconfigdir, pkgconfig_base), pc),
906             File.join(pkgconfig_base, "pkgconfig", pc))
907     end
908   end
911 install?(:ext, :arch, :'ext-arch') do
912   prepare "extension objects", archlibdir
913   noinst = %w[-* -*/] | (CONFIG["no_install_files"] || "").split
914   install_recursive("#{$extout}/#{CONFIG['arch']}", archlibdir, :no_install => noinst, :mode => $prog_mode, :strip => $strip)
915   prepare "extension objects", sitearchlibdir
916   prepare "extension objects", vendorarchlibdir
917   if extso = File.read("exts.mk")[/^EXTSO[ \t]*=[ \t]*((?:.*\\\n)*.*)/, 1] and
918     !(extso = extso.gsub(/\\\n/, '').split).empty?
919     libpathenv = CONFIG["LIBPATHENV"]
920     dest = CONFIG[!libpathenv || libpathenv == "PATH" ? "bindir" : "libdir"]
921     prepare "external libraries", dest
922     for file in extso
923       install file, dest, :mode => $prog_mode
924     end
925   end
928 install?(:ext, :arch, :hdr, :'arch-hdr', :'hdr-arch') do
929   prepare "extension headers", archhdrdir
930   install_recursive("#{$extout}/include/#{CONFIG['arch']}", archhdrdir, :glob => "*.h", :mode => $data_mode)
931   install_recursive("#{$extout}/include/#{CONFIG['arch']}", archhdrdir, :glob => "rb_rjit_header-*.obj", :mode => $data_mode)
932   install_recursive("#{$extout}/include/#{CONFIG['arch']}", archhdrdir, :glob => "rb_rjit_header-*.pch", :mode => $data_mode)
935 install?(:ext, :comm, :'ext-comm') do
936   prepare "extension scripts", rubylibdir
937   install_recursive("#{$extout}/common", rubylibdir, :mode => $data_mode)
938   prepare "extension scripts", sitelibdir
939   prepare "extension scripts", vendorlibdir
942 install?(:ext, :comm, :hdr, :'comm-hdr', :'hdr-comm') do
943   hdrdir = rubyhdrdir + "/ruby"
944   prepare "extension headers", hdrdir
945   install_recursive("#{$extout}/include/ruby", hdrdir, :glob => "*.h", :mode => $data_mode)
948 install?(:doc, :rdoc) do
949   if $rdocdir
950     ridatadir = File.join(CONFIG['ridir'], CONFIG['ruby_version'], "system")
951     prepare "rdoc", ridatadir
952     install_recursive($rdocdir, ridatadir, :no_install => rdoc_noinst, :mode => $data_mode)
953   end
956 install?(:doc, :html) do
957   if $htmldir
958     prepare "html-docs", docdir
959     install_recursive($htmldir, docdir+"/html", :no_install => rdoc_noinst, :mode => $data_mode)
960   end
963 install?(:doc, :capi) do
964   prepare "capi-docs", docdir
965   install_recursive "doc/capi", docdir+"/capi", :mode => $data_mode
968 install?(:local, :comm, :bin, :'bin-comm') do
969   prepare "command scripts", bindir
971   install_recursive(File.join(srcdir, "bin"), bindir, :maxdepth => 1) do |src, cmd|
972     $script_installer.install(src, cmd)
973   end
976 install?(:local, :comm, :lib) do
977   prepare "library scripts", rubylibdir
978   noinst = %w[*.txt *.rdoc *.gemspec]
979   install_recursive(File.join(srcdir, "lib"), rubylibdir, :no_install => noinst, :mode => $data_mode)
982 install?(:local, :comm, :hdr, :'comm-hdr') do
983   prepare "common headers", rubyhdrdir
985   noinst = []
986   unless RUBY_PLATFORM =~ /mswin|mingw|bccwin/
987     noinst << "win32.h"
988   end
989   noinst = nil if noinst.empty?
990   install_recursive(File.join(srcdir, "include"), rubyhdrdir, :no_install => noinst, :glob => "*.{h,hpp}", :mode => $data_mode)
993 install?(:local, :comm, :man) do
994   mdocs = Dir["#{srcdir}/man/*.[1-9]"]
995   prepare "manpages", mandir, ([] | mdocs.collect {|mdoc| mdoc[/\d+$/]}).sort.collect {|sec| "man#{sec}"}
997   case $mantype
998   when /\.(?:(gz)|bz2)\z/
999     compress = $1 ? "gzip" : "bzip2"
1000     suffix = $&
1001   end
1002   mandir = File.join(mandir, "man")
1003   has_goruby = File.exist?(goruby_install_name+exeext)
1004   require File.join(srcdir, "tool/mdoc2man.rb") if /\Adoc\b/ !~ $mantype
1005   mdocs.each do |mdoc|
1006     next unless File.file?(mdoc) and File.read(mdoc, 1) == '.'
1007     base = File.basename(mdoc)
1008     if base == "goruby.1"
1009       next unless has_goruby
1010     end
1012     destdir = mandir + (section = mdoc[/\d+$/])
1013     destname = ruby_install_name.sub(/ruby/, base.chomp(".#{section}"))
1014     destfile = File.join(destdir, "#{destname}.#{section}")
1016     if /\Adoc\b/ =~ $mantype
1017       if compress
1018         begin
1019           w = IO.popen(compress, "rb", in: mdoc, &:read)
1020         rescue
1021         else
1022           destfile << suffix
1023         end
1024       end
1025       if w
1026         open_for_install(destfile, $data_mode) {w}
1027       else
1028         install mdoc, destfile, :mode => $data_mode
1029       end
1030     else
1031       class << (w = [])
1032         alias print push
1033       end
1034       if File.basename(mdoc).start_with?('bundle') ||
1035          File.basename(mdoc).start_with?('gemfile')
1036         w = File.read(mdoc)
1037       else
1038         File.open(mdoc) {|r| Mdoc2Man.mdoc2man(r, w)}
1039         w = w.join("")
1040       end
1041       if compress
1042         begin
1043           w = IO.popen(compress, "r+b") do |f|
1044             Thread.start {f.write w; f.close_write}
1045             f.read
1046           end
1047         rescue
1048         else
1049           destfile << suffix
1050         end
1051       end
1052       open_for_install(destfile, $data_mode) {w}
1053     end
1054   end
1057 install?(:dbg, :nodefault) do
1058   prepare "debugger commands", bindir
1059   prepare "debugger scripts", rubylibdir
1060   conf = MAKEFILE_CONFIG.merge({"prefix"=>"${prefix#/}"})
1061   Dir.glob(File.join(srcdir, "template/ruby-*db.in")) do |src|
1062     cmd = $script_installer.transform(File.basename(src, ".in"))
1063     open_for_install(File.join(bindir, cmd), $script_mode) {
1064       RbConfig.expand(File.read(src), conf)
1065     }
1066   end
1067   Dir.glob(File.join(srcdir, "misc/lldb_*")) do |src|
1068     if File.directory?(src)
1069       install_recursive src, File.join(rubylibdir, File.basename(src))
1070     else
1071       install src, rubylibdir
1072     end
1073   end
1074   install File.join(srcdir, ".gdbinit"), File.join(rubylibdir, "gdbinit")
1075   if $debug_symbols
1076     {
1077       ruby_install_name => archbindir || bindir,
1078       rubyw_install_name => archbindir || bindir,
1079       goruby_install_name => archbindir || bindir,
1080       dll => libdir,
1081     }.each do |src, dest|
1082       next if src.empty?
1083       src += $debug_symbols
1084       if File.directory?(src)
1085         install_recursive src, File.join(dest, src)
1086       end
1087     end
1088   end
1091 install?(:ext, :comm, :gem, :'default-gems', :'default-gems-comm') do
1092   install_default_gem('lib', srcdir, bindir)
1095 install?(:ext, :arch, :gem, :'default-gems', :'default-gems-arch') do
1096   install_default_gem('ext', srcdir, bindir)
1099 install?(:ext, :comm, :gem, :'bundled-gems') do
1100   gem_dir = Gem.default_dir
1101   install_dir = with_destdir(gem_dir)
1102   prepare "bundled gems", gem_dir
1103   RbInstall.no_write do
1104     makedirs(Gem.ensure_gem_subdirectories(install_dir, $dir_mode).map {|d| File.join(gem_dir, d)})
1105   end
1107   installed_gems = {}
1108   skipped = {}
1109   options = {
1110     :install_dir => install_dir,
1111     :bin_dir => with_destdir(bindir),
1112     :domain => :local,
1113     :ignore_dependencies => true,
1114     :dir_mode => $dir_mode,
1115     :data_mode => $data_mode,
1116     :prog_mode => $script_mode,
1117     :wrappers => true,
1118     :format_executable => true,
1119   }
1121   extensions_dir = Gem::StubSpecification.gemspec_stub("", gem_dir, gem_dir).extensions_dir
1122   specifications_dir = File.join(gem_dir, "specifications")
1123   build_dir = Gem::StubSpecification.gemspec_stub("", ".bundle", ".bundle").extensions_dir
1125   # We are about to build extensions, and want to configure extensions with the
1126   # newly installed ruby.
1127   Gem.instance_variable_set(:@ruby, with_destdir(File.join(bindir, ruby_install_name)))
1128   # Prevent fake.rb propagation. It conflicts with the natural mkmf configs of
1129   # the newly installed ruby.
1130   ENV.delete('RUBYOPT')
1132   File.foreach("#{srcdir}/gems/bundled_gems") do |name|
1133     next if /^\s*(?:#|$)/ =~ name
1134     next unless /^(\S+)\s+(\S+).*/ =~ name
1135     gem = $1
1136     gem_name = "#$1-#$2"
1137     # Try to find the original gemspec file
1138     path = "#{srcdir}/.bundle/gems/#{gem_name}/#{gem}.gemspec"
1139     unless File.exist?(path)
1140       # Try to find the gemspec file for C ext gems
1141       # ex .bundle/gems/debug-1.7.1/debug-1.7.1.gemspec
1142       # This gemspec keep the original dependencies
1143       path = "#{srcdir}/.bundle/gems/#{gem_name}/#{gem_name}.gemspec"
1144       unless File.exist?(path)
1145         # Try to find the gemspec file for gems that hasn't own gemspec
1146         path = "#{srcdir}/.bundle/specifications/#{gem_name}.gemspec"
1147         unless File.exist?(path)
1148           skipped[gem_name] = "gemspec not found"
1149           next
1150         end
1151       end
1152     end
1153     spec = load_gemspec(path, "#{srcdir}/.bundle/gems/#{gem_name}")
1154     unless spec.platform == Gem::Platform::RUBY
1155       skipped[gem_name] = "not ruby platform (#{spec.platform})"
1156       next
1157     end
1158     unless spec.full_name == gem_name
1159       skipped[gem_name] = "full name unmatch #{spec.full_name}"
1160       next
1161     end
1162     # Skip install C ext bundled gem if it is build failed or not found
1163     if !spec.extensions.empty? && !File.exist?("#{build_dir}/#{gem_name}/gem.build_complete")
1164       skipped[gem_name] = "extensions not found or build failed #{spec.full_name}"
1165       next
1166     end
1167     spec.extension_dir = "#{extensions_dir}/#{spec.full_name}"
1168     package = RbInstall::DirPackage.new spec
1169     ins = RbInstall::UnpackedInstaller.new(package, options)
1170     puts "#{INDENT}#{spec.name} #{spec.version}"
1171     ins.install
1172     install_recursive("#{build_dir}/#{gem_name}", "#{extensions_dir}/#{gem_name}") do |src, dest|
1173       # puts "#{INDENT}    #{dest[extensions_dir.size+gem_name.size+2..-1]}"
1174       install src, dest, :mode => (File.executable?(src) ? $prog_mode : $data_mode)
1175     end
1176     installed_gems[spec.full_name] = true
1177   end
1178   installed_gems, gems = Dir.glob(srcdir+'/gems/*.gem').partition {|gem| installed_gems.key?(File.basename(gem, '.gem'))}
1179   unless installed_gems.empty?
1180     prepare "bundled gem cache", gem_dir+"/cache"
1181     install installed_gems, gem_dir+"/cache"
1182   end
1183   unless gems.empty?
1184     skipped.default = "not found in bundled_gems"
1185     puts "skipped bundled gems:"
1186     gems.each do |gem|
1187       printf "    %-32s%s\n", File.basename(gem), skipped[gem]
1188     end
1189   end
1192 parse_args()
1194 include FileUtils
1195 include FileUtils::NoWrite if $dryrun
1196 @fileutils_output = STDOUT
1197 @fileutils_label = ''
1199 $install << :all if $install.empty?
1200 installs = $install.map do |inst|
1201   if !(procs = $install_procs[inst]) || procs.empty?
1202     next warn("unknown install target - #{inst}")
1203   end
1204   procs
1206 installs.flatten!
1207 installs -= $exclude.map {|exc| $install_procs[exc]}.flatten
1208 puts "Installing to #$destdir" unless installs.empty?
1209 installs.each do |block|
1210   dir = Dir.pwd
1211   begin
1212     block.call
1213   ensure
1214     Dir.chdir(dir)
1215   end
1218 # vi:set sw=2: