From c5a7ab7953372763f8b1f12c097f5dcc3edd219f Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 24 Nov 2013 11:04:54 -0800 Subject: [PATCH] core: Add the MachineReadable UI, --machine-readable flag --- bin/vagrant | 6 ++++++ lib/vagrant/ui.rb | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/bin/vagrant b/bin/vagrant index 170527070..3d61feae3 100755 --- a/bin/vagrant +++ b/bin/vagrant @@ -55,6 +55,12 @@ if ARGV.include?("--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 diff --git a/lib/vagrant/ui.rb b/lib/vagrant/ui.rb index 2e6d0fb8a..6d4fb5e59 100644 --- a/lib/vagrant/ui.rb +++ b/lib/vagrant/ui.rb @@ -31,6 +31,14 @@ module Vagrant define_method(method) { |*args| } end + # For machine-readable output. + # + # @param [String] type The type of the data + # @param [Array] data The data associated with the type + def machine(type, *data) + @logger.info("Machine: #{type} #{data.inspect}") + end + # Returns a new UI class that is scoped to the given resource name. # Subclasses can then use this scope name to do whatever they please. # @@ -51,6 +59,43 @@ module Vagrant end end + class MachineReadable < Interface + def initialize + super + + @lock = Mutex.new + end + + def ask(*args) + super + + # Machine-readable can't ask for input + raise Errors::UIExpectsTTY + end + + def machine(type, *data) + opts = {} + opts = data.pop if data.last.kind_of?(Hash) + + target = opts[:scope] || "" + + # Prepare the data by replacing characters that aren't outputted + data.each_index do |i| + data[i].gsub!(",", "%!(VAGRANT_COMMA)") + data[i].gsub!("\n", "\\n") + data[i].gsub!("\r", "\\r") + end + + @lock.synchronize do + safe_puts("#{Time.now.utc.to_i},#{target},#{type},#{data.join(",")}") + end + end + + def scope(scope_name) + BasicScope.new(self, scope_name) + end + end + # This is a UI implementation that outputs the text as is. It # doesn't add any color. class Basic < Interface @@ -172,6 +217,14 @@ module Vagrant # By default do nothing, these aren't logged define_method(method) { |*args| @ui.send(method, *args) } end + + def machine(type, *data) + opts = {} + opts = data.pop if data.last.is_a?(Hash) + opts[:scope] = @scope + data << opts + @ui.machine(type, *data) + end end # This is a UI implementation that outputs color for various types