lib/dip/interaction_tree.rb
# frozen_string_literal: true
require "shellwords"
require "dip/ext/hash"
using ActiveSupportHashHelpers
module Dip
class InteractionTree
def initialize(entries)
@entries = entries
end
def find(name, *argv)
entry = entries[name.to_sym]
return unless entry
commands = expand(name.to_s, entry)
keys = [name, *argv]
rest = []
keys.size.times do
if (command = commands[keys.join(" ")])
return {command: command, argv: rest.reverse!}
else
rest << keys.pop
end
end
nil
end
def list
entries.each_with_object({}) do |(name, entry), memo|
expand(name.to_s, entry, tree: memo)
end
end
private
attr_reader :entries
def expand(name, entry, tree: {})
cmd = build_command(entry)
tree[name] = cmd
base_cmd = entry.select { |k, _| k != :subcommands }
entry[:subcommands]&.each do |sub_name, sub_entry|
sub_command_defaults!(sub_entry)
expand("#{name} #{sub_name}", base_cmd.deep_merge(sub_entry), tree: tree)
end
tree
end
def build_command(entry)
{
description: entry[:description],
runner: entry[:runner],
service: entry[:service],
pod: entry[:pod],
entrypoint: entry[:entrypoint],
command: entry[:command].to_s.strip,
shell: entry.fetch(:shell, true),
default_args: entry[:default_args].to_s.strip,
environment: entry[:environment] || {},
compose: {
method: entry.dig(:compose, :method) || entry[:compose_method] || "run",
profiles: Array(entry.dig(:compose, :profiles)),
run_options: compose_run_options(entry.dig(:compose, :run_options) || entry[:compose_run_options])
}
}
end
def sub_command_defaults!(entry)
entry[:command] ||= nil
entry[:default_args] ||= nil
entry[:subcommands] ||= nil
entry[:description] ||= nil
end
def compose_run_options(value)
return [] unless value
value.map do |o|
o = o.start_with?("-") ? o : "--#{o}"
o.shellsplit
end.flatten
end
end
end