Class: FastlaneCore::FastlanePty
- Inherits:
-
Object
- Object
- FastlaneCore::FastlanePty
- Defined in:
- fastlane_core/lib/fastlane_core/fastlane_pty.rb
Class Method Summary collapse
-
.process_status ⇒ Object
to ease mocking.
- .spawn(command, &block) ⇒ Object
- .spawn_with_popen(command, &block) ⇒ Object
- .spawn_with_pty(original_command, &block) ⇒ Object
Class Method Details
.process_status ⇒ Object
to ease mocking
92 93 94 |
# File 'fastlane_core/lib/fastlane_core/fastlane_pty.rb', line 92 def self.process_status $? end |
.spawn(command, &block) ⇒ Object
23 24 25 26 27 |
# File 'fastlane_core/lib/fastlane_core/fastlane_pty.rb', line 23 def self.spawn(command, &block) spawn_with_pty(command, &block) rescue LoadError spawn_with_popen(command, &block) end |
.spawn_with_popen(command, &block) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'fastlane_core/lib/fastlane_core/fastlane_pty.rb', line 74 def self.spawn_with_popen(command, &block) status = nil require 'open3' Open3.popen2e(command) do |command_stdin, command_stdout, p| # note the inversion status = p.value yield(command_stdout, command_stdin, status.pid) command_stdin.close command_stdout.close raise StandardError, "Process crashed" if status.signaled? status.exitstatus end rescue StandardError => e # Wrapping any error in FastlanePtyError to allow callers to see and use # $?.exitstatus that would usually get returned raise FastlanePtyError.new(e, status.exitstatus || e.exit_status, status) end |
.spawn_with_pty(original_command, &block) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'fastlane_core/lib/fastlane_core/fastlane_pty.rb', line 29 def self.spawn_with_pty(original_command, &block) require 'pty' # this forces the PTY flush - fixes #21792 command = ENV['FASTLANE_EXEC_FLUSH_PTY_WORKAROUND'] ? "#{original_command};" : original_command # The status is produced in the ensure below and read after the block. It # travels in a local rather than in $?, which is a thread global: anything # that runs a subprocess in between overwrites it, and nothing writes it at # all when the wait does not happen. See fastlane#30188. status = nil PTY.spawn(command) do |command_stdout, command_stdin, pid| begin yield(command_stdout, command_stdin, pid) rescue Errno::EIO # Exception ignored intentionally. # https://stackoverflow.com/questions/10238298/ruby-on-linux-pty-goes-away-without-eof-raises-errnoeio # This is expected on some linux systems, that indicates that the subcommand finished # and we kept trying to read, ignore it ensure command_stdin.close command_stdout.close begin _pid, status = Process.wait2(pid) rescue PTY::ChildExited => e # The pty saw the child go before we asked for it. The exception # carries the status we were about to wait for. status = e.status rescue Errno::ECHILD # Something else reaped it, so there is nothing left to ask for. $? # may still hold it, and may just as easily hold someone else's. end end end status ||= self.process_status # Better a plain error than a NoMethodError raised from inside the handler # that exists to report the failure, which is what nil used to produce. raise StandardError, "Could not determine the exit status of the command" if status.nil? raise StandardError, "Process crashed" if status.signaled? status.exitstatus rescue StandardError => e # Wrapping any error in FastlanePtyError to allow callers to see and use # the exit status that would usually get returned status ||= self.process_status raise FastlanePtyError.new(e, status&.exitstatus || e.exit_status, status) end |