Class: Rubycc::Doctor::Fetcher

Inherits:
Object
  • Object
show all
Defined in:
lib/rubycc/doctor/fetcher.rb

Overview

Downloads a gem's package from rubygems.org and reads its real specification. This is the authoritative source of a gem's extensions list: neither the versions API nor the "quick" (light) gemspec carries the extensions field, so the only reliable way to know whether a gem has a C extension is to read the full .gem's embedded gemspec. That full package is also exactly what an on-the-fly build needs, so probe and build share it.

Everything here touches the network; callers treat any failure (offline, 404, timeout) as "unknown" and degrade gracefully.

Defined Under Namespace

Classes: FetchError

Constant Summary collapse

HOST =
"https://rubygems.org"
OPEN_TIMEOUT =

A .gem is a few hundred KB at most for the extension gems we target; this only guards against a hung connection.

15
READ_TIMEOUT =
60

Instance Method Summary collapse

Constructor Details

#initialize(cache_dir) ⇒ Fetcher

Returns a new instance of Fetcher.



28
29
30
# File 'lib/rubycc/doctor/fetcher.rb', line 28

def initialize(cache_dir)
  @cache_dir = cache_dir
end

Instance Method Details

#download(name, version) ⇒ Object

Download NAME-VERSION.gem into the cache and return its local path. Raises FetchError on any network failure so the caller can report "unknown".



43
44
45
46
47
48
49
50
51
52
# File 'lib/rubycc/doctor/fetcher.rb', line 43

def download(name, version)
  dest = File.join(@cache_dir, "#{name}-#{version}.gem")
  return dest if File.file?(dest) && File.size(dest).positive?

  body = get("#{HOST}/gems/#{name}-#{version}.gem")
  File.binwrite(dest, body)
  dest
rescue StandardError => e
  raise FetchError, e.message
end

#latest_version(name) ⇒ Object

Resolve the latest released (non-prerelease) version of name via the v1 API. Returns a version string, or nil when the lookup fails.



34
35
36
37
38
39
# File 'lib/rubycc/doctor/fetcher.rb', line 34

def latest_version(name)
  body = get("#{HOST}/api/v1/gems/#{name}.json")
  JSON.parse(body)["version"]
rescue StandardError
  nil
end

#spec(gem_path) ⇒ Object

The Gem::Specification embedded in a downloaded .gem.



55
56
57
# File 'lib/rubycc/doctor/fetcher.rb', line 55

def spec(gem_path)
  Gem::Package.new(gem_path).spec
end