makit 0.0.140 → 0.0.141
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +41 -41
- data/exe/makit +5 -5
- data/lib/makit/apache.rb +28 -28
- data/lib/makit/auto.rb +48 -48
- data/lib/makit/cli/build_commands.rb +500 -500
- data/lib/makit/cli/generators/base_generator.rb +74 -74
- data/lib/makit/cli/generators/dotnet_generator.rb +50 -50
- data/lib/makit/cli/generators/generator_factory.rb +49 -49
- data/lib/makit/cli/generators/node_generator.rb +50 -50
- data/lib/makit/cli/generators/ruby_generator.rb +77 -77
- data/lib/makit/cli/generators/rust_generator.rb +50 -50
- data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -167
- data/lib/makit/cli/generators/templates/node_templates.rb +161 -161
- data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -26
- data/lib/makit/cli/generators/templates/ruby/gemspec.rb +40 -40
- data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -33
- data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -35
- data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -63
- data/lib/makit/cli/generators/templates/ruby/test.rb +39 -39
- data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -29
- data/lib/makit/cli/generators/templates/ruby/version.rb +29 -29
- data/lib/makit/cli/generators/templates/rust_templates.rb +128 -128
- data/lib/makit/cli/main.rb +69 -69
- data/lib/makit/cli/project_commands.rb +868 -868
- data/lib/makit/cli/repository_commands.rb +661 -661
- data/lib/makit/cli/strategy_commands.rb +203 -203
- data/lib/makit/cli/utility_commands.rb +521 -521
- data/lib/makit/commands/factory.rb +359 -359
- data/lib/makit/commands/middleware/base.rb +73 -73
- data/lib/makit/commands/middleware/cache.rb +248 -248
- data/lib/makit/commands/middleware/command_logger.rb +312 -312
- data/lib/makit/commands/middleware/validator.rb +269 -269
- data/lib/makit/commands/request.rb +316 -316
- data/lib/makit/commands/result.rb +323 -323
- data/lib/makit/commands/runner.rb +388 -385
- data/lib/makit/commands/strategies/base.rb +171 -171
- data/lib/makit/commands/strategies/child_process.rb +165 -165
- data/lib/makit/commands/strategies/factory.rb +136 -136
- data/lib/makit/commands/strategies/synchronous.rb +139 -139
- data/lib/makit/commands.rb +50 -50
- data/lib/makit/configuration/dotnet_project.rb +12 -12
- data/lib/makit/configuration/gitlab_helper.rb +58 -58
- data/lib/makit/configuration/project.rb +168 -168
- data/lib/makit/configuration/rakefile_helper.rb +43 -43
- data/lib/makit/configuration/step.rb +34 -34
- data/lib/makit/configuration/timeout.rb +74 -74
- data/lib/makit/configuration.rb +15 -15
- data/lib/makit/content/default_gitignore.rb +7 -7
- data/lib/makit/content/default_gitignore.txt +225 -225
- data/lib/makit/content/default_rakefile.rb +13 -13
- data/lib/makit/content/gem_rakefile.rb +16 -16
- data/lib/makit/context.rb +1 -1
- data/lib/makit/data.rb +49 -49
- data/lib/makit/directories.rb +140 -140
- data/lib/makit/directory.rb +262 -262
- data/lib/makit/docs/files.rb +89 -89
- data/lib/makit/docs/rake.rb +102 -102
- data/lib/makit/dotnet/cli.rb +69 -69
- data/lib/makit/dotnet/project.rb +217 -217
- data/lib/makit/dotnet/solution.rb +38 -38
- data/lib/makit/dotnet/solution_classlib.rb +239 -239
- data/lib/makit/dotnet/solution_console.rb +264 -264
- data/lib/makit/dotnet/solution_maui.rb +354 -354
- data/lib/makit/dotnet/solution_wasm.rb +275 -275
- data/lib/makit/dotnet/solution_wpf.rb +304 -304
- data/lib/makit/dotnet.rb +102 -102
- data/lib/makit/email.rb +90 -90
- data/lib/makit/environment.rb +142 -142
- data/lib/makit/examples/runner.rb +370 -370
- data/lib/makit/exceptions.rb +45 -45
- data/lib/makit/fileinfo.rb +24 -24
- data/lib/makit/files.rb +43 -43
- data/lib/makit/gems.rb +40 -40
- data/lib/makit/git/cli.rb +54 -54
- data/lib/makit/git/repository.rb +90 -90
- data/lib/makit/git.rb +98 -98
- data/lib/makit/gitlab_runner.rb +59 -59
- data/lib/makit/humanize.rb +137 -137
- data/lib/makit/indexer.rb +47 -47
- data/lib/makit/logging/configuration.rb +308 -308
- data/lib/makit/logging/format_registry.rb +84 -84
- data/lib/makit/logging/formatters/base.rb +39 -39
- data/lib/makit/logging/formatters/console_formatter.rb +140 -140
- data/lib/makit/logging/formatters/json_formatter.rb +65 -65
- data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -71
- data/lib/makit/logging/formatters/text_formatter.rb +64 -64
- data/lib/makit/logging/log_request.rb +119 -119
- data/lib/makit/logging/logger.rb +199 -199
- data/lib/makit/logging/sinks/base.rb +91 -91
- data/lib/makit/logging/sinks/console.rb +72 -72
- data/lib/makit/logging/sinks/file_sink.rb +92 -92
- data/lib/makit/logging/sinks/structured.rb +123 -123
- data/lib/makit/logging/sinks/unified_file_sink.rb +296 -296
- data/lib/makit/logging.rb +565 -565
- data/lib/makit/markdown.rb +75 -75
- data/lib/makit/mp/basic_object_mp.rb +17 -17
- data/lib/makit/mp/command_mp.rb +13 -13
- data/lib/makit/mp/command_request.mp.rb +17 -17
- data/lib/makit/mp/project_mp.rb +199 -199
- data/lib/makit/mp/string_mp.rb +199 -191
- data/lib/makit/nuget.rb +74 -74
- data/lib/makit/port.rb +32 -32
- data/lib/makit/process.rb +163 -163
- data/lib/makit/protoc.rb +107 -107
- data/lib/makit/rake/cli.rb +196 -196
- data/lib/makit/rake/trace_controller.rb +173 -173
- data/lib/makit/rake.rb +80 -80
- data/lib/makit/ruby/cli.rb +185 -185
- data/lib/makit/ruby.rb +25 -25
- data/lib/makit/secrets.rb +51 -51
- data/lib/makit/serializer.rb +130 -130
- data/lib/makit/services/builder.rb +186 -186
- data/lib/makit/services/error_handler.rb +226 -226
- data/lib/makit/services/repository_manager.rb +231 -231
- data/lib/makit/services/validator.rb +112 -112
- data/lib/makit/setup/classlib.rb +101 -101
- data/lib/makit/setup/gem.rb +268 -268
- data/lib/makit/setup/razorclasslib.rb +101 -101
- data/lib/makit/setup/runner.rb +54 -54
- data/lib/makit/setup.rb +5 -5
- data/lib/makit/show.rb +110 -110
- data/lib/makit/storage.rb +126 -126
- data/lib/makit/symbols.rb +170 -170
- data/lib/makit/task_info.rb +130 -130
- data/lib/makit/tasks/at_exit.rb +15 -15
- data/lib/makit/tasks/build.rb +22 -22
- data/lib/makit/tasks/clean.rb +13 -13
- data/lib/makit/tasks/configure.rb +10 -10
- data/lib/makit/tasks/format.rb +10 -10
- data/lib/makit/tasks/hook_manager.rb +443 -443
- data/lib/makit/tasks/init.rb +49 -49
- data/lib/makit/tasks/integrate.rb +29 -29
- data/lib/makit/tasks/pull_incoming.rb +13 -13
- data/lib/makit/tasks/setup.rb +13 -13
- data/lib/makit/tasks/sync.rb +17 -17
- data/lib/makit/tasks/tag.rb +16 -16
- data/lib/makit/tasks/task_monkey_patch.rb +81 -81
- data/lib/makit/tasks/test.rb +22 -22
- data/lib/makit/tasks/update.rb +18 -18
- data/lib/makit/tasks.rb +20 -20
- data/lib/makit/test_cache.rb +239 -239
- data/lib/makit/tree.rb +37 -37
- data/lib/makit/v1/makit.v1_pb.rb +35 -35
- data/lib/makit/v1/makit.v1_services_pb.rb +27 -27
- data/lib/makit/version.rb +99 -99
- data/lib/makit/version_util.rb +21 -21
- data/lib/makit/wix.rb +95 -95
- data/lib/makit/yaml.rb +29 -29
- data/lib/makit/zip.rb +17 -17
- data/lib/makit copy.rb +44 -44
- data/lib/makit.rb +42 -42
- metadata +2 -2
@@ -1,385 +1,388 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "request"
|
4
|
-
require_relative "result"
|
5
|
-
require_relative "strategies/synchronous"
|
6
|
-
require_relative "strategies/factory"
|
7
|
-
require_relative "middleware/base"
|
8
|
-
require_relative "middleware/command_logger"
|
9
|
-
|
10
|
-
module Makit
|
11
|
-
module Commands
|
12
|
-
# Modern command execution engine with proper separation of concerns.
|
13
|
-
#
|
14
|
-
# The Runner coordinates command execution through a middleware chain and
|
15
|
-
# execution strategies. It provides a clean, extensible architecture for
|
16
|
-
# command processing with support for caching, logging, validation, and
|
17
|
-
# custom execution patterns.
|
18
|
-
#
|
19
|
-
# @example Basic usage
|
20
|
-
# runner = Runner.new
|
21
|
-
# request = Request.from_string("git --version")
|
22
|
-
# result = runner.execute(request)
|
23
|
-
# puts result.stdout
|
24
|
-
#
|
25
|
-
# @example With custom middleware
|
26
|
-
# runner = Runner.new(middleware: [Logger.new, Cache.new])
|
27
|
-
# result = runner.execute(request)
|
28
|
-
#
|
29
|
-
# @example With custom strategy
|
30
|
-
# runner = Runner.new(strategy: Strategies::Parallel.new)
|
31
|
-
# results = runner.execute_batch(requests)
|
32
|
-
class Runner
|
33
|
-
# @!attribute [r] middleware
|
34
|
-
# @return [Array<Middleware::Base>] middleware chain
|
35
|
-
# @!attribute [r] strategy
|
36
|
-
# @return [Strategies::Base] execution strategy
|
37
|
-
attr_reader :middleware, :strategy
|
38
|
-
|
39
|
-
# Get the default configured runner instance.
|
40
|
-
#
|
41
|
-
# @return [Runner] default runner with standard middleware
|
42
|
-
def self.default
|
43
|
-
# Recreate the runner if the log level has changed
|
44
|
-
current_log_level = defined?(Makit::Logging) ? Makit::Logging.current_log_level : :info
|
45
|
-
if @default.nil? || @last_log_level != current_log_level
|
46
|
-
@last_log_level = current_log_level
|
47
|
-
begin
|
48
|
-
@default = new(
|
49
|
-
middleware: [
|
50
|
-
Middleware::CommandLogger.new(
|
51
|
-
log_stdout: true,
|
52
|
-
log_stderr: true,
|
53
|
-
log_performance: true,
|
54
|
-
max_output_lines: 50,
|
55
|
-
),
|
56
|
-
],
|
57
|
-
)
|
58
|
-
rescue => e
|
59
|
-
# Fallback to basic runner if there are issues
|
60
|
-
@default = new
|
61
|
-
end
|
62
|
-
end
|
63
|
-
@default
|
64
|
-
end
|
65
|
-
|
66
|
-
# Initialize a new command runner.
|
67
|
-
#
|
68
|
-
# @param middleware [Array<Middleware::Base>] middleware chain
|
69
|
-
# @param strategy [Strategies::Base] execution strategy
|
70
|
-
# @param options [Hash] additional configuration
|
71
|
-
def initialize(middleware: nil, strategy: nil, **options)
|
72
|
-
@middleware = Array(middleware || default_middleware)
|
73
|
-
@strategy = strategy || Strategies::Factory.create(options)
|
74
|
-
@options = options
|
75
|
-
|
76
|
-
validate_middleware
|
77
|
-
validate_strategy
|
78
|
-
|
79
|
-
# Log runner initialization
|
80
|
-
log_runner_initialization
|
81
|
-
end
|
82
|
-
|
83
|
-
# Execute a single command request.
|
84
|
-
#
|
85
|
-
# @param request [Request, String, Hash] command request to execute
|
86
|
-
# @return [Result] execution result
|
87
|
-
# @raise [ArgumentError] if request is invalid
|
88
|
-
def execute(request)
|
89
|
-
Makit::Logging.debug("Makit::Commands::Runner.execute starting")
|
90
|
-
# Makit::Logging.debug("Executing request: #{request.to_json_pretty}")
|
91
|
-
# Normalize request to Request object
|
92
|
-
normalized_request = normalize_request(request)
|
93
|
-
|
94
|
-
# Apply middleware chain
|
95
|
-
Makit::Logging.debug("Makit::Commands::Runner.execute applying middleware chain")
|
96
|
-
result = execute_with_middleware(normalized_request) do |processed_request|
|
97
|
-
Makit::Logging.debug("Makit::Commands::Runner.execute executing strategy")
|
98
|
-
result = @strategy.execute(processed_request)
|
99
|
-
Makit::Logging.debug("Makit::Commands::Runner.execute strategy returned result")
|
100
|
-
result
|
101
|
-
end
|
102
|
-
Makit::Logging.debug("Makit::Commands::Runner.execute returning result")
|
103
|
-
Makit::Logging.debug("Makit::Commands::Runner request.exit_on_failure?: #{request.exit_on_failure?}")
|
104
|
-
# stderr often contains warnings that we don't want to exit on
|
105
|
-
if request.exit_on_failure? && (result.failure?)
|
106
|
-
Makit::Logging.error("exiting with exit code: #{result.exit_code}")
|
107
|
-
exit result.exit_code
|
108
|
-
end
|
109
|
-
result
|
110
|
-
end
|
111
|
-
|
112
|
-
# Execute multiple command requests.
|
113
|
-
#
|
114
|
-
# @param requests [Array<Request, String, Hash>] requests to execute
|
115
|
-
# @return [Array<Result>] execution results
|
116
|
-
def execute_batch(requests)
|
117
|
-
# Normalize all requests
|
118
|
-
normalized_requests = requests.map { |req| normalize_request(req) }
|
119
|
-
|
120
|
-
# Use strategy's batch execution if available, otherwise execute individually
|
121
|
-
if @strategy.respond_to?(:execute_batch)
|
122
|
-
# Apply middleware to the entire batch
|
123
|
-
execute_with_middleware_batch(normalized_requests) do |processed_requests|
|
124
|
-
@strategy.execute_batch(processed_requests)
|
125
|
-
end
|
126
|
-
else
|
127
|
-
# Execute each request individually with middleware
|
128
|
-
normalized_requests.map { |request| execute(request) }
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
# Add middleware to the execution chain.
|
133
|
-
#
|
134
|
-
# @param middleware_instance [Middleware::Base] middleware to add
|
135
|
-
# @return [self] for method chaining
|
136
|
-
def add_middleware(middleware_instance)
|
137
|
-
validate_middleware_instance(middleware_instance)
|
138
|
-
@middleware << middleware_instance
|
139
|
-
self
|
140
|
-
end
|
141
|
-
|
142
|
-
# Remove middleware from the execution chain.
|
143
|
-
#
|
144
|
-
# @param middleware_class [Class] middleware class to remove
|
145
|
-
# @return [self] for method chaining
|
146
|
-
def remove_middleware(middleware_class)
|
147
|
-
@middleware.reject! { |m| m.is_a?(middleware_class) }
|
148
|
-
self
|
149
|
-
end
|
150
|
-
|
151
|
-
# Check if specific middleware is present.
|
152
|
-
#
|
153
|
-
# @param middleware_class [Class] middleware class to check
|
154
|
-
# @return [Boolean] true if middleware is present
|
155
|
-
def has_middleware?(middleware_class)
|
156
|
-
@middleware.any? { |m| m.is_a?(middleware_class) }
|
157
|
-
end
|
158
|
-
|
159
|
-
# Get runner configuration for debugging.
|
160
|
-
#
|
161
|
-
# @return [Hash] runner configuration
|
162
|
-
def config
|
163
|
-
{
|
164
|
-
middleware: @middleware.map(&:config),
|
165
|
-
strategy: @strategy.config,
|
166
|
-
options: @options,
|
167
|
-
}
|
168
|
-
end
|
169
|
-
|
170
|
-
# Get execution statistics.
|
171
|
-
#
|
172
|
-
# @return [Hash] execution statistics
|
173
|
-
def stats
|
174
|
-
@stats ||= {
|
175
|
-
total_executions: 0,
|
176
|
-
successful_executions: 0,
|
177
|
-
failed_executions: 0,
|
178
|
-
total_duration: 0.0,
|
179
|
-
}
|
180
|
-
end
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
#
|
185
|
-
#
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
#
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
#
|
242
|
-
#
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
#
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
#
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
#
|
311
|
-
#
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
#
|
324
|
-
#
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
#
|
338
|
-
#
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
#
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
#
|
364
|
-
result.stderr.
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
logger_middleware.
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "request"
|
4
|
+
require_relative "result"
|
5
|
+
require_relative "strategies/synchronous"
|
6
|
+
require_relative "strategies/factory"
|
7
|
+
require_relative "middleware/base"
|
8
|
+
require_relative "middleware/command_logger"
|
9
|
+
|
10
|
+
module Makit
|
11
|
+
module Commands
|
12
|
+
# Modern command execution engine with proper separation of concerns.
|
13
|
+
#
|
14
|
+
# The Runner coordinates command execution through a middleware chain and
|
15
|
+
# execution strategies. It provides a clean, extensible architecture for
|
16
|
+
# command processing with support for caching, logging, validation, and
|
17
|
+
# custom execution patterns.
|
18
|
+
#
|
19
|
+
# @example Basic usage
|
20
|
+
# runner = Runner.new
|
21
|
+
# request = Request.from_string("git --version")
|
22
|
+
# result = runner.execute(request)
|
23
|
+
# puts result.stdout
|
24
|
+
#
|
25
|
+
# @example With custom middleware
|
26
|
+
# runner = Runner.new(middleware: [Logger.new, Cache.new])
|
27
|
+
# result = runner.execute(request)
|
28
|
+
#
|
29
|
+
# @example With custom strategy
|
30
|
+
# runner = Runner.new(strategy: Strategies::Parallel.new)
|
31
|
+
# results = runner.execute_batch(requests)
|
32
|
+
class Runner
|
33
|
+
# @!attribute [r] middleware
|
34
|
+
# @return [Array<Middleware::Base>] middleware chain
|
35
|
+
# @!attribute [r] strategy
|
36
|
+
# @return [Strategies::Base] execution strategy
|
37
|
+
attr_reader :middleware, :strategy
|
38
|
+
|
39
|
+
# Get the default configured runner instance.
|
40
|
+
#
|
41
|
+
# @return [Runner] default runner with standard middleware
|
42
|
+
def self.default
|
43
|
+
# Recreate the runner if the log level has changed
|
44
|
+
current_log_level = defined?(Makit::Logging) ? Makit::Logging.current_log_level : :info
|
45
|
+
if @default.nil? || @last_log_level != current_log_level
|
46
|
+
@last_log_level = current_log_level
|
47
|
+
begin
|
48
|
+
@default = new(
|
49
|
+
middleware: [
|
50
|
+
Middleware::CommandLogger.new(
|
51
|
+
log_stdout: true,
|
52
|
+
log_stderr: true,
|
53
|
+
log_performance: true,
|
54
|
+
max_output_lines: 50,
|
55
|
+
),
|
56
|
+
],
|
57
|
+
)
|
58
|
+
rescue => e
|
59
|
+
# Fallback to basic runner if there are issues
|
60
|
+
@default = new
|
61
|
+
end
|
62
|
+
end
|
63
|
+
@default
|
64
|
+
end
|
65
|
+
|
66
|
+
# Initialize a new command runner.
|
67
|
+
#
|
68
|
+
# @param middleware [Array<Middleware::Base>] middleware chain
|
69
|
+
# @param strategy [Strategies::Base] execution strategy
|
70
|
+
# @param options [Hash] additional configuration
|
71
|
+
def initialize(middleware: nil, strategy: nil, **options)
|
72
|
+
@middleware = Array(middleware || default_middleware)
|
73
|
+
@strategy = strategy || Strategies::Factory.create(options)
|
74
|
+
@options = options
|
75
|
+
|
76
|
+
validate_middleware
|
77
|
+
validate_strategy
|
78
|
+
|
79
|
+
# Log runner initialization
|
80
|
+
log_runner_initialization
|
81
|
+
end
|
82
|
+
|
83
|
+
# Execute a single command request.
|
84
|
+
#
|
85
|
+
# @param request [Request, String, Hash] command request to execute
|
86
|
+
# @return [Result] execution result
|
87
|
+
# @raise [ArgumentError] if request is invalid
|
88
|
+
def execute(request)
|
89
|
+
Makit::Logging.debug("Makit::Commands::Runner.execute starting")
|
90
|
+
# Makit::Logging.debug("Executing request: #{request.to_json_pretty}")
|
91
|
+
# Normalize request to Request object
|
92
|
+
normalized_request = normalize_request(request)
|
93
|
+
|
94
|
+
# Apply middleware chain
|
95
|
+
Makit::Logging.debug("Makit::Commands::Runner.execute applying middleware chain")
|
96
|
+
result = execute_with_middleware(normalized_request) do |processed_request|
|
97
|
+
Makit::Logging.debug("Makit::Commands::Runner.execute executing strategy")
|
98
|
+
result = @strategy.execute(processed_request)
|
99
|
+
Makit::Logging.debug("Makit::Commands::Runner.execute strategy returned result")
|
100
|
+
result
|
101
|
+
end
|
102
|
+
Makit::Logging.debug("Makit::Commands::Runner.execute returning result")
|
103
|
+
Makit::Logging.debug("Makit::Commands::Runner request.exit_on_failure?: #{request.exit_on_failure?}")
|
104
|
+
# stderr often contains warnings that we don't want to exit on
|
105
|
+
if request.exit_on_failure? && (result.failure?)
|
106
|
+
Makit::Logging.error("exiting with exit code: #{result.exit_code}")
|
107
|
+
exit result.exit_code
|
108
|
+
end
|
109
|
+
result
|
110
|
+
end
|
111
|
+
|
112
|
+
# Execute multiple command requests.
|
113
|
+
#
|
114
|
+
# @param requests [Array<Request, String, Hash>] requests to execute
|
115
|
+
# @return [Array<Result>] execution results
|
116
|
+
def execute_batch(requests)
|
117
|
+
# Normalize all requests
|
118
|
+
normalized_requests = requests.map { |req| normalize_request(req) }
|
119
|
+
|
120
|
+
# Use strategy's batch execution if available, otherwise execute individually
|
121
|
+
if @strategy.respond_to?(:execute_batch)
|
122
|
+
# Apply middleware to the entire batch
|
123
|
+
execute_with_middleware_batch(normalized_requests) do |processed_requests|
|
124
|
+
@strategy.execute_batch(processed_requests)
|
125
|
+
end
|
126
|
+
else
|
127
|
+
# Execute each request individually with middleware
|
128
|
+
normalized_requests.map { |request| execute(request) }
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Add middleware to the execution chain.
|
133
|
+
#
|
134
|
+
# @param middleware_instance [Middleware::Base] middleware to add
|
135
|
+
# @return [self] for method chaining
|
136
|
+
def add_middleware(middleware_instance)
|
137
|
+
validate_middleware_instance(middleware_instance)
|
138
|
+
@middleware << middleware_instance
|
139
|
+
self
|
140
|
+
end
|
141
|
+
|
142
|
+
# Remove middleware from the execution chain.
|
143
|
+
#
|
144
|
+
# @param middleware_class [Class] middleware class to remove
|
145
|
+
# @return [self] for method chaining
|
146
|
+
def remove_middleware(middleware_class)
|
147
|
+
@middleware.reject! { |m| m.is_a?(middleware_class) }
|
148
|
+
self
|
149
|
+
end
|
150
|
+
|
151
|
+
# Check if specific middleware is present.
|
152
|
+
#
|
153
|
+
# @param middleware_class [Class] middleware class to check
|
154
|
+
# @return [Boolean] true if middleware is present
|
155
|
+
def has_middleware?(middleware_class)
|
156
|
+
@middleware.any? { |m| m.is_a?(middleware_class) }
|
157
|
+
end
|
158
|
+
|
159
|
+
# Get runner configuration for debugging.
|
160
|
+
#
|
161
|
+
# @return [Hash] runner configuration
|
162
|
+
def config
|
163
|
+
{
|
164
|
+
middleware: @middleware.map(&:config),
|
165
|
+
strategy: @strategy.config,
|
166
|
+
options: @options,
|
167
|
+
}
|
168
|
+
end
|
169
|
+
|
170
|
+
# Get execution statistics.
|
171
|
+
#
|
172
|
+
# @return [Hash] execution statistics
|
173
|
+
def stats
|
174
|
+
@stats ||= {
|
175
|
+
total_executions: 0,
|
176
|
+
successful_executions: 0,
|
177
|
+
failed_executions: 0,
|
178
|
+
total_duration: 0.0,
|
179
|
+
}
|
180
|
+
end
|
181
|
+
|
182
|
+
# Make this method public as it is used by rake hooks and CLI output
|
183
|
+
# Get information about the current strategy
|
184
|
+
#
|
185
|
+
# @return [Hash] strategy information
|
186
|
+
def strategy_info
|
187
|
+
{
|
188
|
+
class: @strategy.class.name,
|
189
|
+
type: @strategy.class.name.split('::').last.downcase,
|
190
|
+
factory_info: Strategies::Factory.strategy_info
|
191
|
+
}
|
192
|
+
end
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
# Execute request with middleware chain.
|
197
|
+
#
|
198
|
+
# @param request [Request] normalized request
|
199
|
+
# @yield [Request] yields processed request to execution
|
200
|
+
# @return [Result] execution result
|
201
|
+
def execute_with_middleware(request, &block)
|
202
|
+
# Build middleware chain
|
203
|
+
chain = build_middleware_chain(request)
|
204
|
+
|
205
|
+
# Execute chain
|
206
|
+
result = chain.call(request, &block)
|
207
|
+
|
208
|
+
# Log high-level success/error using the default logger
|
209
|
+
log_command_result(request, result)
|
210
|
+
|
211
|
+
# Update statistics
|
212
|
+
update_stats(result)
|
213
|
+
|
214
|
+
result
|
215
|
+
end
|
216
|
+
|
217
|
+
# Execute batch with middleware chain.
|
218
|
+
#
|
219
|
+
# @param requests [Array<Request>] normalized requests
|
220
|
+
# @yield [Array<Request>] yields processed requests to execution
|
221
|
+
# @return [Array<Result>] execution results
|
222
|
+
def execute_with_middleware_batch(requests, &block)
|
223
|
+
# For batch execution, apply middleware to each request individually
|
224
|
+
# This maintains the middleware contract while supporting batch execution
|
225
|
+
results = requests.map do |request|
|
226
|
+
execute_with_middleware(request) { |req| [req] }
|
227
|
+
end.flatten
|
228
|
+
|
229
|
+
# Then execute the batch
|
230
|
+
processed_requests = results.map(&:command).map { |cmd| Request.from_string(cmd) }
|
231
|
+
batch_results = block.call(processed_requests)
|
232
|
+
|
233
|
+
# Update statistics for batch
|
234
|
+
batch_results.each { |result| update_stats(result) }
|
235
|
+
|
236
|
+
batch_results
|
237
|
+
end
|
238
|
+
|
239
|
+
# Build middleware execution chain.
|
240
|
+
#
|
241
|
+
# @param request [Request] the request to process
|
242
|
+
# @return [Proc] middleware chain
|
243
|
+
def build_middleware_chain(request)
|
244
|
+
# Filter middleware that applies to this request
|
245
|
+
applicable_middleware = @middleware.select { |m| m.applicable?(request) }
|
246
|
+
|
247
|
+
# Build chain in reverse order so first middleware wraps everything
|
248
|
+
applicable_middleware.reverse.reduce(method(:execute_final)) do |chain, middleware|
|
249
|
+
->(req) { middleware.call(req, &chain) }
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# Final execution step (after all middleware).
|
254
|
+
#
|
255
|
+
# @param request [Request] processed request
|
256
|
+
# @return [Result] execution result
|
257
|
+
def execute_final(request)
|
258
|
+
@strategy.execute(request)
|
259
|
+
end
|
260
|
+
|
261
|
+
# Normalize various input types to Request objects.
|
262
|
+
#
|
263
|
+
# @param request [Request, String, Hash] request in various formats
|
264
|
+
# @return [Request] normalized request
|
265
|
+
# @raise [ArgumentError] if request cannot be normalized
|
266
|
+
def normalize_request(request)
|
267
|
+
case request
|
268
|
+
when Request
|
269
|
+
request
|
270
|
+
when String
|
271
|
+
Request.from_string(request)
|
272
|
+
when Hash
|
273
|
+
Request.from_hash(request)
|
274
|
+
else
|
275
|
+
raise ArgumentError, "Invalid request type: #{request.class}. Expected Request, String, or Hash."
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# Update execution statistics.
|
280
|
+
#
|
281
|
+
# @param result [Result] execution result
|
282
|
+
def update_stats(result)
|
283
|
+
stats[:total_executions] += 1
|
284
|
+
|
285
|
+
if result.success?
|
286
|
+
stats[:successful_executions] += 1
|
287
|
+
else
|
288
|
+
stats[:failed_executions] += 1
|
289
|
+
end
|
290
|
+
|
291
|
+
stats[:total_duration] += result.duration if result.duration
|
292
|
+
end
|
293
|
+
|
294
|
+
# Get default middleware chain.
|
295
|
+
#
|
296
|
+
# @return [Array<Middleware::Base>] default middleware
|
297
|
+
def default_middleware
|
298
|
+
# No default middleware for now - keep it simple
|
299
|
+
# Subclasses or configuration can add middleware as needed
|
300
|
+
[]
|
301
|
+
end
|
302
|
+
|
303
|
+
# Validate middleware array.
|
304
|
+
def validate_middleware
|
305
|
+
@middleware.each { |m| validate_middleware_instance(m) }
|
306
|
+
end
|
307
|
+
|
308
|
+
# Validate individual middleware instance.
|
309
|
+
#
|
310
|
+
# @param middleware [Object] middleware to validate
|
311
|
+
# @raise [ArgumentError] if middleware is invalid
|
312
|
+
def validate_middleware_instance(middleware)
|
313
|
+
unless middleware.respond_to?(:call)
|
314
|
+
raise ArgumentError, "Middleware must respond to #call: #{middleware.class}"
|
315
|
+
end
|
316
|
+
|
317
|
+
return if middleware.respond_to?(:applicable?)
|
318
|
+
|
319
|
+
raise ArgumentError, "Middleware must respond to #applicable?: #{middleware.class}"
|
320
|
+
end
|
321
|
+
|
322
|
+
# Validate execution strategy.
|
323
|
+
#
|
324
|
+
# @raise [ArgumentError] if strategy is invalid
|
325
|
+
def validate_strategy
|
326
|
+
unless @strategy.respond_to?(:execute)
|
327
|
+
raise ArgumentError, "Strategy must respond to #execute: #{@strategy.class}"
|
328
|
+
end
|
329
|
+
|
330
|
+
return if @strategy.respond_to?(:supports?)
|
331
|
+
|
332
|
+
raise ArgumentError, "Strategy must respond to #supports?: #{@strategy.class}"
|
333
|
+
end
|
334
|
+
|
335
|
+
|
336
|
+
|
337
|
+
# Log command execution result using the default logger.
|
338
|
+
#
|
339
|
+
# @param request [Request] the executed request
|
340
|
+
# @param result [Result] the execution result
|
341
|
+
# @return [void]
|
342
|
+
def log_command_result(request, result)
|
343
|
+
# Build the full command string
|
344
|
+
command_string = "#{request.command} #{request.arguments&.join(" ")}".strip
|
345
|
+
|
346
|
+
# Log success or error using the default logger
|
347
|
+
if result.success?
|
348
|
+
Makit::Logging.success(command_string)
|
349
|
+
else
|
350
|
+
Makit::Logging.error(command_string)
|
351
|
+
end
|
352
|
+
|
353
|
+
# Log the stdout, if there is an error or stdout is enabled
|
354
|
+
if result.failure? || request.show_stdout?
|
355
|
+
if (!result.stdout.empty?)
|
356
|
+
# split the stdout into lines and print each line
|
357
|
+
result.stdout.split("\n").each do |line|
|
358
|
+
Makit::Logging.info(line)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
# Log the stderr
|
364
|
+
return unless request.show_stderr? && !result.stderr.empty?
|
365
|
+
|
366
|
+
# split the stderr into lines and print each line
|
367
|
+
result.stderr.split("\n").each do |line|
|
368
|
+
Makit::Logging.info(line)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
# Log runner initialization for debugging.
|
373
|
+
#
|
374
|
+
# @return [void]
|
375
|
+
def log_runner_initialization
|
376
|
+
# Only log if we have a command logger middleware
|
377
|
+
logger_middleware = @middleware.find { |m| m.is_a?(Middleware::CommandLogger) }
|
378
|
+
return unless logger_middleware
|
379
|
+
|
380
|
+
logger_middleware.logger.debug("Command runner initialized",
|
381
|
+
middleware_count: @middleware.length,
|
382
|
+
strategy: @strategy.class.name,
|
383
|
+
working_directory: Dir.pwd,
|
384
|
+
options: @options)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|