Module: Corgibytes::Freshli::Commons::Execute
- Defined in:
- lib/corgibytes/freshli/commons/execute.rb
Overview
Contains utility methods for executing commands and working with their output.
Constant Summary collapse
- BUFFER_LEN =
8
- WAIT_TIMEOUT =
1
Instance Method Summary collapse
- #enable_dotnet_command_colors ⇒ Object
- #execute(command) ⇒ Object
- #fill_buffer_from_stream(stream, buffer) ⇒ Object
- #msbuild_dll_path ⇒ Object
- #null_output_target ⇒ Object
- #read_streams(for_reading, readable, stdout, stderr) ⇒ Object
- #safe_to_read?(status) ⇒ Boolean
- #skip_or_read_streams(for_reading, readable, stdout, stderr) ⇒ Object
- #stream_eof?(status) ⇒ Boolean
- #stream_open_but_empty?(status) ⇒ Boolean
- #write_buffered_output_to_correct_stream(buffer, stream, stdout, stderr) ⇒ Object
Instance Method Details
#enable_dotnet_command_colors ⇒ Object
24 25 26 |
# File 'lib/corgibytes/freshli/commons/execute.rb', line 24 def enable_dotnet_command_colors ENV['DOTNET_SYSTEM_CONSOLE_ALLOW_ANSI_COLOR_REDIRECTION'] = 'true' end |
#execute(command) ⇒ Object
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/corgibytes/freshli/commons/execute.rb', line 91 def execute(command) exit_status = nil Open3.popen3(command) do |_in, stdout, stderr, wait_thread| for_reading = [stdout, stderr] until for_reading.empty? # IO.select blocks until one of the streams is has something to read # or the wait timeout is reached readable, _writable, _errors = IO.select(for_reading, [], [], WAIT_TIMEOUT) for_reading = skip_or_read_streams(for_reading, readable, stdout, stderr) end exit_status = wait_thread.value end exit_status end |
#fill_buffer_from_stream(stream, buffer) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/corgibytes/freshli/commons/execute.rb', line 50 def fill_buffer_from_stream(stream, buffer) # loop through reading data until there is an EOF (value is nil) # or there is no more data to read (value is empty) result = nil loop do local_buffer = ''.dup result = stream.read_nonblock(BUFFER_LEN, local_buffer, exception: false) buffer << local_buffer break unless safe_to_read?(result) && buffer.length < BUFFER_LEN end result end |
#msbuild_dll_path ⇒ Object
11 12 13 14 15 16 17 18 |
# File 'lib/corgibytes/freshli/commons/execute.rb', line 11 def msbuild_dll_path dotnet_exe_path = File.realpath(find_executable('dotnet')) dotnet_dir = File.dirname(dotnet_exe_path) sdk_dir = File.join(dotnet_dir, 'sdk', Dir.children(File.join(dotnet_dir, 'sdk')).max) result = File.join(sdk_dir, 'MSBuild.dll') result = result.gsub('/', '\\') if Gem.win_platform? result end |
#null_output_target ⇒ Object
20 21 22 |
# File 'lib/corgibytes/freshli/commons/execute.rb', line 20 def null_output_target Gem.win_platform? ? '\\\\.\\nul' : '/dev/null' end |
#read_streams(for_reading, readable, stdout, stderr) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/corgibytes/freshli/commons/execute.rb', line 64 def read_streams(for_reading, readable, stdout, stderr) # In the case that both streams are readable (and thus have content) # read from each of them. In this case, we cannot guarantee any order # because we recieve the items at essentially the same time. # We can still ensure that we don't mix data incorrectly. readable.each do |stream| buffer = ''.dup result = fill_buffer_from_stream(stream, buffer) for_reading -= [stream] if stream_eof?(result) write_buffered_output_to_correct_stream(buffer, stream, stdout, stderr) end for_reading end |
#safe_to_read?(status) ⇒ Boolean
36 37 38 |
# File 'lib/corgibytes/freshli/commons/execute.rb', line 36 def safe_to_read?(status) !stream_eof?(status) && !stream_open_but_empty?(status) end |
#skip_or_read_streams(for_reading, readable, stdout, stderr) ⇒ Object
80 81 82 83 84 85 86 87 88 |
# File 'lib/corgibytes/freshli/commons/execute.rb', line 80 def skip_or_read_streams(for_reading, readable, stdout, stderr) # readable is nil in the case of a timeout - loop back again if readable.nil? Thread.pass else for_reading = read_streams(for_reading, readable, stdout, stderr) end for_reading end |
#stream_eof?(status) ⇒ Boolean
28 29 30 |
# File 'lib/corgibytes/freshli/commons/execute.rb', line 28 def stream_eof?(status) status.nil? end |
#stream_open_but_empty?(status) ⇒ Boolean
32 33 34 |
# File 'lib/corgibytes/freshli/commons/execute.rb', line 32 def stream_open_but_empty?(status) status.empty? || status == :wait_readable end |
#write_buffered_output_to_correct_stream(buffer, stream, stdout, stderr) ⇒ Object
40 41 42 43 44 45 46 |
# File 'lib/corgibytes/freshli/commons/execute.rb', line 40 def write_buffered_output_to_correct_stream(buffer, stream, stdout, stderr) if stream == stdout $stdout.print(buffer) elsif stream == stderr $stderr.print(buffer) end end |