makit 0.0.173 → 0.0.174

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.
Files changed (180) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +41 -41
  3. data/exe/makit +5 -5
  4. data/lib/makit/apache.rb +28 -28
  5. data/lib/makit/auto.rb +48 -48
  6. data/lib/makit/azure/blob_storage.rb +257 -257
  7. data/lib/makit/azure/cli.rb +284 -284
  8. data/lib/makit/azure-pipelines.rb +187 -187
  9. data/lib/makit/cli/base.rb +17 -17
  10. data/lib/makit/cli/build_commands.rb +500 -500
  11. data/lib/makit/cli/generators/base_generator.rb +74 -74
  12. data/lib/makit/cli/generators/dotnet_generator.rb +50 -50
  13. data/lib/makit/cli/generators/generator_factory.rb +49 -49
  14. data/lib/makit/cli/generators/node_generator.rb +50 -50
  15. data/lib/makit/cli/generators/ruby_generator.rb +77 -77
  16. data/lib/makit/cli/generators/rust_generator.rb +50 -50
  17. data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -167
  18. data/lib/makit/cli/generators/templates/node_templates.rb +161 -161
  19. data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -26
  20. data/lib/makit/cli/generators/templates/ruby/gemspec.rb +41 -41
  21. data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -33
  22. data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -35
  23. data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -63
  24. data/lib/makit/cli/generators/templates/ruby/test.rb +39 -39
  25. data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -29
  26. data/lib/makit/cli/generators/templates/ruby/version.rb +29 -29
  27. data/lib/makit/cli/generators/templates/rust_templates.rb +128 -128
  28. data/lib/makit/cli/main.rb +78 -78
  29. data/lib/makit/cli/pipeline_commands.rb +311 -311
  30. data/lib/makit/cli/project_commands.rb +868 -868
  31. data/lib/makit/cli/repository_commands.rb +661 -661
  32. data/lib/makit/cli/strategy_commands.rb +207 -207
  33. data/lib/makit/cli/utility_commands.rb +521 -521
  34. data/lib/makit/commands/factory.rb +359 -359
  35. data/lib/makit/commands/middleware/base.rb +73 -73
  36. data/lib/makit/commands/middleware/cache.rb +248 -248
  37. data/lib/makit/commands/middleware/command_logger.rb +312 -312
  38. data/lib/makit/commands/middleware/validator.rb +269 -269
  39. data/lib/makit/commands/request.rb +316 -316
  40. data/lib/makit/commands/result.rb +323 -323
  41. data/lib/makit/commands/runner.rb +386 -386
  42. data/lib/makit/commands/strategies/base.rb +171 -171
  43. data/lib/makit/commands/strategies/child_process.rb +162 -162
  44. data/lib/makit/commands/strategies/factory.rb +136 -136
  45. data/lib/makit/commands/strategies/synchronous.rb +139 -139
  46. data/lib/makit/commands.rb +50 -50
  47. data/lib/makit/configuration/dotnet_project.rb +48 -48
  48. data/lib/makit/configuration/gitlab_helper.rb +61 -61
  49. data/lib/makit/configuration/project.rb +292 -292
  50. data/lib/makit/configuration/rakefile_helper.rb +43 -43
  51. data/lib/makit/configuration/step.rb +34 -34
  52. data/lib/makit/configuration/timeout.rb +74 -74
  53. data/lib/makit/configuration.rb +21 -21
  54. data/lib/makit/content/default_gitignore.rb +7 -7
  55. data/lib/makit/content/default_gitignore.txt +225 -225
  56. data/lib/makit/content/default_rakefile.rb +13 -13
  57. data/lib/makit/content/gem_rakefile.rb +16 -16
  58. data/lib/makit/context.rb +1 -1
  59. data/lib/makit/data.rb +49 -49
  60. data/lib/makit/directories.rb +170 -170
  61. data/lib/makit/directory.rb +262 -262
  62. data/lib/makit/docs/files.rb +89 -89
  63. data/lib/makit/docs/rake.rb +102 -102
  64. data/lib/makit/dotnet/cli.rb +224 -224
  65. data/lib/makit/dotnet/project.rb +217 -217
  66. data/lib/makit/dotnet/solution.rb +38 -38
  67. data/lib/makit/dotnet/solution_classlib.rb +239 -239
  68. data/lib/makit/dotnet/solution_console.rb +264 -264
  69. data/lib/makit/dotnet/solution_maui.rb +354 -354
  70. data/lib/makit/dotnet/solution_wasm.rb +275 -275
  71. data/lib/makit/dotnet/solution_wpf.rb +304 -304
  72. data/lib/makit/dotnet.rb +110 -110
  73. data/lib/makit/email.rb +90 -90
  74. data/lib/makit/environment.rb +142 -142
  75. data/lib/makit/examples/runner.rb +370 -370
  76. data/lib/makit/exceptions.rb +45 -45
  77. data/lib/makit/fileinfo.rb +32 -32
  78. data/lib/makit/files.rb +43 -43
  79. data/lib/makit/gems.rb +49 -49
  80. data/lib/makit/git/cli.rb +103 -103
  81. data/lib/makit/git/repository.rb +100 -100
  82. data/lib/makit/git.rb +104 -104
  83. data/lib/makit/github_actions.rb +202 -202
  84. data/lib/makit/gitlab/pipeline.rb +857 -857
  85. data/lib/makit/gitlab/pipeline_service_impl.rb +1535 -1535
  86. data/lib/makit/gitlab_runner.rb +59 -59
  87. data/lib/makit/humanize.rb +218 -218
  88. data/lib/makit/indexer.rb +47 -47
  89. data/lib/makit/io/filesystem.rb +111 -111
  90. data/lib/makit/io/filesystem_service_impl.rb +337 -337
  91. data/lib/makit/lint.rb +212 -212
  92. data/lib/makit/logging/configuration.rb +309 -309
  93. data/lib/makit/logging/format_registry.rb +84 -84
  94. data/lib/makit/logging/formatters/base.rb +39 -39
  95. data/lib/makit/logging/formatters/console_formatter.rb +140 -140
  96. data/lib/makit/logging/formatters/json_formatter.rb +65 -65
  97. data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -71
  98. data/lib/makit/logging/formatters/text_formatter.rb +64 -64
  99. data/lib/makit/logging/log_request.rb +119 -119
  100. data/lib/makit/logging/logger.rb +199 -199
  101. data/lib/makit/logging/sinks/base.rb +91 -91
  102. data/lib/makit/logging/sinks/console.rb +72 -72
  103. data/lib/makit/logging/sinks/file_sink.rb +92 -92
  104. data/lib/makit/logging/sinks/structured.rb +123 -123
  105. data/lib/makit/logging/sinks/unified_file_sink.rb +296 -296
  106. data/lib/makit/logging.rb +578 -578
  107. data/lib/makit/markdown.rb +75 -75
  108. data/lib/makit/mp/basic_object_mp.rb +17 -17
  109. data/lib/makit/mp/command_mp.rb +13 -13
  110. data/lib/makit/mp/command_request.mp.rb +17 -17
  111. data/lib/makit/mp/project_mp.rb +199 -199
  112. data/lib/makit/mp/string_mp.rb +205 -205
  113. data/lib/makit/nuget.rb +604 -604
  114. data/lib/makit/podman/podman.rb +458 -458
  115. data/lib/makit/podman/podman_service_impl.rb +1081 -1081
  116. data/lib/makit/port.rb +212 -212
  117. data/lib/makit/port_utility.rb +17 -17
  118. data/lib/makit/process.rb +377 -377
  119. data/lib/makit/protoc.rb +112 -112
  120. data/lib/makit/rake/cli.rb +196 -196
  121. data/lib/makit/rake/trace_controller.rb +174 -174
  122. data/lib/makit/rake.rb +81 -81
  123. data/lib/makit/ruby/cli.rb +185 -185
  124. data/lib/makit/ruby.rb +25 -25
  125. data/lib/makit/rubygems.rb +137 -137
  126. data/lib/makit/secrets/azure_key_vault.rb +322 -322
  127. data/lib/makit/secrets/azure_secrets.rb +221 -221
  128. data/lib/makit/secrets/local_secrets.rb +72 -72
  129. data/lib/makit/secrets/secrets_manager.rb +105 -105
  130. data/lib/makit/secrets.rb +96 -96
  131. data/lib/makit/serializer.rb +130 -130
  132. data/lib/makit/services/builder.rb +186 -186
  133. data/lib/makit/services/error_handler.rb +226 -226
  134. data/lib/makit/services/repository_manager.rb +367 -367
  135. data/lib/makit/services/validator.rb +112 -112
  136. data/lib/makit/setup/classlib.rb +101 -101
  137. data/lib/makit/setup/gem.rb +268 -268
  138. data/lib/makit/setup/pages.rb +11 -11
  139. data/lib/makit/setup/razorclasslib.rb +101 -101
  140. data/lib/makit/setup/runner.rb +54 -54
  141. data/lib/makit/setup.rb +5 -5
  142. data/lib/makit/show.rb +110 -110
  143. data/lib/makit/storage.rb +126 -126
  144. data/lib/makit/symbols.rb +175 -175
  145. data/lib/makit/task_info.rb +130 -130
  146. data/lib/makit/tasks/at_exit.rb +15 -15
  147. data/lib/makit/tasks/build.rb +22 -22
  148. data/lib/makit/tasks/bump.rb +7 -7
  149. data/lib/makit/tasks/clean.rb +13 -13
  150. data/lib/makit/tasks/configure.rb +10 -10
  151. data/lib/makit/tasks/format.rb +10 -10
  152. data/lib/makit/tasks/hook_manager.rb +443 -443
  153. data/lib/makit/tasks/info.rb +368 -368
  154. data/lib/makit/tasks/init.rb +49 -49
  155. data/lib/makit/tasks/integrate.rb +60 -60
  156. data/lib/makit/tasks/pull_incoming.rb +13 -13
  157. data/lib/makit/tasks/secrets.rb +7 -7
  158. data/lib/makit/tasks/setup.rb +16 -16
  159. data/lib/makit/tasks/sync.rb +14 -14
  160. data/lib/makit/tasks/tag.rb +27 -27
  161. data/lib/makit/tasks/task_monkey_patch.rb +81 -81
  162. data/lib/makit/tasks/test.rb +22 -22
  163. data/lib/makit/tasks/update.rb +16 -21
  164. data/lib/makit/tasks/version.rb +6 -6
  165. data/lib/makit/tasks.rb +24 -24
  166. data/lib/makit/test_cache.rb +239 -239
  167. data/lib/makit/tree.rb +37 -37
  168. data/lib/makit/v1/configuration/project_service_impl.rb +370 -370
  169. data/lib/makit/v1/git/git_repository_service_impl.rb +295 -295
  170. data/lib/makit/v1/makit.v1_pb.rb +35 -35
  171. data/lib/makit/v1/makit.v1_services_pb.rb +27 -27
  172. data/lib/makit/v1/services/repository_manager_service_impl.rb +572 -572
  173. data/lib/makit/version.rb +661 -661
  174. data/lib/makit/version_util.rb +21 -21
  175. data/lib/makit/wix.rb +95 -95
  176. data/lib/makit/yaml.rb +29 -29
  177. data/lib/makit/zip.rb +17 -17
  178. data/lib/makit copy.rb +44 -44
  179. data/lib/makit.rb +122 -122
  180. metadata +2 -2
data/lib/makit/port.rb CHANGED
@@ -1,212 +1,212 @@
1
- # frozen_string_literal: true
2
-
3
- require "open3"
4
-
5
- # This module provides classes for the Makit gem.
6
- module Makit
7
- # This class provide methods for working with ports
8
- #
9
- class Port
10
- class Error < StandardError; end
11
-
12
- def self.is_port_available?(port)
13
- socket = Socket.new(:INET, :STREAM)
14
- socket.bind(Socket.sockaddr_in(port, ""))
15
- socket.close
16
- true # Port is available for use
17
- rescue Errno::EADDRINUSE, Errno::EACCES
18
- false # Port is not available for use
19
- end
20
-
21
- def self.get_available_port(start_port = 1024, end_port = 65_535)
22
- (start_port..end_port).each do |port|
23
- return port if is_port_available?(port)
24
- end
25
- nil # No available port found in the range
26
- end
27
-
28
- def self.get_random_port
29
- rand(1024..65_535)
30
- end
31
-
32
- def self.get_random_available_port
33
- get_available_port(get_random_port)
34
- end
35
-
36
- # Ensures a port is available by killing any process using it, or finding the next available port.
37
- #
38
- # @param port [Integer] The port to ensure is available
39
- # @param force [Boolean] If true (default), retries up to 3 times to kill processes on the port.
40
- # If false, does not kill; finds and returns the next available port starting from +port+.
41
- # @return [Integer] The port number (guaranteed to be available)
42
- # @raise [Makit::Port::Error] If force is true and the port is still in use after 3 attempts
43
- #
44
- # @example Force free the port (default)
45
- # Makit::Port.ensure_available(5261) # => 5261
46
- # Makit::Port.ensure_available(5261, force: true)
47
- #
48
- # @example Find next available port without killing
49
- # Makit::Port.ensure_available(5261, force: false) # => 5261 or next free port
50
- #
51
- def self.ensure_available(port, force: true)
52
- raise ArgumentError, "port must be a positive integer" unless port.is_a?(Integer) && port > 0
53
-
54
- return port unless port_in_use?(port)
55
-
56
- if force
57
- max_retries = 3
58
- retries = 0
59
-
60
- while port_in_use?(port) && retries < max_retries
61
- kill_process_on_port(port)
62
- sleep(0.5)
63
- retries += 1
64
- end
65
-
66
- if port_in_use?(port)
67
- raise Error, "Port #{port} is still in use after #{max_retries} attempts to free it"
68
- end
69
-
70
- return port
71
- end
72
-
73
- find_available_port(port)
74
- end
75
-
76
- # Ensures a port is free by killing any process using it.
77
- #
78
- # Examples:
79
- # Makit::Port.ensure_port_free(5261)
80
- # Makit::Port.ensure_port_free(5261, verbose: true)
81
- #
82
- # Returns true if the port is now free, false if it couldn't be freed.
83
- #
84
- def self.ensure_port_free(port, verbose: false)
85
- raise ArgumentError, "port must be a positive integer" unless port.is_a?(Integer) && port > 0
86
-
87
- return true unless port_in_use?(port)
88
-
89
- puts "Port #{port} is in use. Attempting to free it..." if verbose
90
-
91
- killed = kill_process_on_port(port, verbose: verbose)
92
-
93
- if killed
94
- # Wait a moment for the port to be released
95
- sleep(1)
96
- # Verify port is now free
97
- unless port_in_use?(port)
98
- puts "Port #{port} is now free." if verbose
99
- return true
100
- else
101
- puts "Warning: Port #{port} is still in use after killing process." if verbose
102
- return false
103
- end
104
- else
105
- puts "Warning: Could not kill process on port #{port}." if verbose
106
- return false
107
- end
108
- rescue Error, ArgumentError => e
109
- puts "Error freeing port #{port}: #{e.message}" if verbose
110
- false
111
- end
112
-
113
- # -----------------------
114
- # Internals
115
- # -----------------------
116
-
117
- def self.port_in_use?(port)
118
- if RUBY_PLATFORM =~ /mswin|mingw|cygwin/
119
- # Windows: Use netstat
120
- stdout, _stderr, status = Open3.capture3("netstat", "-ano")
121
- return false unless status.success?
122
- stdout.lines.any? { |line| line.include?(":#{port}") && line.include?("LISTENING") }
123
- else
124
- # Unix/macOS: Use lsof
125
- stdout, _stderr, status = Open3.capture3("lsof", "-ti:#{port}")
126
- status.success? && !stdout.strip.empty?
127
- end
128
- rescue Errno::ENOENT
129
- # Command not found - assume port is not in use
130
- false
131
- end
132
- private_class_method :port_in_use?
133
-
134
- def self.kill_process_on_port(port, verbose: false)
135
- if RUBY_PLATFORM =~ /mswin|mingw|cygwin/
136
- # Windows: Use netstat to find PID, then taskkill
137
- stdout, _stderr, status = Open3.capture3("netstat", "-ano")
138
- return false unless status.success?
139
-
140
- pids = []
141
- stdout.lines.each do |line|
142
- if line.include?(":#{port}") && line.include?("LISTENING")
143
- parts = line.split
144
- pid = parts.last
145
- pids << pid if pid && pid.match?(/^\d+$/)
146
- end
147
- end
148
-
149
- killed_any = false
150
- pids.uniq.each do |pid|
151
- begin
152
- stdout, _stderr, status = Open3.capture3("taskkill", "/F", "/PID", pid)
153
- if status.success?
154
- puts "Killed process #{pid} on port #{port}" if verbose
155
- killed_any = true
156
- end
157
- rescue Errno::ENOENT
158
- # taskkill not found
159
- return false
160
- end
161
- end
162
-
163
- killed_any
164
- else
165
- # Unix/macOS: Use lsof to find PID, then kill
166
- stdout, _stderr, status = Open3.capture3("lsof", "-ti:#{port}")
167
- return false unless status.success?
168
- return true if stdout.strip.empty? # Port is already free
169
-
170
- pids = stdout.strip.split("\n").map(&:strip).reject(&:empty?)
171
- return false if pids.empty?
172
-
173
- killed_any = false
174
- pids.each do |pid|
175
- begin
176
- stdout, _stderr, status = Open3.capture3("kill", "-9", pid)
177
- if status.success?
178
- puts "Killed process #{pid} on port #{port}" if verbose
179
- killed_any = true
180
- end
181
- rescue Errno::ENOENT
182
- # kill not found
183
- return false
184
- end
185
- end
186
-
187
- killed_any
188
- end
189
- rescue Errno::ENOENT
190
- # Command not found
191
- false
192
- end
193
- private_class_method :kill_process_on_port
194
-
195
- def self.find_available_port(start_port, max_attempts = 100)
196
- port = start_port
197
- attempts = 0
198
-
199
- while port_in_use?(port) && attempts < max_attempts
200
- port += 1
201
- attempts += 1
202
- end
203
-
204
- if attempts >= max_attempts
205
- raise Error, "Could not find available port starting from #{start_port}"
206
- end
207
-
208
- port
209
- end
210
- private_class_method :find_available_port
211
- end
212
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+
5
+ # This module provides classes for the Makit gem.
6
+ module Makit
7
+ # This class provide methods for working with ports
8
+ #
9
+ class Port
10
+ class Error < StandardError; end
11
+
12
+ def self.is_port_available?(port)
13
+ socket = Socket.new(:INET, :STREAM)
14
+ socket.bind(Socket.sockaddr_in(port, ""))
15
+ socket.close
16
+ true # Port is available for use
17
+ rescue Errno::EADDRINUSE, Errno::EACCES
18
+ false # Port is not available for use
19
+ end
20
+
21
+ def self.get_available_port(start_port = 1024, end_port = 65_535)
22
+ (start_port..end_port).each do |port|
23
+ return port if is_port_available?(port)
24
+ end
25
+ nil # No available port found in the range
26
+ end
27
+
28
+ def self.get_random_port
29
+ rand(1024..65_535)
30
+ end
31
+
32
+ def self.get_random_available_port
33
+ get_available_port(get_random_port)
34
+ end
35
+
36
+ # Ensures a port is available by killing any process using it, or finding the next available port.
37
+ #
38
+ # @param port [Integer] The port to ensure is available
39
+ # @param force [Boolean] If true (default), retries up to 3 times to kill processes on the port.
40
+ # If false, does not kill; finds and returns the next available port starting from +port+.
41
+ # @return [Integer] The port number (guaranteed to be available)
42
+ # @raise [Makit::Port::Error] If force is true and the port is still in use after 3 attempts
43
+ #
44
+ # @example Force free the port (default)
45
+ # Makit::Port.ensure_available(5261) # => 5261
46
+ # Makit::Port.ensure_available(5261, force: true)
47
+ #
48
+ # @example Find next available port without killing
49
+ # Makit::Port.ensure_available(5261, force: false) # => 5261 or next free port
50
+ #
51
+ def self.ensure_available(port, force: true)
52
+ raise ArgumentError, "port must be a positive integer" unless port.is_a?(Integer) && port > 0
53
+
54
+ return port unless port_in_use?(port)
55
+
56
+ if force
57
+ max_retries = 3
58
+ retries = 0
59
+
60
+ while port_in_use?(port) && retries < max_retries
61
+ kill_process_on_port(port)
62
+ sleep(0.5)
63
+ retries += 1
64
+ end
65
+
66
+ if port_in_use?(port)
67
+ raise Error, "Port #{port} is still in use after #{max_retries} attempts to free it"
68
+ end
69
+
70
+ return port
71
+ end
72
+
73
+ find_available_port(port)
74
+ end
75
+
76
+ # Ensures a port is free by killing any process using it.
77
+ #
78
+ # Examples:
79
+ # Makit::Port.ensure_port_free(5261)
80
+ # Makit::Port.ensure_port_free(5261, verbose: true)
81
+ #
82
+ # Returns true if the port is now free, false if it couldn't be freed.
83
+ #
84
+ def self.ensure_port_free(port, verbose: false)
85
+ raise ArgumentError, "port must be a positive integer" unless port.is_a?(Integer) && port > 0
86
+
87
+ return true unless port_in_use?(port)
88
+
89
+ puts "Port #{port} is in use. Attempting to free it..." if verbose
90
+
91
+ killed = kill_process_on_port(port, verbose: verbose)
92
+
93
+ if killed
94
+ # Wait a moment for the port to be released
95
+ sleep(1)
96
+ # Verify port is now free
97
+ unless port_in_use?(port)
98
+ puts "Port #{port} is now free." if verbose
99
+ return true
100
+ else
101
+ puts "Warning: Port #{port} is still in use after killing process." if verbose
102
+ return false
103
+ end
104
+ else
105
+ puts "Warning: Could not kill process on port #{port}." if verbose
106
+ return false
107
+ end
108
+ rescue Error, ArgumentError => e
109
+ puts "Error freeing port #{port}: #{e.message}" if verbose
110
+ false
111
+ end
112
+
113
+ # -----------------------
114
+ # Internals
115
+ # -----------------------
116
+
117
+ def self.port_in_use?(port)
118
+ if RUBY_PLATFORM =~ /mswin|mingw|cygwin/
119
+ # Windows: Use netstat
120
+ stdout, _stderr, status = Open3.capture3("netstat", "-ano")
121
+ return false unless status.success?
122
+ stdout.lines.any? { |line| line.include?(":#{port}") && line.include?("LISTENING") }
123
+ else
124
+ # Unix/macOS: Use lsof
125
+ stdout, _stderr, status = Open3.capture3("lsof", "-ti:#{port}")
126
+ status.success? && !stdout.strip.empty?
127
+ end
128
+ rescue Errno::ENOENT
129
+ # Command not found - assume port is not in use
130
+ false
131
+ end
132
+ private_class_method :port_in_use?
133
+
134
+ def self.kill_process_on_port(port, verbose: false)
135
+ if RUBY_PLATFORM =~ /mswin|mingw|cygwin/
136
+ # Windows: Use netstat to find PID, then taskkill
137
+ stdout, _stderr, status = Open3.capture3("netstat", "-ano")
138
+ return false unless status.success?
139
+
140
+ pids = []
141
+ stdout.lines.each do |line|
142
+ if line.include?(":#{port}") && line.include?("LISTENING")
143
+ parts = line.split
144
+ pid = parts.last
145
+ pids << pid if pid && pid.match?(/^\d+$/)
146
+ end
147
+ end
148
+
149
+ killed_any = false
150
+ pids.uniq.each do |pid|
151
+ begin
152
+ stdout, _stderr, status = Open3.capture3("taskkill", "/F", "/PID", pid)
153
+ if status.success?
154
+ puts "Killed process #{pid} on port #{port}" if verbose
155
+ killed_any = true
156
+ end
157
+ rescue Errno::ENOENT
158
+ # taskkill not found
159
+ return false
160
+ end
161
+ end
162
+
163
+ killed_any
164
+ else
165
+ # Unix/macOS: Use lsof to find PID, then kill
166
+ stdout, _stderr, status = Open3.capture3("lsof", "-ti:#{port}")
167
+ return false unless status.success?
168
+ return true if stdout.strip.empty? # Port is already free
169
+
170
+ pids = stdout.strip.split("\n").map(&:strip).reject(&:empty?)
171
+ return false if pids.empty?
172
+
173
+ killed_any = false
174
+ pids.each do |pid|
175
+ begin
176
+ stdout, _stderr, status = Open3.capture3("kill", "-9", pid)
177
+ if status.success?
178
+ puts "Killed process #{pid} on port #{port}" if verbose
179
+ killed_any = true
180
+ end
181
+ rescue Errno::ENOENT
182
+ # kill not found
183
+ return false
184
+ end
185
+ end
186
+
187
+ killed_any
188
+ end
189
+ rescue Errno::ENOENT
190
+ # Command not found
191
+ false
192
+ end
193
+ private_class_method :kill_process_on_port
194
+
195
+ def self.find_available_port(start_port, max_attempts = 100)
196
+ port = start_port
197
+ attempts = 0
198
+
199
+ while port_in_use?(port) && attempts < max_attempts
200
+ port += 1
201
+ attempts += 1
202
+ end
203
+
204
+ if attempts >= max_attempts
205
+ raise Error, "Could not find available port starting from #{start_port}"
206
+ end
207
+
208
+ port
209
+ end
210
+ private_class_method :find_available_port
211
+ end
212
+ end
@@ -1,17 +1,17 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "port"
4
-
5
- module Makit
6
- # @deprecated Use {Makit::Port} instead. This module delegates to Makit::Port for backward compatibility.
7
- module PortUtility
8
- Error = Makit::Port::Error
9
-
10
- # @see Makit::Port.ensure_port_free
11
- def self.ensure_port_free(port, verbose: false)
12
- warn "[Makit::PortUtility] DEPRECATED: Makit::PortUtility.ensure_port_free is deprecated. " \
13
- "Use Makit::Port.ensure_port_free(port, verbose: false) instead."
14
- Makit::Port.ensure_port_free(port, verbose: verbose)
15
- end
16
- end
17
- end
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "port"
4
+
5
+ module Makit
6
+ # @deprecated Use {Makit::Port} instead. This module delegates to Makit::Port for backward compatibility.
7
+ module PortUtility
8
+ Error = Makit::Port::Error
9
+
10
+ # @see Makit::Port.ensure_port_free
11
+ def self.ensure_port_free(port, verbose: false)
12
+ warn "[Makit::PortUtility] DEPRECATED: Makit::PortUtility.ensure_port_free is deprecated. " \
13
+ "Use Makit::Port.ensure_port_free(port, verbose: false) instead."
14
+ Makit::Port.ensure_port_free(port, verbose: verbose)
15
+ end
16
+ end
17
+ end