* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / instruby.rb
blob85fea0ec0f5b4544ae82e58610c940580ff9a3de
1 #!./miniruby
3 load "./rbconfig.rb"
4 include RbConfig
6 srcdir = File.dirname(__FILE__)
7 $:.unshift File.expand_path("lib", srcdir)
8 require 'fileutils'
9 require 'shellwords'
10 require 'optparse'
11 require 'optparse/shellwords'
12 require 'tempfile'
14 STDOUT.sync = true
15 File.umask(0)
17 def parse_args(argv = ARGV)
18   $mantype = 'doc'
19   $destdir = nil
20   $extout = nil
21   $make = 'make'
22   $mflags = []
23   $install = []
24   $installed_list = nil
25   $dryrun = false
26   $rdocdir = nil
27   $data_mode = 0644
28   $prog_mode = 0755
29   $dir_mode = nil
30   $script_mode = nil
31   $cmdtype = ('bat' if File::ALT_SEPARATOR == '\\')
32   mflags = []
33   opt = OptionParser.new
34   opt.on('-n') {$dryrun = true}
35   opt.on('--dest-dir=DIR') {|dir| $destdir = dir}
36   opt.on('--extout=DIR') {|dir| $extout = (dir unless dir.empty?)}
37   opt.on('--make=COMMAND') {|make| $make = make}
38   opt.on('--mantype=MAN') {|man| $mantype = man}
39   opt.on('--make-flags=FLAGS', '--mflags', Shellwords) do |v|
40     if arg = v.first
41       arg.insert(0, '-') if /\A[^-][^=]*\Z/ =~ arg
42     end
43     $mflags.concat(v)
44   end
45   opt.on('-i', '--install=TYPE',
46          [:local, :bin, :"bin-arch", :"bin-comm", :lib, :man, :ext, :"ext-arch", :"ext-comm", :rdoc]) do |ins|
47     $install << ins
48   end
49   opt.on('--data-mode=OCTAL-MODE', OptionParser::OctalInteger) do |mode|
50     $data_mode = mode
51   end
52   opt.on('--prog-mode=OCTAL-MODE', OptionParser::OctalInteger) do |mode|
53     $prog_mode = mode
54   end
55   opt.on('--dir-mode=OCTAL-MODE', OptionParser::OctalInteger) do |mode|
56     $dir_mode = mode
57   end
58   opt.on('--script-mode=OCTAL-MODE', OptionParser::OctalInteger) do |mode|
59     $script_mode = mode
60   end
61   opt.on('--installed-list [FILENAME]') {|name| $installed_list = name}
62   opt.on('--rdoc-output [DIR]') {|dir| $rdocdir = dir}
63   opt.on('--cmd-type=TYPE', %w[bat cmd plain]) {|cmd| $cmdtype = (cmd unless cmd == 'plain')}
65   opt.order!(argv) do |v|
66     case v
67     when /\AINSTALL[-_]([-\w]+)=(.*)/
68       argv.unshift("--#{$1.tr('_', '-')}=#{$2}")
69     when /\A\w[-\w+]*=\z/
70       mflags << v
71     when /\A\w[-\w+]*\z/
72       $install << v.intern
73     else
74       raise OptionParser::InvalidArgument, v
75     end
76   end rescue abort [$!.message, opt].join("\n")
78   $make, *rest = Shellwords.shellwords($make)
79   $mflags.unshift(*rest) unless rest.empty?
80   $mflags.unshift(*mflags)
82   def $mflags.set?(flag)
83     grep(/\A-(?!-).*#{flag.chr}/i) { return true }
84     false
85   end
86   def $mflags.defined?(var)
87     grep(/\A#{var}=(.*)/) {return block_given? ? yield($1) : $1}
88     false
89   end
91   if $mflags.set?(?n)
92     $dryrun = true
93   else
94     $mflags << '-n' if $dryrun
95   end
97   $destdir ||= $mflags.defined?("DESTDIR")
98   if $extout ||= $mflags.defined?("EXTOUT")
99     Config.expand($extout)
100   end
102   $continue = $mflags.set?(?k)
104   if $installed_list ||= $mflags.defined?('INSTALLED_LIST')
105     Config.expand($installed_list, Config::CONFIG)
106     $installed_list = open($installed_list, "ab")
107     $installed_list.sync = true
108   end
110   $rdocdir ||= $mflags.defined?('RDOCOUT')
112   $dir_mode ||= $prog_mode | 0700
113   $script_mode ||= $prog_mode
116 parse_args()
118 include FileUtils
119 include FileUtils::NoWrite if $dryrun
120 @fileutils_output = STDOUT
121 @fileutils_label = ''
123 $install_procs = Hash.new {[]}
124 def install?(*types, &block)
125   $install_procs[:all] <<= block
126   types.each do |type|
127     $install_procs[type] <<= block
128   end
131 def install(src, dest, options = {})
132   options[:preserve] = true
133   super(src, with_destdir(dest), options)
134   if $installed_list
135     dest = File.join(dest, File.basename(src)) if $made_dirs[dest]
136     $installed_list.puts dest
137   end
140 def ln_sf(src, dest)
141   super(src, with_destdir(dest))
142   $installed_list.puts dest if $installed_list
145 $made_dirs = {}
146 def makedirs(dirs)
147   dirs = fu_list(dirs)
148   dirs.collect! do |dir|
149     realdir = with_destdir(dir)
150     realdir unless $made_dirs.fetch(dir) do
151       $made_dirs[dir] = true
152       $installed_list.puts(File.join(dir, "")) if $installed_list
153       File.directory?(realdir)
154     end
155   end.compact!
156   super(dirs, :mode => $dir_mode) unless dirs.empty?
159 def install_recursive(srcdir, dest, options = {})
160   opts = options.clone
161   noinst = opts.delete(:no_install)
162   glob = opts.delete(:glob) || "*"
163   subpath = srcdir.size..-1
164   Dir.glob("#{srcdir}/**/#{glob}") do |src|
165     case base = File.basename(src)
166     when /\A\#.*\#\z/, /~\z/
167       next
168     end
169     if noinst
170       if Array === noinst
171         next if noinst.any? {|n| File.fnmatch?(n, base)}
172       else
173         next if File.fnmatch?(noinst, base)
174       end
175     end
176     d = dest + src[subpath]
177     if File.directory?(src)
178       makedirs(d)
179     else
180       makedirs(File.dirname(d))
181       install src, d, opts
182     end
183   end
186 def open_for_install(path, mode)
187   data = open(realpath = with_destdir(path), "rb") {|f| f.read} rescue nil
188   newdata = yield
189   unless $dryrun
190     unless newdata == data
191       open(realpath, "wb", mode) {|f| f.write newdata}
192     end
193     File.chmod(mode, realpath)
194   end
195   $installed_list.puts path if $installed_list
198 def with_destdir(dir)
199   return dir if !$destdir or $destdir.empty?
200   dir = dir.sub(/\A\w:/, '') if File::PATH_SEPARATOR == ';'
201   $destdir + dir
204 exeext = CONFIG["EXEEXT"]
206 ruby_install_name = CONFIG["ruby_install_name"]
207 rubyw_install_name = CONFIG["rubyw_install_name"]
208 goruby_install_name = "go" + ruby_install_name
210 version = CONFIG["ruby_version"]
211 bindir = CONFIG["bindir"]
212 libdir = CONFIG["libdir"]
213 archhdrdir = rubyhdrdir = CONFIG["rubyhdrdir"]
214 archhdrdir += "/" + CONFIG["arch"]
215 rubylibdir = CONFIG["rubylibdir"]
216 archlibdir = CONFIG["archdir"]
217 sitelibdir = CONFIG["sitelibdir"]
218 sitearchlibdir = CONFIG["sitearchdir"]
219 vendorlibdir = CONFIG["vendorlibdir"]
220 vendorarchlibdir = CONFIG["vendorarchdir"]
221 mandir = File.join(CONFIG["mandir"], "man")
222 configure_args = Shellwords.shellwords(CONFIG["configure_args"])
223 enable_shared = CONFIG["ENABLE_SHARED"] == 'yes'
224 dll = CONFIG["LIBRUBY_SO"]
225 lib = CONFIG["LIBRUBY"]
226 arc = CONFIG["LIBRUBY_A"]
228 install?(:local, :arch, :bin, :'bin-arch') do
229   puts "installing binary commands"
231   makedirs [bindir, libdir, archlibdir]
233   install ruby_install_name+exeext, bindir, :mode => $prog_mode
234   if rubyw_install_name and !rubyw_install_name.empty?
235     install rubyw_install_name+exeext, bindir, :mode => $prog_mode
236   end
237   if File.exist? goruby_install_name+exeext
238     install goruby_install_name+exeext, bindir, :mode => $prog_mode
239   end
240   if enable_shared and dll != lib
241     install dll, bindir, :mode => $prog_mode
242   end
243   install lib, libdir, :mode => $prog_mode unless lib == arc
244   install arc, libdir, :mode => $data_mode
245   install "rbconfig.rb", archlibdir, :mode => $data_mode
246   if CONFIG["ARCHFILE"]
247     for file in CONFIG["ARCHFILE"].split
248       install file, archlibdir, :mode => $data_mode
249     end
250   end
252   if dll == lib and dll != arc
253     for link in CONFIG["LIBRUBY_ALIASES"].split
254       ln_sf(dll, File.join(libdir, link))
255     end
256   end
259 if $extout
260   extout = "#$extout"
261   install?(:ext, :arch, :'ext-arch') do
262     puts "installing extension objects"
263     makedirs [archlibdir, sitearchlibdir, vendorarchlibdir, archhdrdir]
264     if noinst = CONFIG["no_install_files"] and noinst.empty?
265       noinst = nil
266     end
267     install_recursive("#{extout}/#{CONFIG['arch']}", archlibdir, :no_install => noinst, :mode => $prog_mode)
268     install_recursive("#{extout}/include/#{CONFIG['arch']}", archhdrdir, :glob => "*.h", :mode => $data_mode)
269   end
270   install?(:ext, :comm, :'ext-comm') do
271     puts "installing extension scripts"
272     hdrdir = rubyhdrdir + "/ruby"
273     makedirs [rubylibdir, sitelibdir, vendorlibdir, hdrdir]
274     install_recursive("#{extout}/common", rubylibdir, :mode => $data_mode)
275     install_recursive("#{extout}/include/ruby", hdrdir, :glob => "*.h", :mode => $data_mode)
276   end
279 install?(:rdoc) do
280   if $rdocdir
281     puts "installing rdoc"
283     ridatadir = File.join(CONFIG['datadir'], 'ri/$(MAJOR).$(MINOR).$(TEENY)/system')
284     Config.expand(ridatadir)
285     makedirs [ridatadir]
286     install_recursive($rdocdir, ridatadir, :mode => $data_mode)
287   end
290 install?(:local, :comm, :bin, :'bin-comm') do
291   puts "installing command scripts"
293   Dir.chdir srcdir
294   makedirs [bindir, rubylibdir]
296   ruby_shebang = File.join(bindir, ruby_install_name)
297   if File::ALT_SEPARATOR
298     ruby_bin = ruby_shebang.tr(File::SEPARATOR, File::ALT_SEPARATOR)
299   end
300   for src in Dir["bin/*"]
301     next unless File.file?(src)
302     next if /\/[.#]|(\.(old|bak|orig|rej|diff|patch|core)|~|\/core)$/i =~ src
304     name = ruby_install_name.sub(/ruby/, File.basename(src))
306     shebang = ''
307     body = ''
308     open(src, "rb") do |f|
309       shebang = f.gets
310       body = f.read
311     end
312     shebang.sub!(/^\#!.*?ruby\b/) {"#!" + ruby_shebang}
313     shebang.sub!(/\r$/, '')
314     body.gsub!(/\r$/, '')
316     cmd = File.join(bindir, name)
317     cmd << ".#{$cmdtype}" if $cmdtype
318     open_for_install(cmd, $script_mode) do
319       case $cmdtype
320       when "bat"
321         "#{<<EOH}#{shebang}#{body}#{<<EOF}".gsub(/$/, "\r")
322 @echo off
323 @if not "%~d0" == "~d0" goto WinNT
324 #{ruby_bin} -x "#{cmd}" %1 %2 %3 %4 %5 %6 %7 %8 %9
325 @goto endofruby
326 :WinNT
327 "%~dp0#{ruby_install_name}" -x "%~f0" %*
328 @goto endofruby
330 __END__
331 :endofruby
333       when "cmd"
334         "#{<<EOH}#{shebang}#{body}"
335 @"%~dp0#{ruby_install_name}" -x "%~f0" %*
336 @exit /b %ERRORLEVEL%
338       else
339         shebang + body
340       end
341     end
342   end
345 install?(:local, :comm, :lib) do
346   puts "installing library scripts"
348   Dir.chdir srcdir
349   makedirs [rubylibdir]
351   for f in Dir["lib/**/*{.rb,help-message}"]
352     dir = File.dirname(f).sub!(/\Alib/, rubylibdir) || rubylibdir
353     makedirs dir
354     install f, dir, :mode => $data_mode
355   end
358 install?(:local, :arch, :lib) do
359   puts "installing headers"
361   Dir.chdir(srcdir)
362   makedirs [rubyhdrdir]
363   noinst = []
364   unless RUBY_PLATFORM =~ /mswin32|mingw|bccwin32/
365     noinst << "win32.h"
366   end
367   noinst = nil if noinst.empty?
368   install_recursive("include", rubyhdrdir, :no_install => noinst, :glob => "*.h", :mode => $data_mode)
371 install?(:local, :comm, :man) do
372   puts "installing manpages"
374   Dir.chdir(srcdir)
375   for mdoc in Dir["*.[1-9]"]
376     next unless File.file?(mdoc) and open(mdoc){|fh| fh.read(1) == '.'}
378     destdir = mandir + mdoc[/(\d+)$/]
379     destfile = File.join(destdir, mdoc.sub(/ruby/, ruby_install_name))
381     makedirs destdir
383     if $mantype == "doc"
384       install mdoc, destfile, :mode => $data_mode
385     else
386       require 'mdoc2man.rb'
388       w = Tempfile.open(mdoc)
390       open(mdoc) { |r|
391         Mdoc2Man.mdoc2man(r, w)
392       }
394       w.close
396       install w.path, destfile, :mode => $data_mode
397     end
398   end
401 $install << :local << :ext if $install.empty?
402 $install.each do |inst|
403   if !(procs = $install_procs[inst]) || procs.empty?
404     next warn("unknown install target - #{inst}")
405   end
406   procs.each do |block|
407     dir = Dir.pwd
408     begin
409       block.call
410     ensure
411       Dir.chdir(dir)
412     end
413   end
416 # vi:set sw=2: