Class: Bundler::LockfileParser

Inherits:
Object
  • Object
show all
Defined in:
lib/bundler/lockfile_parser.rb

Defined Under Namespace

Classes: Position

Constant Summary collapse

BUNDLED =
"BUNDLED WITH"
DEPENDENCIES =
"DEPENDENCIES"
CHECKSUMS =
"CHECKSUMS"
PLATFORMS =
"PLATFORMS"
RUBY =
"RUBY VERSION"
GIT =
"GIT"
GEM =
"GEM"
PATH =
"PATH"
PLUGIN =
"PLUGIN SOURCE"
SPECS =
"  specs:"
OPTIONS =
/^  ([a-z]+): (.*)$/i
SOURCE =
[GIT, GEM, PATH, PLUGIN].freeze
SECTIONS_BY_VERSION_INTRODUCED =
{
  Gem::Version.create("1.0") => [DEPENDENCIES, PLATFORMS, GIT, GEM, PATH].freeze,
  Gem::Version.create("1.10") => [BUNDLED].freeze,
  Gem::Version.create("1.12") => [RUBY].freeze,
  Gem::Version.create("1.13") => [PLUGIN].freeze,
  Gem::Version.create("2.5.0") => [CHECKSUMS].freeze,
}.freeze
KNOWN_SECTIONS =
SECTIONS_BY_VERSION_INTRODUCED.values.flatten!.freeze
ENVIRONMENT_VERSION_SECTIONS =
[BUNDLED, RUBY].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(lockfile) ⇒ LockfileParser

Returns a new instance of LockfileParser.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/bundler/lockfile_parser.rb', line 94

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
  @specs = @specs.values.sort_by!(&:full_name)
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

Instance Attribute Details

#bundler_versionObject (readonly)

Returns the value of attribute bundler_version.



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

def bundler_version
  @bundler_version
end

#dependenciesObject (readonly)

Returns the value of attribute dependencies.



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

def dependencies
  @dependencies
end

#platformsObject (readonly)

Returns the value of attribute platforms.



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

def platforms
  @platforms
end

#ruby_versionObject (readonly)

Returns the value of attribute ruby_version.



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

def ruby_version
  @ruby_version
end

#sourcesObject (readonly)

Returns the value of attribute sources.



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

def sources
  @sources
end

#specsObject (readonly)

Returns the value of attribute specs.



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

def specs
  @specs
end

Class Method Details

.bundled_withObject



84
85
86
87
88
89
90
91
92
# File 'lib/bundler/lockfile_parser.rb', line 84

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) ⇒ Object



63
64
65
66
67
# File 'lib/bundler/lockfile_parser.rb', line 63

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

.sections_to_ignore(base_version = nil) ⇒ Object



73
74
75
76
77
78
79
80
81
82
# File 'lib/bundler/lockfile_parser.rb', line 73

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) ⇒ Object



69
70
71
# File 'lib/bundler/lockfile_parser.rb', line 69

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

Instance Method Details

#may_include_redundant_platform_specific_gems?Boolean

Returns:

  • (Boolean)


147
148
149
# File 'lib/bundler/lockfile_parser.rb', line 147

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