vaguerent/plugins/commands/serve/service/command_service.rb
Chris Roberts 7350b85902
Implement enough of the command service to get things working.
Also updates the UI setup so that we can properly get the
    output streaming back to us.
2022-04-25 12:23:55 -05:00

136 lines
4.4 KiB
Ruby

module VagrantPlugins
module CommandServe
module Service
class CommandService < Hashicorp::Vagrant::Sdk::CommandService::Service
def help_spec(*args)
Hashicorp::Vagrant::Sdk::FuncSpec.new
end
def help(*args)
options = command_options_for(args.last.metadata["plugin_name"])
Hashicorp::Vagrant::Sdk::Command::HelpResp.new(
help: options.help
)
end
def synopsis_spec(*args)
return Hashicorp::Vagrant::Sdk::FuncSpec.new
end
def synopsis(*args)
plugin_name = args.last.metadata["plugin_name"]
plugin = Vagrant::Plugin::V2::Plugin.manager.commands[plugin_name.to_sym].to_a.first
if !plugin
raise "Failed to locate command plugin for: #{plugin_name}"
end
klass = plugin.call
Hashicorp::Vagrant::Sdk::Command::SynopsisResp.new(
synopsis: klass.synopsis
)
end
def flags_spec(*args)
Hashicorp::Vagrant::Sdk::FuncSpec.new
end
def flags(*args)
options = command_options_for(args.last.metadata["plugin_name"])
# Now we can build our list of flags
flags = options.top.list.find_all { |o|
o.is_a?(OptionParser::Switch)
}.map { |o|
Hashicorp::Vagrant::Sdk::Command::Flag.new(
description: o.desc.join(" "),
long_name: o.switch_name,
short_name: o.short.first,
type: o.is_a?(OptionParser::Switch::NoArgument) ?
Hashicorp::Vagrant::Sdk::Command::Flag::Type::BOOL :
Hashicorp::Vagrant::Sdk::Command::Flag::Type::STRING
)
}
Hashicorp::Vagrant::Sdk::Command::FlagsResp.new(
flags: flags
)
end
def command_options_for(name)
plugin = Vagrant::Plugin::V2::Plugin.manager.commands[name.to_sym].to_a.first
if !plugin
raise "Failed to locate command plugin for: #{name}"
end
# Create a new anonymous class based on the command class
# so we can modify the setup behavior
klass = Class.new(plugin.call)
# Update the option parsing to store the provided options, and then return
# a nil value. The nil return will force the command to call help and not
# actually execute anything.
klass.class_eval do
def parse_options(opts)
Thread.current.thread_variable_set(:command_options, opts)
nil
end
end
# Execute the command to populate our options
klass.new([], {}).execute
options = Thread.current.thread_variable_get(:command_options)
# Clean our option data out of the thread
Thread.current.thread_variable_set(:command_options, nil)
# Send the options back
options
end
def execute_spec(req, ctx)
Hashicorp::Vagrant::Sdk::FuncSpec.new(
args: [
Hashicorp::Vagrant::Sdk::FuncSpec::Value.new(
type: "hashicorp.vagrant.sdk.Args.TerminalUI",
name: "",
),
],
result: [
Hashicorp::Vagrant::Sdk::FuncSpec::Value.new(
type: "hashicorp.vagrant.sdk.Command.ExecuteResp",
name: "",
),
],
)
end
def execute(req, ctx)
plugin_name = ctx.metadata["plugin_name"]
if plugin_name.nil?
raise "missing plugin name in context: #{ctx.metadata.inspect}"
end
raw_terminal = req.args.first.value.value
ui_client = Client::TerminalClient.terminal_arg_to_terminal_ui(raw_terminal)
ui = Vagrant::UI::RemoteUI.new(ui_client)
env = Vagrant::Environment.new(ui: ui, ui_class: Vagrant::UI::Silent)
plugin = Vagrant::Plugin::V2::Plugin.manager.commands[plugin_name.to_sym].to_a.first
if !plugin
raise "Failed to locate command plugin for: #{plugin_name}"
end
cmd_klass = plugin.call
cmd = cmd_klass.new([], env)
begin
result = cmd.execute
rescue => e
raise e.to_s + "\n" + e.backtrace.join("\n")
end
Hashicorp::Vagrant::Sdk::Command::ExecuteResp.new(
exit_code: result
)
end
end
end
end
end