makit 0.0.143 → 0.0.144
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 +212 -212
- 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 +386 -386
- data/lib/makit/commands/strategies/base.rb +171 -171
- data/lib/makit/commands/strategies/child_process.rb +162 -162
- 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 +48 -39
- 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 +16 -16
- 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 -199
- data/lib/makit/nuget.rb +74 -74
- data/lib/makit/port.rb +32 -32
- data/lib/makit/process.rb +377 -163
- data/lib/makit/protoc.rb +107 -107
- data/lib/makit/rake/cli.rb +196 -196
- data/lib/makit/rake/trace_controller.rb +174 -174
- data/lib/makit/rake.rb +81 -81
- 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/pages.rb +11 -11
- 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 +16 -16
- 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 +100 -100
- 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 +43 -43
- metadata +2 -2
data/lib/makit/process.rb
CHANGED
@@ -1,163 +1,377 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# This module provides classes for the Makit gem.
|
4
|
-
module Makit
|
5
|
-
# Cross-platform process management utilities
|
6
|
-
#
|
7
|
-
# This class provides methods for checking, listing, and terminating processes
|
8
|
-
# across different operating systems (Windows, Linux, macOS). It abstracts
|
9
|
-
# platform-specific commands into a unified interface.
|
10
|
-
class Process
|
11
|
-
# Check if a process with the given name is currently running
|
12
|
-
#
|
13
|
-
# Uses platform-specific commands:
|
14
|
-
# - Windows: tasklist command
|
15
|
-
# - Unix: ps command with grep filtering
|
16
|
-
#
|
17
|
-
# @param name [String] Name of the process to check (without .exe extension)
|
18
|
-
# @return [Boolean] True if the process is running, false otherwise
|
19
|
-
def self.is_running?(name)
|
20
|
-
return false if name.nil? || name.strip.empty?
|
21
|
-
|
22
|
-
# provide a cross-platform way to check if a process is running
|
23
|
-
results = if Makit::Environment.is_windows?
|
24
|
-
# on windows, use the tasklist command
|
25
|
-
`tasklist /FI "imagename eq #{name}.exe" 2>nul`
|
26
|
-
else
|
27
|
-
# on linux/mac, use the ps command
|
28
|
-
`ps aux | grep "#{name}" | grep -v grep 2>/dev/null`
|
29
|
-
end
|
30
|
-
results.include?(name)
|
31
|
-
end
|
32
|
-
|
33
|
-
# Terminate all processes that match a given name
|
34
|
-
#
|
35
|
-
# Uses platform-specific termination commands:
|
36
|
-
# - Windows: taskkill command
|
37
|
-
# - Unix: kill command with SIGKILL (-9)
|
38
|
-
#
|
39
|
-
# @param name [String] Name of the process(es) to terminate
|
40
|
-
# @return [Array<String>] Array of killed process IDs (empty if none found/killed)
|
41
|
-
def self.kill(name)
|
42
|
-
return [] if name.nil? || name.strip.empty?
|
43
|
-
|
44
|
-
killed_pids = []
|
45
|
-
|
46
|
-
if Makit::Environment.is_windows?
|
47
|
-
# Windows: Use tasklist to find PIDs first, then kill them
|
48
|
-
begin
|
49
|
-
# Find processes by name
|
50
|
-
tasklist_output = `tasklist /FI "imagename eq #{name}.exe" /FO CSV 2>nul`
|
51
|
-
|
52
|
-
# Parse CSV output to extract PIDs
|
53
|
-
lines = tasklist_output.split("\n")
|
54
|
-
if lines.length > 1 # Skip header line
|
55
|
-
lines[1..].each do |line|
|
56
|
-
parts = line.split(",")
|
57
|
-
next unless parts.length >= 2
|
58
|
-
|
59
|
-
pid = parts[1]&.gsub('"', "")&.strip
|
60
|
-
next unless pid && !pid.empty? && pid.match?(/^\d+$/)
|
61
|
-
|
62
|
-
begin
|
63
|
-
`taskkill /PID #{pid} /F 2>nul`
|
64
|
-
killed_pids << pid
|
65
|
-
rescue StandardError => e
|
66
|
-
# Log error but continue with other processes
|
67
|
-
puts "Failed to kill process #{pid}: #{e.message}"
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
rescue StandardError => e
|
72
|
-
# If tasklist fails, try direct taskkill by name
|
73
|
-
begin
|
74
|
-
`taskkill /IM "#{name}.exe" /F 2>nul`
|
75
|
-
# Since we can't get PIDs from direct kill, return empty array
|
76
|
-
# but don't raise error
|
77
|
-
rescue StandardError => e2
|
78
|
-
# Both methods failed, return empty array
|
79
|
-
puts "Failed to kill processes by name #{name}: #{e2.message}"
|
80
|
-
end
|
81
|
-
end
|
82
|
-
else
|
83
|
-
# Unix (Linux/Mac): Use pgrep to find PIDs, then kill them
|
84
|
-
begin
|
85
|
-
# Use pgrep to find PIDs, handle both Linux and Mac
|
86
|
-
pids = if Makit::Environment.is_mac?
|
87
|
-
# Mac: pgrep -f might not work the same way
|
88
|
-
`pgrep -x "#{name}" 2>/dev/null`.split("\n").reject(&:empty?)
|
89
|
-
else
|
90
|
-
# Linux: pgrep -f works well
|
91
|
-
`pgrep -f "#{name}" 2>/dev/null`.split("\n").reject(&:empty?)
|
92
|
-
end
|
93
|
-
|
94
|
-
pids.each do |pid|
|
95
|
-
next unless pid.match?(/^\d+$/)
|
96
|
-
|
97
|
-
begin
|
98
|
-
`kill -9 #{pid} 2>/dev/null`
|
99
|
-
killed_pids << pid
|
100
|
-
rescue StandardError => e
|
101
|
-
puts "Failed to kill process #{pid}: #{e.message}"
|
102
|
-
end
|
103
|
-
end
|
104
|
-
rescue StandardError => e
|
105
|
-
# If pgrep fails, return empty array but don't raise error
|
106
|
-
puts "Failed to find processes by name #{name}: #{e.message}"
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
killed_pids
|
111
|
-
end
|
112
|
-
|
113
|
-
# List all running processes on the system
|
114
|
-
#
|
115
|
-
# Uses platform-specific commands to get a complete process listing:
|
116
|
-
# - Windows: tasklist command
|
117
|
-
# - Unix: ps aux command
|
118
|
-
#
|
119
|
-
# @return [String] Raw output from the system process listing command
|
120
|
-
def self.list
|
121
|
-
if Makit::Environment.is_windows?
|
122
|
-
`tasklist 2>nul`
|
123
|
-
else
|
124
|
-
`ps aux 2>/dev/null`
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
# List all running processes for the current user
|
129
|
-
#
|
130
|
-
# Filters the process list to show only processes owned by the current user.
|
131
|
-
# Uses platform-specific filtering:
|
132
|
-
# - Windows: tasklist with USERNAME filter
|
133
|
-
# - Unix: ps aux with grep filtering
|
134
|
-
#
|
135
|
-
# @return [String] Raw output from the filtered process listing command
|
136
|
-
def self.list_current_user
|
137
|
-
if Makit::Environment.is_windows?
|
138
|
-
`tasklist /FI "STATUS eq running and USERNAME eq #{Makit::Environment.current_user}" 2>nul`
|
139
|
-
else
|
140
|
-
`ps aux | grep "#{Makit::Environment.current_user}" | grep -v grep 2>/dev/null`
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
# List processes for the current user filtered by name
|
145
|
-
#
|
146
|
-
# Returns an array of process lines for consistency across platforms.
|
147
|
-
# Filters by both current user and process name.
|
148
|
-
#
|
149
|
-
# @param name [String] Process name to filter by
|
150
|
-
# @return [Array<String>] Array of process lines matching the criteria
|
151
|
-
def self.list_current_user_processes(name)
|
152
|
-
if Makit::Environment.is_windows?
|
153
|
-
# filter the results to only include the current user
|
154
|
-
results = `tasklist /FI "STATUS eq running and USERNAME eq #{Makit::Environment.current_user}" 2>nul`
|
155
|
-
results.split("\n").select { |line| line.include?(Makit::Environment.current_user) }
|
156
|
-
else
|
157
|
-
# Unix (Linux/Mac): return as array for consistency
|
158
|
-
results = `ps aux | grep "#{name}" | grep -v grep 2>/dev/null`
|
159
|
-
results.split("\n").reject(&:empty?)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This module provides classes for the Makit gem.
|
4
|
+
module Makit
|
5
|
+
# Cross-platform process management utilities
|
6
|
+
#
|
7
|
+
# This class provides methods for checking, listing, and terminating processes
|
8
|
+
# across different operating systems (Windows, Linux, macOS). It abstracts
|
9
|
+
# platform-specific commands into a unified interface.
|
10
|
+
class Process
|
11
|
+
# Check if a process with the given name is currently running
|
12
|
+
#
|
13
|
+
# Uses platform-specific commands:
|
14
|
+
# - Windows: tasklist command
|
15
|
+
# - Unix: ps command with grep filtering
|
16
|
+
#
|
17
|
+
# @param name [String] Name of the process to check (without .exe extension)
|
18
|
+
# @return [Boolean] True if the process is running, false otherwise
|
19
|
+
def self.is_running?(name)
|
20
|
+
return false if name.nil? || name.strip.empty?
|
21
|
+
|
22
|
+
# provide a cross-platform way to check if a process is running
|
23
|
+
results = if Makit::Environment.is_windows?
|
24
|
+
# on windows, use the tasklist command
|
25
|
+
`tasklist /FI "imagename eq #{name}.exe" 2>nul`
|
26
|
+
else
|
27
|
+
# on linux/mac, use the ps command
|
28
|
+
`ps aux | grep "#{name}" | grep -v grep 2>/dev/null`
|
29
|
+
end
|
30
|
+
results.include?(name)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Terminate all processes that match a given name
|
34
|
+
#
|
35
|
+
# Uses platform-specific termination commands:
|
36
|
+
# - Windows: taskkill command
|
37
|
+
# - Unix: kill command with SIGKILL (-9)
|
38
|
+
#
|
39
|
+
# @param name [String] Name of the process(es) to terminate
|
40
|
+
# @return [Array<String>] Array of killed process IDs (empty if none found/killed)
|
41
|
+
def self.kill(name)
|
42
|
+
return [] if name.nil? || name.strip.empty?
|
43
|
+
|
44
|
+
killed_pids = []
|
45
|
+
|
46
|
+
if Makit::Environment.is_windows?
|
47
|
+
# Windows: Use tasklist to find PIDs first, then kill them
|
48
|
+
begin
|
49
|
+
# Find processes by name
|
50
|
+
tasklist_output = `tasklist /FI "imagename eq #{name}.exe" /FO CSV 2>nul`
|
51
|
+
|
52
|
+
# Parse CSV output to extract PIDs
|
53
|
+
lines = tasklist_output.split("\n")
|
54
|
+
if lines.length > 1 # Skip header line
|
55
|
+
lines[1..].each do |line|
|
56
|
+
parts = line.split(",")
|
57
|
+
next unless parts.length >= 2
|
58
|
+
|
59
|
+
pid = parts[1]&.gsub('"', "")&.strip
|
60
|
+
next unless pid && !pid.empty? && pid.match?(/^\d+$/)
|
61
|
+
|
62
|
+
begin
|
63
|
+
`taskkill /PID #{pid} /F 2>nul`
|
64
|
+
killed_pids << pid
|
65
|
+
rescue StandardError => e
|
66
|
+
# Log error but continue with other processes
|
67
|
+
puts "Failed to kill process #{pid}: #{e.message}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
rescue StandardError => e
|
72
|
+
# If tasklist fails, try direct taskkill by name
|
73
|
+
begin
|
74
|
+
`taskkill /IM "#{name}.exe" /F 2>nul`
|
75
|
+
# Since we can't get PIDs from direct kill, return empty array
|
76
|
+
# but don't raise error
|
77
|
+
rescue StandardError => e2
|
78
|
+
# Both methods failed, return empty array
|
79
|
+
puts "Failed to kill processes by name #{name}: #{e2.message}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
else
|
83
|
+
# Unix (Linux/Mac): Use pgrep to find PIDs, then kill them
|
84
|
+
begin
|
85
|
+
# Use pgrep to find PIDs, handle both Linux and Mac
|
86
|
+
pids = if Makit::Environment.is_mac?
|
87
|
+
# Mac: pgrep -f might not work the same way
|
88
|
+
`pgrep -x "#{name}" 2>/dev/null`.split("\n").reject(&:empty?)
|
89
|
+
else
|
90
|
+
# Linux: pgrep -f works well
|
91
|
+
`pgrep -f "#{name}" 2>/dev/null`.split("\n").reject(&:empty?)
|
92
|
+
end
|
93
|
+
|
94
|
+
pids.each do |pid|
|
95
|
+
next unless pid.match?(/^\d+$/)
|
96
|
+
|
97
|
+
begin
|
98
|
+
`kill -9 #{pid} 2>/dev/null`
|
99
|
+
killed_pids << pid
|
100
|
+
rescue StandardError => e
|
101
|
+
puts "Failed to kill process #{pid}: #{e.message}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
rescue StandardError => e
|
105
|
+
# If pgrep fails, return empty array but don't raise error
|
106
|
+
puts "Failed to find processes by name #{name}: #{e.message}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
killed_pids
|
111
|
+
end
|
112
|
+
|
113
|
+
# List all running processes on the system
|
114
|
+
#
|
115
|
+
# Uses platform-specific commands to get a complete process listing:
|
116
|
+
# - Windows: tasklist command
|
117
|
+
# - Unix: ps aux command
|
118
|
+
#
|
119
|
+
# @return [String] Raw output from the system process listing command
|
120
|
+
def self.list
|
121
|
+
if Makit::Environment.is_windows?
|
122
|
+
`tasklist 2>nul`
|
123
|
+
else
|
124
|
+
`ps aux 2>/dev/null`
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# List all running processes for the current user
|
129
|
+
#
|
130
|
+
# Filters the process list to show only processes owned by the current user.
|
131
|
+
# Uses platform-specific filtering:
|
132
|
+
# - Windows: tasklist with USERNAME filter
|
133
|
+
# - Unix: ps aux with grep filtering
|
134
|
+
#
|
135
|
+
# @return [String] Raw output from the filtered process listing command
|
136
|
+
def self.list_current_user
|
137
|
+
if Makit::Environment.is_windows?
|
138
|
+
`tasklist /FI "STATUS eq running and USERNAME eq #{Makit::Environment.current_user}" 2>nul`
|
139
|
+
else
|
140
|
+
`ps aux | grep "#{Makit::Environment.current_user}" | grep -v grep 2>/dev/null`
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# List processes for the current user filtered by name
|
145
|
+
#
|
146
|
+
# Returns an array of process lines for consistency across platforms.
|
147
|
+
# Filters by both current user and process name.
|
148
|
+
#
|
149
|
+
# @param name [String] Process name to filter by
|
150
|
+
# @return [Array<String>] Array of process lines matching the criteria
|
151
|
+
def self.list_current_user_processes(name)
|
152
|
+
if Makit::Environment.is_windows?
|
153
|
+
# filter the results to only include the current user
|
154
|
+
results = `tasklist /FI "STATUS eq running and USERNAME eq #{Makit::Environment.current_user}" 2>nul`
|
155
|
+
results.split("\n").select { |line| line.include?(Makit::Environment.current_user) }
|
156
|
+
else
|
157
|
+
# Unix (Linux/Mac): return as array for consistency
|
158
|
+
results = `ps aux | grep "#{name}" | grep -v grep 2>/dev/null`
|
159
|
+
results.split("\n").reject(&:empty?)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Run a command in the background and track it with a PID file
|
164
|
+
#
|
165
|
+
# This method starts a process in the background and stores its PID in a file
|
166
|
+
# for later management. It handles cross-platform differences in process spawning.
|
167
|
+
#
|
168
|
+
# @param command [String] The command to run in the background
|
169
|
+
# @param pid_file [String] Path to the PID file to store the process ID
|
170
|
+
# @param working_dir [String, nil] Working directory for the process (optional)
|
171
|
+
# @param environment [Hash, nil] Environment variables to set (optional)
|
172
|
+
# @return [Integer] The process ID of the started process
|
173
|
+
# @raise [StandardError] If the process fails to start
|
174
|
+
def self.run_background(command, pid_file, working_dir: nil, environment: {})
|
175
|
+
# Ensure the command is not nil or empty
|
176
|
+
raise ArgumentError, "Command cannot be nil or empty" if command.nil? || command.strip.empty?
|
177
|
+
raise ArgumentError, "PID file path cannot be nil or empty" if pid_file.nil? || pid_file.strip.empty?
|
178
|
+
|
179
|
+
# Convert command to array for Process.spawn
|
180
|
+
cmd_array = if Makit::Environment.is_windows?
|
181
|
+
# Windows: Use cmd /c for complex commands
|
182
|
+
["cmd", "/c", command]
|
183
|
+
else
|
184
|
+
# Unix-like: Use shell for command parsing
|
185
|
+
["sh", "-c", command]
|
186
|
+
end
|
187
|
+
|
188
|
+
# Prepare spawn options
|
189
|
+
spawn_options = {}
|
190
|
+
spawn_options[:chdir] = working_dir if working_dir
|
191
|
+
spawn_options[:pgroup] = true unless Makit::Environment.is_windows?
|
192
|
+
|
193
|
+
# Set environment variables
|
194
|
+
env = ENV.to_h.merge(environment)
|
195
|
+
spawn_options[:unsetenv_others] = false
|
196
|
+
|
197
|
+
begin
|
198
|
+
# Start the process
|
199
|
+
pid = Process.spawn(env, *cmd_array, spawn_options)
|
200
|
+
|
201
|
+
# Write PID to file
|
202
|
+
File.write(pid_file, pid.to_s)
|
203
|
+
|
204
|
+
# Give the process a moment to start
|
205
|
+
sleep(0.5)
|
206
|
+
|
207
|
+
# Verify the process is still running
|
208
|
+
begin
|
209
|
+
Process.getpgid(pid) if Makit::Environment.is_windows?
|
210
|
+
Process.getpgid(pid) unless Makit::Environment.is_windows?
|
211
|
+
rescue Errno::ESRCH
|
212
|
+
raise StandardError, "Process failed to start or exited immediately"
|
213
|
+
end
|
214
|
+
|
215
|
+
pid
|
216
|
+
rescue => e
|
217
|
+
# Clean up PID file if process failed to start
|
218
|
+
File.delete(pid_file) if File.exist?(pid_file)
|
219
|
+
raise StandardError, "Failed to start background process: #{e.message}"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Stop a background process using its PID file
|
224
|
+
#
|
225
|
+
# This method reads the PID from a file and terminates the process gracefully.
|
226
|
+
# It handles cross-platform differences in process termination.
|
227
|
+
#
|
228
|
+
# @param pid_file [String] Path to the PID file containing the process ID
|
229
|
+
# @param signal [String] Signal to send (default: "TERM" for graceful shutdown)
|
230
|
+
# @return [Boolean] True if the process was stopped, false if it wasn't running
|
231
|
+
def self.stop_background(pid_file, signal: "TERM")
|
232
|
+
return false unless File.exist?(pid_file)
|
233
|
+
|
234
|
+
begin
|
235
|
+
pid = File.read(pid_file).strip.to_i
|
236
|
+
return false if pid <= 0
|
237
|
+
|
238
|
+
# Check if process is still running
|
239
|
+
begin
|
240
|
+
if Makit::Environment.is_windows?
|
241
|
+
# Windows: Use taskkill
|
242
|
+
if signal == "TERM"
|
243
|
+
system("taskkill /PID #{pid} /F >nul 2>&1")
|
244
|
+
else
|
245
|
+
system("taskkill /PID #{pid} /F >nul 2>&1")
|
246
|
+
end
|
247
|
+
else
|
248
|
+
# Unix-like: Use kill with specified signal
|
249
|
+
Process.kill(signal, pid)
|
250
|
+
end
|
251
|
+
|
252
|
+
# Wait a moment for the process to terminate
|
253
|
+
sleep(0.5)
|
254
|
+
|
255
|
+
# Verify the process is gone
|
256
|
+
begin
|
257
|
+
Process.getpgid(pid)
|
258
|
+
# Process still running, force kill if TERM didn't work
|
259
|
+
if signal == "TERM"
|
260
|
+
return stop_background(pid_file, signal: "KILL")
|
261
|
+
end
|
262
|
+
return false
|
263
|
+
rescue Errno::ESRCH
|
264
|
+
# Process is gone, success
|
265
|
+
true
|
266
|
+
end
|
267
|
+
rescue Errno::ESRCH, Errno::EPERM
|
268
|
+
# Process was not running or permission denied
|
269
|
+
false
|
270
|
+
end
|
271
|
+
rescue => e
|
272
|
+
# Log error but don't raise
|
273
|
+
puts "Error stopping background process: #{e.message}" if defined?(puts)
|
274
|
+
false
|
275
|
+
ensure
|
276
|
+
# Clean up PID file
|
277
|
+
File.delete(pid_file) if File.exist?(pid_file)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
# Check if a background process is still running using its PID file
|
282
|
+
#
|
283
|
+
# @param pid_file [String] Path to the PID file containing the process ID
|
284
|
+
# @return [Boolean] True if the process is running, false otherwise
|
285
|
+
def self.background_running?(pid_file)
|
286
|
+
return false unless File.exist?(pid_file)
|
287
|
+
|
288
|
+
begin
|
289
|
+
pid = File.read(pid_file).strip.to_i
|
290
|
+
return false if pid <= 0
|
291
|
+
|
292
|
+
# Check if process is still running
|
293
|
+
Process.getpgid(pid)
|
294
|
+
true
|
295
|
+
rescue Errno::ESRCH, Errno::EPERM
|
296
|
+
false
|
297
|
+
rescue => e
|
298
|
+
# Log error but return false
|
299
|
+
puts "Error checking background process: #{e.message}" if defined?(puts)
|
300
|
+
false
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
# Get the PID of a background process from its PID file
|
305
|
+
#
|
306
|
+
# @param pid_file [String] Path to the PID file containing the process ID
|
307
|
+
# @return [Integer, nil] The process ID, or nil if not found or invalid
|
308
|
+
def self.get_background_pid(pid_file)
|
309
|
+
return nil unless File.exist?(pid_file)
|
310
|
+
|
311
|
+
begin
|
312
|
+
pid = File.read(pid_file).strip.to_i
|
313
|
+
return nil if pid <= 0
|
314
|
+
pid
|
315
|
+
rescue => e
|
316
|
+
puts "Error reading PID file: #{e.message}" if defined?(puts)
|
317
|
+
nil
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
# Clean up stale PID files (processes that are no longer running)
|
322
|
+
#
|
323
|
+
# @param pid_files [Array<String>] Array of PID file paths to check
|
324
|
+
# @return [Array<String>] Array of cleaned up PID file paths
|
325
|
+
def self.cleanup_stale_pids(pid_files)
|
326
|
+
cleaned = []
|
327
|
+
|
328
|
+
pid_files.each do |pid_file|
|
329
|
+
next unless File.exist?(pid_file)
|
330
|
+
|
331
|
+
unless background_running?(pid_file)
|
332
|
+
File.delete(pid_file)
|
333
|
+
cleaned << pid_file
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
cleaned
|
338
|
+
end
|
339
|
+
|
340
|
+
# Health check for a service running on a specific port
|
341
|
+
#
|
342
|
+
# @param port [Integer] Port number to check
|
343
|
+
# @param host [String] Host to check (default: "localhost")
|
344
|
+
# @param timeout [Integer] Timeout in seconds (default: 5)
|
345
|
+
# @return [Boolean] True if the service is responding, false otherwise
|
346
|
+
def self.health_check_port(port, host: "localhost", timeout: 5)
|
347
|
+
require 'net/http'
|
348
|
+
require 'timeout'
|
349
|
+
|
350
|
+
begin
|
351
|
+
uri = URI("http://#{host}:#{port}")
|
352
|
+
Timeout.timeout(timeout) do
|
353
|
+
response = Net::HTTP.get_response(uri)
|
354
|
+
response.code.to_i < 500 # Consider 4xx as "responding" but 5xx as "unhealthy"
|
355
|
+
end
|
356
|
+
rescue => e
|
357
|
+
false
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
# Health check for multiple ports
|
362
|
+
#
|
363
|
+
# @param ports [Array<Integer>] Array of port numbers to check
|
364
|
+
# @param host [String] Host to check (default: "localhost")
|
365
|
+
# @param timeout [Integer] Timeout in seconds (default: 5)
|
366
|
+
# @return [Hash] Hash with port numbers as keys and health status as values
|
367
|
+
def self.health_check_ports(ports, host: "localhost", timeout: 5)
|
368
|
+
results = {}
|
369
|
+
|
370
|
+
ports.each do |port|
|
371
|
+
results[port] = health_check_port(port, host: host, timeout: timeout)
|
372
|
+
end
|
373
|
+
|
374
|
+
results
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|