153 lines
5.2 KiB
Ruby
153 lines
5.2 KiB
Ruby
module VagrantPlugins
|
|
module CommandServe
|
|
module Util
|
|
module FuncSpec
|
|
module Client
|
|
# Generate FuncSpec proto args based on provided spec
|
|
# using given args
|
|
#
|
|
# @param spec [SDK::FuncSpec] Spec for function
|
|
# @param args [Array<Object>] List of arguments to generate from
|
|
# @return [SDK::FuncSpec::Args]
|
|
def generate_funcspec_args(spec, *args)
|
|
logger.trace("generating funcspec args for spec: #{spec}")
|
|
if !spec.is_a?(SDK::FuncSpec)
|
|
raise TypeError,
|
|
"Expected `#{SDK::FuncSpec.name}' but received `#{spec.class.name}'"
|
|
end
|
|
m_args = args.dup
|
|
if respond_to?(:seeds)
|
|
m_args = m_args +
|
|
seeds.typed.to_a +
|
|
seeds.named.map { |name, val|
|
|
val = mapper.unany(val)
|
|
Type::NamedArgument.new(
|
|
name: name,
|
|
value: val,
|
|
)
|
|
}
|
|
end
|
|
|
|
m_args += m_args.find_all { |arg|
|
|
arg.is_a?(Type::Direct)
|
|
}.map(&:value).flatten
|
|
|
|
SDK::FuncSpec::Args.new(
|
|
args: spec.args.map { |farg|
|
|
logger.trace("starting funcspec generation for #{farg}")
|
|
type = mapper.find_type(farg.type)
|
|
gen = mapper.generate(*m_args, named: farg.name, type: type)
|
|
logger.trace("generated value for type #{type.inspect} (name: #{farg.name.inspect}) -> #{gen}")
|
|
any = Google::Protobuf::Any.pack(gen)
|
|
SDK::FuncSpec::Value.new(
|
|
type: any.type_name.split("/").last,
|
|
value: any,
|
|
name: farg.name,
|
|
)
|
|
}
|
|
)
|
|
end
|
|
|
|
# Convert all given args to FuncSpec::Args proto
|
|
#
|
|
# @param extra [Array<Object>] Extra arguments to use during mapping
|
|
# @param args [Array<Object>] Arguments to be mapped
|
|
# @return [SDK::FuncSpec::Args]
|
|
def to_funcspec(*args, extra: [])
|
|
SDK::FuncSpec::Args.new(
|
|
args: args.map { |arg|
|
|
if arg.is_a?(Type::NamedArgument)
|
|
name = arg.name
|
|
arg = arg.value
|
|
else
|
|
name = ""
|
|
end
|
|
any = mapper.map(arg, *extra, to: Google::Protobuf::Any)
|
|
SDK::FuncSpec::Value.new(
|
|
name: name,
|
|
type: any.type_name.split("/").last,
|
|
value: any,
|
|
)
|
|
}
|
|
)
|
|
end
|
|
|
|
# Call a defined func and execute the callback.
|
|
#
|
|
# @param name [String,Symbol] Name of method which provides a spec and callback
|
|
# (defaults to name of caller method with `_func` suffix)
|
|
# @param args [Array<Object>] Optional list of arguments
|
|
def run_func(*args, name: nil, func_args: [])
|
|
if name.nil?
|
|
name = caller_locations.first.label.to_s
|
|
if name.end_with?("!") || name.end_with?("?")
|
|
name = name[0, name.length - 1]
|
|
end
|
|
name += "_func"
|
|
end
|
|
if !respond_to?(name)
|
|
raise ArgumentError,
|
|
"Class `#{self.class}' does not contain method `##{name}'"
|
|
end
|
|
logger.trace("running func #{name} for spec and callback")
|
|
func_args = [name] + Array(func_args)
|
|
spec, cb = send(*func_args)
|
|
f_args = generate_funcspec_args(spec, *args)
|
|
logger.trace("executing func #{name.to_s.sub(/_func$/, "")}")
|
|
cb.call(f_args)
|
|
end
|
|
end
|
|
|
|
module Service
|
|
def funcspec(args: [], named: {}, name: nil, result: nil)
|
|
if name.nil?
|
|
name = caller_locations.first.label.to_s
|
|
if name.end_with?("!") || name.end_with?("?")
|
|
name = name[0, name.length - 1]
|
|
end
|
|
end
|
|
|
|
fargs = args.map { |a|
|
|
a = make_proto(a)
|
|
SDK::FuncSpec::Value.new(
|
|
type: a.descriptor.name
|
|
)
|
|
} + named.map { |name, a|
|
|
a = make_proto(a)
|
|
SDK::FuncSpec::Value.new(
|
|
name: name,
|
|
type: a.descriptor.name
|
|
)
|
|
}
|
|
|
|
result = Empty if result.nil?
|
|
result = make_proto(result)
|
|
|
|
SDK::FuncSpec.new(
|
|
name: name,
|
|
args: fargs,
|
|
result: [
|
|
SDK::FuncSpec::Value.new(
|
|
type: result.descriptor.name,
|
|
)
|
|
]
|
|
)
|
|
end
|
|
|
|
def make_proto(v)
|
|
return v if v.respond_to?(:descriptor)
|
|
v = Mapper::REVERSE_MAP.detect do |k, v|
|
|
v if value.class.ancestors.include?(k)
|
|
end
|
|
if v.nil?
|
|
raise TypeError,
|
|
"Type `#{v.class}' is not a proto message and a mapping cannot be found"
|
|
end
|
|
v
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|