# frozen_string_literal: true module Lino module Model class CommandLine COMPONENTS = [ %i[environment_variables], %i[command], %i[options after_command], %i[subcommands], %i[options after_subcommands], %i[arguments], %i[options after_arguments] ].freeze attr_reader :command, :subcommands, :options, :arguments, :environment_variables, :executor, :working_directory def initialize(command, opts = {}) opts = with_defaults(opts) @command = command @subcommands = Hamster::Vector.new(opts[:subcommands]) @options = Hamster::Vector.new(opts[:options]) @arguments = Hamster::Vector.new(opts[:arguments]) @environment_variables = Hamster::Vector.new(opts[:environment_variables]) @executor = opts[:executor] @working_directory = opts[:working_directory] end def execute(opts = {}) @executor.execute(self, opts) end def env @environment_variables.to_h(&:array) end def array format_components(:array, COMPONENTS.drop(1)).flatten end alias to_a array def string format_components(:string, COMPONENTS).join(' ') end alias to_s string def ==(other) self.class == other.class && state == other.state end alias eql? == def hash [self.class, state].hash end protected def state [ @command, @subcommands, @options, @arguments, @environment_variables, @executor, @working_directory ] end private def with_defaults(opts) { subcommands: opts.fetch(:subcommands, []), options: opts.fetch(:options, []), arguments: opts.fetch(:arguments, []), environment_variables: opts.fetch(:environment_variables, []), executor: opts.fetch(:executor, Executors::Childprocess.new), working_directory: opts.fetch(:working_directory, nil) } end def format_components(format, paths) paths .collect { |p| components_at_path(formatted_components(format), p) } .compact .reject(&:empty?) end def formatted_components(format) { environment_variables: @environment_variables.map(&format), command: @command, options: @options .group_by(&:placement) .map { |p, o| [p, o.map(&format)] }, subcommands: @subcommands.map(&format), arguments: @arguments.map(&format) } end def components_at_path(components, path) path.inject(components) { |c, p| c && c[p] } end end end end