twitter/spitball

View on GitHub
lib/spitball/remote.rb

Summary

Maintainability
A
35 mins
Test Coverage
require 'net/http'
require 'uri'
require 'digest/md5'

class Spitball::Remote

  include Spitball::ClientCommon

  def initialize(gemfile, gemfile_lock, opts = {})
    @gemfile, @gemfile_lock = gemfile, gemfile_lock
    @host      = opts[:host]
    @port      = opts[:port]
    @without   = (opts[:without] || []).map{|w| w.to_sym}
    @cache_dir = ENV['SPITBALL_CACHE'] || "/tmp/spitball-#{ENV['USER']}/client"
    @bundle_config = opts[:bundle_config]
    FileUtils.mkdir_p(@cache_dir)
    use_cache_file
  end

  def use_cache_file
    if File.exist?(cache_file)
      @tarball_url = cache_file
    end
  end

  def cache_file
    hash = ::Digest::MD5.hexdigest(([@host, @port, @gemfile, @gemfile_lock, Spitball::PROTOCOL_VERSION, @bundle_config] + @without).join('/'))
    File.join(@cache_dir, hash)
  end

  def cached?
    !!@tarball_url
  end

  def cache!(sync = true) # ignore sync
    return if cached?

    url = URI.parse("https://#{@host}:#{@port}/create")
    req = Net::HTTP::Post.new(url.path)
    data = {'gemfile' => @gemfile, 'gemfile_lock' => @gemfile_lock}
    data['bundle_config'] = @bundle_config if @bundle_config
    req.form_data = data
    req.add_field Spitball::PROTOCOL_HEADER, Spitball::PROTOCOL_VERSION
    req.add_field Spitball::WITHOUT_HEADER, @without.join(',')

    res = Net::HTTP.new(url.host, url.port).start do |http|
      http.read_timeout = 3000
      http.request(req) {|r| puts r.read_body }
    end

    case res.code
    when '201', '202' # Created, Accepted
      @tarball_url = res['Location']
    when '403'
    else
      raise Spitball::ServerFailure, "Expected 2xx response code. Got #{res.code}."
    end
  rescue URI::InvalidURIError => e
    raise Spitball::ClientError, e.message
  end

  private

  def copy_tarball_data(path)
    cache!
    print "\nDownloading tarball..."; $stdout.flush
    data = get_tarball_data @tarball_url
    puts "done."

    File.open(path, 'w') { |f| f.write data }
  end

  def get_tarball_data(location)
    if File.exist?(location)
      File.read(location)
    else
      uri = URI.parse(location)

      if (res = Net::HTTP.get_response(uri)).code == '200'
        File.open(cache_file, 'w') {|f| f << res.body}
        return res.body
      else
        raise Spitball::ServerFailure, "Spitball download failed."
      end
    end
  #rescue URI::InvalidURIError => e
  #  raise Spitball::ClientError, e.message
  end
end