#! /usr/bin/env ruby

require 'rbconfig'
require 'tempfile'
require 'fileutils'

require 'rubygems'
gem 'main', '2.8.2'
require 'main'


Main {

  name "shebangify"

  description " 
    shebangify is a script that adds the correct shebang line according to the
    ruby version running the script.  for instance, if you had ruby 1.8.7
    installed as ruby187 and ruby 1.8.6 installed as ruby186 you could do

      ruby187 foo.rb bar.rb

    to have foo.rb and bar.rb adjusted such that the shebang line would be
    
      #! /full/path/to/ruby187

    or

      ruby186 foobar.rb

    to have foobar.rb have it's shebang line adjusted to 

      #! /full/path/to/ruby186
    
    run simply as 'shebangify' the script is going to adjust to the first ruby
    in your path which would normally be the latest one.

    shebangify accepts one, or more, filenames on the command-line.  if 
    command-line of '-' to indicate reading a list of files to shebangify on
    STDIN
  "

  option("ruby"){
    description "path to ruby to use in shebang line"
    cast{|path| File.expand_path path}
    attr
  }

  argument("paths"){
    description "one or more paths to shebangify, '-' reads paths from stdin"
    arity -1
    attr
  }

  def run
    each_path{|path| shebangify?(path){ puts path }}
  end

  def each_path &b
    stdin = paths.delete('-')
    paths.push(*STDIN.readlines) if stdin
    paths.each do |path|
      next if path.strip.empty?
      b.call File.expand_path(path)
    end
  end

  def shebangify? path, &b
    re = %r/^\s*#\s*!/o
    pid = Process.pid
    basename = File.basename path
    fullpath = File.expand_path( ruby || which_ruby )
    shebang = "#! #{ fullpath }"
    fu = FileUtils

    lines = IO.readlines(path)
    matched = false

    while(( line = lines.first ))
      match = re.match line
      blank = line.strip.empty?
      if match or blank
        matched = true if match
        lines.shift
      else
        break
      end
    end

    if matched
      bak = "#{ path }.bak"
      fu.cp path, bak
      open(path, 'w'){|fd| fd.puts shebang, "\n", lines}
      fu.rm_f bak
      b ? b.call(path) : path
    else
      false
    end
  end

  def which_ruby
    c                 = Config::CONFIG
    bindir            = c["bindir"] || c['BINDIR']
    ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
    ruby_ext          = c['EXEEXT'] || ''
    ruby              = File.join(bindir, (ruby_install_name + ruby_ext))
  end

}