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.

Parameters:

  • middleware (Array<Middleware::Base>) (defaults to: nil)

    middleware chain

  • strategy (Strategies::Base) (defaults to: nil)

    execution strategy

  • options (Hash)

    additional configuration



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)

Returns middleware chain.

Returns:



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.

Returns:

  • (Runner)

    default runner with standard middleware



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.

Parameters:

Returns:

  • (self)

    for method chaining



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.

Returns:

  • (Hash)

    runner configuration



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.

Parameters:

Returns:

  • (Result)

    execution result

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.

Parameters:

  • requests (Array<Request, String, Hash>)

    requests to execute

Returns:

  • (Array<Result>)

    execution results



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.

Parameters:

  • middleware_class (Class)

    middleware class to check

Returns:

  • (Boolean)

    true if 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.

Parameters:

  • middleware_class (Class)

    middleware class to remove

Returns:

  • (self)

    for method chaining



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.

Returns:

  • (Hash)

    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

Returns:

  • (Hash)

    strategy information



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