123456789_123456789_123456789_123456789_123456789_

Class: Bundler::LockfileParser

Relationships & Source Files
Namespace Children
Classes:
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
self, GemHelpers
Inherits: Object
Defined in: lib/bundler/lockfile_parser.rb

Constant Summary

GemHelpers - Included

GENERICS, GENERIC_CACHE

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(lockfile) ⇒ LockfileParser

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 97

def initialize(lockfile)
  @platforms    = []
  @sources      = []
  @dependencies = {}
  @parse_method = nil
  @specs        = {}
  @lockfile_path = begin
    SharedHelpers.relative_lockfile_path
  rescue GemfileNotFound
    "Gemfile.lock"
  end
  @pos = Position.new(1, 1)

  if lockfile.match?(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/)
    raise LockfileError, "Your #{@lockfile_path} contains merge conflicts.\n" \
      "Run `git checkout HEAD -- #{@lockfile_path}` first to get a clean lock."
  end

  lockfile.split(/((?:\r?\n)+)/) do |line|
    # split alternates between the line and the following whitespace
    next @pos.advance!(line) if line.match?(/^\s*$/)

    if SOURCE.include?(line)
      @parse_method = :parse_source
      parse_source(line)
    elsif line == DEPENDENCIES
      @parse_method = :parse_dependency
    elsif line == CHECKSUMS
      # This is a temporary solution to make this feature disabled by default
      # for all gemfiles that don't already explicitly include the feature.
      @checksums = true
      @parse_method = :parse_checksum
    elsif line == PLATFORMS
      @parse_method = :parse_platform
    elsif line == RUBY
      @parse_method = :parse_ruby
    elsif line == BUNDLED
      @parse_method = :parse_bundled_with
    elsif /^[^\s]/.match?(line)
      @parse_method = nil
    elsif @parse_method
      send(@parse_method, line)
    end
    @pos.advance!(line)
  end
  @most_specific_locked_platform = @platforms.min_by do |bundle_platform|
    platform_specificity_match(bundle_platform, local_platform)
  end
  @specs = @specs.values.sort_by!(&:full_name).each do |spec|
    spec.most_specific_locked_platform = @most_specific_locked_platform
  end
rescue ArgumentError => e
  Bundler.ui.debug(e)
  raise LockfileError, "Your lockfile is unreadable. Run `rm #{@lockfile_path}` " \
    "and then `bundle install` to generate a new lockfile. The error occurred while " \
    "evaluating #{@lockfile_path}:#{@pos}"
end

Class Method Details

.bundled_with

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 87

def self.bundled_with
  lockfile = Bundler.default_lockfile
  return unless lockfile.file?

  lockfile_contents = Bundler.read_file(lockfile)
  return unless lockfile_contents.include?(BUNDLED)

  lockfile_contents.split(BUNDLED).last.strip
end

.sections_in_lockfile(lockfile_contents)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 66

def self.sections_in_lockfile(lockfile_contents)
  sections = lockfile_contents.scan(/^\w[\w ]*$/)
  sections.uniq!
  sections
end

.sections_to_ignore(base_version = nil)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 76

def self.sections_to_ignore(base_version = nil)
  base_version &&= base_version.release
  base_version ||= Gem::Version.create("1.0")
  attributes = []
  SECTIONS_BY_VERSION_INTRODUCED.each do |version, introduced|
    next if version <= base_version
    attributes += introduced
  end
  attributes
end

.unknown_sections_in_lockfile(lockfile_contents)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 72

def self.unknown_sections_in_lockfile(lockfile_contents)
  sections_in_lockfile(lockfile_contents) - KNOWN_SECTIONS
end

Instance Attribute Details

#bundler_version (readonly)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 29

attr_reader(
  :sources,
  :dependencies,
  :specs,
  :platforms,
  :most_specific_locked_platform,
  :bundler_version,
  :ruby_version,
  :checksums,
)

#dependencies (readonly)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 29

attr_reader(
  :sources,
  :dependencies,
  :specs,
  :platforms,
  :most_specific_locked_platform,
  :bundler_version,
  :ruby_version,
  :checksums,
)

#may_include_redundant_platform_specific_gems?Boolean (readonly)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 155

def may_include_redundant_platform_specific_gems?
  bundler_version.nil? || bundler_version < Gem::Version.new("1.16.2")
end

#most_specific_locked_platform (readonly)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 29

attr_reader(
  :sources,
  :dependencies,
  :specs,
  :platforms,
  :most_specific_locked_platform,
  :bundler_version,
  :ruby_version,
  :checksums,
)

#platforms (readonly)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 29

attr_reader(
  :sources,
  :dependencies,
  :specs,
  :platforms,
  :most_specific_locked_platform,
  :bundler_version,
  :ruby_version,
  :checksums,
)

#ruby_version (readonly)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 29

attr_reader(
  :sources,
  :dependencies,
  :specs,
  :platforms,
  :most_specific_locked_platform,
  :bundler_version,
  :ruby_version,
  :checksums,
)

#sources (readonly)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 29

attr_reader(
  :sources,
  :dependencies,
  :specs,
  :platforms,
  :most_specific_locked_platform,
  :bundler_version,
  :ruby_version,
  :checksums,
)

#specs (readonly)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 29

attr_reader(
  :sources,
  :dependencies,
  :specs,
  :platforms,
  :most_specific_locked_platform,
  :bundler_version,
  :ruby_version,
  :checksums,
)

Instance Method Details

#parse_bundled_with(line) (private)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 286

def parse_bundled_with(line)
  line.strip!
  return unless Gem::Version.correct?(line)
  @bundler_version = Gem::Version.create(line)
end

#parse_checksum(line) (private)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 236

def parse_checksum(line)
  return unless line =~ NAME_VERSION

  spaces = $1
  return unless spaces.size == 2
  checksums = $6
  return unless checksums
  name = $2
  version = $3
  platform = $4

  version = Gem::Version.new(version)
  platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
  full_name = Gem::NameTuple.new(name, version, platform).full_name
  return unless spec = @specs[full_name]

  checksums.split(",") do |lock_checksum|
    column = line.index(lock_checksum) + 1
    checksum = Checksum.from_lock(lock_checksum, "#{@lockfile_path}:#{@pos.line}:#{column}")
    spec.source.checksum_store.register(spec, checksum)
  end
end

#parse_dependency(line) (private)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 207

def parse_dependency(line)
  return unless line =~ NAME_VERSION
  spaces = $1
  return unless spaces.size == 2
  name = -$2
  version = $3
  pinned = $5

  version = version.split(",").each(&:strip!) if version

  dep = Bundler::Dependency.new(name, version)

  if pinned && dep.name != "bundler"
    spec = @specs.find {|_, v| v.name == dep.name }
    dep.source = spec.last.source if spec

    # Path sources need to know what the default name / version
    # to use in the case that there are no gemspecs present. A fake
    # gemspec is created based on the version set on the dependency
    # TODO: Use the version from the spec instead of from the dependency
    if version && version.size == 1 && version.first =~ /^\s*= (.+)\s*$/ && dep.source.is_a?(Bundler::Source::Path)
      dep.source.name    = name
      dep.source.version = $1
    end
  end

  @dependencies[dep.name] = dep
end

#parse_platform(line) (private)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 282

def parse_platform(line)
  @platforms << Gem::Platform.new($1.strip) if line =~ /^  (.*)$/
end

#parse_ruby(line) (private)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 292

def parse_ruby(line)
  line.strip!
  @ruby_version = line
end

#parse_source(line) (private)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 168

def parse_source(line)
  case line
  when SPECS
    return unless TYPES.key?(@type)
    @current_source = TYPES[@type].from_lock(@opts)
    @sources << @current_source
  when OPTIONS
    value = $2
    value = true if value == "true"
    value = false if value == "false"

    key = $1

    if @opts[key]
      @opts[key] = Array(@opts[key])
      @opts[key] << value
    else
      @opts[key] = value
    end
  when *SOURCE
    @current_source = nil
    @opts = {}
    @type = line
  else
    parse_spec(line)
  end
end

#parse_spec(line) (private)

[ GitHub ]

  
# File 'lib/bundler/lockfile_parser.rb', line 259

def parse_spec(line)
  return unless line =~ NAME_VERSION
  spaces = $1
  name = -$2
  version = $3

  if spaces.size == 4
    # only load platform for non-dependency (spec) line
    platform = $4

    version = Gem::Version.new(version)
    platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
    @current_spec = LazySpecification.new(name, version, platform, @current_source)
    @current_source.add_dependency_names(name)

    @specs[@current_spec.full_name] = @current_spec
  elsif spaces.size == 6
    version = version.split(",").each(&:strip!) if version
    dep = Gem::Dependency.new(name, version)
    @current_spec.dependencies << dep
  end
end