668 lines
16 KiB
Ruby
668 lines
16 KiB
Ruby
# Patch things to produce proto messages
|
|
require "pathname"
|
|
require "securerandom"
|
|
require "google/protobuf/wrappers_pb"
|
|
require "google/protobuf/well_known_types"
|
|
|
|
PROTO_LOGGER = Log4r::Logger.new("vagrant::protologger")
|
|
|
|
# Default proto mapping
|
|
class Object
|
|
def self.to_proto
|
|
Hashicorp::Vagrant::Sdk::Args::Class.new(name: name)
|
|
end
|
|
|
|
def to_any
|
|
pro = to_proto
|
|
begin
|
|
Google::Protobuf::Any.pack(pro)
|
|
rescue
|
|
PROTO_LOGGER.warn("failed to any this type: #{self.class} value: #{self}")
|
|
raise
|
|
end
|
|
end
|
|
|
|
def to_proto
|
|
begin
|
|
klass = self.class.to_proto
|
|
data = Hash.new.tap do |h|
|
|
instance_variables.each do |v|
|
|
h[v.to_s.sub('@', '')] = instance_variable_get(v)
|
|
end
|
|
end
|
|
|
|
entries = data.map do |k, v|
|
|
Hashicorp::Vagrant::Sdk::Args::HashEntry.new(
|
|
key: k.to_any,
|
|
value: v.to_any,
|
|
)
|
|
end.compact
|
|
Hashicorp::Vagrant::Sdk::Config::RawRubyValue.new(
|
|
source: klass,
|
|
data: Hashicorp::Vagrant::Sdk::Args::Hash.new(entries: entries)
|
|
)
|
|
end
|
|
rescue => err
|
|
PROTO_LOGGER.warn("failed to proto #{self.class} | reason: #{err}")
|
|
raise
|
|
end
|
|
end
|
|
|
|
# Base types
|
|
class Array
|
|
def to_proto
|
|
Hashicorp::Vagrant::Sdk::Args::Array.new(
|
|
list: map(&:to_any)
|
|
)
|
|
end
|
|
end
|
|
|
|
class FalseClass
|
|
def to_proto
|
|
Google::Protobuf::BoolValue.new(value: false)
|
|
end
|
|
end
|
|
|
|
class Float
|
|
def to_proto
|
|
Google::Protobuf::FloatValue.new(value: self)
|
|
end
|
|
end
|
|
|
|
class Hash
|
|
def to_proto
|
|
entries = map do |k, v|
|
|
Hashicorp::Vagrant::Sdk::Args::HashEntry.new(
|
|
key: k.to_any,
|
|
value: v.to_any,
|
|
)
|
|
end
|
|
Hashicorp::Vagrant::Sdk::Args::Hash.new(entries: entries)
|
|
end
|
|
end
|
|
|
|
class Integer
|
|
def to_proto
|
|
Google::Protobuf::Int64Value.new(value: self)
|
|
end
|
|
end
|
|
|
|
class NilClass
|
|
def to_proto
|
|
Hashicorp::Vagrant::Sdk::Args::Null.new
|
|
end
|
|
end
|
|
|
|
class Pathname
|
|
def to_proto
|
|
Hashicorp::Vagrant::Sdk::Args::Path.new(
|
|
path: to_s
|
|
)
|
|
end
|
|
end
|
|
|
|
class Proc
|
|
def to_proto
|
|
Hashicorp::Vagrant::Sdk::Args::ProcRef.new(
|
|
id: VagrantPlugins::CommandServe::Mappers::ProcRegistry.instance.register(self)
|
|
)
|
|
end
|
|
end
|
|
|
|
class Range
|
|
def to_proto
|
|
Hashicorp::Vagrant::Sdk::Args::Range.new(start: first, end: last)
|
|
end
|
|
end
|
|
|
|
class Set
|
|
def to_proto
|
|
Hashicorp::Vagrant::Sdk::Args::Set.new(list: to_a.to_proto)
|
|
end
|
|
end
|
|
|
|
class String
|
|
def to_proto
|
|
Google::Protobuf::StringValue.new(value: to_s)
|
|
end
|
|
end
|
|
|
|
class Symbol
|
|
def to_proto
|
|
Hashicorp::Vagrant::Sdk::Args::Symbol.new(str: to_s)
|
|
end
|
|
end
|
|
|
|
class TrueClass
|
|
def to_proto
|
|
Google::Protobuf::BoolValue.new(value: true)
|
|
end
|
|
end
|
|
|
|
# Complex types
|
|
class Vagrant::Plugin::V2::Config
|
|
def to_proto
|
|
data = Hash.new.tap do |h|
|
|
instance_variables.each do |v|
|
|
h[v.to_s.sub('@', '')] = instance_variable_get(v)
|
|
end
|
|
end
|
|
|
|
# Include a unique identifier for this configuration instance. This
|
|
# will allow us to identifier it later when it is decoded.
|
|
if !data.key?("_vagrant_config_identifier")
|
|
data["_vagrant_config_identifier"] = SecureRandom.uuid
|
|
end
|
|
|
|
entries = data.map do |k, v|
|
|
Hashicorp::Vagrant::Sdk::Args::HashEntry.new(
|
|
key: k.to_any,
|
|
value: v.to_any,
|
|
)
|
|
end
|
|
Hashicorp::Vagrant::Sdk::Args::ConfigData.new(
|
|
data: Hashicorp::Vagrant::Sdk::Args::Hash.new(entries: entries),
|
|
source: self.class.to_proto,
|
|
)
|
|
end
|
|
end
|
|
|
|
class Vagrant::Config::V2::Root
|
|
def to_proto
|
|
__internal_state["keys"].to_proto
|
|
end
|
|
end
|
|
|
|
class VagrantPlugins::CommandServe::Type::CommunicatorCommandArguments
|
|
def to_proto
|
|
Hashicorp::Vagrant::Sdk::Communicator::Command.new(command: value)
|
|
end
|
|
end
|
|
|
|
class VagrantPlugins::CommandServe::Type::CommandInfo
|
|
def to_proto
|
|
flags = info.flags.map do |f|
|
|
Vagrant::Hashicorp::Sdk::Command::Flag.new(
|
|
long_name: f.long_name,
|
|
short_name: f.short_name,
|
|
description: f.description,
|
|
default_value: f.default_value,
|
|
type: f.type == :BOOL ? Vagrant::Hashicorp::Sdk::Command::Flag::Type::BOOL :
|
|
Hashicorp::Vagrant::Sdk::Command::Flag::Type::STRING
|
|
)
|
|
end
|
|
subcommands = info.subcommands.map do |s_info|
|
|
converter(s_info)
|
|
end
|
|
Hashicorp::Vagrant::Sdk::Command::CommandInfo.new(
|
|
name: info.name,
|
|
help: info.help,
|
|
synopsis: info.synopsis,
|
|
flags: flags,
|
|
subcommands: subcommands,
|
|
primary: info.primary,
|
|
)
|
|
end
|
|
end
|
|
|
|
class VagrantPlugins::CommandServe::Type::Direct
|
|
def to_proto
|
|
Hashicorp::Vagrant::Sdk::Args::Direct.new(
|
|
arguments: value.to_proto
|
|
)
|
|
end
|
|
end
|
|
|
|
class VagrantPlugins::CommandServe::Type::Duration
|
|
def to_proto
|
|
Hashicorp::Vagrant::Sdk::Args::Duration.new(
|
|
duration: value
|
|
)
|
|
end
|
|
end
|
|
|
|
class VagrantPlugins::CommandServe::Type::Folders
|
|
def to_proto
|
|
Hashicorp::Vagrant::Sdk::Args::Folders.new(
|
|
folders: value.to_proto
|
|
)
|
|
end
|
|
end
|
|
|
|
class VagrantPlugins::CommandServe::Type::Options
|
|
def to_proto
|
|
Hashicorp::Vagrant::Sdk::Args::Options.new(
|
|
options: value.to_proto
|
|
)
|
|
end
|
|
end
|
|
|
|
class Log4r::Logger
|
|
def to_proto
|
|
Hashicorp::Vagrant::Sdk::Args::RubyLogger.new(name: fullname)
|
|
end
|
|
end
|
|
|
|
# Proto conversions
|
|
class Google::Protobuf::Any
|
|
def to_ruby
|
|
_vagrant_unany(self).to_ruby
|
|
end
|
|
end
|
|
|
|
module Google::Protobuf::MessageExts
|
|
def to_ruby
|
|
return value if self.respond_to?(:value)
|
|
|
|
raise NotImplementedError,
|
|
"#{self.class}#to_ruby has not been implemented"
|
|
end
|
|
|
|
# Convert Any proto message to actual message type
|
|
#
|
|
# @param any [Google::Protobuf::Any]
|
|
# @return [Google::Protobuf::MessageExts]
|
|
def _vagrant_unany(any)
|
|
type = _vagrant_find_type(any.type_name.split("/").last.to_s)
|
|
any.unpack(type)
|
|
end
|
|
|
|
# Get const from name
|
|
#
|
|
# @param name [String]
|
|
# @return [Class]
|
|
def _vagrant_find_type(name)
|
|
parent_module_options = []
|
|
name.to_s.split(".").inject(Object) { |memo, n|
|
|
c = memo.constants.detect { |mc| mc.to_s.downcase == n.to_s.downcase }
|
|
if c.nil?
|
|
parent_module_options.delete(memo)
|
|
parent_module_options.each do |pm|
|
|
c = pm.constants.detect { |mc| mc.to_s.downcase == n.to_s.downcase }
|
|
if !c.nil?
|
|
memo = pm
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
raise NameError,
|
|
"Failed to find constant for `#{name}'" if c.nil?
|
|
|
|
parent_module_options = memo.constants.select {
|
|
|mc| mc.to_s.downcase == n.to_s.downcase
|
|
}.map {
|
|
|mc| memo.const_get(mc)
|
|
}
|
|
memo.const_get(c)
|
|
}
|
|
end
|
|
|
|
def _vagrant_load_client(klass)
|
|
raise TypeError,
|
|
"Proto is not a valid client message type (#{self.class})" if
|
|
!respond_to?(:addr)
|
|
|
|
cid = "client+" + addr.to_s
|
|
return VagrantPlugins::CommandServe.cache.get(cid) if
|
|
VagrantPlugins::CommandServe.cache.registered?(cid)
|
|
|
|
v = klass.load(self, broker: VagrantPlugins::CommandServe.broker)
|
|
VagrantPlugins::CommandServe.cache.register(cid, v)
|
|
v
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Array
|
|
def to_ruby
|
|
list.map { |a|
|
|
val = _vagrant_unany(a).to_ruby
|
|
val.is_a?(VagrantPlugins::CommandServe::Type) ? val.value : val
|
|
}
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::BoxMetadata
|
|
# TODO(spox): should this be returning a box metadata instance instead of client?
|
|
def to_ruby
|
|
_vagrant_load_client(VagrantPlugins::CommandServe::Client::BoxMetadata)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Class
|
|
def to_ruby
|
|
if name.to_s.empty?
|
|
raise NameError,
|
|
"No name defined for for class"
|
|
end
|
|
name.to_s.split("::").inject(Object) { |memo, n|
|
|
c = memo.constants.detect { |mc| mc.to_s.downcase == n.to_s.downcase }
|
|
raise NameError,
|
|
"Failed to find constant for `#{name}'" if c.nil?
|
|
memo.const_get(c)
|
|
}
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::CorePluginManager
|
|
def to_ruby
|
|
_vagrant_load_client(VagrantPlugins::CommandServe::Client::CorePluginManager)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::ConfigData
|
|
def to_ruby
|
|
base_klass = source.to_ruby
|
|
if [0, -1].include?(base_klass.instance_method(:initialize).arity)
|
|
klass = base_klass
|
|
else
|
|
klass = Class.new(base_klass)
|
|
klass.class_eval("
|
|
def self.to_proto
|
|
#{base_klass.name}.to_proto
|
|
end
|
|
def self.class
|
|
#{base_klass.name}
|
|
end
|
|
def initialize
|
|
end
|
|
")
|
|
end
|
|
instance = klass.new
|
|
d = data.to_ruby
|
|
|
|
# Since we are restoring the config, if the config this
|
|
# represents was already finalized we finalize it first
|
|
# before we inject the instance variables to get as close
|
|
# to the correct original state as possible
|
|
if d.key?("__finalized")
|
|
instance.finalize!
|
|
instance._finalize!
|
|
end
|
|
|
|
# Now set our data into the instance
|
|
d.each_pair do |k, v|
|
|
instance.instance_variable_set("@#{k}", v)
|
|
end
|
|
|
|
instance
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Direct
|
|
def to_ruby
|
|
VagrantPlugins::CommandServe::Type::Direct.new(
|
|
arguments: arguments.map { |arg|
|
|
val = arg.to_ruby
|
|
val.is_a?(VagrantPlugins::CommandServe::Type) ? val.value : val
|
|
}
|
|
)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Folders
|
|
def to_ruby
|
|
VagrantPlugins::CommandServe::Type::Folders.new(value: folders.to_ruby)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Guest
|
|
def to_ruby
|
|
_vagrant_load_client(VagrantPlugins::CommandServe::Client::Guest)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Hash
|
|
def to_ruby
|
|
data = Hash.new
|
|
entries.each do |e|
|
|
key = _vagrant_unany(e.key).to_ruby
|
|
value = _vagrant_unany(e.value).to_ruby
|
|
data[key] = value.is_a?(VagrantPlugins::CommandServe::Type) ? value.value : value
|
|
end
|
|
|
|
data
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Host
|
|
def to_ruby
|
|
client = _vagrant_load_client(VagrantPlugins::CommandServe::Client::Host)
|
|
Vagrant::Host.new(client, nil, Vagrant.plugin("2").local_manager.host_capabilities)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::NamedCapability
|
|
def to_ruby
|
|
capability.to_s.to_sym
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Null
|
|
def to_ruby
|
|
nil
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Options
|
|
def to_ruby
|
|
VagrantPlugins::CommandServe::Type::Options.new(value: options.to_ruby)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Path
|
|
def to_ruby
|
|
Pathname.new(path.to_s)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::ProcRef
|
|
def to_ruby
|
|
VagrantPlugins::CommandServe::Mappers::ProcRegistry.instance.fetch(id)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Project
|
|
def to_ruby
|
|
cid = "environment"+addr.to_s
|
|
return VagrantPlugins::CommandServe.cache.get(cid) if
|
|
VagrantPlugins::CommandServe.cache.registered?(cid)
|
|
|
|
client = _vagrant_load_client(VagrantPlugins::CommandServe::Client::Project)
|
|
ui = client.ui.to_ui
|
|
|
|
env = Vagrant::Environment.new(client: client, ui: ui)
|
|
VagrantPlugins::CommandServe.cache.register(cid, env)
|
|
env
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Provisioner
|
|
def to_ruby
|
|
_vagrant_load_client(VagrantPlugins::CommandServe::Client::Provisioner)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Provider
|
|
def to_ruby
|
|
_vagrant_load_client(VagrantPlugins::CommandServe::Client::Provider)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Range
|
|
def to_ruby
|
|
Range.new(self.start, self.end)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Config::RawRubyValue
|
|
def to_ruby
|
|
base_klass = source.to_ruby
|
|
if [0, -1].include?(base_klass.instance_method(:initialize).arity)
|
|
klass = base_klass
|
|
else
|
|
klass = Class.new(base_klass)
|
|
klass.class_eval("
|
|
def self.class
|
|
#{base_klass.name}
|
|
end
|
|
def initialize
|
|
end
|
|
")
|
|
end
|
|
|
|
instance = klass.new
|
|
d = data.to_ruby
|
|
|
|
d.each_pair do |k, v|
|
|
instance.instance_variable_set("@#{k}", v)
|
|
end
|
|
|
|
instance
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::RubyLogger
|
|
def to_ruby
|
|
Log4r::Logger.new(name)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Set
|
|
def to_ruby
|
|
::Set.new(list.to_ruby)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::StateBag
|
|
def to_ruby
|
|
_vagrant_load_client(VagrantPlugins::CommandServe::Client::StateBag)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::SyncedFolder
|
|
def to_ruby
|
|
cid = "syncedfolder+" + addr.to_s
|
|
return VagrantPlugins::CommandServe.cache.get(cid) if
|
|
VagrantPlugins::CommandServe.cache.registered?(cid)
|
|
|
|
client = _vagrant_load_client(VagrantPlugins::CommandServe::Client::SyncedFolder)
|
|
fld = Vagrant::Plugin::Remote::SyncedFolder.new(client: client)
|
|
VagrantPlugins::CommandServe.cache.register(cid, fld)
|
|
fld
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Symbol
|
|
def to_ruby
|
|
str.to_sym
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Target
|
|
def to_ruby
|
|
cid = "machine+" + addr.to_s
|
|
return VagrantPlugins::CommandServe.cache.get(cid) if
|
|
VagrantPlugins::CommandServe.cache.registered?(cid)
|
|
|
|
client = _vagrant_load_client(VagrantPlugins::CommandServe::Client::Target)
|
|
env = client.project.to_ruby
|
|
machine = env.machine(client.name.to_sym, client.provider_name.to_sym)
|
|
VagrantPlugins::CommandServe.cache.register(cid, machine)
|
|
machine
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Target::Machine
|
|
def to_ruby
|
|
cid = "machine+" + addr.to_s
|
|
return VagrantPlugins::CommandServe.cache.get(cid) if
|
|
VagrantPlugins::CommandServe.cache.registered?(cid)
|
|
|
|
client = _vagrant_load_client(VagrantPlugins::CommandServe::Client::Target::Machine)
|
|
m = Vagrant::Machine.new(client: client)
|
|
VagrantPlugins::CommandServe.cache.register(cid, m)
|
|
m
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Target::Machine::State
|
|
def to_ruby
|
|
Vagrant::MachineState.new(
|
|
m.id.to_sym, m.short_description, m.long_description
|
|
)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::TargetIndex
|
|
def to_ruby
|
|
_vagrant_load_client(VagrantPlugins::CommandServe::Client::TargetIndex)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::TimeDuration
|
|
def to_ruby
|
|
VagrantPlugins::CommandServe::Type::Duration.new(value: duration)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::TerminalUI
|
|
def to_ruby
|
|
client = _vagrant_load_client(VagrantPlugins::CommandServe::Client::Terminal)
|
|
Vagrant::UI::Remote.new(client)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Args::Vagrantfile
|
|
def to_ruby
|
|
client = _vagrant_load_client(VagrantPlugins::CommandServe::Client::Vagrantfile)
|
|
Vagrant::Vagrantfile.new(client: client)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Command::Arguments
|
|
def to_ruby
|
|
_args = args.to_a
|
|
_flags = Hash.new.tap do |flgs|
|
|
flags.each do |f|
|
|
if f.type == :BOOL
|
|
flgs[f.name] = f.bool
|
|
else
|
|
flgs[f.name] = f.string
|
|
end
|
|
end
|
|
end
|
|
VagrantPlugins::CommandServe::Type::CommandArguments.new(args: _args, flags: _flags)
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Command::CommandInfo
|
|
def to_ruby
|
|
VagrantPlugins::CommandServe::Type::CommandInfo.new(
|
|
name: name,
|
|
help: help,
|
|
synopsis: synopsis,
|
|
primary: primary,
|
|
).tap do |c|
|
|
flags.each do |f|
|
|
c.add_flag(
|
|
long_name: f.long_name,
|
|
short_name: f.short_name,
|
|
description: f.description,
|
|
default_value: f.default_value,
|
|
type: f.type,
|
|
)
|
|
end
|
|
subcommands.each do |s_proto|
|
|
c.add_subcommand(s_proto.to_ruby)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
class Hashicorp::Vagrant::Sdk::Communicator::Command
|
|
def to_ruby
|
|
VagrantPlugins::CommandServe::Type::CommunicatorCommandArguments.new(value: command)
|
|
end
|
|
end
|