From f5194342855ec1d4e0d9dc295671bd56562f3533 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 27 Nov 2011 16:26:31 -0700 Subject: [PATCH] Rip out Thor::Shell --- bin/vagrant | 8 ++-- lib/vagrant/ui.rb | 120 ++++++++++++++++++++++++---------------------- 2 files changed, 68 insertions(+), 60 deletions(-) diff --git a/bin/vagrant b/bin/vagrant index 714d00936..5a3b90428 100755 --- a/bin/vagrant +++ b/bin/vagrant @@ -9,17 +9,17 @@ begin env.logger.info("vagrant") { "`vagrant` invoked: #{ARGV.inspect}" } # Disable color if the proper argument was passed - shell = nil + ui = nil if !$stdout.tty? || ARGV.include?("--no-color") - shell = Thor::Shell::Basic.new + ui = Vagrant::UI::Colored.new(env) else - shell = Thor::Base.shell.new + ui = Vagrant::UI::Colored.new(env) end # Set the UI early in case any errors are raised, and load # the config immediately, so we gather any new commands from # plugins - env.ui = Vagrant::UI::Shell.new(env, shell) + env.ui = ui env.load! # Kick start the CLI diff --git a/lib/vagrant/ui.rb b/lib/vagrant/ui.rb index dca694351..958f03d32 100644 --- a/lib/vagrant/ui.rb +++ b/lib/vagrant/ui.rb @@ -1,80 +1,88 @@ 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 - attr_accessor :env + module UI + # Vagrant UIs handle communication with the outside world (typically + # through a shell). They must respond to the following methods: + # + # * `info` + # * `warn` + # * `error` + # * `success` + class Interface + attr_accessor :env - def initialize(env) - @env = env - end + def initialize(env) + @env = env + end - [:warn, :error, :info, :confirm].each do |method| - define_method(method) do |message, *opts| - # Log normal console messages - env.logger.info("ui") { message } + [:warn, :error, :info, :success].each do |method| + define_method(method) do |message, *opts| + # Log normal console messages + env.logger.info("ui") { message } + end + end + + [:clear_line, :report_progress].each do |method| + # By default do nothing, these aren't logged + define_method(method) { |*args| } end end - [:clear_line, :report_progress, :ask, :no?, :yes?].each do |method| - # By default do nothing, these aren't logged - define_method(method) { |*args| } - end - - # A shell UI, which uses a `Thor::Shell` object to talk with - # a terminal. - class Shell < UI - def initialize(env, shell) - super(env) - - @shell = shell - end - - [[:warn, :yellow], [:error, :red], [:info, nil], [:confirm, :green]].each do |method, color| + # This is a UI implementation that outputs color for various types + # of messages. This should only be used with a TTY that supports color, + # but is up to the user of the class to verify this is the case. + class Colored < Interface + # Use some light meta-programming to create the various methods to + # output text to the UI. These all delegate the real functionality + # to `say`. + [:info, :warn, :error, :success].each do |method| class_eval <<-CODE - def #{method}(message, opts=nil) + def #{method}(message, *args) super(message) - opts ||= {} - opts[:new_line] = true if !opts.has_key?(:new_line) - @shell.say("\#{format_message(message, opts)}", #{color.inspect}, opts[:new_line]) - end - CODE - end - - [:ask, :no?, :yes?].each do |method| - class_eval <<-CODE - def #{method}(message, opts=nil) - super(message) - opts ||= {} - @shell.send(#{method.inspect}, format_message(message, opts), opts[:color]) + say(#{method.inspect}, message, *args) end CODE end + # This is used to output progress reports to the UI. + # Send this method progress/total and it will output it + # to the UI. Send `clear_line` to clear the line to show + # a continuous progress meter. def report_progress(progress, total, show_parts=true) percent = (progress.to_f / total.to_f) * 100 - line = "Progress: #{percent.to_i}%" - line << " (#{progress} / #{total})" if show_parts + line = "Progress: #{percent.to_i}%" + line << " (#{progress} / #{total})" if show_parts - @shell.say(line, nil, false) + info(line, :new_line => false) end def clear_line - @shell.say(line_reset, nil, false) - end - - protected - - def format_message(message, opts=nil) - opts = { :prefix => true }.merge(opts || {}) - message = "[#{env.resource}] #{message}" if opts[:prefix] - message - end - - def line_reset reset = "\r" reset += "\e[0K" unless Util::Platform.windows? reset + + info(reset, :new_line => false) + end + + # This method handles actually outputting a message of a given type + # to the console. + def say(type, message, opts=nil) + defaults = { :new_line => true, :prefix => true } + opts = defaults.merge(opts || {}) + + # Determine whether we're expecting to output our + # own new line or not. + printer = opts[:new_line] ? :puts : :print + + # Determine the proper IO channel to send this message + # to based on the type of the message + channel = type == :error ? $stderr : $stdout + + # Format the message + message = "[#{env.resource}] #{message}" if opts[:prefix] + + # Output! + # TODO: Color + channel.send(printer, message) end end end