#!/usr/bin/env ruby

# Trap interrupts to quit cleanly. This will be overriden at some point
# by Vagrant. This is made to catch any interrupts while Vagrant is
# initializing which have historically resulted in stack traces.
Signal.trap("INT") { exit 1 }

# Split arguments by "--" if its there, we'll recombine them later
argv = ARGV.dup
argv_extra = []
if idx = argv.index("--")
  argv_extra = argv.slice(idx+1, argv.length-2)
  argv = argv.slice(0, idx)
end

# Set logging level to `debug`. This is done before loading 'vagrant', as it
# sets up the logging system.
if argv.include?("--debug")
  argv.delete("--debug")
  ENV["VAGRANT_LOG"] = "debug"
end

require 'log4r'
require 'vagrant'
require 'vagrant/cli'
require 'vagrant/util/platform'

# Create a logger right away
logger = Log4r::Logger.new("vagrant::bin::vagrant")
logger.info("`vagrant` invoked: #{ARGV.inspect}")

# Stdout/stderr should not buffer output
$stdout.sync = true
$stderr.sync = true

# These will be the options that are passed to initialze the Vagrant
# environment.
opts = {}

# Disable color in a few cases:
#
#   * --no-color is anywhere in our arguments
#   * STDOUT is not a TTY
#   * The terminal doesn't support colors (Windows)
#
if argv.include?("--no-color") || ENV["VAGRANT_NO_COLOR"]
  # Delete the argument from the list so that it doesn't
  # cause any invalid arguments down the road.
  argv.delete("--no-color")

  opts[:ui_class] = Vagrant::UI::Basic
elsif !Vagrant::Util::Platform.terminal_supports_colors?
  opts[:ui_class] = Vagrant::UI::Basic
elsif !$stdout.tty? && !Vagrant::Util::Platform.cygwin?
  # Cygwin always reports STDOUT is not a TTY, so we only disable
  # colors if its not a TTY AND its not Cygwin.
  opts[:ui_class] = Vagrant::UI::Basic
end

# Also allow users to force colors.
if argv.include?("--color")
  argv.delete("--color")
  opts[:ui_class] = Vagrant::UI::Colored
end

# Highest precedence is if we have enabled machine-readable output
if argv.include?("--machine-readable")
  argv.delete("--machine-readable")
  opts[:ui_class] = Vagrant::UI::MachineReadable
end

# Default to colored output
opts[:ui_class] ||= Vagrant::UI::Colored

# This is kind of hacky, and I'd love to find a better way to do this, but
# if we're accessing the plugin interface, we want to NOT load plugins
# for this run, because they can actually interfere with the function
# of the plugin interface.
argv.each do |arg|
  if !arg.start_with?("-")
    if arg == "plugin"
      ENV["VAGRANT_NO_PLUGINS"] = "1"
      ENV["VAGRANT_VAGRANTFILE"] = "plugin_command_#{Time.now.to_i}"
    end

    break
  end
end

# Fast path the version of Vagrant
if argv.include?("-v") || argv.include?("--version")
  puts "Vagrant #{Vagrant::VERSION}"
  exit 0
end

# Recombine the arguments
argv << "--"
argv += argv_extra

env = nil
begin
  # Create the environment, which is the cwd of wherever the
  # `vagrant` command was invoked from
  logger.debug("Creating Vagrant environment")
  env = Vagrant::Environment.new(opts)

  if !Vagrant.in_installer?
    warned = false

    # If we're in a bundler environment, we assume it is for plugin
    # development and will let the user know that.
    if defined?(Bundler)
      require 'bundler/shared_helpers'
      if Bundler::SharedHelpers.in_bundle?
        env.ui.warn(I18n.t("vagrant.general.in_bundler"))
        env.ui.warn("")
        warned = true
      end
    end

    # If we're not in the installer, warn.
    env.ui.warn(I18n.t("vagrant.general.not_in_installer")) if !warned
  end

  begin
    # Execute the CLI interface, and exit with the proper error code
    exit_status = env.cli(argv)
  ensure
    # Unload the environment so cleanup can be done
    env.unload
  end

  # Exit with the exit status from our CLI command
  exit(exit_status)
rescue Vagrant::Errors::VagrantError => e
  logger.error("Vagrant experienced an error! Details:")
  logger.error(e.inspect)
  logger.error(e.message)
  logger.error(e.backtrace.join("\n"))

  if env
    opts = { :prefix => false }
    env.ui.error e.message, opts if e.message
  else
    $stderr.puts "Vagrant failed to initialize at a very early stage:\n\n"
    $stderr.puts e.message
  end

  exit e.status_code if e.respond_to?(:status_code)
  exit 999 # An error occurred with no status code defined
end
