lib/logstash-docket/rubygem_info.rb (57 lines of code) (raw):
# encoding: utf-8
require 'thread' # Mutex
require 'net/http'
require 'uri'
require 'json'
require_relative 'util/threadsafe_deferral'
module LogstashDocket
##
# In order to avoid hitting rubygems.org too frequently, a `RubygemInfo` caches
# metadata from the API about a specific gem.
#
# @api private
#
class RubygemInfo
def initialize(gem_name)
@gem_name = gem_name
@mutex = Mutex.new
@gemdata_by_version = Util::ThreadsafeDeferral.for { fetch_versions_from_rubygems }
end
##
# @return [Array[String]]: release versions from rubygems, newest first
def versions
gemdata_by_version.keys
end
##
# @return [Hash{String=>Object},nil]: gem data as returned from the rubygems.org API
def for_version(version)
gemdata_by_version.fetch(version.to_s, nil)
end
##
# @return [String]: the latest version, or nil if no releases of this gem are available
# via the rubygems.org api
def latest
versions.first
end
private
def gemdata_by_version
@gemdata_by_version.value
end
def fetch_versions_from_rubygems
$stderr.puts("[gem:#{@gem_name}]: fetching release metadata from rubygems\n")
uri = URI("https://rubygems.org/api/v1/versions/#{@gem_name}.json")
response = Stud::try(5.times) do
r = Net::HTTP.get_response(uri)
if r.kind_of?(Net::HTTPSuccess)
r
elsif r.kind_of?(Net::HTTPNotFound)
nil
elsif r.kind_of?(Net::HTTPTooManyRequests)
sleep 1
raise "TOO MANY REQUESTS #{uri}"
else
raise "Fetch rubygems metadata #{uri} failed: #{r}"
end
end
body = response && response.body
if body.nil?
$stderr.puts("[#{@gem_name}]: failed to fetch versions.")
return {}
end
# HACK: One of our default plugins, the webhdfs, has a bad encoding in the
# gemspec which make our parser trip with this error:
#
# Encoding::UndefinedConversionError message: ""\xC3"" from ASCII-8BIT to
# UTF-8. We dont have much choice than to force utf-8.
body.encode(Encoding::UTF_8, :invalid => :replace, :undef => :replace)
JSON.parse(body)
.sort_by { |gem_data| Gem::Version.new(gem_data['number']) }
.reverse
.each_with_object({}) do |gem_data, index|
version = gem_data['number']
index[version] = gem_data
end
end
end
end