diff --git a/plugins/commands/serve/mappers/config_data.rb b/plugins/commands/serve/mappers/config_data.rb new file mode 100644 index 000000000..28613f1ee --- /dev/null +++ b/plugins/commands/serve/mappers/config_data.rb @@ -0,0 +1,232 @@ +module VagrantPlugins + module CommandServe + class Mappers + class ConfigDataFromSpec < Mapper + def initialize + super( + inputs: [Input.new(type: SDK::FuncSpec::Value) { |arg| + arg.type == "hashicorp.vagrant.sdk.Args.ConfigData" && + !arg&.value&.value.nil? + } + ], + output: SDK::Args::ConfigData, + func: method(:converter), + ) + end + + def converter(fv) + SDK::Args::ConfigData.decode(fv.value.value) + end + end + + # NOTE: Disabled + class ConfigDataFromProto # < Mapper + def initialize + super( + inputs: [ + Input.new(type: SDK::Args::ConfigData), + Input.new(type: Mappers) + ], + output: Type::ConfigData, + func: method(:converter), + ) + end + + def converter(proto, m) + Type::ConfigData.new(value: m.map(proto.data, to: Hash)) + end + end + + class ConfigFromConfigDataProto < Mapper + include Util::HasLogger + + def initialize + super( + inputs: [ + Input.new(type: SDK::Args::ConfigData), + Input.new(type: Mappers), + ], + output: Vagrant::Plugin::V2::Config, + func: method(:converter) + ) + end + + def converter(c, m) + base_klass = m.map(c.source, to: Class) + 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 + data = m.map(c.data, to: Hash) + + if data.key?("__service_finalized") + instance.finalize! + end + data.each_pair do |k, v| + instance.instance_variable_set("@#{k}", v) + end + instance + end + end + + class RootConfigToHashProto < Mapper + include Util::HasLogger + + def initialize + super( + inputs: [ + Input.new(type: Vagrant::Config::V2::Root), + Input.new(type: Mappers), + ], + output: SDK::Args::Hash, + func: method(:converter), + ) + end + + def converter(c, m) + data = c.__internal_state["keys"] + entries = data.map do |k, v| + value = m.map(v, to: SDK::Args::ConfigData) + SDK::Args::HashEntry.new( + key: m.map(k, to: Google::Protobuf::Any), + value: Google::Protobuf::Any.pack(value) + ) + end + + SDK::Args::Hash.new(entries: entries) + end + end + + class ConfigToProto < Mapper + include Util::HasLogger + + def initialize + super( + inputs: [ + Input.new(type: Vagrant::Plugin::V2::Config), + Input.new(type: Mappers), + ], + output: SDK::Args::ConfigData, + func: method(:converter), + ) + end + + def converter(c, m) + data = Hash.new.tap do |h| + c.instance_variables.each do |v| + h[v.to_s.sub('@', '')] = c.instance_variable_get(v) + end + end + + entries = data.map do |k, v| + begin + SDK::Args::HashEntry.new( + key: m.map(k, to: Google::Protobuf::Any), + value: m.map(v, to: Google::Protobuf::Any), + ) + rescue Internal::Graph::Search::NoPathError, TypeError + logger.warn("failed to map '#{k}' value of type `#{v.class}'") + nil + end + end.compact + SDK::Args::ConfigData.new( + data: SDK::Args::Hash.new(entries: entries), + source: m.map(c.class, to: SDK::Args::Class), + ) + end + end + + class RawRubyValueToProto < Mapper + include Util::HasLogger + + def initialize + super( + inputs: [ + Input.new(type: Object, origin_restricted: true), + Input.new(type: Mappers), + ], + output: SDK::Config::RawRubyValue, + func: method(:converter) + ) + end + + def converter(o, m) + klass = m.map(o.class, to: SDK::Args::Class) + data = Hash.new.tap do |h| + o.instance_variables.each do |v| + h[v.to_s.sub('@', '')] = o.instance_variable_get(v) + end + end + + entries = data.map do |k, v| + next if v.is_a?(Log4r::Logger) + begin + SDK::Args::HashEntry.new( + key: m.map(k, to: Google::Protobuf::Any), + value: m.map(v, to: Google::Protobuf::Any), + ) + rescue Internal::Graph::Search::NoPathError, TypeError + logger.warn("failed to map '#{k}' value of type `#{v.class}'") + nil + end + end.compact + SDK::Config::RawRubyValue.new( + source: klass, + data: SDK::Args::Hash.new(entries: entries) + ) + end + + def extra_weight + 1_000_000_000_000 + end + end + + class RawRubyValueFromProto < Mapper + include Util::HasLogger + + def initialize + super( + inputs: [ + Input.new(type: SDK::Config::RawRubyValue, origin_restricted: true), + Input.new(type: Mappers) + ], + output: Object, + func: method(:converter), + ) + end + + def converter(r, m) + base_klass = m.map(r.source, to: Class) + 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 + data = m.map(r.data, to: Hash) + + data.each_pair do |k, v| + instance.instance_variable_set("@#{k}", v) + end + instance + end + end + end + end +end diff --git a/plugins/commands/serve/mappers/proc.rb b/plugins/commands/serve/mappers/proc.rb new file mode 100644 index 000000000..a712dc377 --- /dev/null +++ b/plugins/commands/serve/mappers/proc.rb @@ -0,0 +1,78 @@ +require "singleton" + +module VagrantPlugins + module CommandServe + class Mappers + class ProcRegistry + include Singleton + + def initialize + @m = Mutex.new + @stored = {} + end + + def register(value) + @m.synchronize do + if !value.is_a?(Proc) + raise TypeError, + "Expected type `Proc' but received `#{value.class}'" + end + + # If this is already stored, return existing ID + idx = @stored.index(value) + return idx if idx + + # Create a new ID and store + id = SecureRandom.uuid + @stored[id] = value + id + end + end + + def fetch(idx) + @m.synchronize do + if !@stored.key?(idx) + raise KeyError, + "No `Proc' registered for given ID (#{idx})" + end + end + @stored[idx] + end + end + + class ProcToProto < Mapper + def initialize + super( + inputs: [ + Input.new(type: Proc), + ], + output: SDK::Args::ProcRef, + func: method(:converter), + ) + end + + def converter(value) + SDK::Args::ProcRef.new( + id: ProcRegistry.instance.register(value), + ) + end + end + + class ProcFromProto < Mapper + def initialize + super( + inputs: [ + Input.new(type: SDK::Args::ProcRef), + ], + output: Proc, + func: method(:converter) + ) + end + + def converter(proto) + ProcRegistry.instance.fetch(proto.id) + end + end + end + end +end