diff --git a/bin/vagrant b/bin/vagrant index 9e9ea3a62..605ab7bf7 100755 --- a/bin/vagrant +++ b/bin/vagrant @@ -1,7 +1,5 @@ #!/usr/bin/env ruby -# Get library -libdir = File.join(File.dirname(__FILE__), '..', 'lib') -require File.expand_path('vagrant', libdir) +require 'vagrant' # Call the command -Vagrant::Command.execute(*ARGV) \ No newline at end of file +Vagrant::Command.execute(*ARGV) diff --git a/bin/vagrant-thor b/bin/vagrant-thor new file mode 100755 index 000000000..dd013c69e --- /dev/null +++ b/bin/vagrant-thor @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby + +# NOTE: This file is TEMPORARY. Eventually the plan is for this binary +# to become the new `vagrant` binary. The only reason for the separation +# now is so that both can be tested in parallel. + +require 'vagrant' +require 'vagrant/cli' + +begin + Vagrant::CLI.start(ARGV, :env => Vagrant::Environment.load!) +rescue Vagrant::VagrantError => e + Vagrant.ui.error e.message + Vagrant.ui.error e.backtrace.join("\n") + exit e.status_code +end diff --git a/lib/vagrant.rb b/lib/vagrant.rb index a5b13e11c..a1948ce4e 100644 --- a/lib/vagrant.rb +++ b/lib/vagrant.rb @@ -4,12 +4,28 @@ require "vagrant/util/glob_loader" module Vagrant class << self + attr_writer :ui + # The source root is the path to the root directory of # the Vagrant gem. def source_root @source_root ||= File.expand_path('../../', __FILE__) end + + # Returns the {UI} class to use for talking with the + # outside world. + def ui + @ui ||= UI.new + end end + + class VagrantError < StandardError + def self.status_code(code = nil) + define_method(:status_code) { code } + end + end + + class CLIMissingEnvironment < VagrantError; status_code(1); end end # Load them up. One day we'll convert this to autoloads. Today diff --git a/lib/vagrant/cli.rb b/lib/vagrant/cli.rb new file mode 100644 index 000000000..d83c9f0af --- /dev/null +++ b/lib/vagrant/cli.rb @@ -0,0 +1,19 @@ +require 'thor' + +module Vagrant + class CLI < Thor + attr_reader :env + + def initialize(args, options, config) + super + + # Set the UI to a shell based UI using the shell object which + # Thor sets up. + Vagrant.ui = UI::Shell.new(shell) + + # The last argument must _always_ be a Vagrant Environment class. + raise CLIMissingEnvironment.new("This command requires that a Vagrant environment be properly passed in as the last parameter.") if !config[:env] + @env = config[:env] + end + end +end diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb index 96be3f008..bfd8ab76b 100644 --- a/lib/vagrant/environment.rb +++ b/lib/vagrant/environment.rb @@ -129,6 +129,12 @@ module Vagrant end end + # Makes a call to the CLI with the given arguments as if they + # came from the real command line (sometimes they do!) + def cli(*args) + Vagrant::CLI.start(args.flatten, :env => self) + end + #--------------------------------------------------------------- # Load Methods #--------------------------------------------------------------- diff --git a/lib/vagrant/ui.rb b/lib/vagrant/ui.rb new file mode 100644 index 000000000..8dea23d69 --- /dev/null +++ b/lib/vagrant/ui.rb @@ -0,0 +1,35 @@ +module Vagrant + # Vagrant UIs handle communication with the outside world (typically + # through a shell). They must respond to the typically logger methods + # of `warn`, `error`, `info`, and `confirm`. + class UI + [:warn, :error, :info, :confirm].each do |method| + # By default these methods don't do anything. A silent UI. + define_method(method) { |message| } + end + + # A shell UI, which uses a `Thor::Shell` object to talk with + # a terminal. + class Shell < UI + def initialize(shell) + @shell = shell + end + + def warn(message) + @shell.say(message, :yellow) + end + + def error(message) + @shell.say(message, :red) + end + + def info(message) + @shell.say(message) + end + + def confirm(message) + @shell.say(message, :green) + end + end + end +end