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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +29 -0
- data/.rubocop.yml +6 -3
- data/Gemfile +9 -0
- data/Gemfile.lock +126 -0
- data/MANIFEST +6 -10
- data/README.md +1 -1
- data/bin/gemirro +7 -1
- data/gemirro.gemspec +9 -9
- data/lib/gemirro/cli/index.rb +12 -3
- data/lib/gemirro/cli/init.rb +6 -1
- data/lib/gemirro/cli/server.rb +2 -4
- data/lib/gemirro/cli/update.rb +6 -0
- data/lib/gemirro/configuration.rb +1 -1
- data/lib/gemirro/gems_fetcher.rb +5 -10
- data/lib/gemirro/http.rb +6 -6
- data/lib/gemirro/indexer.rb +397 -90
- data/lib/gemirro/mirror_file.rb +1 -0
- data/lib/gemirro/server.rb +73 -160
- data/lib/gemirro/source.rb +2 -2
- data/lib/gemirro/utils.rb +123 -68
- data/lib/gemirro/version.rb +1 -1
- data/lib/gemirro/versions_fetcher.rb +6 -2
- data/lib/gemirro.rb +1 -1
- data/spec/gemirro/http_spec.rb +83 -24
- data/spec/gemirro/indexer_spec.rb +3 -0
- data/spec/gemirro/server_spec.rb +76 -47
- data/template/config.rb +6 -0
- data/template/public/dist/css/gemirro.css +25 -1
- data/template/public/latest_specs.4.8 +0 -0
- data/template/public/prerelease_specs.4.8 +0 -0
- data/template/public/specs.4.8 +0 -0
- data/views/gem.erb +46 -37
- data/views/index.erb +41 -33
- data/views/layout.erb +5 -25
- data/views/not_found.erb +4 -4
- metadata +72 -89
- 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/indexer.rb
CHANGED
@@ -19,12 +19,14 @@ module Gemirro
|
|
19
19
|
# @return [Array]
|
20
20
|
#
|
21
21
|
class Indexer < ::Gem::Indexer
|
22
|
-
attr_accessor(
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
attr_accessor(
|
23
|
+
:files,
|
24
|
+
:quick_marshal_dir,
|
25
|
+
:directory,
|
26
|
+
:dest_directory,
|
27
|
+
:only_origin,
|
28
|
+
:updated_gems
|
29
|
+
)
|
28
30
|
|
29
31
|
##
|
30
32
|
# Create an indexer that will index the gems in +directory+.
|
@@ -37,34 +39,38 @@ module Gemirro
|
|
37
39
|
require 'fileutils'
|
38
40
|
require 'tmpdir'
|
39
41
|
require 'zlib'
|
42
|
+
require 'builder/xchar'
|
43
|
+
require 'compact_index'
|
40
44
|
|
41
|
-
|
42
|
-
raise 'Gem::Indexer requires that the XML Builder ' \
|
43
|
-
'library be installed:' \
|
44
|
-
"\n\tgem install builder"
|
45
|
-
end
|
46
|
-
|
47
|
-
options = { build_modern: true }.merge options
|
45
|
+
options.merge!({ build_modern: true, build_compact: true })
|
48
46
|
|
49
47
|
@build_modern = options[:build_modern]
|
48
|
+
@build_compact = options[:build_compact]
|
50
49
|
|
51
50
|
@dest_directory = directory
|
52
|
-
@directory =
|
53
|
-
|
51
|
+
@directory =
|
52
|
+
File.join(Dir.tmpdir, "gem_generate_index_#{rand(1_000_000_000)}")
|
54
53
|
|
55
54
|
marshal_name = "Marshal.#{::Gem.marshal_version}"
|
56
55
|
|
57
|
-
@master_index =
|
58
|
-
|
56
|
+
@master_index =
|
57
|
+
File.join(@directory, 'yaml')
|
58
|
+
@marshal_index =
|
59
|
+
File.join(@directory, marshal_name)
|
59
60
|
|
60
|
-
@quick_dir = File.join
|
61
|
-
@quick_marshal_dir =
|
62
|
-
|
61
|
+
@quick_dir = File.join(@directory, 'quick')
|
62
|
+
@quick_marshal_dir =
|
63
|
+
File.join(@quick_dir, marshal_name)
|
64
|
+
@quick_marshal_dir_base =
|
65
|
+
File.join(@dest_directory, 'quick', marshal_name) # FIX: UGH
|
63
66
|
|
64
|
-
@quick_index =
|
65
|
-
|
67
|
+
@quick_index =
|
68
|
+
File.join(@quick_dir, 'index')
|
69
|
+
@latest_index =
|
70
|
+
File.join(@quick_dir, 'latest_index')
|
66
71
|
|
67
|
-
@specs_index =
|
72
|
+
@specs_index =
|
73
|
+
File.join(@directory, "specs.#{::Gem.marshal_version}")
|
68
74
|
@latest_specs_index =
|
69
75
|
File.join(@directory, "latest_specs.#{::Gem.marshal_version}")
|
70
76
|
@prerelease_specs_index =
|
@@ -75,6 +81,10 @@ module Gemirro
|
|
75
81
|
File.join(@dest_directory, "latest_specs.#{::Gem.marshal_version}")
|
76
82
|
@dest_prerelease_specs_index =
|
77
83
|
File.join(@dest_directory, "prerelease_specs.#{::Gem.marshal_version}")
|
84
|
+
@infos_dir =
|
85
|
+
File.join(@dest_directory, 'info')
|
86
|
+
@api_v1_dependencies_dir =
|
87
|
+
File.join(@dest_directory, 'api', 'v1', 'dependencies')
|
78
88
|
|
79
89
|
@files = []
|
80
90
|
end
|
@@ -100,28 +110,24 @@ module Gemirro
|
|
100
110
|
|
101
111
|
if files.include?(@quick_marshal_dir) && !files.include?(@quick_dir)
|
102
112
|
files.delete @quick_marshal_dir
|
103
|
-
|
104
|
-
FileUtils.
|
105
|
-
FileUtils.
|
106
|
-
FileUtils.mv(@quick_marshal_dir, dst_name,
|
107
|
-
verbose: verbose, force: true)
|
113
|
+
FileUtils.mkdir_p(File.dirname(@quick_marshal_dir_base), verbose: verbose)
|
114
|
+
FileUtils.rm_rf(@quick_marshal_dir_base, verbose: verbose)
|
115
|
+
FileUtils.mv(@quick_marshal_dir, @quick_marshal_dir_base, verbose: verbose, force: true)
|
108
116
|
end
|
109
117
|
|
110
118
|
files.each do |path|
|
111
119
|
file = path.sub(%r{^#{Regexp.escape @directory}/?}, '')
|
112
|
-
src_name = File.join(@directory, file)
|
113
|
-
dst_name = File.join(@dest_directory, file)
|
114
120
|
|
115
121
|
if ["#{@specs_index}.gz",
|
116
122
|
"#{@latest_specs_index}.gz",
|
117
123
|
"#{@prerelease_specs_index}.gz"].include?(path)
|
118
|
-
res = build_zlib_file(file,
|
124
|
+
res = build_zlib_file(file, File.join(@directory, file), File.join(@dest_directory, file), true)
|
119
125
|
next unless res
|
120
126
|
else
|
121
127
|
source_content = download_from_source(file)
|
122
128
|
next if source_content.nil?
|
123
129
|
|
124
|
-
MirrorFile.new(
|
130
|
+
MirrorFile.new(File.join(@dest_directory, file)).write(source_content)
|
125
131
|
end
|
126
132
|
|
127
133
|
FileUtils.rm_rf(path)
|
@@ -129,7 +135,7 @@ module Gemirro
|
|
129
135
|
end
|
130
136
|
|
131
137
|
##
|
132
|
-
# Download file from source
|
138
|
+
# Download file from source (example: rubygems.org)
|
133
139
|
#
|
134
140
|
# @param [String] file File path
|
135
141
|
# @return [String]
|
@@ -164,14 +170,255 @@ module Gemirro
|
|
164
170
|
::Gem::Specification.all = specs
|
165
171
|
|
166
172
|
if ::Gem::VERSION >= '2.5.0'
|
167
|
-
build_marshal_gemspecs
|
168
|
-
build_modern_indices
|
173
|
+
build_marshal_gemspecs(specs)
|
174
|
+
build_modern_indices(specs) if @build_modern
|
169
175
|
compress_indices
|
170
176
|
else
|
171
177
|
build_marshal_gemspecs
|
172
178
|
build_modern_indicies if @build_modern
|
173
179
|
compress_indicies
|
174
180
|
end
|
181
|
+
|
182
|
+
build_api_v1_dependencies(specs)
|
183
|
+
|
184
|
+
return unless @build_compact
|
185
|
+
|
186
|
+
build_compact_index_names
|
187
|
+
build_compact_index_infos(specs)
|
188
|
+
build_compact_index_versions(specs)
|
189
|
+
end
|
190
|
+
|
191
|
+
##
|
192
|
+
# Cache Modern Index endpoints /api/v1/dependencies?gems= and /api/v1/dependencies.json?gems=
|
193
|
+
# This single request may include many fragments. server.rb determines which are required per request.
|
194
|
+
#
|
195
|
+
# @return nil
|
196
|
+
#
|
197
|
+
def build_api_v1_dependencies(specs, partial = false)
|
198
|
+
FileUtils.mkdir_p(@api_v1_dependencies_dir)
|
199
|
+
|
200
|
+
if partial
|
201
|
+
specs.collect(&:name).uniq do |name|
|
202
|
+
FileUtils.rm_rf(Dir.glob(File.join(@api_v1_dependencies_dir, "#{name}.*.*.list")))
|
203
|
+
end
|
204
|
+
else
|
205
|
+
FileUtils.rm_rf(Dir.glob(File.join(@api_v1_dependencies_dir, '*.list')))
|
206
|
+
end
|
207
|
+
|
208
|
+
grouped_specs = specs.sort_by(&:name).group_by(&:name)
|
209
|
+
grouped_specs.each_with_index do |(name, gem_versions), index|
|
210
|
+
Utils.logger.info("[#{index + 1}/#{grouped_specs.size}]: Caching /api/v1/dependencies/#{name}")
|
211
|
+
|
212
|
+
gem_versions =
|
213
|
+
gem_versions.sort do |a, b|
|
214
|
+
a.version <=> b.version
|
215
|
+
end
|
216
|
+
|
217
|
+
cg = []
|
218
|
+
Parallel.each_with_index(
|
219
|
+
gem_versions,
|
220
|
+
in_threads: Utils.configuration.update_thread_count
|
221
|
+
) do |spec, index2|
|
222
|
+
next if spec.nil?
|
223
|
+
|
224
|
+
dependencies = spec.dependencies.select do |d|
|
225
|
+
d.type == :runtime
|
226
|
+
end
|
227
|
+
|
228
|
+
dependencies = dependencies.collect do |d|
|
229
|
+
[d.name.is_a?(Array) ? d.name.first : d.name, d.requirement.to_s]
|
230
|
+
end
|
231
|
+
|
232
|
+
cg[index2] =
|
233
|
+
{
|
234
|
+
name: spec.name,
|
235
|
+
number: spec.version.to_s,
|
236
|
+
platform: spec.platform,
|
237
|
+
dependencies: dependencies
|
238
|
+
}
|
239
|
+
end
|
240
|
+
|
241
|
+
Tempfile.create("api_v1_dependencies_#{name}.list") do |f|
|
242
|
+
f.write Marshal.dump(cg)
|
243
|
+
f.rewind
|
244
|
+
|
245
|
+
FileUtils.cp(
|
246
|
+
f.path,
|
247
|
+
File.join(
|
248
|
+
@api_v1_dependencies_dir,
|
249
|
+
"#{name}.#{Digest::MD5.file(f.path).hexdigest}.#{Digest::SHA256.file(f.path).hexdigest}.list"
|
250
|
+
)
|
251
|
+
)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
##
|
257
|
+
# Cache compact_index endpoint /names
|
258
|
+
# Report all gems with versions available. Does not require opening spec files.
|
259
|
+
#
|
260
|
+
# @return nil
|
261
|
+
#
|
262
|
+
def build_compact_index_names
|
263
|
+
Utils.logger.info('[1/1]: Caching /names')
|
264
|
+
FileUtils.rm_rf(Dir.glob(File.join(@dest_directory, 'names*.list')))
|
265
|
+
|
266
|
+
gem_name_list = Dir.glob('*.gem', base: File.join(@dest_directory, 'gems')).collect do |x|
|
267
|
+
x.sub(/-\d+(\.\d+)*(\.[a-zA-Z\d]+)*([-_a-zA-Z\d]+)?\.gem/, '')
|
268
|
+
end.uniq.sort!
|
269
|
+
|
270
|
+
Tempfile.create('names.list') do |f|
|
271
|
+
f.write CompactIndex.names(gem_name_list).to_s
|
272
|
+
f.rewind
|
273
|
+
FileUtils.cp(
|
274
|
+
f.path,
|
275
|
+
File.join(
|
276
|
+
@dest_directory,
|
277
|
+
"names.#{Digest::MD5.file(f.path).hexdigest}.#{Digest::SHA256.file(f.path).hexdigest}.list"
|
278
|
+
),
|
279
|
+
verbose: verbose
|
280
|
+
)
|
281
|
+
end
|
282
|
+
|
283
|
+
nil
|
284
|
+
end
|
285
|
+
|
286
|
+
##
|
287
|
+
# Cache compact_index endpoint /versions
|
288
|
+
#
|
289
|
+
# @param [Array] specs Gems list
|
290
|
+
# @param [Boolean] partial Is gem list an update or a full index
|
291
|
+
# @return nil
|
292
|
+
#
|
293
|
+
def build_compact_index_versions(specs, partial = false)
|
294
|
+
Utils.logger.info('[1/1]: Caching /versions')
|
295
|
+
|
296
|
+
cg =
|
297
|
+
specs
|
298
|
+
.sort_by(&:name)
|
299
|
+
.group_by(&:name)
|
300
|
+
.collect do |name, gem_versions|
|
301
|
+
gem_versions =
|
302
|
+
gem_versions.sort do |a, b|
|
303
|
+
a.version <=> b.version
|
304
|
+
end
|
305
|
+
|
306
|
+
info_file = Dir.glob(File.join(@infos_dir, "#{name}.*.*.list")).last
|
307
|
+
|
308
|
+
throw "Info file for #{name} not found" unless info_file
|
309
|
+
|
310
|
+
info_file_checksum = info_file.split('.', -4)[-3]
|
311
|
+
|
312
|
+
CompactIndex::Gem.new(
|
313
|
+
name,
|
314
|
+
gem_versions.collect do |y|
|
315
|
+
CompactIndex::GemVersion.new(
|
316
|
+
y.version.to_s,
|
317
|
+
y.platform,
|
318
|
+
nil,
|
319
|
+
info_file_checksum
|
320
|
+
)
|
321
|
+
end
|
322
|
+
)
|
323
|
+
end
|
324
|
+
|
325
|
+
Tempfile.create('versions.list') do |f|
|
326
|
+
previous_versions_file = Dir.glob(File.join(@dest_directory, 'versions*.list')).last
|
327
|
+
|
328
|
+
if partial && previous_versions_file
|
329
|
+
versions_file = CompactIndex::VersionsFile.new(previous_versions_file)
|
330
|
+
else
|
331
|
+
versions_file = CompactIndex::VersionsFile.new(f.path)
|
332
|
+
f.write format('created_at: %s', Time.now.utc.iso8601)
|
333
|
+
f.write "\n---\n"
|
334
|
+
end
|
335
|
+
|
336
|
+
f.write CompactIndex.versions(versions_file, cg)
|
337
|
+
f.rewind
|
338
|
+
|
339
|
+
FileUtils.rm_rf(Dir.glob(File.join(@dest_directory, 'versions*.list')))
|
340
|
+
|
341
|
+
FileUtils.cp(
|
342
|
+
f.path,
|
343
|
+
File.join(
|
344
|
+
@dest_directory,
|
345
|
+
"versions.#{Digest::MD5.file(f.path).hexdigest}.#{Digest::SHA256.file(f.path).hexdigest}.list"
|
346
|
+
),
|
347
|
+
verbose: verbose
|
348
|
+
)
|
349
|
+
end
|
350
|
+
|
351
|
+
nil
|
352
|
+
end
|
353
|
+
|
354
|
+
##
|
355
|
+
# Cache compact_index endpoint /info/[gemname]
|
356
|
+
#
|
357
|
+
# @param [Array] specs Gems list
|
358
|
+
# @param [Boolean] partial Is gem list an update or a full index
|
359
|
+
# @return nil
|
360
|
+
#
|
361
|
+
def build_compact_index_infos(specs, partial = false)
|
362
|
+
FileUtils.mkdir_p(@infos_dir)
|
363
|
+
|
364
|
+
if partial
|
365
|
+
specs.collect(&:name).uniq do |name|
|
366
|
+
FileUtils.rm_rf(Dir.glob(File.join(@infos_dir, "#{name}.*.*.list")))
|
367
|
+
end
|
368
|
+
else
|
369
|
+
FileUtils.rm_rf(Dir.glob(File.join(@infos_dir, '*.list')))
|
370
|
+
end
|
371
|
+
|
372
|
+
grouped_specs = specs.sort_by(&:name).group_by(&:name)
|
373
|
+
grouped_specs.each_with_index do |(name, gem_versions), index|
|
374
|
+
Utils.logger.info("[#{index + 1}/#{grouped_specs.size}]: Caching /info/#{name}")
|
375
|
+
|
376
|
+
gem_versions =
|
377
|
+
gem_versions.sort do |a, b|
|
378
|
+
a.version <=> b.version
|
379
|
+
end
|
380
|
+
|
381
|
+
versions =
|
382
|
+
Parallel.map(gem_versions, in_threads: Utils.configuration.update_thread_count) do |spec|
|
383
|
+
deps =
|
384
|
+
spec
|
385
|
+
.dependencies
|
386
|
+
.select { |d| d.type == :runtime }
|
387
|
+
.sort_by(&:name)
|
388
|
+
.collect do |dependency|
|
389
|
+
CompactIndex::Dependency.new(
|
390
|
+
dependency.name,
|
391
|
+
dependency.requirement.to_s
|
392
|
+
)
|
393
|
+
end
|
394
|
+
|
395
|
+
CompactIndex::GemVersion.new(
|
396
|
+
spec.version,
|
397
|
+
spec.platform,
|
398
|
+
Digest::SHA256.file(spec.loaded_from).hexdigest,
|
399
|
+
nil,
|
400
|
+
deps,
|
401
|
+
spec.required_ruby_version.to_s,
|
402
|
+
spec.required_rubygems_version.to_s
|
403
|
+
)
|
404
|
+
end
|
405
|
+
|
406
|
+
Tempfile.create("info_#{name}.list") do |f|
|
407
|
+
f.write CompactIndex.info(versions).to_s
|
408
|
+
f.rewind
|
409
|
+
|
410
|
+
FileUtils.cp(
|
411
|
+
f.path,
|
412
|
+
File.join(
|
413
|
+
@infos_dir,
|
414
|
+
"#{name}.#{Digest::MD5.file(f.path).hexdigest}.#{Digest::SHA256.file(f.path).hexdigest}.list"
|
415
|
+
),
|
416
|
+
verbose: verbose
|
417
|
+
)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
nil
|
175
422
|
end
|
176
423
|
|
177
424
|
##
|
@@ -181,21 +428,23 @@ module Gemirro
|
|
181
428
|
# @return [Array]
|
182
429
|
#
|
183
430
|
def map_gems_to_specs(gems)
|
184
|
-
|
431
|
+
results = []
|
432
|
+
|
433
|
+
Parallel.each_with_index(gems, in_threads: Utils.configuration.update_thread_count) do |gemfile, index|
|
185
434
|
Utils.logger.info("[#{index + 1}/#{gems.size}]: Processing #{gemfile.split('/')[-1]}")
|
186
|
-
if File.
|
435
|
+
if File.empty?(gemfile)
|
187
436
|
Utils.logger.warn("Skipping zero-length gem: #{gemfile}")
|
188
437
|
next
|
189
438
|
end
|
190
439
|
|
191
440
|
begin
|
192
441
|
begin
|
193
|
-
spec =
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
442
|
+
spec =
|
443
|
+
if ::Gem::Package.respond_to? :open
|
444
|
+
::Gem::Package.open(File.open(gemfile, 'rb'), 'r', &:metadata)
|
445
|
+
else
|
446
|
+
::Gem::Package.new(gemfile).spec
|
447
|
+
end
|
199
448
|
rescue NotImplementedError
|
200
449
|
next
|
201
450
|
end
|
@@ -213,7 +462,7 @@ module Gemirro
|
|
213
462
|
end
|
214
463
|
|
215
464
|
version = spec.version.version
|
216
|
-
unless version =~ /^\d
|
465
|
+
unless version =~ /^\d+(\.\d+)?(\.\d+)?.*/
|
217
466
|
msg = "Skipping gem #{spec.full_name} - invalid version #{version}"
|
218
467
|
Utils.logger.warn(msg)
|
219
468
|
next
|
@@ -223,8 +472,8 @@ module Gemirro
|
|
223
472
|
spec.abbreviate
|
224
473
|
spec.sanitize
|
225
474
|
else
|
226
|
-
abbreviate
|
227
|
-
sanitize
|
475
|
+
abbreviate(spec)
|
476
|
+
sanitize(spec)
|
228
477
|
end
|
229
478
|
|
230
479
|
spec
|
@@ -238,20 +487,48 @@ module Gemirro
|
|
238
487
|
"\t#{e.backtrace.join "\n\t"}"].join("\n")
|
239
488
|
Utils.logger.debug(msg)
|
240
489
|
end
|
241
|
-
|
490
|
+
|
491
|
+
results[index] = spec
|
492
|
+
end
|
493
|
+
|
494
|
+
# nils can result from insert by index
|
495
|
+
results.compact
|
242
496
|
end
|
243
497
|
|
498
|
+
##
|
499
|
+
# Handle `index --update`, detecting changed files and file lists.
|
500
|
+
#
|
501
|
+
# @return nil
|
502
|
+
#
|
244
503
|
def update_index
|
245
504
|
make_temp_directories
|
246
505
|
|
247
|
-
|
506
|
+
present_gemfiles = Dir.glob('*.gem', base: File.join(@dest_directory, 'gems'))
|
507
|
+
indexed_gemfiles = Dir.glob('*.gemspec.rz', base: @quick_marshal_dir_base).collect { |x| x.gsub(/spec.rz$/, '') }
|
508
|
+
|
509
|
+
@updated_gems = []
|
510
|
+
# detect files manually added to public/gems
|
511
|
+
@updated_gems += (present_gemfiles - indexed_gemfiles).collect { |x| File.join(@dest_directory, 'gems', x) }
|
512
|
+
# detect files manually deleted from public/gems
|
513
|
+
@updated_gems += (indexed_gemfiles - present_gemfiles).collect { |x| File.join(@dest_directory, 'gems', x) }
|
514
|
+
|
515
|
+
specs_mtime =
|
516
|
+
begin
|
517
|
+
File.stat(@dest_specs_index).mtime
|
518
|
+
rescue StandardError
|
519
|
+
Time.at(0)
|
520
|
+
end
|
248
521
|
newest_mtime = Time.at(0)
|
249
522
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
523
|
+
# files that have been replaced
|
524
|
+
@updated_gems +=
|
525
|
+
gem_file_list.select do |gem|
|
526
|
+
gem_mtime = File.stat(gem).mtime
|
527
|
+
newest_mtime = gem_mtime if gem_mtime > newest_mtime
|
528
|
+
gem_mtime > specs_mtime
|
529
|
+
end
|
530
|
+
|
531
|
+
@updated_gems.uniq!
|
255
532
|
|
256
533
|
if @updated_gems.empty?
|
257
534
|
Utils.logger.info('No new gems')
|
@@ -259,24 +536,46 @@ module Gemirro
|
|
259
536
|
end
|
260
537
|
|
261
538
|
specs = map_gems_to_specs(@updated_gems)
|
539
|
+
|
540
|
+
# specs only includes latest discovered files.
|
541
|
+
# /info/[gemname] and /api/v1/dependencies can not be rebuilt
|
542
|
+
# incrementally, so retrive specs for all versions of these gems.
|
543
|
+
gem_name_updates = specs.collect(&:name).uniq
|
544
|
+
u2 =
|
545
|
+
Dir.glob(File.join(File.join(@dest_directory, 'gems'), '*.gem')).select do |possibility|
|
546
|
+
gem_name_updates.any? { |updated| File.basename(possibility) =~ /^#{updated}-\d/ }
|
547
|
+
end
|
548
|
+
|
549
|
+
Utils.logger.info('Reloading for /info/[gemname]')
|
550
|
+
version_specs = map_gems_to_specs(u2)
|
551
|
+
|
262
552
|
prerelease, released = specs.partition { |s| s.version.prerelease? }
|
263
553
|
|
264
554
|
::Gem::Specification.dirs = []
|
265
555
|
::Gem::Specification.all = *specs
|
266
|
-
files =
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
556
|
+
files =
|
557
|
+
if ::Gem::VERSION >= '2.5.0'
|
558
|
+
build_marshal_gemspecs specs
|
559
|
+
else
|
560
|
+
build_marshal_gemspecs
|
561
|
+
end
|
271
562
|
|
272
563
|
::Gem.time('Updated indexes') do
|
273
|
-
update_specs_index(
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
564
|
+
update_specs_index(
|
565
|
+
released,
|
566
|
+
@dest_specs_index,
|
567
|
+
@specs_index
|
568
|
+
)
|
569
|
+
update_specs_index(
|
570
|
+
released,
|
571
|
+
@dest_latest_specs_index,
|
572
|
+
@latest_specs_index
|
573
|
+
)
|
574
|
+
update_specs_index(
|
575
|
+
prerelease,
|
576
|
+
@dest_prerelease_specs_index,
|
577
|
+
@prerelease_specs_index
|
578
|
+
)
|
280
579
|
end
|
281
580
|
|
282
581
|
if ::Gem::VERSION >= '2.5.0'
|
@@ -285,6 +584,14 @@ module Gemirro
|
|
285
584
|
compress_indicies
|
286
585
|
end
|
287
586
|
|
587
|
+
build_api_v1_dependencies(version_specs, true)
|
588
|
+
|
589
|
+
if @build_compact
|
590
|
+
build_compact_index_names
|
591
|
+
build_compact_index_infos(version_specs, true)
|
592
|
+
build_compact_index_versions(specs, true)
|
593
|
+
end
|
594
|
+
|
288
595
|
Utils.logger.info("Updating production dir #{@dest_directory}") if verbose
|
289
596
|
files << @specs_index
|
290
597
|
files << "#{@specs_index}.gz"
|
@@ -295,36 +602,36 @@ module Gemirro
|
|
295
602
|
|
296
603
|
files.each do |path|
|
297
604
|
file = path.sub(%r{^#{Regexp.escape @directory}/?}, '')
|
298
|
-
src_name = File.join(@directory, file)
|
299
|
-
dst_name = File.join(@dest_directory, file)
|
300
605
|
|
301
|
-
if ["#{@specs_index}.gz",
|
302
|
-
|
303
|
-
"#{@prerelease_specs_index}.gz"].include?(path)
|
304
|
-
res = build_zlib_file(file, src_name, dst_name)
|
606
|
+
if ["#{@specs_index}.gz", "#{@latest_specs_index}.gz", "#{@prerelease_specs_index}.gz"].include?(path)
|
607
|
+
res = build_zlib_file(file, File.join(@directory, file), File.join(@dest_directory, file))
|
305
608
|
next unless res
|
306
609
|
else
|
307
|
-
FileUtils.mv(
|
308
|
-
|
309
|
-
|
310
|
-
|
610
|
+
FileUtils.mv(
|
611
|
+
File.join(@directory, file),
|
612
|
+
File.join(@dest_directory, file),
|
613
|
+
verbose: verbose,
|
614
|
+
force: true
|
615
|
+
)
|
311
616
|
end
|
312
617
|
|
313
|
-
File.utime(newest_mtime, newest_mtime,
|
618
|
+
File.utime(newest_mtime, newest_mtime, File.join(@dest_directory, file))
|
314
619
|
end
|
315
620
|
end
|
316
621
|
|
317
622
|
def build_zlib_file(file, src_name, dst_name, from_source = false)
|
318
623
|
content = Marshal.load(Zlib::GzipReader.open(src_name).read)
|
319
|
-
create_zlib_file("#{dst_name}.
|
624
|
+
create_zlib_file("#{dst_name}.local", content)
|
320
625
|
|
321
626
|
return false if @only_origin
|
322
627
|
|
323
628
|
if from_source
|
324
629
|
source_content = download_from_source(file)
|
325
|
-
source_content = Marshal.load(
|
326
|
-
|
327
|
-
|
630
|
+
source_content = Marshal.load(
|
631
|
+
Zlib::GzipReader.new(
|
632
|
+
StringIO.new(source_content)
|
633
|
+
).read
|
634
|
+
)
|
328
635
|
else
|
329
636
|
source_content = Marshal.load(Zlib::GzipReader.open(dst_name).read)
|
330
637
|
end
|
@@ -336,17 +643,17 @@ module Gemirro
|
|
336
643
|
end
|
337
644
|
|
338
645
|
def create_zlib_file(dst_name, content)
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
646
|
+
Tempfile.create(File.basename(dst_name)) do |f|
|
647
|
+
gzf = Zlib::GzipWriter.new(f)
|
648
|
+
gzf.write(Marshal.dump(content))
|
649
|
+
gzf.close
|
650
|
+
|
651
|
+
FileUtils.cp(
|
652
|
+
f.path,
|
653
|
+
dst_name,
|
654
|
+
verbose: verbose
|
655
|
+
)
|
343
656
|
end
|
344
|
-
|
345
|
-
FileUtils.mv(temp_file.path,
|
346
|
-
dst_name,
|
347
|
-
verbose: verbose,
|
348
|
-
force: true)
|
349
|
-
Utils.cache.flush_key(File.basename(dst_name))
|
350
657
|
end
|
351
658
|
|
352
659
|
def verbose
|