Merge pull request #276 from hashicorp/machine-readable-flag

Machine readable flag
This commit is contained in:
Sophia Castellarin 2022-06-03 12:11:15 -05:00 committed by GitHub
commit fa1f45732b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 104 additions and 16 deletions

2
go.mod
View File

@ -45,7 +45,7 @@ require (
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/hcl/v2 v2.7.1-0.20201023000745-3de61ecba298
github.com/hashicorp/nomad/api v0.0.0-20200814140818-42de70466a9d
github.com/hashicorp/vagrant-plugin-sdk v0.0.0-20220525200400-f1459dc0d92b
github.com/hashicorp/vagrant-plugin-sdk v0.0.0-20220603142803-c69edee0b0a1
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect
github.com/imdario/mergo v0.3.11
github.com/improbable-eng/grpc-web v0.13.0

2
go.sum
View File

@ -357,6 +357,8 @@ github.com/hashicorp/nomad/api v0.0.0-20200814140818-42de70466a9d h1:afuZ/KNbxwU
github.com/hashicorp/nomad/api v0.0.0-20200814140818-42de70466a9d/go.mod h1:DCi2k47yuUDzf2qWAK8E1RVmWgz/lc0jZQeEnICTxmY=
github.com/hashicorp/vagrant-plugin-sdk v0.0.0-20220525200400-f1459dc0d92b h1:GidqljOXwQSIFn+nk4DOpa0kpR/1x/yS/yCNnA7sUFE=
github.com/hashicorp/vagrant-plugin-sdk v0.0.0-20220525200400-f1459dc0d92b/go.mod h1:KWfWOiotOWKiAqdroXVc7GUFnuOzlzhnRkGTV9Js7/s=
github.com/hashicorp/vagrant-plugin-sdk v0.0.0-20220603142803-c69edee0b0a1 h1:zp+NV96agdfbsO7FI7U8VaL3PkbTNCOvPJxCuIZB8rM=
github.com/hashicorp/vagrant-plugin-sdk v0.0.0-20220603142803-c69edee0b0a1/go.mod h1:KWfWOiotOWKiAqdroXVc7GUFnuOzlzhnRkGTV9Js7/s=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce h1:7UnVY3T/ZnHUrfviiAgIUjg2PXxsQfs5bphsG8F7Keo=
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=

View File

@ -91,6 +91,9 @@ type baseCommand struct {
// flagInteractive is whether the output is interactive
flagInteractive bool
// flagMachineReadable is whether the terminal ui should only output machine readable data
flagMachineReadable bool
// flagConnection contains manual flag-based connection info.
flagConnection clicontext.Config
@ -154,8 +157,11 @@ func BaseCommand(ctx context.Context, log hclog.Logger, logOutput io.Writer, opt
// Set UI
var ui terminal.UI
// Set non interactive if the --no-interactive flag is provided
if !bc.flagInteractive {
if bc.flagMachineReadable {
// Set machine readable ui if the --machine-readable flag is provided
ui = terminal.MachineReadableUI(ctx, terminal.TableFormat)
} else if !bc.flagInteractive {
// Set non interactive if the --no-interactive flag is provided
ui = terminal.NonInteractiveUI(ctx)
} else {
// If no ui related flags are set, create a new one
@ -285,8 +291,11 @@ func (c *baseCommand) Init(opts ...Option) (err error) {
// Set UI
var ui terminal.UI
// Set non interactive if the --no-interactive flag is provided
if !c.flagInteractive {
if c.flagMachineReadable {
// Set machine readable ui if the --machine-readable flag is provided
ui = terminal.MachineReadableUI(c.Ctx, terminal.TableFormat)
} else if !c.flagInteractive {
// Set non interactive if the --no-interactive flag is provided
ui = terminal.NonInteractiveUI(c.Ctx)
} else {
// If no ui related flags are set, use the base config ui
@ -407,6 +416,12 @@ func (c *baseCommand) flagSet(bit flagSetBit, f func([]*component.CommandFlag) [
DefaultValue: "true",
Type: component.FlagBool,
},
{
LongName: "machine-readable",
Description: "Target to apply command",
DefaultValue: "false",
Type: component.FlagBool,
},
}
if bit&flagSetOperation != 0 {
@ -493,6 +508,8 @@ func (c *baseCommand) Parse(
c.flagRemote = pf.DefaultValue().(bool)
case "interactive":
c.flagInteractive = pf.DefaultValue().(bool)
case "machine-readable":
c.flagMachineReadable = pf.DefaultValue().(bool)
}
if !pf.Updated() {
continue
@ -509,6 +526,8 @@ func (c *baseCommand) Parse(
c.flagRemote = pf.Value().(bool)
case "interactive":
c.flagInteractive = pf.Value().(bool)
case "machine-readable":
c.flagMachineReadable = pf.Value().(bool)
}
c.flagData[f] = pf.Value()
}

View File

@ -42,6 +42,10 @@ func (u *runnerUI) Interactive() bool {
return false
}
func (u *runnerUI) MachineReadable() bool {
return false
}
func (u *runnerUI) ClearLine() {
// NO-OP - noninteractive
}

View File

@ -52,6 +52,15 @@ func (u *multiUI) Interactive() bool {
return false
}
func (u *multiUI) MachineReadable() bool {
for _, u := range u.UIs {
if u.MachineReadable() {
return true
}
}
return false
}
func (u *multiUI) Output(msg string, raw ...interface{}) {
for _, u := range u.UIs {
u.Output(msg, raw...)

View File

@ -62,16 +62,6 @@ module Vagrant
@state_mutex = Mutex.new
# TODO: get trigger config from go
@triggers = Vagrant::Plugin::V2::Trigger.new(@env, @config.trigger, self, @ui)
# If the ID is the special not created ID, then set our ID to
# nil so that we destroy all our data.
# if state.id == MachineState::NOT_CREATED_ID
# self.id = nil
# end
# Output a bunch of information about this machine in
# machine-readable format in case someone is listening.
@ui.machine("metadata", "provider", provider_name)
end
# @return [Box]

View File

@ -308,6 +308,9 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
add_message "hashicorp.vagrant.sdk.TerminalUI.IsInteractiveResponse" do
optional :interactive, :bool, 1
end
add_message "hashicorp.vagrant.sdk.TerminalUI.IsMachineReadableResponse" do
optional :machine_readable, :bool, 1
end
add_message "hashicorp.vagrant.sdk.TerminalUI.OutputRequest" do
repeated :lines, :string, 1
optional :style, :enum, 2, "hashicorp.vagrant.sdk.TerminalUI.OutputRequest.Style"
@ -1020,6 +1023,7 @@ module Hashicorp
ImplementsResp = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.ImplementsResp").msgclass
TerminalUI = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.TerminalUI").msgclass
TerminalUI::IsInteractiveResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.TerminalUI.IsInteractiveResponse").msgclass
TerminalUI::IsMachineReadableResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.TerminalUI.IsMachineReadableResponse").msgclass
TerminalUI::OutputRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.TerminalUI.OutputRequest").msgclass
TerminalUI::OutputRequest::Style = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.TerminalUI.OutputRequest.Style").enummodule
TerminalUI::Response = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.TerminalUI.Response").msgclass

View File

@ -26,6 +26,7 @@ module Hashicorp
rpc :Output, ::Hashicorp::Vagrant::Sdk::TerminalUI::OutputRequest, ::Google::Protobuf::Empty
rpc :Events, stream(::Hashicorp::Vagrant::Sdk::TerminalUI::Event), stream(::Hashicorp::Vagrant::Sdk::TerminalUI::Response)
rpc :IsInteractive, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::TerminalUI::IsInteractiveResponse
rpc :IsMachineReadable, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::TerminalUI::IsMachineReadableResponse
end
Stub = Service.rpc_stub_class

View File

@ -20,6 +20,7 @@ module Vagrant
def initialize(client)
super()
@client = client
@logger = Log4r::Logger.new("vagrant::ui")
end
def clear_line
@ -42,6 +43,30 @@ module Vagrant
client.output(message.gsub("%", "%%"), **opts)
end
def machine(type, *data)
if !client.is_machine_readable
@logger.info("Machine: #{type} #{data.inspect}")
return
end
opts = {}
opts = data.pop if data.last.kind_of?(Hash)
target = opts[:target] || ""
# Prepare the data by replacing characters that aren't outputted
data.each_index do |i|
data[i] = data[i].to_s.dup
data[i].gsub!(",", "%!(VAGRANT_COMMA)")
data[i].gsub!("\n", "\\n")
data[i].gsub!("\r", "\\r")
end
table_data = {
rows: [[Time.now.utc.to_i, target, type, data.join(",")]]
}
client.table(table_data, **opts)
end
def to_proto
@client.proto
end

View File

@ -19,7 +19,11 @@ module VagrantPlugins
end
def is_interactive
client.is_interactive.interactive
client.is_interactive(Empty.new).interactive
end
def is_machine_readable
client.is_machine_readable(Empty.new).machine_readable
end
def input(prompt, **opts)
@ -72,6 +76,36 @@ module VagrantPlugins
].each
).each {}
end
# @params [Map] data has the table data for the event. The form of
# this map is:
# { headers: List<string>, rows: List<List<string>> }
def table(data, **opts)
rows = data[:rows].map { |r|
SDK::TerminalUI::Event::TableRow.new(
entries: r.map { |e|
SDK::TerminalUI::Event::TableEntry.new(value: e.to_s)
}
)
}
event_resp = client.events(
[
SDK::TerminalUI::Event.new(
table: SDK::TerminalUI::Event::Table.new(
headers: data[:headers],
rows: rows
)
),
].each
)
event_resp.map { |resp|
input = resp.input
if !input.error.nil?
raise Vagrant::Errors::VagrantRemoteError, msg: input.error.message
end
}
end
end
end
end