Class: Prebake::Backends::Gemstash

Inherits:
Base
  • Object
show all
Includes:
HttpClient
Defined in:
lib/prebake/backends/gemstash.rb

Constant Summary

Constants included from HttpClient

HttpClient::HTTP_METHODS, HttpClient::TIMEOUT

Instance Method Summary collapse

Constructor Details

#initialize(url:, key: nil) ⇒ Gemstash

Gemstash serves private gems at /private/gems/name-version-platform.gem based on the gem’s internal metadata. Our cache key includes the Ruby ABI (e.g., puma-6.4.3-arm64-darwin-ruby4.0.gem) which Gemstash doesn’t know about.

To make this work, we encode the Ruby ABI into the gem version when building: puma version 6.4.3 becomes 6.4.3.pre.ruby40 in the Gemstash-stored gem. Gemstash then serves it at /private/gems/puma-6.4.3.pre.ruby40-arm64-darwin.gem

The push endpoint is POST /api/v1/gems (standard RubyGems push). The fetch endpoint is GET /private/gems/gem_filename. Auth is via Authorization header with the Gemstash API key.



26
27
28
29
30
31
# File 'lib/prebake/backends/gemstash.rb', line 26

def initialize(url:, key: nil)
  @url = url.chomp("/")
  @key = key

  warn_if_insecure_http(@url)
end

Instance Method Details

#checksums_supported?Boolean

Returns:

  • (Boolean)


53
54
55
# File 'lib/prebake/backends/gemstash.rb', line 53

def checksums_supported?
  false
end

#delete(_cache_key) ⇒ Object



57
58
59
# File 'lib/prebake/backends/gemstash.rb', line 57

def delete(_cache_key)
  false
end

#exists?(cache_key) ⇒ Boolean

Returns:

  • (Boolean)


79
80
81
82
83
84
85
86
# File 'lib/prebake/backends/gemstash.rb', line 79

def exists?(cache_key)
  gem_filename = gemstash_filename(cache_key)
  uri = URI("#{@url}/private/gems/#{gem_filename}")
  response = http_request(:head, uri)
  response.is_a?(Net::HTTPSuccess)
rescue StandardError
  false
end

#fetch(cache_key) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/prebake/backends/gemstash.rb', line 33

def fetch(cache_key)
  gem_filename = gemstash_filename(cache_key)
  uri = URI("#{@url}/private/gems/#{gem_filename}")
  response = http_request(:get, uri)
  return nil unless response.is_a?(Net::HTTPSuccess)

  path = File.join(Dir.tmpdir, "prebake-#{SecureRandom.hex(16)}.gem")
  File.binwrite(path, response.body)
  path
rescue StandardError => e
  Logger.debug "Fetch failed for #{cache_key}: #{e.message}"
  nil
end

#fetch_checksum(_cache_key) ⇒ Object



47
48
49
50
51
# File 'lib/prebake/backends/gemstash.rb', line 47

def fetch_checksum(_cache_key)
  # Gemstash doesn't store arbitrary files alongside gems.
  # Checksum verification is skipped for Gemstash backend.
  nil
end

#push(gem_path, cache_key, _checksum) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/prebake/backends/gemstash.rb', line 61

def push(gem_path, cache_key, _checksum)
  uri = URI("#{@url}/private/api/v1/gems")
  gem_content = File.binread(gem_path)
  response = http_request(:post, uri, body: gem_content)

  case response
  when Net::HTTPSuccess, Net::HTTPConflict
    Logger.info "Pushed #{cache_key} to Gemstash"
    true
  else
    Logger.warn "Failed to push #{cache_key}: #{response.code} #{response.message}"
    false
  end
rescue StandardError => e
  Logger.warn "Push failed for #{cache_key}: #{e.message}"
  false
end