Skip to content

Instantly share code, notes, and snippets.

@kddnewton
Last active March 15, 2023 17:02
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kddnewton/aa8ff90c9383caa5d3b7d80e2f3d1f4a to your computer and use it in GitHub Desktop.
Save kddnewton/aa8ff90c9383caa5d3b7d80e2f3d1f4a to your computer and use it in GitHub Desktop.
Extract the latest versions of each Ruby gem on your system
# frozen_string_literal: true
require "rubygems/package"
require "net/http"
require "tmpdir"
queue = Queue.new
Gem::SpecFetcher.new.available_specs(:latest).first.each do |source, gems|
gems.each do |tuple|
gem_name = File.basename(tuple.spec_name, ".gemspec")
gem_url = source.uri.merge("/gems/#{gem_name}.gem")
queue << [gem_name, gem_url]
end
end
workers =
16.times.map do
Thread.new do
Net::HTTP.start("rubygems.org", 443, use_ssl: true) do |http|
until queue.empty?
(gem_name, gem_url) = queue.shift
http.request(Net::HTTP::Get.new(gem_url)) do |response|
result =
case response
when Net::HTTPSuccess
Dir.mktmpdir do |directory|
filepath = File.join(directory, "#{gem_name}.gem")
File.write(filepath, response.body)
begin
Gem::Package.new(filepath).extract_files(directory, "[!~]*")
["OK", ""]
rescue ArgumentError => error
if error.message == "invalid byte sequence in UTF-8"
["FAIL", "Gem incorrectly encoded"]
else
["ERROR", "#{error.class.name}: #{error.message}"]
end
rescue RangeError => error
if error.message == "integer 100644 too big to convert to `unsigned short'"
["FAIL", "Gem incorrectly packaged"]
else
["ERROR", "#{error.class.name}: #{error.message}"]
end
rescue Errno::EACCES
["FAIL", "Permission denied when creating files"]
rescue Errno::EEXIST
["FAIL", "File exists in a path that a directory needs to be created"]
rescue Errno::EILSEQ
["FAIL", "File path contains invalid byte sequence"]
rescue Gem::InvalidSpecificationException
["FAIL", "The gemspec contains some kind of invalid values"]
rescue Gem::Package::FormatError
["FAIL", "The gem is missing some files in the package"]
rescue Gem::Package::SymlinkError
["FAIL", "Attempting to create a symlink outside the destination directory"]
rescue Psych::DisallowedClass
["FAIL", "The gemspec YAML metadata contains a disallowed Ruby class"]
rescue Psych::SyntaxError
["FAIL", "The gemspec YAML metadata contains a syntax error"]
rescue => error
["ERROR", "#{error.class.name}: #{error.message}"]
end
end
else
["UNEXPECTED", response]
end
puts "%-70s %-12s %s" % [gem_name, *result]
end
end
end
end
end
workers.each(&:join)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment