summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSutou Kouhei <kou@clear-code.com>2020-01-08 06:53:52 +0900
committerSutou Kouhei <kou@clear-code.com>2020-01-12 07:27:48 +0900
commit1478b3525977447dbf06135dbdf6d9978aa637b6 (patch)
tree80167a075558ce90b69d29aa6143402e0a0f651f
parent971d39b32d3ec8bfcdc951061c88e364f864423e (diff)
downloadbundler-1478b3525977447dbf06135dbdf6d9978aa637b6.tar.gz
Fix ruby version parsing in compact index
We can't use the same logic as "dependencies" for "requirements". Because "," in "requirements" isn't escaped as "&".
-rw-r--r--lib/bundler/compact_index_client/cache.rb18
-rw-r--r--lib/bundler/compact_index_client/gem_parser.rb66
-rw-r--r--spec/bundler/compact_index_client/gem_parser_spec.rb174
3 files changed, 245 insertions, 13 deletions
diff --git a/lib/bundler/compact_index_client/cache.rb b/lib/bundler/compact_index_client/cache.rb
index f6105d3bb3..af3522e609 100644
--- a/lib/bundler/compact_index_client/cache.rb
+++ b/lib/bundler/compact_index_client/cache.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require_relative "gem_parser"
+
module Bundler
class CompactIndexClient
class Cache
@@ -92,19 +94,9 @@ module Bundler
header ? lines[header + 1..-1] : lines
end
- def parse_gem(string)
- version_and_platform, rest = string.split(" ", 2)
- version, platform = version_and_platform.split("-", 2)
- dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest
- dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : []
- requirements = requirements ? requirements.map {|r| parse_dependency(r) } : []
- [version, platform, dependencies, requirements]
- end
-
- def parse_dependency(string)
- dependency = string.split(":")
- dependency[-1] = dependency[-1].split("&") if dependency.size > 1
- dependency
+ def parse_gem(line)
+ @dependency_parser ||= GemParser.new
+ @dependency_parser.parse(line)
end
def info_roots
diff --git a/lib/bundler/compact_index_client/gem_parser.rb b/lib/bundler/compact_index_client/gem_parser.rb
new file mode 100644
index 0000000000..117da64ce6
--- /dev/null
+++ b/lib/bundler/compact_index_client/gem_parser.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+module Bundler
+ class CompactIndexClient
+ class GemParser
+ def parse(line)
+ version_and_platform, rest = line.split(" ", 2)
+ version, platform = version_and_platform.split("-", 2)
+ dependencies, requirements = rest.split("|", 2) if rest
+ dependencies = dependencies ? parse_dependencies(dependencies) : []
+ requirements = requirements ? parse_requirements(requirements) : []
+ [version, platform, dependencies, requirements]
+ end
+
+ private
+
+ def parse_dependencies(raw_dependencies)
+ raw_dependencies.split(",").map {|d| parse_dependency(d) }
+ end
+
+ def parse_dependency(raw_dependency)
+ dependency = raw_dependency.split(":")
+ dependency[-1] = dependency[-1].split("&") if dependency.size > 1
+ dependency
+ end
+
+ # Parse the following format:
+ #
+ # line = "checksum:#{checksum}"
+ # line << ",ruby:#{ruby_version}" if ruby_version && ruby_version != ">= 0"
+ # line << ",rubygems:#{rubygems_version}" if rubygems_version && rubygems_version != ">= 0"
+ #
+ # See compact_index/gem_version.rb for details.
+ #
+ # We can't use parse_dependencies for requirements because "," in
+ # ruby_version and rubygems_version isn't escaped as "&". For example,
+ # "checksum:XXX,ruby:>=2.2, < 2.7.dev" can't be parsed as expected.
+ def parse_requirements(raw_requirements)
+ requirements = []
+ checksum = raw_requirements.match(/\A(checksum):([^,]+)/)
+ if checksum
+ requirements << [checksum[1], [checksum[2]]]
+ raw_requirements = checksum.post_match
+ if raw_requirements.start_with?(",")
+ raw_requirements = raw_requirements[1..-1]
+ end
+ end
+ rubygems = raw_requirements.match(/(rubygems):(.+)\z/)
+ if rubygems
+ raw_requirements = rubygems.pre_match
+ if raw_requirements.start_with?(",")
+ raw_requirements = raw_requirements[1..-1]
+ end
+ end
+ ruby = raw_requirements.match(/\A(ruby):(.+)\z/)
+ if ruby
+ requirements << [ruby[1], ruby[2].split(/\s*,\s*/)]
+ end
+ if rubygems
+ requirements << [rubygems[1], rubygems[2].split(/\s*,\s*/)]
+ end
+ requirements
+ end
+ end
+ end
+end
diff --git a/spec/bundler/compact_index_client/gem_parser_spec.rb b/spec/bundler/compact_index_client/gem_parser_spec.rb
new file mode 100644
index 0000000000..5f5305426f
--- /dev/null
+++ b/spec/bundler/compact_index_client/gem_parser_spec.rb
@@ -0,0 +1,174 @@
+# frozen_string_literal: true
+
+require "bundler/compact_index_client/gem_parser"
+
+RSpec.describe Bundler::CompactIndexClient::GemParser do
+ def parse(line)
+ parser = Bundler::CompactIndexClient::GemParser.new
+ parser.parse(line)
+ end
+
+ context "platform" do
+ it "existent" do
+ checksum = "d5956d2bcb509af2cd07c90d9e5fdb331be8845a75bfd823a31c147b52cff471"
+ line = "1.11.3-java |checksum:#{checksum}"
+ expected = [
+ "1.11.3",
+ "java",
+ [],
+ [
+ ["checksum", [checksum]],
+ ],
+ ]
+ expect(parse(line)).to eq expected
+ end
+
+ it "nonexistent" do
+ checksum = "6da2eb3c4867e64df28d3e0b1008422dfacda7c046f9a8f3c56c52505b195e81"
+ line = "1.11.3 |checksum:#{checksum}"
+ expected = [
+ "1.11.3",
+ nil,
+ [],
+ [
+ ["checksum", [checksum]],
+ ],
+ ]
+ expect(parse(line)).to eq expected
+ end
+ end
+
+ context "dependencies" do
+ it "nothing" do
+ checksum = "6da2eb3c4867e64df28d3e0b1008422dfacda7c046f9a8f3c56c52505b195e81"
+ line = "1.11.3 |checksum:#{checksum}"
+ expected = [
+ "1.11.3",
+ nil,
+ [],
+ [
+ ["checksum", [checksum]],
+ ],
+ ]
+ expect(parse(line)).to eq expected
+ end
+
+ it "one" do
+ checksum = "5f0b378d12ab5665e2b6a1525274de97350238963002583cf088dae988527647"
+ line = "0.3.2 bones:>= 2.4.2|checksum:#{checksum}"
+ expected = [
+ "0.3.2",
+ nil,
+ [
+ ["bones", [">= 2.4.2"]],
+ ],
+ [
+ ["checksum", [checksum]],
+ ],
+ ]
+ expect(parse(line)).to eq expected
+ end
+
+ it "multiple" do
+ checksum = "199e892ada86c44d1f2e110b822d5da46b52fa2cbd2f00d89695b4cf610f9927"
+ line = "3.1.2 native-package-installer:>= 0,pkg-config:>= 0|checksum:#{checksum}"
+ expected = [
+ "3.1.2",
+ nil,
+ [
+ ["native-package-installer", [">= 0"]],
+ ["pkg-config", [">= 0"]],
+ ],
+ [
+ ["checksum", [checksum]],
+ ],
+ ]
+ expect(parse(line)).to eq expected
+ end
+
+ context "version" do
+ it "multiple" do
+ checksum = "1ec894b8090cb2c9393153552be2f3b6b1975265cbc1e0a3c6b28ebfea7e76a1"
+ line = "3.1.5 multi_json:< 1.3&>= 1.0|checksum:#{checksum}"
+ expected = [
+ "3.1.5",
+ nil,
+ [
+ ["multi_json", ["< 1.3", ">= 1.0"]],
+ ],
+ [
+ ["checksum", [checksum]],
+ ],
+ ]
+ expect(parse(line)).to eq expected
+ end
+ end
+ end
+
+ context "requirements" do
+ context "ruby" do
+ it "one version" do
+ checksum ="6da2eb3c4867e64df28d3e0b1008422dfacda7c046f9a8f3c56c52505b195e81"
+ line = "1.11.3 |checksum:#{checksum},ruby:>= 2.0"
+ expected = [
+ "1.11.3",
+ nil,
+ [],
+ [
+ ["checksum", [checksum]],
+ ["ruby", [">= 2.0"]],
+ ],
+ ]
+ expect(parse(line)).to eq expected
+ end
+
+ it "multiple versions" do
+ checksum = "99e4845796c8dec1c3fc80dc772860a01633b33291bd7534007f5c7724f0b876"
+ line = "1.11.3-x86-mingw32 |checksum:#{checksum},ruby:>= 2.2, < 2.7.dev"
+ expected = [
+ "1.11.3",
+ "x86-mingw32",
+ [],
+ [
+ ["checksum", [checksum]],
+ ["ruby", [">= 2.2", "< 2.7.dev"]],
+ ],
+ ]
+ expect(parse(line)).to eq expected
+ end
+
+ it "with rubygems" do
+ checksum = "7a82b358f00da749b01f8c84df8e8eb21c1bc389740aab9a2bf4ce59894564ac"
+ line = "1.9.23.pre1 |checksum:#{checksum},ruby:>= 1.9, < 2.7.dev,rubygems:> 1.3.1"
+ expected = [
+ "1.9.23.pre1",
+ nil,
+ [],
+ [
+ ["checksum", [checksum]],
+ ["ruby", [">= 1.9", "< 2.7.dev"]],
+ ["rubygems", ["> 1.3.1"]],
+ ],
+ ]
+ expect(parse(line)).to eq expected
+ end
+ end
+
+ context "rubygems" do
+ it "existent" do
+ checksum = "91ddb4c1b5482a4aff957f6733e282ce2767b2d3051138e0203e39d6df4eba10"
+ line = "1.0.12.pre |checksum:#{checksum},rubygems:> 1.3.1"
+ expected = [
+ "1.0.12.pre",
+ nil,
+ [],
+ [
+ ["checksum", [checksum]],
+ ["rubygems", ["> 1.3.1"]],
+ ],
+ ]
+ expect(parse(line)).to eq expected
+ end
+ end
+ end
+end