Class: Makit::Commands::Runner

Inherits:
Object
  • Object
show all
Defined in:
lib/makit/commands/runner.rb

Overview

Modern command execution engine with proper separation of concerns.

The Runner coordinates command execution through a middleware chain and execution strategies. It provides a clean, extensible architecture for command processing with support for caching, logging, validation, and custom execution patterns.

Examples:

Basic usage

runner = Runner.new
request = Request.from_string("git --version")
result = runner.execute(request)
puts result.stdout

With custom middleware

runner = Runner.new(middleware: [Logger.new, Cache.new])
result = runner.execute(request)

With custom strategy

runner = Runner.new(strategy: Strategies::Parallel.new)
results = runner.execute_batch(requests)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(middleware: nil, strategy: nil, **options) ⇒ Runner

Initialize a new command runner.



71
72
73
74
75
76
77
78
79
80
81
# File 'lib/makit/commands/runner.rb', line 71

def initialize(middleware: nil, strategy: nil, **options)
  @middleware = Array(middleware || default_middleware)
  @strategy = strategy || Strategies::Factory.create(options)
  @options = options

  validate_middleware
  validate_strategy

  # Log runner initialization

  log_runner_initialization
end

Instance Attribute Details

#middlewareArray<Middleware::Base> (readonly)



37
38
39
# File 'lib/makit/commands/runner.rb', line 37

def middleware
  @middleware
end

#strategyObject (readonly)

Returns the value of attribute strategy.



37
# File 'lib/makit/commands/runner.rb', line 37

attr_reader :middleware, :strategy

Class Method Details

.defaultRunner

Get the default configured runner instance.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/makit/commands/runner.rb', line 42

def self.default
  # Recreate the runner if the log level has changed

  current_log_level = defined?(Makit::Logging) ? Makit::Logging.current_log_level : :info
  if @default.nil? || @last_log_level != current_log_level
    @last_log_level = current_log_level
    begin
      @default = new(
        middleware: [
          Middleware::CommandLogger.new(
            log_stdout: true,
            log_stderr: true,
            log_performance: true,
            max_output_lines: 50,
          ),
        ],
      )
    rescue => e
      # Fallback to basic runner if there are issues

      @default = new
    end
  end
  @default
end

Instance Method Details

#add_middleware(middleware_instance) ⇒ self

Add middleware to the execution chain.



136
137
138
139
140
# File 'lib/makit/commands/runner.rb', line 136

def add_middleware(middleware_instance)
  validate_middleware_instance(middleware_instance)
  @middleware << middleware_instance
  self
end

#configHash

Get runner configuration for debugging.



162
163
164
165
166
167
168
# File 'lib/makit/commands/runner.rb', line 162

def config
  {
    middleware: @middleware.map(&:config),
    strategy: @strategy.config,
    options: @options,
  }
end

#execute(request) ⇒ Result

Execute a single command request.

Raises:

  • (ArgumentError)

    if request is invalid



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/makit/commands/runner.rb', line 88

def execute(request)
  Makit::Logging.debug("Makit::Commands::Runner.execute starting")
  # Makit::Logging.debug("Executing request: #{request.to_json_pretty}")

  # Normalize request to Request object

  normalized_request = normalize_request(request)

  # Apply middleware chain

  Makit::Logging.debug("Makit::Commands::Runner.execute applying middleware chain")
  result = execute_with_middleware(normalized_request) do |processed_request|
    Makit::Logging.debug("Makit::Commands::Runner.execute executing strategy")
    result = @strategy.execute(processed_request)
    Makit::Logging.debug("Makit::Commands::Runner.execute strategy returned result")
    result
  end
  Makit::Logging.debug("Makit::Commands::Runner.execute returning result")
  Makit::Logging.debug("Makit::Commands::Runner request.exit_on_failure?: #{request.exit_on_failure?}")
  # stderr often contains warnings that we don't want to exit on

  if request.exit_on_failure? && (result.failure?)
    Makit::Logging.error("exiting with exit code: #{result.exit_code}")
    exit result.exit_code
  end
  result
end

#execute_batch(requests) ⇒ Array<Result>

Execute multiple command requests.



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/makit/commands/runner.rb', line 116

def execute_batch(requests)
  # Normalize all requests

  normalized_requests = requests.map { |req| normalize_request(req) }

  # Use strategy's batch execution if available, otherwise execute individually

  if @strategy.respond_to?(:execute_batch)
    # Apply middleware to the entire batch

    execute_with_middleware_batch(normalized_requests) do |processed_requests|
      @strategy.execute_batch(processed_requests)
    end
  else
    # Execute each request individually with middleware

    normalized_requests.map { |request| execute(request) }
  end
end

#has_middleware?(middleware_class) ⇒ Boolean

Check if specific middleware is present.



155
156
157
# File 'lib/makit/commands/runner.rb', line 155

def has_middleware?(middleware_class)
  @middleware.any? { |m| m.is_a?(middleware_class) }
end

#remove_middleware(middleware_class) ⇒ self

Remove middleware from the execution chain.



146
147
148
149
# File 'lib/makit/commands/runner.rb', line 146

def remove_middleware(middleware_class)
  @middleware.reject! { |m| m.is_a?(middleware_class) }
  self
end

#statsHash

Get execution statistics.



173
174
175
176
177
178
179
180
# File 'lib/makit/commands/runner.rb', line 173

def stats
  @stats ||= {
    total_executions: 0,
    successful_executions: 0,
    failed_executions: 0,
    total_duration: 0.0,
  }
end

#strategy_infoHash

Make this method public as it is used by rake hooks and CLI output Get information about the current strategy



186
187
188
189
190
191
192
# File 'lib/makit/commands/runner.rb', line 186

def strategy_info
  {
    class: @strategy.class.name,
    type: @strategy.class.name.split("::").last.downcase,
    factory_info: Strategies::Factory.strategy_info,
  }
end