From 68ed3ba1d9caecae8c8fa6f86091d9835abdbc4c Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Fri, 29 Oct 2021 09:03:07 -0700 Subject: [PATCH] Add any unpacking. Filter blind maps. --- plugins/commands/serve/mappers.rb | 56 ++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/plugins/commands/serve/mappers.rb b/plugins/commands/serve/mappers.rb index 6aaf51e77..5a06f1ffa 100644 --- a/plugins/commands/serve/mappers.rb +++ b/plugins/commands/serve/mappers.rb @@ -21,10 +21,15 @@ module VagrantPlugins # available to all mapper calls def initialize(*args) @known_arguments = args + Mapper.generate_anys @mappers = Mapper.registered.map(&:new) @identifiers = [] end + def clone + n = self.class.new(*known_arguments) + end + # Add an argument to be included with mapping calls # # @param v [Object] Argument value @@ -55,6 +60,13 @@ module VagrantPlugins thing.object_id.to_s end + def unany(any) + type = any.type.split('/').last.to_s.split('.').inject(Object) { |memo, name| + memo.const_get(name.to_s.capitalize) + } + any.unpack(type) + end + # Map a given value # # @param value [Object] Value to map @@ -74,16 +86,37 @@ module VagrantPlugins return val if val end + if value.is_a?(Google::Protobuf::Any) + value = unany(value) + end + args = ([value] + extra_args + known_arguments).compact result = nil + # For funcspec values, we want to pre-filter since they use + # a custom validator. This will prevent invalid paths. + if value.is_a?(SDK::FuncSpec::Value) + map_mapper = self.clone + valid_mappers = map_mapper.mappers.map do |m| + next if !m.inputs.first.valid?(SDK::FuncSpec::Value) && + m.output.ancestors.include?(Google::Protobuf::MessageExts) + next m if !m.inputs.first.valid?(SDK::FuncSpec::Value) || + m.inputs.first.valid?(value) + logger.warn("removing mapper - invalid funcspec match - #{m}") + nil + end.compact + map_mapper.mappers.replace(valid_mappers) + else + map_mapper = self + end + # If we don't have a desired final type, test for mappers # that are satisfied by the arguments we have and run that # directly if to.nil? valid_outputs = [] cb = lambda do |k| - matches = mappers.find_all do |m| + matches = map_mapper.mappers.find_all do |m| m.inputs.first.valid?(k) end outs = matches.map(&:output) @@ -98,20 +131,21 @@ module VagrantPlugins if valid_outputs.empty? raise TypeError, - "No valid mappers found for input type `#{value.class}'" + "No valid mappers found for input type `#{value.class}' (#{value})" end valid_outputs.reverse! - logger.debug("mapper output types discovered for input type `#{value.class}': #{valid_outputs}") + logger.debug("mapper output types discovered for input type `#{value.class}': #{valid_outputs}, mappers:\n" + map_mapper.mappers.map(&:to_s).join("\n")) last_error = nil valid_outputs.each do |out| begin m_graph = Internal::Graph::Mappers.new( output_type: out, - mappers: self, + mappers: map_mapper, input_values: args, ) result = m_graph.execute + break rescue => err logger.debug("typeless mapping failure (non-critical): #{err} (input - #{value} / output #{out})") last_error = err @@ -121,12 +155,13 @@ module VagrantPlugins else m_graph = Internal::Graph::Mappers.new( output_type: to, - mappers: self, + mappers: map_mapper, input_values: args, ) result = m_graph.execute end cacher[cache_key] = result if cacher + logger.debug("map of #{value} to #{to.inspect} => #{result}") result end @@ -140,10 +175,15 @@ module VagrantPlugins # actual values # # @param spec [SDK::FuncSpec::Spec] + # @param expect [Array] Expected types for each argument # @return [Array, Object] - def funcspec_map(spec, *extra_args) - result = spec.args.map do |arg| - map(arg, *extra_args) + def funcspec_map(spec, *extra_args, expect: []) + expect = Array(expect) + expect.unshift(expect.pop).compact + result = Array.new.tap do |result_args| + spec.args.each_with_index do |arg, i| + result_args << map(arg, *extra_args + result_args, to: expect[i]) + end end if result.size == 1 return result.first