gemirro 1.6.0 → 3.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 +1 -1
- data/.gitignore +2 -0
- data/.rubocop.yml +3 -1
- data/Gemfile +2 -1
- data/Gemfile.lock +73 -61
- data/MANIFEST +0 -3
- data/bin/gemirro +1 -8
- data/gemirro.gemspec +4 -6
- data/lib/gemirro/cli/index.rb +48 -27
- data/lib/gemirro/cli/init.rb +48 -29
- data/lib/gemirro/cli/list.rb +37 -17
- data/lib/gemirro/cli/server.rb +173 -114
- data/lib/gemirro/cli/update.rb +42 -17
- data/lib/gemirro/cli.rb +64 -21
- data/lib/gemirro/configuration.rb +26 -20
- data/lib/gemirro/gem_version.rb +1 -0
- data/lib/gemirro/gem_version_collection.rb +4 -4
- data/lib/gemirro/gems_fetcher.rb +9 -9
- data/lib/gemirro/http.rb +115 -41
- data/lib/gemirro/indexer.rb +33 -232
- data/lib/gemirro/mirror_file.rb +3 -10
- data/lib/gemirro/server.rb +12 -43
- data/lib/gemirro/source.rb +2 -15
- data/lib/gemirro/utils.rb +22 -12
- data/lib/gemirro/version.rb +1 -1
- data/lib/gemirro/versions_fetcher.rb +7 -12
- data/lib/gemirro/versions_file.rb +26 -24
- data/lib/gemirro.rb +3 -7
- data/spec/gemirro/cli_spec.rb +49 -15
- data/spec/gemirro/configuration_spec.rb +9 -2
- data/spec/gemirro/gems_fetcher_spec.rb +2 -2
- data/spec/gemirro/http_spec.rb +58 -54
- data/spec/gemirro/indexer_spec.rb +5 -5
- data/spec/gemirro/server_spec.rb +30 -52
- data/spec/gemirro/source_spec.rb +2 -10
- data/spec/gemirro/versions_fetcher_spec.rb +3 -4
- data/spec/gemirro/versions_file_spec.rb +8 -32
- data/template/config.rb +1 -1
- metadata +29 -69
- 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/lib/gemirro/http.rb
CHANGED
|
@@ -2,61 +2,135 @@
|
|
|
2
2
|
|
|
3
3
|
module Gemirro
|
|
4
4
|
##
|
|
5
|
-
# The Http class is responsible for executing GET
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# @!attribute [r] client
|
|
9
|
-
# @return [HTTPClient]
|
|
5
|
+
# The Http class is responsible for executing GET requests against a
|
|
6
|
+
# given URL, following redirects and reusing keep-alive connections.
|
|
10
7
|
#
|
|
11
8
|
class Http
|
|
12
|
-
attr_accessor :client
|
|
13
|
-
|
|
14
9
|
##
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# @param [String] url
|
|
18
|
-
# @return [HTTP::Message]
|
|
10
|
+
# Raised when a request comes back with a non-successful,
|
|
11
|
+
# non-redirect HTTP status.
|
|
19
12
|
#
|
|
20
|
-
|
|
21
|
-
response = client.get(url, follow_redirect: true)
|
|
13
|
+
class Error < StandardError; end
|
|
22
14
|
|
|
23
|
-
|
|
15
|
+
MAX_REDIRECTS = 10
|
|
24
16
|
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
class << self
|
|
18
|
+
##
|
|
19
|
+
# Requests the given HTTP resource, following redirects.
|
|
20
|
+
#
|
|
21
|
+
# @param [String] url
|
|
22
|
+
# @return [Net::HTTPResponse]
|
|
23
|
+
#
|
|
24
|
+
def get(url)
|
|
25
|
+
fetch(URI.parse(url), MAX_REDIRECTS)
|
|
26
|
+
end
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
28
|
+
##
|
|
29
|
+
# Closes and forgets every connection cached for the current
|
|
30
|
+
# Thread. Mostly useful for tests.
|
|
31
|
+
#
|
|
32
|
+
def reset!
|
|
33
|
+
pool.each_value { |connection| connection.finish if connection.started? }
|
|
34
|
+
pool.clear
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# @param [URI] uri
|
|
41
|
+
# @param [Integer] redirects_left
|
|
42
|
+
# @return [Net::HTTPResponse]
|
|
43
|
+
#
|
|
44
|
+
def fetch(uri, redirects_left)
|
|
45
|
+
response = connection_for(uri).request(build_request(uri))
|
|
46
|
+
|
|
47
|
+
case response
|
|
48
|
+
when Net::HTTPRedirection
|
|
49
|
+
raise Error, "Too many redirects for #{uri}" if redirects_left <= 0
|
|
50
|
+
|
|
51
|
+
fetch(URI.parse(response['location']), redirects_left - 1)
|
|
52
|
+
when Net::HTTPSuccess
|
|
53
|
+
response
|
|
54
|
+
else
|
|
55
|
+
raise Error, "#{response.code} #{response.message}"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
##
|
|
60
|
+
# @param [URI] uri
|
|
61
|
+
# @return [Net::HTTP::Get]
|
|
62
|
+
#
|
|
63
|
+
def build_request(uri)
|
|
64
|
+
request = Net::HTTP::Get.new(uri)
|
|
65
|
+
config = Utils.configuration
|
|
66
|
+
request.basic_auth(config.upstream_user, config.upstream_password) if defined?(config.upstream_user)
|
|
67
|
+
|
|
68
|
+
request
|
|
39
69
|
end
|
|
40
70
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
71
|
+
##
|
|
72
|
+
# Returns a started, keep-alive connection for the given URI,
|
|
73
|
+
# reusing one already opened by the current Thread when possible.
|
|
74
|
+
#
|
|
75
|
+
# @param [URI] uri
|
|
76
|
+
# @return [Net::HTTP]
|
|
77
|
+
#
|
|
78
|
+
def connection_for(uri)
|
|
79
|
+
key = "#{uri.scheme}://#{uri.host}:#{uri.port}"
|
|
80
|
+
pool[key] ||= build_connection(uri)
|
|
44
81
|
end
|
|
45
82
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
83
|
+
##
|
|
84
|
+
# Connection pool for the current Thread. Kept per-Thread so
|
|
85
|
+
# sockets are never shared/interleaved across concurrent requests.
|
|
86
|
+
#
|
|
87
|
+
# @return [Hash]
|
|
88
|
+
#
|
|
89
|
+
def pool
|
|
90
|
+
Thread.current[:gemirro_http_pool] ||= {}
|
|
53
91
|
end
|
|
54
92
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
93
|
+
##
|
|
94
|
+
# @param [URI] uri
|
|
95
|
+
# @return [Net::HTTP]
|
|
96
|
+
#
|
|
97
|
+
def build_connection(uri)
|
|
98
|
+
config = Utils.configuration
|
|
99
|
+
http = Net::HTTP.new(uri.host, uri.port, *proxy_args(config))
|
|
100
|
+
http.use_ssl = uri.scheme == 'https'
|
|
101
|
+
configure_ssl(http, config)
|
|
102
|
+
|
|
103
|
+
http.start
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
##
|
|
107
|
+
# @param [Net::HTTP] http
|
|
108
|
+
# @param [Gemirro::Configuration] config
|
|
109
|
+
#
|
|
110
|
+
def configure_ssl(http, config)
|
|
111
|
+
if defined?(config.rootca)
|
|
112
|
+
abort "The configuration file #{config.rootca} does not exist" unless File.file?(config.rootca)
|
|
113
|
+
|
|
114
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
115
|
+
http.ca_file = config.rootca
|
|
116
|
+
elsif defined?(config.verify_mode) && !config.verify_mode
|
|
117
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
##
|
|
122
|
+
# Splits a `proxy 'http://user:pass@host:port'` configuration
|
|
123
|
+
# value into the args expected by `Net::HTTP.new`.
|
|
124
|
+
#
|
|
125
|
+
# @param [Gemirro::Configuration] config
|
|
126
|
+
# @return [Array]
|
|
127
|
+
#
|
|
128
|
+
def proxy_args(config)
|
|
129
|
+
return [] unless defined?(config.proxy) && config.proxy
|
|
130
|
+
|
|
131
|
+
proxy_uri = URI.parse(config.proxy)
|
|
132
|
+
[proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password]
|
|
58
133
|
end
|
|
59
|
-
@client = client
|
|
60
134
|
end
|
|
61
135
|
end
|
|
62
136
|
end
|
data/lib/gemirro/indexer.rb
CHANGED
|
@@ -35,19 +35,16 @@ module Gemirro
|
|
|
35
35
|
# @param [Hash] options Indexer options
|
|
36
36
|
# @return [Array]
|
|
37
37
|
##
|
|
38
|
-
def initialize(
|
|
38
|
+
def initialize(options = {})
|
|
39
39
|
require 'fileutils'
|
|
40
40
|
require 'tmpdir'
|
|
41
41
|
require 'zlib'
|
|
42
42
|
require 'builder/xchar'
|
|
43
43
|
require 'compact_index'
|
|
44
44
|
|
|
45
|
-
options.merge!({ build_modern:
|
|
45
|
+
options.merge!({ build_modern: false })
|
|
46
46
|
|
|
47
|
-
@
|
|
48
|
-
@build_compact = options[:build_compact]
|
|
49
|
-
|
|
50
|
-
@dest_directory = directory
|
|
47
|
+
@dest_directory = Gemirro.configuration.destination
|
|
51
48
|
@directory =
|
|
52
49
|
File.join(Dir.tmpdir, "gem_generate_index_#{rand(1_000_000_000)}")
|
|
53
50
|
|
|
@@ -69,22 +66,12 @@ module Gemirro
|
|
|
69
66
|
@latest_index =
|
|
70
67
|
File.join(@quick_dir, 'latest_index')
|
|
71
68
|
|
|
72
|
-
@specs_index =
|
|
73
|
-
File.join(@directory, "specs.#{::Gem.marshal_version}")
|
|
74
69
|
@latest_specs_index =
|
|
75
70
|
File.join(@directory, "latest_specs.#{::Gem.marshal_version}")
|
|
76
|
-
@prerelease_specs_index =
|
|
77
|
-
File.join(@directory, "prerelease_specs.#{::Gem.marshal_version}")
|
|
78
|
-
@dest_specs_index =
|
|
79
|
-
File.join(@dest_directory, "specs.#{::Gem.marshal_version}")
|
|
80
71
|
@dest_latest_specs_index =
|
|
81
72
|
File.join(@dest_directory, "latest_specs.#{::Gem.marshal_version}")
|
|
82
|
-
@dest_prerelease_specs_index =
|
|
83
|
-
File.join(@dest_directory, "prerelease_specs.#{::Gem.marshal_version}")
|
|
84
73
|
@infos_dir =
|
|
85
74
|
File.join(@dest_directory, 'info')
|
|
86
|
-
@api_v1_dependencies_dir =
|
|
87
|
-
File.join(@dest_directory, 'api', 'v1', 'dependencies')
|
|
88
75
|
|
|
89
76
|
@files = []
|
|
90
77
|
end
|
|
@@ -92,16 +79,9 @@ module Gemirro
|
|
|
92
79
|
##
|
|
93
80
|
# Generate indices on the destination directory
|
|
94
81
|
#
|
|
95
|
-
def install_indices
|
|
96
|
-
install_indicies
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
##
|
|
100
|
-
# Generate indicies on the destination directory
|
|
101
|
-
#
|
|
102
82
|
# @return [Array]
|
|
103
83
|
#
|
|
104
|
-
def
|
|
84
|
+
def install_indices
|
|
105
85
|
Utils.logger
|
|
106
86
|
.debug("Downloading index into production dir #{@dest_directory}")
|
|
107
87
|
|
|
@@ -111,24 +91,19 @@ module Gemirro
|
|
|
111
91
|
if files.include?(@quick_marshal_dir) && !files.include?(@quick_dir)
|
|
112
92
|
files.delete @quick_marshal_dir
|
|
113
93
|
FileUtils.mkdir_p(File.dirname(@quick_marshal_dir_base), verbose: verbose)
|
|
114
|
-
|
|
94
|
+
if @quick_marshal_dir_base && File.exist?(@quick_marshal_dir_base)
|
|
95
|
+
FileUtils.rm_rf(@quick_marshal_dir_base, verbose: verbose)
|
|
96
|
+
end
|
|
115
97
|
FileUtils.mv(@quick_marshal_dir, @quick_marshal_dir_base, verbose: verbose, force: true)
|
|
116
98
|
end
|
|
117
99
|
|
|
118
100
|
files.each do |path|
|
|
119
101
|
file = path.sub(%r{^#{Regexp.escape @directory}/?}, '')
|
|
120
102
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
"#{@prerelease_specs_index}.gz"].include?(path)
|
|
124
|
-
res = build_zlib_file(file, File.join(@directory, file), File.join(@dest_directory, file), true)
|
|
125
|
-
next unless res
|
|
126
|
-
else
|
|
127
|
-
source_content = download_from_source(file)
|
|
128
|
-
next if source_content.nil?
|
|
103
|
+
source_content = download_from_source(file)
|
|
104
|
+
next if source_content.nil?
|
|
129
105
|
|
|
130
|
-
|
|
131
|
-
end
|
|
106
|
+
MirrorFile.new(File.join(@dest_directory, file)).write(source_content)
|
|
132
107
|
|
|
133
108
|
FileUtils.rm_rf(path)
|
|
134
109
|
end
|
|
@@ -142,9 +117,9 @@ module Gemirro
|
|
|
142
117
|
#
|
|
143
118
|
def download_from_source(file)
|
|
144
119
|
source_host = Gemirro.configuration.source.host
|
|
145
|
-
Utils.logger.info("Download from source
|
|
120
|
+
Utils.logger.info("Download from source #{source_host}/#{file}")
|
|
146
121
|
resp = Http.get("#{source_host}/#{File.basename(file)}")
|
|
147
|
-
return unless resp.code == 200
|
|
122
|
+
return unless resp.code.to_i == 200
|
|
148
123
|
|
|
149
124
|
resp.body
|
|
150
125
|
end
|
|
@@ -155,104 +130,18 @@ module Gemirro
|
|
|
155
130
|
# @return [Array]
|
|
156
131
|
#
|
|
157
132
|
def build_indices
|
|
158
|
-
build_indicies
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
##
|
|
162
|
-
# Build indicies
|
|
163
|
-
#
|
|
164
|
-
# @return [Array]
|
|
165
|
-
#
|
|
166
|
-
def build_indicies
|
|
167
133
|
specs = *map_gems_to_specs(gem_file_list)
|
|
168
134
|
specs.select! { |s| s.instance_of?(::Gem::Specification) }
|
|
169
135
|
::Gem::Specification.dirs = []
|
|
170
136
|
::Gem::Specification.all = specs
|
|
171
137
|
|
|
172
|
-
|
|
173
|
-
build_marshal_gemspecs(specs)
|
|
174
|
-
build_modern_indices(specs) if @build_modern
|
|
175
|
-
compress_indices
|
|
176
|
-
else
|
|
177
|
-
build_marshal_gemspecs
|
|
178
|
-
build_modern_indicies if @build_modern
|
|
179
|
-
compress_indicies
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
build_api_v1_dependencies(specs)
|
|
183
|
-
|
|
184
|
-
return unless @build_compact
|
|
138
|
+
build_marshal_gemspecs(specs)
|
|
185
139
|
|
|
186
140
|
build_compact_index_names
|
|
187
141
|
build_compact_index_infos(specs)
|
|
188
142
|
build_compact_index_versions(specs)
|
|
189
143
|
end
|
|
190
144
|
|
|
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
145
|
##
|
|
257
146
|
# Cache compact_index endpoint /names
|
|
258
147
|
# Report all gems with versions available. Does not require opening spec files.
|
|
@@ -323,7 +212,7 @@ module Gemirro
|
|
|
323
212
|
end
|
|
324
213
|
|
|
325
214
|
Tempfile.create('versions.list') do |f|
|
|
326
|
-
previous_versions_file = Dir.glob(File.join(@dest_directory, 'versions
|
|
215
|
+
previous_versions_file = Dir.glob(File.join(@dest_directory, 'versions.*.*.list')).last
|
|
327
216
|
|
|
328
217
|
if partial && previous_versions_file
|
|
329
218
|
versions_file = CompactIndex::VersionsFile.new(previous_versions_file)
|
|
@@ -336,7 +225,7 @@ module Gemirro
|
|
|
336
225
|
f.write CompactIndex.versions(versions_file, cg)
|
|
337
226
|
f.rewind
|
|
338
227
|
|
|
339
|
-
FileUtils.rm_rf(Dir.glob(File.join(@dest_directory, 'versions
|
|
228
|
+
FileUtils.rm_rf(Dir.glob(File.join(@dest_directory, 'versions.*.*.list')))
|
|
340
229
|
|
|
341
230
|
FileUtils.cp(
|
|
342
231
|
f.path,
|
|
@@ -359,7 +248,7 @@ module Gemirro
|
|
|
359
248
|
# @return nil
|
|
360
249
|
#
|
|
361
250
|
def build_compact_index_infos(specs, partial = false)
|
|
362
|
-
FileUtils.mkdir_p(@infos_dir)
|
|
251
|
+
FileUtils.mkdir_p(@infos_dir, verbose: verbose)
|
|
363
252
|
|
|
364
253
|
if partial
|
|
365
254
|
specs.collect(&:name).uniq do |name|
|
|
@@ -468,13 +357,8 @@ module Gemirro
|
|
|
468
357
|
next
|
|
469
358
|
end
|
|
470
359
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
spec.sanitize
|
|
474
|
-
else
|
|
475
|
-
abbreviate(spec)
|
|
476
|
-
sanitize(spec)
|
|
477
|
-
end
|
|
360
|
+
spec.abbreviate
|
|
361
|
+
spec.sanitize
|
|
478
362
|
|
|
479
363
|
spec
|
|
480
364
|
rescue SignalException
|
|
@@ -507,14 +391,15 @@ module Gemirro
|
|
|
507
391
|
indexed_gemfiles = Dir.glob('*.gemspec.rz', base: @quick_marshal_dir_base).collect { |x| x.gsub(/spec.rz$/, '') }
|
|
508
392
|
|
|
509
393
|
@updated_gems = []
|
|
394
|
+
|
|
510
395
|
# detect files manually added to public/gems
|
|
511
396
|
@updated_gems += (present_gemfiles - indexed_gemfiles).collect { |x| File.join(@dest_directory, 'gems', x) }
|
|
512
397
|
# detect files manually deleted from public/gems
|
|
513
398
|
@updated_gems += (indexed_gemfiles - present_gemfiles).collect { |x| File.join(@dest_directory, 'gems', x) }
|
|
514
399
|
|
|
515
|
-
|
|
400
|
+
versions_mtime =
|
|
516
401
|
begin
|
|
517
|
-
File.stat(@
|
|
402
|
+
File.stat(Dir.glob(File.join(@dest_directory, 'versions*.list')).last).mtime
|
|
518
403
|
rescue StandardError
|
|
519
404
|
Time.at(0)
|
|
520
405
|
end
|
|
@@ -525,7 +410,7 @@ module Gemirro
|
|
|
525
410
|
gem_file_list.select do |gem|
|
|
526
411
|
gem_mtime = File.stat(gem).mtime
|
|
527
412
|
newest_mtime = gem_mtime if gem_mtime > newest_mtime
|
|
528
|
-
gem_mtime >
|
|
413
|
+
gem_mtime > versions_mtime
|
|
529
414
|
end
|
|
530
415
|
|
|
531
416
|
@updated_gems.uniq!
|
|
@@ -538,7 +423,7 @@ module Gemirro
|
|
|
538
423
|
specs = map_gems_to_specs(@updated_gems)
|
|
539
424
|
|
|
540
425
|
# specs only includes latest discovered files.
|
|
541
|
-
# /info/[gemname]
|
|
426
|
+
# /info/[gemname] can not be rebuilt
|
|
542
427
|
# incrementally, so retrive specs for all versions of these gems.
|
|
543
428
|
gem_name_updates = specs.collect(&:name).uniq
|
|
544
429
|
u2 =
|
|
@@ -549,108 +434,24 @@ module Gemirro
|
|
|
549
434
|
Utils.logger.info('Reloading for /info/[gemname]')
|
|
550
435
|
version_specs = map_gems_to_specs(u2)
|
|
551
436
|
|
|
552
|
-
prerelease, released = specs.partition { |s| s.version.prerelease? }
|
|
553
|
-
|
|
554
437
|
::Gem::Specification.dirs = []
|
|
555
438
|
::Gem::Specification.all = *specs
|
|
556
|
-
|
|
557
|
-
if ::Gem::VERSION >= '2.5.0'
|
|
558
|
-
build_marshal_gemspecs specs
|
|
559
|
-
else
|
|
560
|
-
build_marshal_gemspecs
|
|
561
|
-
end
|
|
562
|
-
|
|
563
|
-
::Gem.time('Updated indexes') do
|
|
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
|
-
)
|
|
579
|
-
end
|
|
580
|
-
|
|
581
|
-
if ::Gem::VERSION >= '2.5.0'
|
|
582
|
-
compress_indices
|
|
583
|
-
else
|
|
584
|
-
compress_indicies
|
|
585
|
-
end
|
|
439
|
+
build_marshal_gemspecs specs
|
|
586
440
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
build_compact_index_names
|
|
591
|
-
build_compact_index_infos(version_specs, true)
|
|
592
|
-
build_compact_index_versions(specs, true)
|
|
593
|
-
end
|
|
594
|
-
|
|
595
|
-
Utils.logger.info("Updating production dir #{@dest_directory}") if verbose
|
|
596
|
-
files << @specs_index
|
|
597
|
-
files << "#{@specs_index}.gz"
|
|
598
|
-
files << @latest_specs_index
|
|
599
|
-
files << "#{@latest_specs_index}.gz"
|
|
600
|
-
files << @prerelease_specs_index
|
|
601
|
-
files << "#{@prerelease_specs_index}.gz"
|
|
602
|
-
|
|
603
|
-
files.each do |path|
|
|
604
|
-
file = path.sub(%r{^#{Regexp.escape @directory}/?}, '')
|
|
605
|
-
|
|
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))
|
|
608
|
-
next unless res
|
|
609
|
-
else
|
|
610
|
-
FileUtils.mv(
|
|
611
|
-
File.join(@directory, file),
|
|
612
|
-
File.join(@dest_directory, file),
|
|
613
|
-
verbose: verbose,
|
|
614
|
-
force: true
|
|
615
|
-
)
|
|
616
|
-
end
|
|
617
|
-
|
|
618
|
-
File.utime(newest_mtime, newest_mtime, File.join(@dest_directory, file))
|
|
619
|
-
end
|
|
620
|
-
end
|
|
621
|
-
|
|
622
|
-
def build_zlib_file(file, src_name, dst_name, from_source = false)
|
|
623
|
-
content = Marshal.load(Zlib::GzipReader.open(src_name).read)
|
|
624
|
-
create_zlib_file("#{dst_name}.local", content)
|
|
625
|
-
|
|
626
|
-
return false if @only_origin
|
|
627
|
-
|
|
628
|
-
if from_source
|
|
629
|
-
source_content = download_from_source(file)
|
|
630
|
-
source_content = Marshal.load(
|
|
631
|
-
Zlib::GzipReader.new(
|
|
632
|
-
StringIO.new(source_content)
|
|
633
|
-
).read
|
|
634
|
-
)
|
|
635
|
-
else
|
|
636
|
-
source_content = Marshal.load(Zlib::GzipReader.open(dst_name).read)
|
|
637
|
-
end
|
|
638
|
-
|
|
639
|
-
return false if source_content.nil?
|
|
640
|
-
|
|
641
|
-
new_content = source_content.concat(content).uniq
|
|
642
|
-
create_zlib_file(dst_name, new_content)
|
|
441
|
+
build_compact_index_infos(version_specs, true)
|
|
442
|
+
build_compact_index_versions(specs, true)
|
|
443
|
+
build_compact_index_names
|
|
643
444
|
end
|
|
644
445
|
|
|
645
|
-
def
|
|
646
|
-
Tempfile.create(File.basename(
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
gzf.close
|
|
446
|
+
def download_source_versions
|
|
447
|
+
Tempfile.create(File.basename(Gemirro.configuration.versions_file)) do |f|
|
|
448
|
+
f.write(download_from_source('versions'))
|
|
449
|
+
f.close
|
|
650
450
|
|
|
451
|
+
FileUtils.rm(Gemirro.configuration.versions_file, verbose: verbose)
|
|
651
452
|
FileUtils.cp(
|
|
652
453
|
f.path,
|
|
653
|
-
|
|
454
|
+
Gemirro.configuration.versions_file,
|
|
654
455
|
verbose: verbose
|
|
655
456
|
)
|
|
656
457
|
end
|
data/lib/gemirro/mirror_file.rb
CHANGED
|
@@ -27,10 +27,8 @@ module Gemirro
|
|
|
27
27
|
#
|
|
28
28
|
def write(content)
|
|
29
29
|
FileUtils.mkdir_p(File.dirname(@path))
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
handle.write(content)
|
|
33
|
-
handle.close
|
|
30
|
+
File.write(@path, content)
|
|
31
|
+
nil
|
|
34
32
|
end
|
|
35
33
|
|
|
36
34
|
##
|
|
@@ -39,12 +37,7 @@ module Gemirro
|
|
|
39
37
|
# @return [String]
|
|
40
38
|
#
|
|
41
39
|
def read
|
|
42
|
-
|
|
43
|
-
content = handle.read
|
|
44
|
-
|
|
45
|
-
handle.close
|
|
46
|
-
|
|
47
|
-
content
|
|
40
|
+
File.read(@path)
|
|
48
41
|
end
|
|
49
42
|
end
|
|
50
43
|
end
|