diff --git a/bin/vagrant b/bin/vagrant
index 170527070..fbfdf58a3 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..5f2cf6a6d 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,46 @@ module Vagrant
end
end
+ class MachineReadable < Interface
+ include Util::SafePuts
+
+ 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] = data[i].to_s
+ 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 +220,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
diff --git a/plugins/commands/box/command/list.rb b/plugins/commands/box/command/list.rb
index 94a4d3964..033c07d1c 100644
--- a/plugins/commands/box/command/list.rb
+++ b/plugins/commands/box/command/list.rb
@@ -30,6 +30,9 @@ module VagrantPlugins
# and which don't, since we plan on doing that transparently.
boxes.each do |name, provider, _v1|
@env.ui.info("#{name.ljust(longest_box_length)} (#{provider})", :prefix => false)
+
+ @env.ui.machine("box-name", name)
+ @env.ui.machine("box-provider", provider)
end
# Success, exit status 0
diff --git a/plugins/commands/status/command.rb b/plugins/commands/status/command.rb
index 9dc5fb724..64145f19e 100644
--- a/plugins/commands/status/command.rb
+++ b/plugins/commands/status/command.rb
@@ -25,7 +25,15 @@ module VagrantPlugins
results = []
with_target_vms(argv) do |machine|
state = machine.state if !state
- results << "#{machine.name.to_s.ljust(max_name_length)} #{machine.state.short_description} (#{machine.provider_name})"
+ current_state = machine.state
+ results << "#{machine.name.to_s.ljust(max_name_length)} " +
+ "#{current_state.short_description} (#{machine.provider_name})"
+
+ opts = { scope: machine.name.to_s }
+ @env.ui.machine("provider-name", machine.provider_name, opts)
+ @env.ui.machine("state", current_state.id, opts)
+ @env.ui.machine("state-human-short", current_state.short_description, opts)
+ @env.ui.machine("state-human-long", current_state.long_description, opts)
end
message = nil
diff --git a/website/docs/source/layouts/layout.erb b/website/docs/source/layouts/layout.erb
index 180268387..ecb68dd04 100644
--- a/website/docs/source/layouts/layout.erb
+++ b/website/docs/source/layouts/layout.erb
@@ -119,6 +119,7 @@
>status
>suspend
>up
+ >Machine Readable Output
<% end %>
diff --git a/website/docs/source/stylesheets/_base.less b/website/docs/source/stylesheets/_base.less
index 5ad3eacff..67bc8fea2 100644
--- a/website/docs/source/stylesheets/_base.less
+++ b/website/docs/source/stylesheets/_base.less
@@ -86,7 +86,7 @@ h6 {
line-height: @font-size;
}
-p {
+p, td {
letter-spacing: 1px;
line-height: 32px;
diff --git a/website/docs/source/stylesheets/_components.less b/website/docs/source/stylesheets/_components.less
index 5e84f3053..06d0564d6 100644
--- a/website/docs/source/stylesheets/_components.less
+++ b/website/docs/source/stylesheets/_components.less
@@ -1,74 +1,80 @@
/* compontents */
+table.mr-types {
+ th.mr-type {
+ width: 200px;
+ }
+}
+
//search
.search-bar {
- border-bottom: 1px solid fade(@black, 10%);
- position: relative;
- z-index: 99999; //keep search above content
- margin-bottom: -1px;
+ border-bottom: 1px solid fade(@black, 10%);
+ position: relative;
+ z-index: 99999; //keep search above content
+ margin-bottom: -1px;
- .search-icon {
- height: 60px;
- width: 40px;
- background: url(/images/search_icon.png) no-repeat 0 center;
- }
-
- .search {
- //.debug;
- background: @white;
- height: 60px;
-
- input,
- button,
- form {
- .kill-effects;
- border: none;
- height: 60px;
- font-size: 20px;
- .museo-sans-light-italic;
+ .search-icon {
+ height: 60px;
+ width: 40px;
+ background: url(/images/search_icon.png) no-repeat 0 center;
}
- input {
- margin:0;
- padding: 0 0 0 0;
- font-size: 20px;
+ .search {
+ //.debug;
+ background: @white;
+ height: 60px;
- &:focus {
+ input,
+ button,
+ form {
+ .kill-effects;
+ border: none;
+ height: 60px;
+ font-size: 20px;
+ .museo-sans-light-italic;
+ }
- } //focus
- }
+ input {
+ margin:0;
+ padding: 0 0 0 0;
+ font-size: 20px;
- button {
- padding: 0 20px;
- text-transform: uppercase;
- }
+ &:focus {
+
+ } //focus
+ }
+
+ button {
+ padding: 0 20px;
+ text-transform: uppercase;
+ }
- } //search
+ } //search
} //search bar
//pagination
.pagination {
- height: 80px;
- background: @gray-background;
- padding: 0;
- margin:0 auto;
- text-transform: uppercase;
- color: @blue-text;
- z-index: 999;
- position:relative;
+ height: 80px;
+ background: @gray-background;
+ padding: 0;
+ margin:0 auto;
+ text-transform: uppercase;
+ color: @blue-text;
+ z-index: 999;
+ position:relative;
- a.previous,
- a.next {
- padding: 25px 0;
- }
+ a.previous,
+ a.next {
+ padding: 25px 0;
+ }
- a.previous {
- margin-left: 20px;
- }
+ a.previous {
+ margin-left: 20px;
+ }
- a.next {
- margin-right: 20px;
- }
+ a.next {
+ margin-right: 20px;
+ }
}
diff --git a/website/docs/source/v2/cli/machine-readable.html.md b/website/docs/source/v2/cli/machine-readable.html.md
new file mode 100644
index 000000000..239273e9f
--- /dev/null
+++ b/website/docs/source/v2/cli/machine-readable.html.md
@@ -0,0 +1,136 @@
+---
+page_title: "Machine Readable Output - Command-Line Interface"
+sidebar_current: "cli-machinereadable"
+---
+
+# Machine Readable Output
+
+Every Vagrant commands accepts a `--machine-readable` flag which enables
+machine readable output mode. In this mode, the output to the terminal
+is replaced with machine-friendly output.
+
+This mode makes it easy to programmatically execute Vagrant and read data
+out of it. This output format is protected by our
+[backwards compatibility](/v2/installation/backwards-compatibility.html)
+policy. Until Vagrant 2.0 is released, however, the machine readable output
+may change as we determine more use cases for it. But the backwards
+compatibility promise should make it safe to write client libraries to
+parse the output format.
+
+
+
+Advanced topic! This is an advanced topic for use only if
+you want to programmatically execute Vagrant. If you're just getting started
+with Vagrant, you may safely skip this section.
+
+
+
+## Work-In-Progress
+
+The machine-readable output is very new (released as part of Vagrant 1.4).
+We're still gathering use cases for it and building up the output for each
+of the commands. It is likely that what you may want to achieve with
+the machine-readable output is not possible due to missing information.
+
+In this case, we ask that you please
+[open an issue](https://github.com/mitchellh/vagrant/issues)
+requesting that certain information become available. We'll most likely add
+it!
+
+## Format
+
+The machine readable format is a line-oriented, comma-delimeted text format.
+This makes it extremely easy to parse using standard Unix tools such as awk or
+grep in addition to full programming languages like Ruby or Python.
+
+The format is:
+
+```
+timestamp,target,type,data...
+```
+
+Each component is explained below:
+
+* **timestamp** is a Unix timestamp in UTC of when the message was printed.
+
+* **target** is the target of the following output. This is empty if the
+ message is related to Vagrant globally. Otherwise, this is generally a machine
+ name so you can relate output to a specific machine when multi-VM is in use.
+
+* **type** is the type of machine-readable message being outputted. There are
+ a set of standard types which are covered later.
+
+* **data** is zero or more comma-seperated values associated with the prior
+ type. The exact amount and meaning of this data is type-dependent, so you
+ must read the documentation associated with the type to understand fully.
+
+Within the format, if data contains a comma, it is replaced with
+`%!(VAGRANT_COMMA)`. This was preferred over an escape character such as \'
+because it is more friendly to tools like awk.
+
+Newlines within the format are replaced with their respective standard escape
+sequence. Newlines become a literal `\n` within the output. Carriage returns
+become a literal `\r`.
+
+## Types
+
+This section documents all the available types that may be outputted
+with the machine-readable output.
+
+
+
+
+Type |
+Description |
+
+
+
+
+box-name |
+
+ Name of a box installed into Vagrant.
+ |
+
+
+
+box-provider |
+
+ Provider for an installed box.
+ |
+
+
+
+provider-name |
+
+ The provider name of the target machine.
+ targetted
+ |
+
+
+
+state |
+
+ The state ID of the target machine.
+ targetted
+ |
+
+
+
+state-human-long |
+
+ Human-readable description of the state of the machine. This is the
+ long version, and may be a paragraph or longer.
+ targetted
+ |
+
+
+
+state-human-short |
+
+ Human-readable description of the state of the machine. This is the
+ short version, limited to at most a sentence.
+ targetted
+ |
+
+
+