require 'open3'
require 'retriable'

class SkopeoHelper
  ImageNotFoundError = Class.new(StandardError)

  class << self
    def login(username, password, registry)
      status = Open3.popen3({}, *%W[skopeo login --tls-verify --username=#{username} --password-stdin #{registry}]) do |stdin, stdout, stderr, wait_thr|
        stdin.puts(password)
        stdin.close

        wait_thr.value
      end

      raise "Failed to login to #{registry}" unless status.success?

      puts "Successfully logged in to #{registry}."
    end

    def copy_image(source, target)
      print "Waiting for source image `#{source}` to be available"
      # Retries for up to 15 minutes (900 seconds)
      Retriable.retriable(tries: 30, max_elapsed_time: 900, on: ImageNotFoundError) do
        Open3.popen2e(*%W[skopeo inspect docker://#{source}]) do |_, stdout_stderr, status|
          print "."

          # To prevent buffer from filling up and execution to hang, force a
          # read from it.
          stdout_stderr.read

          raise ImageNotFoundError, "Image `#{source}` not found." unless status.value.success?
        end
      end

      puts "\nCopying image `#{source}` to `#{target}`"

      # The --all flag is used to support multi-arch, so we can copy all images
      # with a single command
      status = system(*%W[skopeo copy --all docker://#{source} docker://#{target}])

      raise "Failed to copy image." unless status
    end
  end
end
