Skip to content

Commit 3ac13e6

Browse files
committed
Add support for an /info_checksums endpoint
This is /versions but without the versions list Since bundler/rubygems only use the name/checksum in /versions, we can use a significantly smaller file that is also easier to parse Signed-off-by: Samuel Giddins <segiddins@segiddins.me>
1 parent 09bd194 commit 3ac13e6

File tree

4 files changed

+108
-13
lines changed

4 files changed

+108
-13
lines changed

lib/compact_index.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ def self.names(gem_names)
2121
gem_names.join("\n").prepend("---\n") << "\n"
2222
end
2323

24+
def self.info_checksums(versions_file, gems = nil, calculate_info_checksums: false)
25+
versions_file.contents(gems, :calculate_info_checksums => calculate_info_checksums)
26+
end
27+
2428
# Returns the versions file content argumented with some extra gems
2529
# @param versions_file [CompactIndex::VersionsFile] which will be used as a base response
2630
# @param gems [Array] an optional list of [CompactIndex::Gem] to be appended on the end
@@ -45,8 +49,8 @@ def self.names(gem_names)
4549
# rails 0.0.1,0.1.0 00fd5c36764f4ec1e8adf1c9adaada55
4650
# sinatra 0.1.1,0.1.2,0.1.3 46f0a24d291725736216b4b6e7412be6
4751
# ```
48-
def self.versions(versions_file, gems = nil, args = {})
49-
versions_file.contents(gems, args)
52+
def self.versions(versions_file, gems = nil, **kwargs)
53+
versions_file.contents(gems, **kwargs)
5054
end
5155

5256
# Formats the versions information of a gem, to be display in the `/info/gemname` endpoint.

lib/compact_index/versions_file.rb

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@
66

77
module CompactIndex
88
class VersionsFile
9-
def initialize(file = nil)
9+
def initialize(file = nil, only_info_checksums: false)
1010
@path = file || "/versions.list"
11+
@only_info_checksums = only_info_checksums
1112
end
1213

13-
def contents(gems = nil, args = {})
14-
gems = calculate_info_checksums(gems) if args.delete(:calculate_info_checksums) { false }
15-
16-
raise ArgumentError, "Unknown options: #{args.keys.join(", ")}" unless args.empty?
14+
def contents(gems = nil, calculate_info_checksums: false)
15+
gems = calculate_info_checksums(gems) if calculate_info_checksums
1716

1817
File.read(@path).tap do |out|
1918
out << gem_lines(gems) if gems
@@ -37,10 +36,12 @@ def create(gems, timestamp = Time.now.iso8601)
3736

3837
def gem_lines(gems)
3938
gems.reduce(+"") do |lines, gem|
40-
version_numbers = gem.versions.map(&:number_and_platform).join(",")
41-
lines << gem.name <<
42-
" " << version_numbers <<
43-
" #{gem.versions.last.info_checksum}\n"
39+
lines << gem.name
40+
unless @only_info_checksums
41+
version_numbers = gem.versions.map(&:number_and_platform).join(",")
42+
lines << " " << version_numbers
43+
end
44+
lines << " #{gem.versions.last.info_checksum}\n"
4445
end
4546
end
4647

spec/compact_index_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,19 @@
3737
end
3838
end
3939

40+
describe ".info_checksums" do
41+
it "delegates to VersionsFile#content" do
42+
file = Tempfile.new("versions-endpoint")
43+
versions_file = CompactIndex::VersionsFile.new(file.path, :only_info_checksums => true)
44+
gems = [CompactIndex::Gem.new("test", [build_version])]
45+
expect(
46+
CompactIndex.info_checksums(versions_file, gems)
47+
).to eq(
48+
versions_file.contents(gems)
49+
)
50+
end
51+
end
52+
4053
describe ".info" do
4154
it "without dependencies" do
4255
param = [build_version(:number => "1.0.1")]

spec/versions_file_spec.rb

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,82 @@
104104
end
105105
end
106106

107+
context "using the file with only_info_checksums" do
108+
let(:file) { Tempfile.new("create_versions.list") }
109+
let(:gems) do
110+
[
111+
CompactIndex::Gem.new("gem5", [build_version(:name => "gem5", :number => "1.0.1")]),
112+
CompactIndex::Gem.new("gem2", [
113+
build_version(:name => "gem2", :number => "1.0.1"),
114+
build_version(:name => "gem2", :number => "1.0.2", :platform => "arch"),
115+
]),
116+
]
117+
end
118+
let(:versions_file) { CompactIndex::VersionsFile.new(file.path, :only_info_checksums => true) }
119+
120+
describe "#create" do
121+
it "writes one line per gem" do
122+
expected_file_output = <<~INDEX
123+
created_at: #{now.iso8601}
124+
---
125+
gem2 info+gem2+1.0.2
126+
gem5 info+gem5+1.0.1
127+
INDEX
128+
versions_file.create(gems)
129+
expect(file.open.read).to eq(expected_file_output)
130+
end
131+
132+
it "adds the date on top" do
133+
versions_file.create(gems)
134+
expect(file.open.read).to start_with "created_at: #{now.iso8601}\n"
135+
end
136+
137+
it "orders gems by name" do
138+
file = Tempfile.new("versions-sort")
139+
versions_file = CompactIndex::VersionsFile.new(file.path, :only_info_checksums => true)
140+
gems = [
141+
CompactIndex::Gem.new("gem_b", [build_version]),
142+
CompactIndex::Gem.new("gem_a", [build_version]),
143+
]
144+
versions_file.create(gems)
145+
expect(file.open.read).to eq(<<~INDEX)
146+
created_at: #{now.iso8601}
147+
---
148+
gem_a info+test_gem+1.0
149+
gem_b info+test_gem+1.0
150+
INDEX
151+
end
152+
153+
it "uses the given version order" do
154+
file = Tempfile.new("versions-sort")
155+
versions_file = CompactIndex::VersionsFile.new(file.path, :only_info_checksums => true)
156+
gems = [
157+
CompactIndex::Gem.new("test",
158+
[
159+
build_version(:number => "1.3.0"),
160+
build_version(:number => "2.2"),
161+
build_version(:number => "1.1.1"),
162+
build_version(:number => "1.1.1"),
163+
build_version(:number => "2.1.2"),
164+
]),
165+
]
166+
versions_file.create(gems)
167+
expect(file.open.read).to include("test info+test_gem+2.1.2")
168+
end
169+
end
170+
171+
context "create with ts" do
172+
file = Tempfile.new
173+
versions_file = CompactIndex::VersionsFile.new(file.path)
174+
ts = Time.new(1999, 9, 9).iso8601
175+
176+
it "is used in created_at header" do
177+
versions_file.create([], ts)
178+
expect(file.open.read).to start_with("created_at: #{ts}")
179+
end
180+
end
181+
end
182+
107183
describe "#updated_at" do
108184
it "is epoch start when file does not exist" do
109185
expect(CompactIndex::VersionsFile.new("/tmp/doesntexist").updated_at).to eq(Time.at(0).to_datetime)
@@ -114,9 +190,10 @@
114190
end
115191

116192
it "is the created_at time when the header exists" do
117-
Tempfile.new("created_at_versions") do |tmp|
193+
Tempfile.create("created_at_versions") do |tmp|
118194
tmp.write("created_at: 2015-08-23T17:22:53-07:00\n---\ngem2 1.0.1\n")
119-
file = CompactIndex::VersionsFile.new(tmp.path).updated_at
195+
tmp.rewind
196+
file = CompactIndex::VersionsFile.new(tmp.path)
120197
expect(file.updated_at).to eq(DateTime.parse("2015-08-23T17:22:53-07:00"))
121198
end
122199
end

0 commit comments

Comments
 (0)