class FastlaneCore::TransporterExecutor

Base class for executing the iTMSTransporter

Constants

ERROR_REGEX
OUTPUT_REGEX
RETURN_VALUE_REGEX
SKIP_ERRORS
WARNING_REGEX

Public Instance Methods

execute(command, hide_output) click to toggle source
# File lib/fastlane_core/itunes_transporter.rb, line 30
def execute(command, hide_output)
  return command if Helper.is_test?

  @errors = []
  @warnings = []

  if hide_output
    # Show a one time message instead
    UI.success("Waiting for iTunes Connect transporter to be finished.")
    UI.success("iTunes Transporter progress... this might take a few minutes...")
  end

  begin
    PTY.spawn(command) do |stdin, stdout, pid|
      begin
        stdin.each do |line|
          parse_line(line, hide_output) # this is where the parsing happens
        end
      rescue Errno::EIO
        # Exception ignored intentionally.
        # https://stackoverflow.com/questions/10238298/ruby-on-linux-pty-goes-away-without-eof-raises-errnoeio
      ensure
        Process.wait(pid)
      end
    end
  rescue => ex
    @errors << ex.to_s
  end

  exit_status = $?.exitstatus
  unless exit_status.zero?
    @errors << "The call to the iTMSTransporter completed with a non-zero exit status: #{exit_status}. This indicates a failure."
  end

  if @warnings.count > 0
    UI.important(@warnings.join("\n"))
  end

  if @errors.join("").include?("app-specific")
    raise TransporterRequiresApplicationSpecificPasswordError
  end

  if @errors.count > 0
    UI.error(@errors.join("\n"))
  end

  # this is to handle GitHub issue #1896, which occurs when an
  #  iTMSTransporter file transfer fails; iTMSTransporter will log an error
  #  but will then retry; if that retry is successful, we will see the error
  #  logged, but since the status code is zero, we want to return success
  if @errors.count > 0 && exit_status.zero?
    UI.important("Although errors occurred during execution of iTMSTransporter, it returned success status.")
  end

  exit_status.zero?
end

Private Instance Methods

parse_line(line, hide_output) click to toggle source
# File lib/fastlane_core/itunes_transporter.rb, line 89
def parse_line(line, hide_output)
  # Taken from https://github.com/sshaw/itunes_store_transporter/blob/master/lib/itunes/store/transporter/output_parser.rb

  output_done = false

  re = Regexp.union(SKIP_ERRORS)
  if line.match(re)
    # Those lines will not be handle like errors or warnings

  elsif line =~ ERROR_REGEX
    @errors << $1
    UI.error("[Transporter Error Output]: #{$1}")

    # Check if it's a login error
    if $1.include? "Your Apple ID or password was entered incorrectly" or
       $1.include? "This Apple ID has been locked for security reasons"

      unless Helper.is_test?
        CredentialsManager::AccountManager.new(user: @user).invalid_credentials
        UI.error("Please run this tool again to apply the new password")
      end
    elsif $1.include? "Redundant Binary Upload. There already exists a binary upload with build"
      UI.error($1)
      UI.error("You have to change the build number of your app to upload your ipa file")
    end

    output_done = true
  elsif line =~ WARNING_REGEX
    @warnings << $1
    UI.important("[Transporter Warning Output]: #{$1}")
    output_done = true
  end

  if line =~ RETURN_VALUE_REGEX
    if $1.to_i != 0
      UI.error("Transporter transfer failed.")
      UI.important(@warnings.join("\n"))
      UI.error(@errors.join("\n"))
      UI.crash!("Return status of iTunes Transporter was #{$1}: #{@errors.join('\n')}")
    else
      UI.success("iTunes Transporter successfully finished its job")
    end
  end

  if !hide_output and line =~ OUTPUT_REGEX
    # General logging for debug purposes
    unless output_done
      UI.verbose("[Transporter]: #{$1}")
    end
  end
end