gemirro 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +29 -0
  3. data/.rubocop.yml +6 -3
  4. data/Gemfile +9 -0
  5. data/Gemfile.lock +126 -0
  6. data/MANIFEST +6 -10
  7. data/README.md +1 -1
  8. data/bin/gemirro +7 -1
  9. data/gemirro.gemspec +9 -9
  10. data/lib/gemirro/cli/index.rb +12 -3
  11. data/lib/gemirro/cli/init.rb +6 -1
  12. data/lib/gemirro/cli/server.rb +2 -4
  13. data/lib/gemirro/cli/update.rb +6 -0
  14. data/lib/gemirro/configuration.rb +1 -1
  15. data/lib/gemirro/gems_fetcher.rb +5 -10
  16. data/lib/gemirro/http.rb +6 -6
  17. data/lib/gemirro/indexer.rb +397 -90
  18. data/lib/gemirro/mirror_file.rb +1 -0
  19. data/lib/gemirro/server.rb +73 -160
  20. data/lib/gemirro/source.rb +2 -2
  21. data/lib/gemirro/utils.rb +123 -68
  22. data/lib/gemirro/version.rb +1 -1
  23. data/lib/gemirro/versions_fetcher.rb +6 -2
  24. data/lib/gemirro.rb +1 -1
  25. data/spec/gemirro/http_spec.rb +83 -24
  26. data/spec/gemirro/indexer_spec.rb +3 -0
  27. data/spec/gemirro/server_spec.rb +76 -47
  28. data/template/config.rb +6 -0
  29. data/template/public/dist/css/gemirro.css +25 -1
  30. data/template/public/latest_specs.4.8 +0 -0
  31. data/template/public/prerelease_specs.4.8 +0 -0
  32. data/template/public/specs.4.8 +0 -0
  33. data/views/gem.erb +46 -37
  34. data/views/index.erb +41 -33
  35. data/views/layout.erb +5 -25
  36. data/views/not_found.erb +4 -4
  37. metadata +72 -89
  38. data/lib/gemirro/cache.rb +0 -115
  39. data/spec/gemirro/cache_spec.rb +0 -32
  40. data/template/public/dist/css/bootstrap.min.css +0 -7
  41. data/template/public/dist/fonts/glyphicons-halflings-regular.eot +0 -0
  42. data/template/public/dist/fonts/glyphicons-halflings-regular.svg +0 -288
  43. data/template/public/dist/fonts/glyphicons-halflings-regular.ttf +0 -0
  44. data/template/public/dist/fonts/glyphicons-halflings-regular.woff +0 -0
  45. data/template/public/dist/fonts/glyphicons-halflings-regular.woff2 +0 -0
  46. data/template/public/dist/js/bootstrap.min.js +0 -7
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'sinatra/base'
4
- require 'sinatra/static_assets'
5
4
  require 'thin'
6
5
  require 'uri'
7
6
  require 'addressable/uri'
@@ -11,14 +10,6 @@ module Gemirro
11
10
  # Launch Sinatra server to easily download gems.
12
11
  #
13
12
  class Server < Sinatra::Base
14
- register Sinatra::StaticAssets
15
-
16
- # rubocop:disable Layout/LineLength
17
- URI_REGEXP = /^(.*)-(\d+(?:\.\d+){1,4}.*?)(?:-(x86-(?:(?:mswin|mingw)(?:32|64)).*?|java))?\.(gem(?:spec\.rz)?)$/.freeze
18
- # rubocop:enable Layout/LineLength
19
- GEMSPEC_TYPE = 'gemspec.rz'
20
- GEM_TYPE = 'gem'
21
-
22
13
  access_logger = Logger.new(Utils.configuration.server.access_log).tap do |logger|
23
14
  ::Logger.class_eval { alias_method :write, :<< }
24
15
  logger.level = ::Logger::INFO
@@ -65,7 +56,7 @@ module Gemirro
65
56
  end
66
57
 
67
58
  ##
68
- # Display information about one gem
59
+ # Display information about one gem, human readable
69
60
  #
70
61
  # @return [nil]
71
62
  #
@@ -79,7 +70,7 @@ module Gemirro
79
70
 
80
71
  ##
81
72
  # Display home page containing the list of gems already
82
- # downloaded on the server
73
+ # downloaded on the server, human readable
83
74
  #
84
75
  # @return [nil]
85
76
  #
@@ -88,13 +79,17 @@ module Gemirro
88
79
  end
89
80
 
90
81
  ##
91
- # Return gem dependencies as binary
82
+ # Return gem dependencies as marshaled binary
92
83
  #
93
84
  # @return [nil]
94
85
  #
95
86
  get '/api/v1/dependencies' do
96
87
  content_type 'application/octet-stream'
97
- query_gems.any? ? Marshal.dump(query_gems_list) : 200
88
+ if params[:gems].to_s != '' && params[:gems].to_s.split(',').any?
89
+ Marshal.dump(dependencies_loader(params[:gems].to_s.split(',')))
90
+ else
91
+ 200
92
+ end
98
93
  end
99
94
 
100
95
  ##
@@ -104,187 +99,105 @@ module Gemirro
104
99
  #
105
100
  get '/api/v1/dependencies.json' do
106
101
  content_type 'application/json'
107
- query_gems.any? ? JSON.dump(query_gems_list) : {}
102
+
103
+ return '[]' unless params[:gems]
104
+
105
+ gem_names = params[:gems].to_s
106
+ .split(',')
107
+ .map(&:strip)
108
+ .reject(&:empty?)
109
+ return '[]' if gem_names.empty?
110
+
111
+ JSON.dump(dependencies_loader(gem_names))
108
112
  end
109
113
 
110
114
  ##
111
- # Try to get all request and download files
112
- # if files aren't found.
115
+ # compact_index, Return list of available gem names
113
116
  #
114
117
  # @return [nil]
115
118
  #
116
- get('*') do |path|
117
- resource = "#{settings.public_folder}#{path}"
119
+ get '/names' do
120
+ content_type 'text/plain'
118
121
 
119
- # Try to download gem
120
- fetch_gem(resource) unless File.exist?(resource)
121
- # If not found again, return a 404
122
- return not_found unless File.exist?(resource)
122
+ content_path = Dir.glob(File.join(Gemirro.configuration.destination, 'names.*.*.list')).last
123
+ _, etag, repr_digest, _ = content_path.split('.', -4)
123
124
 
124
- send_file(resource)
125
+ headers 'etag' => etag
126
+ headers 'repr-digest' => %(sha-256="#{repr_digest}")
127
+ send_file content_path
125
128
  end
126
129
 
127
130
  ##
128
- # Try to fetch gem and download its if it's possible, and
129
- # build and install indicies.
131
+ # compact_index, Return list of gem, including versions
130
132
  #
131
- # @param [String] resource
132
- # @return [Indexer]
133
+ # @return [nil]
133
134
  #
134
- def fetch_gem(resource)
135
- return unless Utils.configuration.fetch_gem
136
-
137
- name = File.basename(resource)
138
- result = name.match(URI_REGEXP)
139
- return unless result
135
+ get '/versions' do
136
+ content_type 'text/plain'
140
137
 
141
- gem_name, gem_version, gem_platform, gem_type = result.captures
142
- return unless gem_name && gem_version
138
+ content_path = Dir.glob(File.join(Utils.configuration.destination, 'versions.*.*.list')).last
139
+ _, etag, repr_digest, _ = content_path.split('.', -4)
143
140
 
144
- begin
145
- gem = Utils.stored_gem(gem_name, gem_version, gem_platform)
146
- gem.gemspec = true if gem_type == GEMSPEC_TYPE
147
-
148
- return if Utils.gems_fetcher.gem_exists?(gem.filename(gem_version)) && gem_type == GEM_TYPE
149
- return if Utils.gems_fetcher.gemspec_exists?(gem.gemspec_filename(gem_version)) && gem_type == GEMSPEC_TYPE
150
-
151
- Utils.logger
152
- .info("Try to download #{gem_name} with version #{gem_version}")
153
- Utils.gems_fetcher.source.gems.clear
154
- Utils.gems_fetcher.source.gems.push(gem)
155
- Utils.gems_fetcher.fetch
156
-
157
- update_indexes if Utils.configuration.update_on_fetch
158
- rescue StandardError => e
159
- Utils.logger.error(e)
160
- end
141
+ headers 'etag' => etag
142
+ headers 'repr-digest' => %(sha-256="#{repr_digest}")
143
+ send_file content_path
161
144
  end
162
145
 
163
- ##
164
- # Update indexes files
146
+ # compact_index, Return gem dependencies for all versions of a gem
165
147
  #
166
- # @return [Indexer]
148
+ # @return [nil]
167
149
  #
168
- def update_indexes
169
- indexer = Gemirro::Indexer.new(Utils.configuration.destination)
170
- indexer.only_origin = true
171
- indexer.ui = ::Gem::SilentUI.new
150
+ get('/info/:gemname') do
151
+ gems = Utils.gems_collection
152
+ gem = gems.find_by_name(params[:gemname])
153
+ return not_found if gem.nil?
172
154
 
173
- Utils.logger.info('Generating indexes')
174
- indexer.update_index
175
- indexer.updated_gems.each do |gem|
176
- Utils.cache.flush_key(File.basename(gem))
177
- end
178
- rescue SystemExit => e
179
- Utils.logger.info(e.message)
180
- end
155
+ content_type 'text/plain'
181
156
 
182
- ##
183
- # Return all gems pass to query
184
- #
185
- # @return [Array]
186
- #
187
- def query_gems
188
- params[:gems].to_s.split(',')
157
+ content_path = Dir.glob(File.join(Utils.configuration.destination, 'info', "#{params[:gemname]}.*.*.list")).last
158
+ _, etag, repr_digest, _ = content_path.split('.', -4)
159
+
160
+ headers 'etag' => etag
161
+ headers 'repr-digest' => %(sha-256="#{repr_digest}")
162
+ send_file content_path
189
163
  end
190
164
 
191
165
  ##
192
- # Return gems list from query params
166
+ # Try to get all request and download files
167
+ # if files aren't found.
193
168
  #
194
- # @return [Array]
169
+ # @return [nil]
195
170
  #
196
- def query_gems_list
197
- Utils.gems_collection(false) # load collection
198
- gems = Parallel.map(query_gems, in_threads: 4) do |query_gem|
199
- gem_dependencies(query_gem)
200
- end
171
+ get('*') do |path|
172
+ resource = "#{settings.public_folder}#{path}"
201
173
 
202
- gems.flatten!
203
- gems.reject!(&:empty?)
204
- gems
174
+ # Try to download gem
175
+ Gemirro::Utils.fetch_gem(resource) unless File.exist?(resource)
176
+ # If not found again, return a 404
177
+ return not_found unless File.exist?(resource)
178
+
179
+ send_file(resource)
205
180
  end
206
181
 
207
182
  ##
208
- # List of versions and dependencies of each version
209
- # from a gem name.
183
+ # Compile fragments for /api/v1/dependencies
210
184
  #
211
- # @return [Array]
185
+ # @return [nil]
212
186
  #
213
- def gem_dependencies(gem_name)
214
- Utils.cache.cache(gem_name) do
215
- gems = Utils.gems_collection(false)
216
- gem_collection = gems.find_by_name(gem_name)
217
-
218
- return '' if gem_collection.nil?
219
-
220
- gem_collection = Parallel.map(gem_collection, in_threads: 4) do |gem|
221
- [gem, spec_for(gem.name, gem.number, gem.platform)]
222
- end
223
- gem_collection.compact!
224
-
225
- Parallel.map(gem_collection, in_threads: 4) do |gem, spec|
226
- dependencies = spec.dependencies.select do |d|
227
- d.type == :runtime
228
- end
229
-
230
- dependencies = Parallel.map(dependencies, in_threads: 4) do |d|
231
- [d.name.is_a?(Array) ? d.name.first : d.name, d.requirement.to_s]
232
- end
233
-
234
- {
235
- name: gem.name,
236
- number: gem.number,
237
- platform: gem.platform,
238
- dependencies: dependencies
239
- }
240
- end
241
- end
242
- end
243
-
244
- helpers do
245
- ##
246
- # Return gem specification from gemname and version
247
- #
248
- # @param [String] gemname
249
- # @param [String] version
250
- # @return [::Gem::Specification]
251
- #
252
- def spec_for(gemname, version, platform = 'ruby')
253
- gem = Utils.stored_gem(gemname, version.to_s, platform)
254
- gemspec_path = File.join('quick',
255
- Gemirro::Configuration.marshal_identifier,
256
- gem.gemspec_filename)
257
- spec_file = File.join(settings.public_folder,
258
- gemspec_path)
259
- fetch_gem(gemspec_path) unless File.exist?(spec_file)
260
-
261
- return unless File.exist?(spec_file)
262
-
263
- File.open(spec_file, 'r') do |uz_file|
264
- uz_file.binmode
265
- Marshal.load(::Gem.inflate(uz_file.read))
187
+ def dependencies_loader(names)
188
+ names.collect do |name|
189
+ f = File.join(settings.public_folder, 'api', 'v1', 'dependencies', "#{name}.*.*.list")
190
+ Marshal.load(File.read(Dir.glob(f).last))
191
+ rescue StandardError => e
192
+ env['rack.errors'].write "Cound not open #{f}\n"
193
+ env['rack.errors'].write "#{e.message}\n"
194
+ e.backtrace.each do |err|
195
+ env['rack.errors'].write "#{err}\n"
266
196
  end
197
+ nil
267
198
  end
268
-
269
- ##
270
- # Escape string
271
- #
272
- # @param [String] string
273
- # @return [String]
274
- #
275
- def escape(string)
276
- Rack::Utils.escape_html(string)
277
- end
278
-
279
- ##
280
- # Homepage link
281
- #
282
- # @param [Gem] spec
283
- # @return [String]
284
- #
285
- def homepage(spec)
286
- URI.parse(Addressable::URI.escape(spec.homepage))
287
- end
199
+ .flatten
200
+ .compact
288
201
  end
289
202
  end
290
203
  end
@@ -46,8 +46,8 @@ module Gemirro
46
46
  #
47
47
  def fetch_prerelease_versions
48
48
  Utils.logger.info(
49
- "Fetching #{Configuration.prerelease_versions_file}" \
50
- " on #{@name} (#{@host})"
49
+ "Fetching #{Configuration.prerelease_versions_file} " \
50
+ "on #{@name} (#{@host})"
51
51
  )
52
52
  Http.get("#{host}/#{Configuration.prerelease_versions_file}").body
53
53
  end
data/lib/gemirro/utils.rb CHANGED
@@ -13,84 +13,52 @@ module Gemirro
13
13
  # @return [Gemirro::GemsFetcher]
14
14
  #
15
15
  class Utils
16
- attr_reader(:cache,
17
- :versions_fetcher,
18
- :gems_fetcher,
19
- :gems_collection,
20
- :stored_gems)
16
+ attr_reader(
17
+ :versions_fetcher,
18
+ :gems_fetcher,
19
+ :gems_collection,
20
+ :stored_gems
21
+ )
21
22
 
22
- ##
23
- # Cache class to store marshal and data into files
24
- #
25
- # @return [Gemirro::Cache]
26
- #
27
- def self.cache
28
- @cache ||= Gemirro::Cache
29
- .new(File.join(configuration.destination, '.cache'))
30
- end
23
+ URI_REGEXP = /^(.*)-(\d+(?:\.\d+){1,4}.*?)(?:-(x86-(?:(?:mswin|mingw)(?:32|64)).*?|java))?\.(gem(?:spec\.rz)?)$/
24
+ GEMSPEC_TYPE = 'gemspec.rz'
25
+ GEM_TYPE = 'gem'
31
26
 
32
27
  ##
33
- # Generate Gems collection from Marshal dump
28
+ # Generate Gems collection from Marshal dump - always the .local file
34
29
  #
35
- # @param [TrueClass|FalseClass] orig Fetch orig files
36
30
  # @return [Gemirro::GemVersionCollection]
37
31
  #
38
- def self.gems_collection(orig = true)
39
- @gems_collection = {} if @gems_collection.nil?
40
-
41
- is_orig = orig ? 1 : 0
42
- data = @gems_collection[is_orig]
43
- data = { files: {}, values: nil } if data.nil?
44
-
45
- file_paths = specs_files_paths(orig)
46
- has_file_changed = false
47
- Parallel.map(file_paths, in_threads: 4) do |file_path|
48
- next if data[:files].key?(file_path) &&
49
- data[:files][file_path] == File.mtime(file_path)
50
-
51
- has_file_changed = true
52
- end
32
+ def self.gems_collection
33
+ @gems_collection ||= { files: {}, values: nil }
34
+
35
+ file_paths =
36
+ %i[specs prerelease_specs].collect do |specs_file_type|
37
+ File.join(
38
+ configuration.destination,
39
+ "#{specs_file_type}.#{Gemirro::Configuration.marshal_version}.gz.local"
40
+ )
41
+ end
42
+
43
+ has_file_changed =
44
+ @gems_collection[:files] != file_paths.each_with_object({}) do |f, r|
45
+ r[f] = File.mtime(f) if File.exist?(f)
46
+ end
53
47
 
54
48
  # Return result if no file changed
55
- return data[:values] if !has_file_changed && !data[:values].nil?
49
+ return @gems_collection[:values] if !has_file_changed && !@gems_collection[:values].nil?
56
50
 
57
51
  gems = []
58
- Parallel.map(file_paths, in_threads: 4) do |file_path|
52
+
53
+ # parallel is not for mtime, it's for the Marshal.
54
+ Parallel.map(file_paths, in_threads: Utils.configuration.update_thread_count) do |file_path|
59
55
  next unless File.exist?(file_path)
60
56
 
61
57
  gems.concat(Marshal.load(Zlib::GzipReader.open(file_path).read))
62
- data[:files][file_path] = File.mtime(file_path)
58
+ @gems_collection[:files][file_path] = File.mtime(file_path)
63
59
  end
64
60
 
65
- collection = GemVersionCollection.new(gems)
66
- data[:values] = collection
67
-
68
- collection
69
- end
70
-
71
- ##
72
- # Return specs fils paths
73
- #
74
- # @param [TrueClass|FalseClass] orig Fetch orig files
75
- # @return [Array]
76
- #
77
- def self.specs_files_paths(orig = true)
78
- marshal_version = Gemirro::Configuration.marshal_version
79
- Parallel.map(specs_file_types, in_threads: 4) do |specs_file_type|
80
- File.join(configuration.destination,
81
- [specs_file_type,
82
- marshal_version,
83
- "gz#{orig ? '.orig' : ''}"].join('.'))
84
- end
85
- end
86
-
87
- ##
88
- # Return specs fils types
89
- #
90
- # @return [Array]
91
- #
92
- def self.specs_file_types
93
- %i[specs prerelease_specs]
61
+ @gems_collection[:values] = GemVersionCollection.new(gems)
94
62
  end
95
63
 
96
64
  ##
@@ -112,8 +80,7 @@ module Gemirro
112
80
  # @see Gemirro::VersionsFetcher.fetch
113
81
  #
114
82
  def self.versions_fetcher
115
- @versions_fetcher ||= Gemirro::VersionsFetcher
116
- .new(configuration.source).fetch
83
+ @versions_fetcher ||= Gemirro::VersionsFetcher.new(configuration.source).fetch
117
84
  end
118
85
 
119
86
  ##
@@ -133,13 +100,101 @@ module Gemirro
133
100
  def self.stored_gem(gem_name, gem_version, platform = 'ruby')
134
101
  platform = 'ruby' if platform.nil?
135
102
  @stored_gems ||= {}
136
- # rubocop:disable Metrics/LineLength
137
103
  @stored_gems[gem_name] = {} unless @stored_gems.key?(gem_name)
138
104
  @stored_gems[gem_name][gem_version] = {} unless @stored_gems[gem_name].key?(gem_version)
139
- @stored_gems[gem_name][gem_version][platform] ||= Gem.new(gem_name, gem_version, platform) unless @stored_gems[gem_name][gem_version].key?(platform)
140
- # rubocop:enable Metrics/LineLength
105
+ unless @stored_gems[gem_name][gem_version].key?(platform)
106
+ @stored_gems[gem_name][gem_version][platform] ||= Gem.new(gem_name, gem_version, platform)
107
+ end
141
108
 
142
109
  @stored_gems[gem_name][gem_version][platform]
143
110
  end
111
+
112
+ ##
113
+ # Return gem specification from gemname and version
114
+ #
115
+ # @param [String] gemname
116
+ # @param [String] version
117
+ # @return [::Gem::Specification]
118
+ #
119
+ def self.spec_for(gemname, version, platform)
120
+ gem = Utils.stored_gem(gemname, version.to_s, platform)
121
+
122
+ spec_file =
123
+ File.join(
124
+ configuration.destination,
125
+ 'quick',
126
+ Gemirro::Configuration.marshal_identifier,
127
+ gem.gemspec_filename
128
+ )
129
+
130
+ fetch_gem(spec_file) unless File.exist?(spec_file)
131
+
132
+ # this is a separate action
133
+ return unless File.exist?(spec_file)
134
+
135
+ File.open(spec_file, 'r') do |uz_file|
136
+ uz_file.binmode
137
+ inflater = Zlib::Inflate.new
138
+ begin
139
+ inflate_data = inflater.inflate(uz_file.read)
140
+ ensure
141
+ inflater.finish
142
+ inflater.close
143
+ end
144
+
145
+ Marshal.load(inflate_data)
146
+ end
147
+ end
148
+
149
+ ##
150
+ # Try to fetch gem and download its if it's possible, and
151
+ # build and install indicies.
152
+ #
153
+ # @param [String] resource
154
+ # @return [Indexer]
155
+ #
156
+ def self.fetch_gem(resource)
157
+ return unless Utils.configuration.fetch_gem
158
+
159
+ name = File.basename(resource)
160
+ result = name.match(URI_REGEXP)
161
+ return unless result
162
+
163
+ gem_name, gem_version, gem_platform, gem_type = result.captures
164
+ return unless gem_name && gem_version
165
+
166
+ begin
167
+ gem = Utils.stored_gem(gem_name, gem_version, gem_platform)
168
+ gem.gemspec = true if gem_type == GEMSPEC_TYPE
169
+
170
+ return if Utils.gems_fetcher.gem_exists?(gem.filename(gem_version)) && gem_type == GEM_TYPE
171
+ return if Utils.gems_fetcher.gemspec_exists?(gem.gemspec_filename(gem_version)) && gem_type == GEMSPEC_TYPE
172
+
173
+ Utils.logger.info("Try to download #{gem_name} with version #{gem_version}")
174
+ Utils.gems_fetcher.source.gems.clear
175
+ Utils.gems_fetcher.source.gems.push(gem)
176
+ Utils.gems_fetcher.fetch
177
+
178
+ update_indexes if Utils.configuration.update_on_fetch
179
+ rescue StandardError => e
180
+ Utils.logger.error(e)
181
+ end
182
+ end
183
+
184
+ ##
185
+ # Update indexes files
186
+ #
187
+ # @return [Indexer]
188
+ #
189
+ def self.update_indexes
190
+ indexer = Gemirro::Indexer.new(Utils.configuration.destination)
191
+ indexer.only_origin = true
192
+ indexer.ui = ::Gem::SilentUI.new
193
+
194
+ Utils.logger.info('Generating indexes')
195
+ indexer.update_index
196
+ rescue SystemExit => e
197
+ Utils.logger.info(e.message)
198
+ end
144
199
  end
145
200
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Gemirro Version
4
4
  module Gemirro
5
- VERSION = '1.4.0'
5
+ VERSION = '1.6.0'
6
6
  end
@@ -22,8 +22,10 @@ module Gemirro
22
22
  # @return [Gemirro::VersionsFile]
23
23
  #
24
24
  def fetch
25
- VersionsFile.load(read_file(Configuration.versions_file),
26
- read_file(Configuration.prerelease_versions_file, true))
25
+ VersionsFile.load(
26
+ read_file(Configuration.versions_file),
27
+ read_file(Configuration.prerelease_versions_file, true)
28
+ )
27
29
  end
28
30
 
29
31
  ##
@@ -36,6 +38,8 @@ module Gemirro
36
38
  destination = Gemirro.configuration.destination
37
39
  file_dst = File.join(destination, file)
38
40
  unless File.exist?(file_dst)
41
+ throw 'No source defined' unless @source
42
+
39
43
  File.write(file_dst, @source.fetch_versions) unless prerelease
40
44
  File.write(file_dst, @source.fetch_prerelease_versions) if prerelease
41
45
  end
data/lib/gemirro.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'builder'
3
4
  require 'confstruct'
4
5
  require 'digest/sha2'
5
6
  require 'fileutils'
@@ -19,7 +20,6 @@ $LOAD_PATH.unshift(File.expand_path('../', __FILE__)) unless $LOAD_PATH.include?
19
20
 
20
21
  require 'gemirro/version'
21
22
  require 'gemirro/configuration'
22
- require 'gemirro/cache'
23
23
  require 'gemirro/utils'
24
24
  require 'gemirro/gem'
25
25
  require 'gemirro/gem_version'