makit 0.0.26 → 0.0.27

Sign up to get free protection for your applications and to get access to all the features.
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