makit 0.0.26 → 0.0.27

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/lib/makit/apache.rb +32 -32
  3. data/lib/makit/cli/clean.rb +14 -14
  4. data/lib/makit/cli/clone.rb +59 -59
  5. data/lib/makit/cli/init.rb +38 -38
  6. data/lib/makit/cli/main.rb +33 -33
  7. data/lib/makit/cli/make.rb +54 -54
  8. data/lib/makit/cli/new.rb +37 -37
  9. data/lib/makit/cli/nuget_cache.rb +38 -38
  10. data/lib/makit/cli/pull.rb +31 -31
  11. data/lib/makit/cli/setup.rb +71 -71
  12. data/lib/makit/cli/work.rb +21 -21
  13. data/lib/makit/command_runner.rb +343 -343
  14. data/lib/makit/commands.rb +21 -21
  15. data/lib/makit/content/default_gitignore.rb +5 -5
  16. data/lib/makit/content/default_rakefile.rb +11 -11
  17. data/lib/makit/content/gem_rakefile.rb +14 -14
  18. data/lib/makit/data.rb +50 -50
  19. data/lib/makit/directories.rb +140 -140
  20. data/lib/makit/directory.rb +184 -181
  21. data/lib/makit/dotnet.rb +104 -104
  22. data/lib/makit/environment.rb +123 -123
  23. data/lib/makit/fileinfo.rb +16 -16
  24. data/lib/makit/files.rb +47 -47
  25. data/lib/makit/git.rb +80 -80
  26. data/lib/makit/gitlab_runner.rb +60 -60
  27. data/lib/makit/humanize.rb +112 -112
  28. data/lib/makit/logging.rb +96 -96
  29. data/lib/makit/markdown.rb +75 -75
  30. data/lib/makit/mp/basic_object_mp.rb +16 -16
  31. data/lib/makit/mp/command_request.mp.rb +16 -16
  32. data/lib/makit/mp/project_mp.rb +210 -210
  33. data/lib/makit/mp/string_mp.rb +117 -117
  34. data/lib/makit/nuget.rb +57 -57
  35. data/lib/makit/protoc.rb +87 -61
  36. data/lib/makit/serializer.rb +115 -115
  37. data/lib/makit/show.rb +65 -0
  38. data/lib/makit/storage.rb +131 -131
  39. data/lib/makit/symbols.rb +149 -149
  40. data/lib/makit/tasks.rb +55 -55
  41. data/lib/makit/tree.rb +37 -37
  42. data/lib/makit/v1/makit.v1_pb.rb +3 -4
  43. data/lib/makit/v1/makit.v1_services_pb.rb +25 -25
  44. data/lib/makit/version.rb +12 -12
  45. data/lib/makit/wix.rb +95 -95
  46. data/lib/makit/zip.rb +17 -17
  47. data/lib/makit.rb +254 -254
  48. metadata +4 -3
@@ -1,343 +1,343 @@
1
- require "English"
2
- require "open3"
3
- require "socket"
4
- require "etc"
5
- require "logger"
6
- require_relative "mp/command_request.mp"
7
-
8
- # This module provides classes for the Makit gem.
9
- module Makit
10
- # This class provide methods running commands.
11
- #
12
- class CommandRunner
13
- attr_accessor :show_output_on_success, :log_to_artifacts, :commands
14
- attr_accessor :debug
15
-
16
- def initialize
17
- @show_output_on_success = false
18
- @log_to_artifacts = false
19
- @commands = []
20
- @debug = false
21
- end
22
-
23
- def get_cache_filename(command)
24
- int_hash = Digest::SHA256.hexdigest("#{command.name}.#{command.arguments.join(" ")}")
25
- hash_string = "#{int_hash}"
26
- cache_filename = Makit::Directories::PROJECT_ARTIFACTS +
27
- "/commands/cache/#{hash_string}.pb"
28
- # create the directory if it does not already exist
29
- FileUtils.mkdir_p(File.dirname(cache_filename))
30
- cache_filename
31
- end
32
-
33
- # if there is a matching cached command result, that then the specified timestamp,
34
- # then return the cached result
35
- # otherwise run the command and save the result to a cache file
36
- # then return the result
37
- def cache_run(command_request, timestamp)
38
- raise "Invalid command_request" unless command_request.is_a? Makit::V1::CommandRequest
39
- cache_filename = get_cache_filename(command_request)
40
-
41
- if debug
42
- puts " timestamp: #{Makit::Humanize.get_humanized_timestamp(timestamp)}"
43
- puts " command.name: #{command_request.name}"
44
- puts " command.arguments: #{command_request.arguments.join(" ")}"
45
- puts " cache_filename: #{cache_filename}"
46
- end
47
- #cache_filename = Makit::Directories::PROJECT_ARTIFACTS + "/commands/#{command_request.name}.#{command_request.arguments.join("_")}.#{timestamp.seconds}.pb"
48
- if File.exist?(cache_filename)
49
- cache_timestamp = File.mtime(cache_filename)
50
- if debug
51
- puts " cache timestamp: #{Makit::Humanize.get_humanized_timestamp(cache_timestamp)}"
52
- end
53
- #puts "cache file date: #{File.mtime(cache_filename)}"
54
- if (File.mtime(cache_filename) > timestamp)
55
-
56
- #puts " found cached command (newer than #{timestamp})".colorize(:grey)
57
- #puts " cache_filename: #{cache_filename}"
58
- command = Makit::Serializer.open(cache_filename, Makit::V1::Command)
59
- show_cached_command(command)
60
- if command.exit_code != 0
61
- abort "cached command failed: #{command.name} #{command.arguments.join(" ")}"
62
- end
63
- return command
64
- else
65
- puts " cache_filename exists, but is older than #{timestamp}" if debug
66
- File.delete(cache_filename)
67
- end
68
- end
69
-
70
- command = run(command_request)
71
- # make sure the cache directory exists
72
- FileUtils.mkdir_p(File.dirname(cache_filename))
73
- #puts "saving command to cache_filename"
74
- Makit::Serializer.save_as(cache_filename, command)
75
- commands.push(command)
76
- command
77
- end
78
-
79
- def show_command(command)
80
- if command.exit_code != 0
81
- puts Makit::CommandRunner.get_command_summary(command) + " (exit code #{command.exit_code})".colorize(:default)
82
- puts " directory: #{command.directory}\n"
83
- puts " duration: #{command.duration.seconds} seconds\n"
84
- puts Makit::Humanize::indent_string(command.output, 2) if command.output.length > 0
85
- puts Makit::Humanize::indent_string(command.error, 2) if command.error.length > 0
86
- #exit 1 if command.exit_on_error
87
- else
88
- puts Makit::CommandRunner.get_command_summary(command) + " (#{command.duration.seconds} seconds)".colorize(:cyan)
89
- puts Makit::Humanize::indent_string(command.output, 2).colorize(:default) if show_output_on_success
90
- end
91
- end
92
-
93
- def show_cached_command(command)
94
- if command.exit_code != 0
95
- puts Makit::CommandRunner.get_command_summary(command) + " (exit code #{command.exit_code})".colorize(:default)
96
- puts " directory: #{command.directory}\n"
97
- puts " duration: #{command.duration.seconds} seconds\n"
98
- puts Makit::Humanize::indent_string(command.output, 2) if command.output.length > 0
99
- puts Makit::Humanize::indent_string(command.error, 2) if command.error.length > 0
100
- #exit 1 if command.exit_on_error
101
- else
102
- puts Makit::CommandRunner.get_command_summary(command).strip_color_codes.colorize(:grey) + " (#{command.duration.seconds} seconds)".colorize(:grey)
103
- puts Makit::Humanize::indent_string(command.output, 2).colorize(:default) if show_output_on_success
104
- end
105
- end
106
-
107
- # Run a command and return a Makit::V1::Command.
108
- def run(command_request)
109
- raise "Invalid command_request" unless command_request.is_a? Makit::V1::CommandRequest
110
- command = execute(command_request)
111
- show_output = true
112
- exit_on_error = true
113
-
114
- log_to_artifacts(command) if @log_to_artifacts
115
- show_command(command)
116
- if command.exit_code != 0
117
- exit 1 if command_request.exit_on_error
118
- end
119
- commands.push(command)
120
- command
121
- end
122
-
123
- def log_to_artifacts(command)
124
- log_filename = get_cache_filename(command)
125
- Makit::Serializer.save_as(log_filename, command)
126
- end
127
-
128
- # Run a command and return a Makit::V1::Command.
129
- def try(args)
130
- request = parse_command_request(args)
131
- request.exit_on_error = false
132
- run(request)
133
- #run2(args, false)
134
- end
135
-
136
- # Show the output of a command and return a Makit::V1::Command.
137
- def show(args)
138
- request = parse_args(args)
139
- command = execute(request)
140
-
141
- show_output = true
142
- exit_on_error = true
143
- Makit::LOGGER.info(Makit::CommandRunner.get_command_summary(command))
144
- show_output = true if command.exit_code != 0
145
- Makit::LOGGER.info(indent_string("\n#{command.output}\n#{command.error}\n".strip, 2)) if show_output
146
- exit(command.exit_code) if exit_on_error && command.exit_code != 0 # unless process_status.success?
147
- command
148
- end
149
-
150
- # Parse and return a Makit::V1::CommandRequest.
151
- def parse_command_request(source)
152
- return Makit::V1::CommandRequest.new(source) if source.is_a? Hash
153
- return source if source.is_a? Makit::V1::CommandRequest
154
- if source.is_a? String
155
- return parse_args(source)
156
- end
157
-
158
- raise "Invalid source" unless source.is_a? Makit::V1::CommandRequest
159
- end
160
-
161
- def parse_command_request_from_hash(hash)
162
- raise "Invalid hash" unless hash.is_a? Hash
163
- Makit::V1::CommandRequest.new(hash)
164
- end
165
-
166
- def parse_command_request_from_string(source)
167
- raise "Invalid source" unless source.is_a? String
168
- words = source.split(" ")
169
- hash = {
170
- name: words.shift,
171
- arguments: words,
172
- exit_on_error: true,
173
- }
174
- end
175
-
176
- # Parse the command line arguments into a Makit::V1::CommandRequest.
177
- def parse_args(args)
178
- #raise "No command specified" if args.empty?
179
- if args.is_a? Makit::V1::CommandRequest
180
- args
181
- else
182
- if args.is_a? String
183
- args = args.split(" ")
184
- if (args.length == 1)
185
- hash = {
186
- name: args[0],
187
- arguments: [],
188
- exit_on_error: true,
189
- }
190
- Makit::V1::CommandRequest.new(hash)
191
- else
192
- hash = {
193
- name: args.shift,
194
- arguments: args,
195
- exit_on_error: true,
196
- }
197
-
198
- Makit::V1::CommandRequest.new(hash)
199
- end
200
- else
201
- Makit::V1::CommandRequest.new(args)
202
- end
203
- end
204
- end
205
-
206
- def get_path_name(name)
207
- # replace all characters that a not valid in a filename with an underscore
208
- name.gsub(/[^0-9a-z]/i, "_")
209
- end
210
-
211
- # Given a Makit::V1::CommandRequest, execute the command and return a Makit::V1::Command.
212
- def execute(args)
213
- command_request = parse_args(args)
214
- command_request.directory = Dir.pwd if command_request.directory.nil?
215
- command_request.directory = Dir.pwd if command_request.directory.length == 0
216
- result = Makit::V1::Command.new(name: command_request.name)
217
- command_request.arguments.each do |arg|
218
- result.arguments.push(arg)
219
- end
220
- command = "#{command_request.name} #{command_request.arguments.join(" ")}"
221
- result.directory = command_request.directory
222
- start = Time.now
223
- filename_friendly_timestamp = Time.now.strftime("%Y.%m.%d_%H%M%S")
224
- log_filename = File.join(Makit::Directories::LOG, "#{filename_friendly_timestamp}.log")
225
-
226
- # assign a directory variable to the current working directory, if not specified,
227
- # otherwise assign the specified directory
228
- command_request.directory = Dir.pwd if command_request.directory.nil?
229
- command_request.directory = Dir.pwd if command_request.directory.length == 0
230
- raise "Invalid directory" unless Dir.exist?(command_request.directory)
231
-
232
- result.started_at = Google::Protobuf::Timestamp.new(seconds: start.to_i, nanos: start.nsec.to_i)
233
- ############# execute the command
234
- (output, error, exit_code) = execute_command(command, command_request.directory, command_request.timeout)
235
- result.output = output.force_encoding("ASCII-8BIT")
236
- result.error = error.force_encoding("ASCII-8BIT")
237
- result.exit_code = exit_code.nil? ? 0 : exit_code
238
-
239
- elapsed_time = Time.now - start
240
- seconds = elapsed_time.to_i
241
- nanos = ((elapsed_time - seconds) * 1_000_000_000).to_i
242
-
243
- result.duration = Google::Protobuf::Duration.new(seconds: seconds, nanos: nanos)
244
-
245
- result
246
- end
247
-
248
- # pure function to execute a command
249
- # returns (stdout, stderr, exit_code) or raise an exception
250
- def execute_command(command, directory, timeout)
251
- original_directory = Dir.pwd
252
- begin
253
- output = nil
254
- error = nil
255
- process_status = nil
256
- Dir.chdir(directory) do
257
- output, error, process_status = Open3.capture3(command)
258
- end
259
- return [output, error, process_status.exitstatus]
260
- rescue => e
261
- # restore the original working directory
262
- Dir.chdir(original_directory)
263
- message_parts = []
264
- message_parts << "failed to execute #{command}"
265
- message_parts << "directory: #{directory}"
266
- message_parts << "timeout: #{timeout}" unless timeout.nil?
267
- message_parts << "error: #{e.message}"
268
- message = message_parts.join("\n") + "\n"
269
- return ["", message, 1]
270
- #raise Makit::Error, message
271
- end
272
- end
273
-
274
- def execute_command_request(command_request)
275
- # if the command_request is not a Makit::V1::CommandRequest, raise an error
276
- raise "Invalid command_request" unless command_request.is_a? Makit::V1::CommandRequest
277
-
278
- args = Array.new
279
- command_request.arguments.each do |arg|
280
- args.push(arg)
281
- end
282
- result = Makit::V1::Command.new({
283
- name: command_request.name,
284
- arguments: args,
285
- started_at: Google::Protobuf::Timestamp.new({ seconds: Time.now.to_i, nanos: Time.now.nsec }),
286
- })
287
-
288
- begin
289
- rescue => e
290
- end
291
- end
292
-
293
- def indent_string(input_string, indent_spaces)
294
- indentation = " " * indent_spaces
295
- input_string.lines.map { |line| indentation + line }.join
296
- end
297
-
298
- def self.get_command_summary(command)
299
- symbol = Makit::Symbols.warning
300
- symbol = Makit::Symbols.checkmark if !command.exit_code.nil? && command.exit_code.zero?
301
- symbol = Makit::Symbols.error if command.exit_code != 0
302
- summary = "#{symbol} #{command.name.colorize(:yellow)} #{command.arguments.join(" ")}"
303
-
304
- if summary.length > 80
305
- summary = summary.to_lines(80, command.name.length + 3)
306
- end
307
-
308
- summary
309
- end
310
-
311
- def log_rake_commands
312
- dir = File.join(Makit::Directories::PROJECT_ARTIFACTS, "commands")
313
- FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
314
-
315
- # open a text file to write to
316
- File.open(File.join(dir, "rake.commands.txt"), "w") do |file|
317
- #rake_commands = commands.select { |command| command.name == "rake" }
318
- commands.each do |command|
319
- file.puts " " + Makit::CommandRunner.get_command_summary(command).strip_color_codes
320
- file.puts " start time: #{command.started_at}"
321
- file.puts command.output.strip_color_codes unless command.output.strip_color_codes.strip.length == 0
322
- file.puts command.error.strip_color_codes unless command.error.strip_color_codes.strip.length == 0
323
- file.puts " "
324
- end
325
- end
326
- end
327
-
328
- def log_slowest_commands
329
- dir = File.join(Makit::Directories::PROJECT_ARTIFACTS, "commands")
330
- FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
331
-
332
- # open a text file to write to
333
- File.open(File.join(dir, "slow.commands.txt"), "w") do |file|
334
- Makit::RUNNER.commands.sort_by { |command| (command.duration.seconds + (command.duration.nanos / 1_000_000_000.0)) }.reverse.first(5).each do |command|
335
- # Convert to float representation
336
- duration_in_float = command.duration.seconds + (command.duration.nanos / 1_000_000_000.0)
337
- #puts " #{command.name} took #{duration_in_float} seconds"
338
- file.puts " " + Makit::CommandRunner.get_command_summary(command).strip_color_codes + " (#{command.duration.seconds} seconds)"
339
- end
340
- end
341
- end
342
- end # class CommandRunner
343
- end # module Makit
1
+ require "English"
2
+ require "open3"
3
+ require "socket"
4
+ require "etc"
5
+ require "logger"
6
+ require_relative "mp/command_request.mp"
7
+
8
+ # This module provides classes for the Makit gem.
9
+ module Makit
10
+ # This class provide methods running commands.
11
+ #
12
+ class CommandRunner
13
+ attr_accessor :show_output_on_success, :log_to_artifacts, :commands
14
+ attr_accessor :debug
15
+
16
+ def initialize
17
+ @show_output_on_success = false
18
+ @log_to_artifacts = false
19
+ @commands = []
20
+ @debug = false
21
+ end
22
+
23
+ def get_cache_filename(command)
24
+ int_hash = Digest::SHA256.hexdigest("#{command.name}.#{command.arguments.join(" ")}")
25
+ hash_string = "#{int_hash}"
26
+ cache_filename = Makit::Directories::PROJECT_ARTIFACTS +
27
+ "/commands/cache/#{hash_string}.pb"
28
+ # create the directory if it does not already exist
29
+ FileUtils.mkdir_p(File.dirname(cache_filename))
30
+ cache_filename
31
+ end
32
+
33
+ # if there is a matching cached command result, that then the specified timestamp,
34
+ # then return the cached result
35
+ # otherwise run the command and save the result to a cache file
36
+ # then return the result
37
+ def cache_run(command_request, timestamp)
38
+ raise "Invalid command_request" unless command_request.is_a? Makit::V1::CommandRequest
39
+ cache_filename = get_cache_filename(command_request)
40
+
41
+ if debug
42
+ puts " timestamp: #{Makit::Humanize.get_humanized_timestamp(timestamp)}"
43
+ puts " command.name: #{command_request.name}"
44
+ puts " command.arguments: #{command_request.arguments.join(" ")}"
45
+ puts " cache_filename: #{cache_filename}"
46
+ end
47
+ #cache_filename = Makit::Directories::PROJECT_ARTIFACTS + "/commands/#{command_request.name}.#{command_request.arguments.join("_")}.#{timestamp.seconds}.pb"
48
+ if File.exist?(cache_filename)
49
+ cache_timestamp = File.mtime(cache_filename)
50
+ if debug
51
+ puts " cache timestamp: #{Makit::Humanize.get_humanized_timestamp(cache_timestamp)}"
52
+ end
53
+ #puts "cache file date: #{File.mtime(cache_filename)}"
54
+ if (File.mtime(cache_filename) > timestamp)
55
+
56
+ #puts " found cached command (newer than #{timestamp})".colorize(:grey)
57
+ #puts " cache_filename: #{cache_filename}"
58
+ command = Makit::Serializer.open(cache_filename, Makit::V1::Command)
59
+ show_cached_command(command)
60
+ if command.exit_code != 0
61
+ abort "cached command failed: #{command.name} #{command.arguments.join(" ")}"
62
+ end
63
+ return command
64
+ else
65
+ puts " cache_filename exists, but is older than #{timestamp}" if debug
66
+ File.delete(cache_filename)
67
+ end
68
+ end
69
+
70
+ command = run(command_request)
71
+ # make sure the cache directory exists
72
+ FileUtils.mkdir_p(File.dirname(cache_filename))
73
+ #puts "saving command to cache_filename"
74
+ Makit::Serializer.save_as(cache_filename, command)
75
+ commands.push(command)
76
+ command
77
+ end
78
+
79
+ def show_command(command)
80
+ if command.exit_code != 0
81
+ puts Makit::CommandRunner.get_command_summary(command) + " (exit code #{command.exit_code})".colorize(:default)
82
+ puts " directory: #{command.directory}\n"
83
+ puts " duration: #{command.duration.seconds} seconds\n"
84
+ puts Makit::Humanize::indent_string(command.output, 2) if command.output.length > 0
85
+ puts Makit::Humanize::indent_string(command.error, 2) if command.error.length > 0
86
+ #exit 1 if command.exit_on_error
87
+ else
88
+ puts Makit::CommandRunner.get_command_summary(command) + " (#{command.duration.seconds} seconds)".colorize(:cyan)
89
+ puts Makit::Humanize::indent_string(command.output, 2).colorize(:default) if show_output_on_success
90
+ end
91
+ end
92
+
93
+ def show_cached_command(command)
94
+ if command.exit_code != 0
95
+ puts Makit::CommandRunner.get_command_summary(command) + " (exit code #{command.exit_code})".colorize(:default)
96
+ puts " directory: #{command.directory}\n"
97
+ puts " duration: #{command.duration.seconds} seconds\n"
98
+ puts Makit::Humanize::indent_string(command.output, 2) if command.output.length > 0
99
+ puts Makit::Humanize::indent_string(command.error, 2) if command.error.length > 0
100
+ #exit 1 if command.exit_on_error
101
+ else
102
+ puts Makit::CommandRunner.get_command_summary(command).strip_color_codes.colorize(:grey) + " (#{command.duration.seconds} seconds)".colorize(:grey)
103
+ puts Makit::Humanize::indent_string(command.output, 2).colorize(:default) if show_output_on_success
104
+ end
105
+ end
106
+
107
+ # Run a command and return a Makit::V1::Command.
108
+ def run(command_request)
109
+ raise "Invalid command_request" unless command_request.is_a? Makit::V1::CommandRequest
110
+ command = execute(command_request)
111
+ show_output = true
112
+ exit_on_error = true
113
+
114
+ log_to_artifacts(command) if @log_to_artifacts
115
+ show_command(command)
116
+ if command.exit_code != 0
117
+ exit 1 if command_request.exit_on_error
118
+ end
119
+ commands.push(command)
120
+ command
121
+ end
122
+
123
+ def log_to_artifacts(command)
124
+ log_filename = get_cache_filename(command)
125
+ Makit::Serializer.save_as(log_filename, command)
126
+ end
127
+
128
+ # Run a command and return a Makit::V1::Command.
129
+ def try(args)
130
+ request = parse_command_request(args)
131
+ request.exit_on_error = false
132
+ run(request)
133
+ #run2(args, false)
134
+ end
135
+
136
+ # Show the output of a command and return a Makit::V1::Command.
137
+ def show(args)
138
+ request = parse_args(args)
139
+ command = execute(request)
140
+
141
+ show_output = true
142
+ exit_on_error = true
143
+ Makit::LOGGER.info(Makit::CommandRunner.get_command_summary(command))
144
+ show_output = true if command.exit_code != 0
145
+ Makit::LOGGER.info(indent_string("\n#{command.output}\n#{command.error}\n".strip, 2)) if show_output
146
+ exit(command.exit_code) if exit_on_error && command.exit_code != 0 # unless process_status.success?
147
+ command
148
+ end
149
+
150
+ # Parse and return a Makit::V1::CommandRequest.
151
+ def parse_command_request(source)
152
+ return Makit::V1::CommandRequest.new(source) if source.is_a? Hash
153
+ return source if source.is_a? Makit::V1::CommandRequest
154
+ if source.is_a? String
155
+ return parse_args(source)
156
+ end
157
+
158
+ raise "Invalid source" unless source.is_a? Makit::V1::CommandRequest
159
+ end
160
+
161
+ def parse_command_request_from_hash(hash)
162
+ raise "Invalid hash" unless hash.is_a? Hash
163
+ Makit::V1::CommandRequest.new(hash)
164
+ end
165
+
166
+ def parse_command_request_from_string(source)
167
+ raise "Invalid source" unless source.is_a? String
168
+ words = source.split(" ")
169
+ hash = {
170
+ name: words.shift,
171
+ arguments: words,
172
+ exit_on_error: true,
173
+ }
174
+ end
175
+
176
+ # Parse the command line arguments into a Makit::V1::CommandRequest.
177
+ def parse_args(args)
178
+ #raise "No command specified" if args.empty?
179
+ if args.is_a? Makit::V1::CommandRequest
180
+ args
181
+ else
182
+ if args.is_a? String
183
+ args = args.split(" ")
184
+ if (args.length == 1)
185
+ hash = {
186
+ name: args[0],
187
+ arguments: [],
188
+ exit_on_error: true,
189
+ }
190
+ Makit::V1::CommandRequest.new(hash)
191
+ else
192
+ hash = {
193
+ name: args.shift,
194
+ arguments: args,
195
+ exit_on_error: true,
196
+ }
197
+
198
+ Makit::V1::CommandRequest.new(hash)
199
+ end
200
+ else
201
+ Makit::V1::CommandRequest.new(args)
202
+ end
203
+ end
204
+ end
205
+
206
+ def get_path_name(name)
207
+ # replace all characters that a not valid in a filename with an underscore
208
+ name.gsub(/[^0-9a-z]/i, "_")
209
+ end
210
+
211
+ # Given a Makit::V1::CommandRequest, execute the command and return a Makit::V1::Command.
212
+ def execute(args)
213
+ command_request = parse_args(args)
214
+ command_request.directory = Dir.pwd if command_request.directory.nil?
215
+ command_request.directory = Dir.pwd if command_request.directory.length == 0
216
+ result = Makit::V1::Command.new(name: command_request.name)
217
+ command_request.arguments.each do |arg|
218
+ result.arguments.push(arg)
219
+ end
220
+ command = "#{command_request.name} #{command_request.arguments.join(" ")}"
221
+ result.directory = command_request.directory
222
+ start = Time.now
223
+ filename_friendly_timestamp = Time.now.strftime("%Y.%m.%d_%H%M%S")
224
+ log_filename = File.join(Makit::Directories::LOG, "#{filename_friendly_timestamp}.log")
225
+
226
+ # assign a directory variable to the current working directory, if not specified,
227
+ # otherwise assign the specified directory
228
+ command_request.directory = Dir.pwd if command_request.directory.nil?
229
+ command_request.directory = Dir.pwd if command_request.directory.length == 0
230
+ raise "Invalid directory" unless Dir.exist?(command_request.directory)
231
+
232
+ result.started_at = Google::Protobuf::Timestamp.new(seconds: start.to_i, nanos: start.nsec.to_i)
233
+ ############# execute the command
234
+ (output, error, exit_code) = execute_command(command, command_request.directory, command_request.timeout)
235
+ result.output = output.force_encoding("ASCII-8BIT")
236
+ result.error = error.force_encoding("ASCII-8BIT")
237
+ result.exit_code = exit_code.nil? ? 0 : exit_code
238
+
239
+ elapsed_time = Time.now - start
240
+ seconds = elapsed_time.to_i
241
+ nanos = ((elapsed_time - seconds) * 1_000_000_000).to_i
242
+
243
+ result.duration = Google::Protobuf::Duration.new(seconds: seconds, nanos: nanos)
244
+
245
+ result
246
+ end
247
+
248
+ # pure function to execute a command
249
+ # returns (stdout, stderr, exit_code) or raise an exception
250
+ def execute_command(command, directory, timeout)
251
+ original_directory = Dir.pwd
252
+ begin
253
+ output = nil
254
+ error = nil
255
+ process_status = nil
256
+ Dir.chdir(directory) do
257
+ output, error, process_status = Open3.capture3(command)
258
+ end
259
+ return [output, error, process_status.exitstatus]
260
+ rescue => e
261
+ # restore the original working directory
262
+ Dir.chdir(original_directory)
263
+ message_parts = []
264
+ message_parts << "failed to execute #{command}"
265
+ message_parts << "directory: #{directory}"
266
+ message_parts << "timeout: #{timeout}" unless timeout.nil?
267
+ message_parts << "error: #{e.message}"
268
+ message = message_parts.join("\n") + "\n"
269
+ return ["", message, 1]
270
+ #raise Makit::Error, message
271
+ end
272
+ end
273
+
274
+ def execute_command_request(command_request)
275
+ # if the command_request is not a Makit::V1::CommandRequest, raise an error
276
+ raise "Invalid command_request" unless command_request.is_a? Makit::V1::CommandRequest
277
+
278
+ args = Array.new
279
+ command_request.arguments.each do |arg|
280
+ args.push(arg)
281
+ end
282
+ result = Makit::V1::Command.new({
283
+ name: command_request.name,
284
+ arguments: args,
285
+ started_at: Google::Protobuf::Timestamp.new({ seconds: Time.now.to_i, nanos: Time.now.nsec }),
286
+ })
287
+
288
+ begin
289
+ rescue => e
290
+ end
291
+ end
292
+
293
+ def indent_string(input_string, indent_spaces)
294
+ indentation = " " * indent_spaces
295
+ input_string.lines.map { |line| indentation + line }.join
296
+ end
297
+
298
+ def self.get_command_summary(command)
299
+ symbol = Makit::Symbols.warning
300
+ symbol = Makit::Symbols.checkmark if !command.exit_code.nil? && command.exit_code.zero?
301
+ symbol = Makit::Symbols.error if command.exit_code != 0
302
+ summary = "#{symbol} #{command.name.colorize(:yellow)} #{command.arguments.join(" ")}"
303
+
304
+ if summary.length > 80
305
+ summary = summary.to_lines(80, command.name.length + 3)
306
+ end
307
+
308
+ summary
309
+ end
310
+
311
+ def log_rake_commands
312
+ dir = File.join(Makit::Directories::PROJECT_ARTIFACTS, "commands")
313
+ FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
314
+
315
+ # open a text file to write to
316
+ File.open(File.join(dir, "rake.commands.txt"), "w") do |file|
317
+ #rake_commands = commands.select { |command| command.name == "rake" }
318
+ commands.each do |command|
319
+ file.puts " " + Makit::CommandRunner.get_command_summary(command).strip_color_codes
320
+ file.puts " start time: #{command.started_at}"
321
+ file.puts command.output.strip_color_codes unless command.output.strip_color_codes.strip.length == 0
322
+ file.puts command.error.strip_color_codes unless command.error.strip_color_codes.strip.length == 0
323
+ file.puts " "
324
+ end
325
+ end
326
+ end
327
+
328
+ def log_slowest_commands
329
+ dir = File.join(Makit::Directories::PROJECT_ARTIFACTS, "commands")
330
+ FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
331
+
332
+ # open a text file to write to
333
+ File.open(File.join(dir, "slow.commands.txt"), "w") do |file|
334
+ Makit::RUNNER.commands.sort_by { |command| (command.duration.seconds + (command.duration.nanos / 1_000_000_000.0)) }.reverse.first(5).each do |command|
335
+ # Convert to float representation
336
+ duration_in_float = command.duration.seconds + (command.duration.nanos / 1_000_000_000.0)
337
+ #puts " #{command.name} took #{duration_in_float} seconds"
338
+ file.puts " " + Makit::CommandRunner.get_command_summary(command).strip_color_codes + " (#{command.duration.seconds} seconds)"
339
+ end
340
+ end
341
+ end
342
+ end # class CommandRunner
343
+ end # module Makit