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