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.rb
CHANGED
@@ -39,8 +39,8 @@ module Gemirro
|
|
39
39
|
expect(Configuration.marshal_identifier).to match(/Marshal\.(\d+)\.(\d+)/)
|
40
40
|
end
|
41
41
|
|
42
|
-
it 'should
|
43
|
-
expect(
|
42
|
+
it 'should error on version since no source is defined' do
|
43
|
+
expect(Gemirro.configuration.versions_file).to match(nil)
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'should return marshal file' do
|
@@ -84,5 +84,12 @@ module Gemirro
|
|
84
84
|
expect(result.host).to eq('https://rubygems.org')
|
85
85
|
expect(result.name).to eq('rubygems')
|
86
86
|
end
|
87
|
+
|
88
|
+
|
89
|
+
it 'should return versions file with source' do
|
90
|
+
result = @config.define_source('RubyGems', 'https://rubygems.org') do
|
91
|
+
end
|
92
|
+
expect(@config.versions_file).to match(/rubygems_org_versions$/)
|
93
|
+
end
|
87
94
|
end
|
88
95
|
end
|
@@ -12,7 +12,7 @@ module Gemirro
|
|
12
12
|
|
13
13
|
before(:each) do
|
14
14
|
@source = Source.new('RubyGems', 'https://rubygems.org')
|
15
|
-
@versions_file = VersionsFile.new(
|
15
|
+
@versions_file = VersionsFile.new(%(created_at: 2025-04-24T03:46:59Z\n---\nrack 3.0.0,3.0.1 d545a45462d63b1b4865bbb89a109366))
|
16
16
|
@fetcher = GemsFetcher.new(@source, @versions_file)
|
17
17
|
Gemirro.configuration.ignored_gems.clear
|
18
18
|
end
|
@@ -24,7 +24,7 @@ module Gemirro
|
|
24
24
|
|
25
25
|
dir = MirrorDirectory.new('/tmp')
|
26
26
|
dir.add_directory('test')
|
27
|
-
indexer = Indexer.new
|
27
|
+
indexer = Indexer.new
|
28
28
|
|
29
29
|
Struct.new('HttpGet', :code, :body)
|
30
30
|
http_get = Struct::HttpGet.new(200, 'bad')
|
@@ -43,7 +43,7 @@ module Gemirro
|
|
43
43
|
allow(::Gem.configuration).to receive(:really_verbose)
|
44
44
|
.once.and_return(true)
|
45
45
|
|
46
|
-
indexer = Indexer.new
|
46
|
+
indexer = Indexer.new
|
47
47
|
indexer.quick_marshal_dir = '/tmp/gem_generate_index/quick/Marshal.4.8'
|
48
48
|
indexer.dest_directory = '/tmp/test'
|
49
49
|
indexer.directory = '/tmp/gem_generate_index'
|
@@ -97,7 +97,7 @@ module Gemirro
|
|
97
97
|
end
|
98
98
|
|
99
99
|
it 'should build indices' do
|
100
|
-
indexer = Indexer.new
|
100
|
+
indexer = Indexer.new
|
101
101
|
dir = MirrorDirectory.new('/')
|
102
102
|
dir.add_directory('gems')
|
103
103
|
dir.add_directory('quick')
|
@@ -140,7 +140,7 @@ module Gemirro
|
|
140
140
|
end
|
141
141
|
|
142
142
|
it 'should update index and exit ruby gems' do
|
143
|
-
indexer = Indexer.new
|
143
|
+
indexer = Indexer.new
|
144
144
|
MirrorDirectory.new('/')
|
145
145
|
MirrorFile.new('/specs.4.8').write('')
|
146
146
|
expect { indexer.update_index }.to raise_error(::Gem::SystemExitException)
|
@@ -152,7 +152,7 @@ module Gemirro
|
|
152
152
|
dir.add_directory('test/gems')
|
153
153
|
dir.add_directory('test/quick')
|
154
154
|
|
155
|
-
indexer = Indexer.new
|
155
|
+
indexer = Indexer.new
|
156
156
|
indexer.quick_marshal_dir = '/tmp/gem_generate_index/quick/Marshal.4.8'
|
157
157
|
indexer.dest_directory = '/tmp/test'
|
158
158
|
indexer.directory = '/tmp/gem_generate_index'
|
data/spec/gemirro/server_spec.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'rack/test'
|
2
2
|
require 'json'
|
3
3
|
require 'parallel'
|
4
|
-
require '
|
4
|
+
require 'sinatra/base'
|
5
|
+
require 'thin'
|
6
|
+
require 'base64'
|
5
7
|
require 'gemirro/utils'
|
6
8
|
require 'gemirro/mirror_directory'
|
7
9
|
require 'gemirro/mirror_file'
|
@@ -37,15 +39,23 @@ module Gemirro
|
|
37
39
|
Utils.instance_eval('@gems_orig_collection = nil')
|
38
40
|
Utils.instance_eval('@gems_source_collection = nil')
|
39
41
|
FakeFS::FileSystem.clone(Gemirro::Configuration.views_directory)
|
42
|
+
allow_any_instance_of(Indexer).to receive(:compress_indices)
|
43
|
+
allow_any_instance_of(Indexer).to receive(:rand).and_return('0')
|
44
|
+
|
45
|
+
source = Source.new('Rubygems', 'https://rubygems.org')
|
46
|
+
allow(Gemirro.configuration).to receive(:source).and_return(source)
|
40
47
|
end
|
41
48
|
|
42
49
|
context 'HTML render' do
|
43
50
|
it 'should display index page' do
|
44
|
-
allow(Logger).to receive(:new).
|
51
|
+
allow(Logger).to receive(:new).exactly(3).times.and_return(@fake_logger)
|
45
52
|
allow(@fake_logger).to receive(:tap)
|
46
53
|
.and_return(nil)
|
47
54
|
.and_yield(@fake_logger)
|
48
55
|
|
56
|
+
|
57
|
+
MirrorFile.new('/var/www/gemirro/versions.md5.aaa256.list').write('created_at: 2025-01-01T00:00:00Z\n---\nvolay 0.1.0\n')
|
58
|
+
|
49
59
|
get '/'
|
50
60
|
expect(last_response).to be_ok
|
51
61
|
end
|
@@ -63,58 +73,53 @@ module Gemirro
|
|
63
73
|
end
|
64
74
|
|
65
75
|
it 'should display gem specifications' do
|
66
|
-
|
67
|
-
::Gem::Version.create('0.1.0'),
|
68
|
-
'ruby']])
|
76
|
+
MirrorFile.new('/var/www/gemirro/versions.md5.aaa256.list').write(%(created_at: 2025-01-01T00:00:00Z\n---\nvolay 0.1.0 checksum))
|
69
77
|
|
70
|
-
|
71
|
-
Struct.new('SuccessGzipReader', :read)
|
72
|
-
gzip_reader = Struct::SuccessGzipReader.new(marshal_dump)
|
73
|
-
MirrorDirectory.new('/var/www/gemirro')
|
74
|
-
.add_directory('quick/Marshal.4.8')
|
75
|
-
# rubocop:disable Metrics/LineLength
|
76
|
-
MirrorFile.new('/var/www/gemirro/quick/Marshal.4.8/' \
|
77
|
-
'volay-0.1.0.gemspec.rz')
|
78
|
-
.write("x\x9C\x8D\x94]\x8F\xD2@\x14\x86\x89Y\xBB\xB4|\xEC\x12\xD7h" \
|
79
|
-
"\xD4h\xD3K\x13J\x01\x97\xC84n\x9A\xA8\xBBi\xE2\xC5\x06\xBB" \
|
80
|
-
"{\xC3\x85)\xE5\x00\x13f:u:E\xD1\xC4\xDF\xE6\xB5\xBF\xCAiK" \
|
81
|
-
"\x11\xE3GK\xEF\x98\xF7\xBC\xCFy\xCF\xC9\xCCQ=A\x0F\xAE\x80" \
|
82
|
-
"\"\xF4>\x82\x00/p\xE0\v\xCC\xC2;\xC1\xDD\xA3\xFA\xF4\xA1k4" \
|
83
|
-
"\x06\xA6e\xF6_(Hy\xEBa\xD55\xB4\r#\xFEV\xB1k\xDE\r\xEAdu" \
|
84
|
-
"\xB7\xC0cY1U\xE4\xA1\x95\x8A\xD3C7A\xAA\x87)\xB4\x9C\x1FO" \
|
85
|
-
"\xBE\xD7\xE4OA\xEA\x17\x16\x82k\xD4o\xBC\xD7\x99\xC2x\xEC" \
|
86
|
-
"\xAD@\xBFe$\xA1\xA0\xC7\xDBX\x00\xD5\x05/\xBC\xEFg\xDE\x13" \
|
87
|
-
"\xF8\x98`\x0E\x14B1U\xE4w\xEC\x1A\xC7\x17\xAF2\x85\xADd\xC4" \
|
88
|
-
"\xBE96\x87\xF9\x1F\xEA\xDF%\x8A\x95\xE3T\x9E\xCC2\xF3i\x9B" \
|
89
|
-
"\xA1\xB3\xCC\xFE\rD\x10\xCE!\f\xB6\x1A\xD2\x9C\xD0\xA7\xB2" \
|
90
|
-
"\xBF\x13\x8A?\x13<\xEB\x06\x04\xA7b\xD4q\xF8\xAF&\x0E!\xDF" \
|
91
|
-
".~\xEF\xE3\xDC\xCC@\xD2Hl\#@M\x9E\x84BN\x00\x9D:\x11\a\x0E" \
|
92
|
-
"\x04\xFC\x18.\xD1#g\x93\xCF\xEB\xC3\x81m\\\xC1\x97\xD9" \
|
93
|
-
"\x9Af7\\\xE3l\xD7_\xBC\x02BX\"\xD23\xBB\xF9o\x83A\xB1\x12" \
|
94
|
-
"\xBBe\xB7\xED\x93K\xFB\xB4\x82\xB6\x80\xA9K\xB1\x1E\x96" \
|
95
|
-
"\x10\xEA\x03sP\xCD\xBFP\x16\xEE\x8D\x85\xBF\x86E\\\x96" \
|
96
|
-
"\xC02G\xF9\b\xEC\x16:\x9D\xC3\x06\b\x8B\xD2\xA9\x95\x84" \
|
97
|
-
"\xD9\x97\xED\xC3p\x89+\x81\xA9}\xAB`\xD9\x9D\xFF\x03\xF6" \
|
98
|
-
"\xD2\xC2\xBF\xCD\xFD`\xDD\x15\x10\x97\xED\xA4.[\xAB\xC6(" \
|
99
|
-
"\x94\x05B\xE3\xB1\xBC\xA5e\xF6\xC3\xAA\x11\n\xE5>A\x8CiD " \
|
100
|
-
"`\x9B\xF2\x04\xE3\xCA\t\xC6\x87\by-f,`Q\xD9\x1E,sp^q\x0F" \
|
101
|
-
"\x85\xD4r\x8Dg\x11\x06\xCE\xC1\xE4>\x9D\xF9\xC9\xFC\xE5" \
|
102
|
-
"\xC8YR\x1F\x133`4\xBB\xF9R~\xEF:\x93\xE8\x93\\\x92\xBF\r" \
|
103
|
-
"\xA3\t\xF8\x84l\xF5<\xBF\xBE\xF9\xE3Q\xD2?q,\x04\x84:\x0E" \
|
104
|
-
"\xF5\xF4\x1D1\xF3\xBA\xE7+!\"\xD4\xEB-\xB1X%\xB3\x14\xD3" \
|
105
|
-
"\xCB\xEDw\xEE\xBD\xFDk\xE99OSz\xF3\xEA\xFA]w7\xF5\xAF\xB5" \
|
106
|
-
"\x9F+\xFEG\x96")
|
107
|
-
# rubocop:enable Metrics/LineLength
|
78
|
+
get '/gem/volay'
|
108
79
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
80
|
+
expect(last_response.status).to eq(200)
|
81
|
+
expect(last_response).to be_ok
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'responds to compact_index /names' do
|
85
|
+
MirrorFile.new('/var/www/gemirro/names.md5.aaa256.list').write(%(---\nvolay))
|
113
86
|
|
114
|
-
get '/
|
87
|
+
get '/names'
|
88
|
+
expect(last_response.status).to eq(200)
|
89
|
+
expect(last_response).to be_ok
|
90
|
+
|
91
|
+
|
92
|
+
expect(last_response.body).to eq(%(---\nvolay))
|
93
|
+
expect(last_response.headers['etag']).to eq('"md5"')
|
94
|
+
expect(last_response.headers['repr-digest']).to eq(%(sha-256=#{Base64.strict_encode64(['aaa256'].pack('H*'))}))
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'responds to compact_index /info/[gemname]' do
|
98
|
+
MirrorDirectory.new('/var/www/gemirro/info')
|
99
|
+
MirrorFile.new('/var/www/gemirro/info/volay.md5.aaa256.list').write('---\n 0.1.0 |checksum:sha256\n')
|
100
|
+
|
101
|
+
|
102
|
+
get '/info/volay'
|
115
103
|
expect(last_response.status).to eq(200)
|
116
104
|
expect(last_response).to be_ok
|
105
|
+
expect(last_response.body).to eq('---\n 0.1.0 |checksum:sha256\n')
|
106
|
+
expect(last_response.headers['etag']).to eq('"md5"')
|
107
|
+
expect(last_response.headers['repr-digest']).to eq(%(sha-256=#{Base64.strict_encode64(['aaa256'].pack('H*'))}))
|
117
108
|
end
|
109
|
+
|
110
|
+
|
111
|
+
it 'responds to compact_index /versions' do
|
112
|
+
MirrorFile.new('/var/www/gemirro/versions.md5.aaa256.list').write(%(created_at: 2025-01-01T00:00:00Z\n---\nvolay 0.1.0))
|
113
|
+
|
114
|
+
get '/versions'
|
115
|
+
expect(last_response.status).to eq(200)
|
116
|
+
expect(last_response).to be_ok
|
117
|
+
expect(last_response.body).to eq(%(created_at: 2025-01-01T00:00:00Z\n---\nvolay 0.1.0))
|
118
|
+
expect(last_response.headers['etag']).to eq('"md5"')
|
119
|
+
expect(last_response.headers['repr-digest']).to eq(%(sha-256=#{Base64.strict_encode64(['aaa256'].pack('H*'))}))
|
120
|
+
end
|
121
|
+
|
122
|
+
|
118
123
|
end
|
119
124
|
|
120
125
|
context 'Download' do
|
@@ -150,8 +155,8 @@ module Gemirro
|
|
150
155
|
allow(::Gem::SilentUI).to receive(:new).once.and_return(true)
|
151
156
|
|
152
157
|
allow(Gemirro.configuration).to receive(:logger)
|
153
|
-
.exactly(
|
154
|
-
allow(@fake_logger).to receive(:info).exactly(
|
158
|
+
.exactly(4).and_return(@fake_logger)
|
159
|
+
allow(@fake_logger).to receive(:info).exactly(4)
|
155
160
|
|
156
161
|
get '/gems/gemirro-0.0.1.gem'
|
157
162
|
expect(last_response).to_not be_ok
|
@@ -200,31 +205,20 @@ module Gemirro
|
|
200
205
|
end
|
201
206
|
|
202
207
|
context 'dependencies' do
|
203
|
-
it 'should retrieve nothing' do
|
208
|
+
it 'should retrieve nothing and give 404' do
|
204
209
|
get '/api/v1/dependencies'
|
205
|
-
expect(last_response.
|
206
|
-
|
207
|
-
expect(last_response.body).to eq('')
|
208
|
-
expect(last_response).to be_ok
|
210
|
+
expect(last_response.status).to eq(404)
|
211
|
+
expect(last_response).to_not be_ok
|
209
212
|
end
|
210
213
|
|
211
|
-
it 'should retrieve empty json' do
|
212
|
-
get '/api/v1/dependencies.json'
|
213
|
-
expect(last_response.headers['Content-Type'])
|
214
|
-
.to eq('application/json')
|
215
|
-
expect(last_response.body).to eq('')
|
216
|
-
expect(last_response).to be_ok
|
217
|
-
end
|
218
214
|
|
219
|
-
it 'should retrieve
|
215
|
+
it 'should retrieve nothing and give 404' do
|
220
216
|
get '/api/v1/dependencies.json?gems=gemirro'
|
221
|
-
expect(last_response.
|
222
|
-
|
223
|
-
expect(last_response.body).to eq('[]')
|
224
|
-
expect(last_response).to be_ok
|
217
|
+
expect(last_response.status).to eq(404)
|
218
|
+
expect(last_response).to_not be_ok
|
225
219
|
end
|
226
220
|
|
227
|
-
it 'should retrieve
|
221
|
+
it 'should retrieve nothing and give 404' do
|
228
222
|
MirrorDirectory.new('/var/www/gemirro')
|
229
223
|
.add_directory('quick/Marshal.4.8')
|
230
224
|
# rubocop:disable Metrics/LineLength
|
@@ -261,16 +255,28 @@ module Gemirro
|
|
261
255
|
"\x9F+\xFEG\x96")
|
262
256
|
# rubocop:enable Metrics/LineLength
|
263
257
|
|
258
|
+
MirrorFile.new('/var/www/gemirro/api/v1/dependencies/volay.md5.sha.list')
|
259
|
+
.write(Marshal.dump([
|
260
|
+
{
|
261
|
+
name: 'volay',
|
262
|
+
number: "0.1.0",
|
263
|
+
platform: 'ruby',
|
264
|
+
dependencies: [
|
265
|
+
{
|
266
|
+
name: 'json',
|
267
|
+
requirement: '~> 2.1'
|
268
|
+
}
|
269
|
+
]
|
270
|
+
}
|
271
|
+
]))
|
272
|
+
|
264
273
|
gem = Gemirro::GemVersion.new('volay', '0.1.0', 'ruby')
|
265
274
|
collection = Gemirro::GemVersionCollection.new([gem])
|
266
275
|
allow(Utils).to receive(:gems_collection)
|
267
276
|
.and_return(collection)
|
268
277
|
get '/api/v1/dependencies.json?gems=volay'
|
269
|
-
expect(last_response.
|
270
|
-
|
271
|
-
|
272
|
-
expect(last_response.body).to match(/"name":"volay"/)
|
273
|
-
expect(last_response).to be_ok
|
278
|
+
expect(last_response.status).to eq(404)
|
279
|
+
expect(last_response).to_not be_ok
|
274
280
|
end
|
275
281
|
end
|
276
282
|
end
|
data/spec/gemirro/source_spec.rb
CHANGED
@@ -21,20 +21,11 @@ module Gemirro
|
|
21
21
|
Struct.new('FetchVersions', :body)
|
22
22
|
result = Struct::FetchVersions.new(true)
|
23
23
|
allow(Http).to receive(:get).once.with(
|
24
|
-
"https://rubygems.org
|
24
|
+
"https://rubygems.org/versions"
|
25
25
|
).and_return(result)
|
26
26
|
expect(@source.fetch_versions).to be_truthy
|
27
27
|
end
|
28
28
|
|
29
|
-
it 'should fetch prereleases versions' do
|
30
|
-
Struct.new('FetchPrereleaseVersions', :body)
|
31
|
-
result = Struct::FetchPrereleaseVersions.new(true)
|
32
|
-
allow(Http).to receive(:get).once.with(
|
33
|
-
"https://rubygems.org/#{Configuration.prerelease_versions_file}"
|
34
|
-
).and_return(result)
|
35
|
-
expect(@source.fetch_prerelease_versions).to be_truthy
|
36
|
-
end
|
37
|
-
|
38
29
|
it 'should fetch gem' do
|
39
30
|
Struct.new('FetchGem', :body)
|
40
31
|
result = Struct::FetchGem.new(true)
|
@@ -17,10 +17,9 @@ module Gemirro
|
|
17
17
|
|
18
18
|
it 'should fetch versions' do
|
19
19
|
allow(@source).to receive(:fetch_versions).once.and_return([])
|
20
|
-
allow(
|
21
|
-
allow(
|
22
|
-
allow(File).to receive(:
|
23
|
-
allow(File).to receive(:read).twice.and_return('nothing')
|
20
|
+
allow(VersionsFile).to receive(:load).with('nothing')
|
21
|
+
allow(File).to receive(:write).once
|
22
|
+
allow(File).to receive(:read).once.and_return('nothing')
|
24
23
|
expect(@fetcher.fetch).to be_nil
|
25
24
|
end
|
26
25
|
end
|
@@ -7,44 +7,20 @@ module Gemirro
|
|
7
7
|
describe 'VersionsFile' do
|
8
8
|
include FakeFS::SpecHelpers
|
9
9
|
|
10
|
-
it 'should be initialized' do
|
11
|
-
@versions_file = VersionsFile.new([['gemirro', '0.0.1'],
|
12
|
-
['gemirro', '0.0.2']])
|
13
|
-
expect(@versions_file.versions).to eq([['gemirro', '0.0.1'],
|
14
|
-
['gemirro', '0.0.2']])
|
15
|
-
expect(@versions_file.versions_hash).to eq(
|
16
|
-
'gemirro' => [
|
17
|
-
['gemirro', '0.0.1'],
|
18
|
-
['gemirro', '0.0.2']
|
19
|
-
]
|
20
|
-
)
|
21
|
-
end
|
22
|
-
|
23
10
|
it 'should load versions file' do
|
24
|
-
spec =
|
25
|
-
w_gz = Zlib::GzipWriter.new(spec)
|
26
|
-
w_gz.write(Marshal.dump([['gemirro', '0.0.1'],
|
27
|
-
['gemirro', '0.0.2']]))
|
28
|
-
w_gz.close
|
29
|
-
prerelease = StringIO.new('w')
|
30
|
-
w_gz = Zlib::GzipWriter.new(prerelease)
|
31
|
-
w_gz.write(Marshal.dump([['gemirro', '0.0.1.alpha1'],
|
32
|
-
['gemirro', '0.0.2.alpha2']]))
|
33
|
-
w_gz.close
|
11
|
+
spec = %(created_at: 2025-01-01T00:00:00Z\n---\ngemirro 0.0.1.alpha1,0.0.1,0.0.2.alpha2,0.0.2 checksum)
|
34
12
|
|
35
|
-
result = VersionsFile.
|
13
|
+
result = VersionsFile.new(spec)
|
36
14
|
expect(result).to be_a(VersionsFile)
|
37
15
|
|
38
|
-
expect(result.
|
39
|
-
|
40
|
-
['gemirro', '0.0.1.alpha1'],
|
41
|
-
['gemirro', '0.0.2.alpha2']])
|
16
|
+
expect(result.versions_string).to eq(%(created_at: 2025-01-01T00:00:00Z\n---\ngemirro 0.0.1.alpha1,0.0.1,0.0.2.alpha2,0.0.2 checksum))
|
17
|
+
|
42
18
|
expect(result.versions_hash).to eq(
|
43
19
|
'gemirro' => [
|
44
|
-
['gemirro', '0.0.1'],
|
45
|
-
['gemirro', '0.0.
|
46
|
-
['gemirro', '0.0.
|
47
|
-
['gemirro', '0.0.2
|
20
|
+
['gemirro', ::Gem::Version.new('0.0.1.alpha1'), 'ruby'],
|
21
|
+
['gemirro', ::Gem::Version.new('0.0.1'), 'ruby'],
|
22
|
+
['gemirro', ::Gem::Version.new('0.0.2.alpha2'), 'ruby'],
|
23
|
+
['gemirro', ::Gem::Version.new('0.0.2'), 'ruby']
|
48
24
|
]
|
49
25
|
)
|
50
26
|
end
|
data/template/config.rb
CHANGED
@@ -23,6 +23,12 @@ Gemirro.configuration.configure do
|
|
23
23
|
server.access_log File.expand_path('../logs/access.log', __FILE__)
|
24
24
|
server.error_log File.expand_path('../logs/error.log', __FILE__)
|
25
25
|
|
26
|
+
# Number of parallel processes while indexing. Too many will kill
|
27
|
+
# your indexing process prematurely.
|
28
|
+
#
|
29
|
+
# update_threads Etc.nprocessors - 1
|
30
|
+
# update_threads 4
|
31
|
+
|
26
32
|
# If you don't want to generate indexes after each fetched gem.
|
27
33
|
#
|
28
34
|
# update_on_fetch false
|
@@ -54,6 +60,6 @@ Gemirro.configuration.configure do
|
|
54
60
|
# All gem in the block will be downloaded with the update command.
|
55
61
|
# Other gems will be downloaded with the server.
|
56
62
|
define_source 'rubygems', 'https://rubygems.org' do
|
57
|
-
gem 'rack', '>=
|
63
|
+
gem 'rack', '>= 3.0.0'
|
58
64
|
end
|
59
65
|
end
|
@@ -1 +1,25 @@
|
|
1
|
-
|
1
|
+
body { max-width: 620px; margin: 0 auto; padding: 0; font-family: sans-serif; }
|
2
|
+
|
3
|
+
dl { display: grid; grid-template-columns: 1fr min-content; }
|
4
|
+
|
5
|
+
dt { grid-column: 1; margin: 0; padding: 8px 0; border-bottom: 1px solid #e2e2e2; }
|
6
|
+
dd { grid-column: 2; margin: 0; padding: 8px 0; border-bottom: 1px solid #e2e2e2; }
|
7
|
+
|
8
|
+
dd.full { grid-column: 1/2; border-bottom: 0; }
|
9
|
+
dd.description, dd.authors, dd.dependencies { grid-column: 1/2; border-bottom: 0; }
|
10
|
+
|
11
|
+
|
12
|
+
a, a:visited, a:active, a:hover { color: #007bff; }
|
13
|
+
.btn { color: #fff; background: #007bff; padding: 5px; border-radius: 4px; text-decoration: none; }
|
14
|
+
.btn:visited, .btn:active, .btn:hover { color: #fff; }
|
15
|
+
|
16
|
+
|
17
|
+
ul { list-style-type: none; margin: 0; padding: 0 0 0 1em; }
|
18
|
+
|
19
|
+
|
20
|
+
@media (prefers-color-scheme: dark) {
|
21
|
+
html, body { background: #16161d; color: #fff; }
|
22
|
+
a, a:visited, a:active, a:hover { color: lightskyblue; }
|
23
|
+
.btn { color: #16161d; background: lightskyblue; padding: 5px; border-radius: 4px; text-decoration: none; }
|
24
|
+
.btn:visited, .btn:active, .btn:hover { color: #16161d; }
|
25
|
+
}
|
data/views/gem.erb
CHANGED
@@ -1,58 +1,67 @@
|
|
1
|
-
|
2
|
-
<div class="col-lg-3 center-block pull-none text-center">
|
1
|
+
|
3
2
|
<a class="btn btn-default" href="<%= url '/'%>">Back to Gem Index</a>
|
4
3
|
</div>
|
5
4
|
</div>
|
6
5
|
|
7
|
-
|
6
|
+
|
7
|
+
<article>
|
8
8
|
<% gem.by_name do |name, versions| %>
|
9
|
-
<
|
10
|
-
<
|
11
|
-
<
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
9
|
+
<dl>
|
10
|
+
<dt>
|
11
|
+
<h2><%= Rack::Utils.escape_html(name) %></h2>
|
12
|
+
</dt>
|
13
|
+
<dd>
|
14
|
+
<h2><%= Rack::Utils.escape_html(versions.newest.number) %></h2>
|
15
|
+
</dd>
|
16
|
+
<% newest_gem = versions.newest %>
|
17
|
+
<% spec = Gemirro::Utils.spec_for(name, newest_gem.number, newest_gem.platform) %>
|
18
|
+
<% if spec %>
|
19
|
+
<dd class="description">
|
20
|
+
<%= Rack::Utils.escape_html(spec.description) %>
|
21
|
+
</dd>
|
20
22
|
|
23
|
+
<% if spec.dependencies.size > 0 %>
|
24
|
+
<dd class="dependencies">
|
21
25
|
<h3>Dependencies</h3>
|
22
|
-
<ul
|
26
|
+
<ul>
|
23
27
|
<% spec.dependencies.each do |dependency| %>
|
24
28
|
<li class="list-group-item">
|
25
|
-
<a href="<%= url("gem/#{dependency.name}") %>"><%=
|
29
|
+
<a href="<%= url("gem/#{dependency.name}") %>"><%= Rack::Utils.escape_html([dependency.name, dependency.requirement].join(' ')) %></a>
|
26
30
|
</li>
|
27
31
|
<% end %>
|
28
32
|
</ul>
|
33
|
+
</dd>
|
34
|
+
<% end %>
|
29
35
|
|
36
|
+
<% if spec.authors.size > 0 %>
|
37
|
+
<dd class="authors">
|
30
38
|
<h3>Authors</h3>
|
31
|
-
<ul
|
39
|
+
<ul>
|
32
40
|
<% spec.authors.each do |author| %>
|
33
41
|
<li class="list-group-item">
|
34
|
-
<a href="<%=
|
42
|
+
<a href="<%= URI.parse(Addressable::URI.escape(spec.homepage)) %>"><%= Rack::Utils.escape_html(author) %></a>
|
35
43
|
</li>
|
36
44
|
<% end %>
|
37
45
|
</ul>
|
38
|
-
|
39
|
-
|
46
|
+
</dd>
|
47
|
+
<% end %>
|
48
|
+
<% end %>
|
40
49
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
</
|
50
|
+
<% versions.each.reverse_each do |version| %>
|
51
|
+
<dt>
|
52
|
+
<code>
|
53
|
+
gem install
|
54
|
+
<%= Rack::Utils.escape_html(version.name) %>
|
55
|
+
--version "<%= Rack::Utils.escape_html(version.number) %>"
|
56
|
+
<% unless version.platform =~ /^ruby/i %>
|
57
|
+
--platform <%= Rack::Utils.escape_html(version.platform) %>
|
58
|
+
<% end %>
|
59
|
+
</code>
|
60
|
+
</dt>
|
61
|
+
<dd>
|
62
|
+
<a class="btn" href="<%= url("/gems/#{version.gemfile_name}.gem") %>">Download</a>
|
63
|
+
</dd>
|
64
|
+
<% end %>
|
65
|
+
</dl>
|
57
66
|
<% end %>
|
58
|
-
</
|
67
|
+
</article>
|
data/views/index.erb
CHANGED
@@ -1,38 +1,46 @@
|
|
1
1
|
|
2
|
-
<
|
3
|
-
<div class="col-lg-3 center-block pull-none">
|
4
|
-
<pre class="bg-info"><code>gem sources -a <%= url("/") %></code></pre>
|
5
|
-
</div>
|
6
|
-
</div>
|
2
|
+
<code>gem sources -a <%= url("/") %></code>
|
7
3
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
<
|
13
|
-
<
|
14
|
-
<
|
15
|
-
|
16
|
-
|
17
|
-
|
4
|
+
<% if gems.any? %>
|
5
|
+
<article>
|
6
|
+
<% gems.by_name do |name, versions| %>
|
7
|
+
<dl>
|
8
|
+
<dt>
|
9
|
+
<a href="<%= url("gem/#{name}") %>">
|
10
|
+
<h2><%= Rack::Utils.escape_html(name) %></h2>
|
11
|
+
</a>
|
12
|
+
</dt>
|
13
|
+
<dd>
|
14
|
+
<h2><%= Rack::Utils.escape_html(versions.newest.number) %></h2>
|
15
|
+
</dd>
|
16
|
+
|
17
|
+
<% spec = Gemirro::Utils.spec_for(name, versions.newest.number, versions.newest.platform) %>
|
18
|
+
<% if spec.is_a?(::Gem::Specification) %>
|
19
|
+
<dd class="description">
|
20
|
+
<%= Rack::Utils.escape_html(spec.description) %>
|
21
|
+
</dd>
|
22
|
+
<% end %>
|
18
23
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
<p>
|
27
|
-
<code>gem install <%= escape(version.name) %> <%= "--prerelease" if version.number.to_s.match(/[a-z]/i) %> -v "<%= escape(version.number) %>"</code>
|
24
|
+
<% versions.reverse_each.first(5).each do |version| %>
|
25
|
+
<dt class="version">
|
26
|
+
<code>
|
27
|
+
gem install
|
28
|
+
<%= Rack::Utils.escape_html(version.name) %>
|
29
|
+
<%= "--prerelease" if version.number.to_s.match(/[a-z]/i) %>
|
30
|
+
--version "<%= Rack::Utils.escape_html(version.number) %>"
|
28
31
|
<% unless version.platform =~ /^ruby/i %>
|
29
|
-
|
32
|
+
--platform <%= Rack::Utils.escape_html(version.platform) %></small>
|
30
33
|
<% end %>
|
31
|
-
</
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
</code>
|
35
|
+
</dt>
|
36
|
+
<dd>
|
37
|
+
<a class="btn btn-primary btn-sm" href="<%= url("/gems/#{version.gemfile_name}.gem") %>">Download</a>
|
38
|
+
</dd>
|
39
|
+
<% end %>
|
40
|
+
<% if versions.size > 5 %>
|
41
|
+
<dd class="full"><a href="<%= url("gem/#{name}") %>"><%= "And %d More..." % [versions.size - 5] %></a></dd>
|
42
|
+
<% end %>
|
43
|
+
</dl>
|
44
|
+
<% end %>
|
45
|
+
</article>
|
46
|
+
<% end %>
|