Class: Bundler::Definition
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Instance Chain:
self,
GemHelpers
|
|
Inherits: | Object |
Defined in: | lib/bundler/definition.rb |
Constant Summary
GemHelpers
- Included
Class Method Summary
-
.build(gemfile, lockfile, unlock) ⇒ Bundler::Definition
Given a gemfile and lockfile creates a
::Bundler
definition. -
.new(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = []) ⇒ Definition
constructor
How does the new system work?
Instance Attribute Summary
- #dependencies readonly
- #gemfiles readonly
- #locked_deps readonly
- #locked_gems readonly
- #lockfile readonly
- #missing_specs readonly
- #missing_specs? ⇒ Boolean readonly
- #nothing_changed? ⇒ Boolean readonly
- #platforms readonly
- #requires readonly
- #ruby_version readonly
- #unlocking? ⇒ Boolean readonly
- #current_platform_locked? ⇒ Boolean readonly private
- #current_ruby_platform_locked? ⇒ Boolean readonly private
- #precompute_source_requirements_for_indirect_dependencies? ⇒ Boolean readonly private
- #sources readonly private
Instance Method Summary
- #add_platform(platform)
- #current_dependencies
- #dependencies_for(groups)
- #ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
- #gem_version_promoter
- #groups
- #lock(file, preserve_unknown_sections = false)
- #locked_bundler_version
- #locked_dependencies
- #locked_ruby_version
- #locked_ruby_version_object
- #most_specific_locked_platform
- #new_specs
- #remove_platform(platform)
- #removed_specs
- #requested_dependencies
- #requested_specs
-
#resolve ⇒ SpecSet
Resolve all the dependencies specified in Gemfile.
- #resolve_only_locally!
- #resolve_remotely!
- #resolve_with_cache!
- #spec_git_paths
-
#specs ⇒ Bundler::SpecSet
For given dependency list returns a
SpecSet
with Gemspec of all the required dependencies. - #specs_for(groups)
- #to_lock
- #validate_platforms!
- #validate_ruby!
- #validate_runtime!
- #add_current_platform private
- #additional_base_requirements_for_resolve private
- #change_reason private
- #compute_requires private
- #converge_dependencies private
-
#converge_locals
private
Get all locals and override their matching sources.
-
#converge_locked_specs
private
Remove elements from the locked specs that are expired.
- #converge_path_source_to_gemspec_source(source) private
- #converge_path_sources_to_gemspec_sources private
- #converge_paths private
- #converge_sources private
- #converge_specs(specs) private
- #dependencies_for_source_changed?(source, locked_source = source) ⇒ Boolean private
- #expand_dependencies(dependencies, remote = false) private
- #expand_dependency_with_platforms(dep, platforms) private
- #lockfiles_equal?(current, proposed, preserve_unknown_sections) ⇒ Boolean private
- #materialize(dependencies) private
- #metadata_dependencies private
- #pretty_dep(dep, source = false) private
- #requested_groups private
- #ruby_version_requirements(ruby_version) private
- #source_map private
- #source_requirements private
-
#specs_changed?(source) ⇒ Boolean
private
Check if the specs of the given source changed according to the locked source.
- #specs_for_source_changed?(source) ⇒ Boolean private
GemHelpers
- Included
Constructor Details
.new(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = []) ⇒ Definition
How does the new system work?
-
Load information from Gemfile and Lockfile
-
Invalidate stale locked specs
-
All specs from stale source are stale
-
All specs that are reachable only through a stale dependency are stale.
-
If all fresh dependencies are satisfied by the locked
specs, then we can try to resolve locally.
# File 'lib/bundler/definition.rb', line 54
def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = []) if [true, false].include?(unlock) @unlocking_bundler = false @unlocking = unlock else @unlocking_bundler = unlock.delete(:bundler) @unlocking = unlock.any? {|_k, v| !Array(v).empty? } end @dependencies = dependencies @sources = sources @unlock = unlock @optional_groups = optional_groups @remote = false @specs = nil @ruby_version = ruby_version @gemfiles = gemfiles @lockfile = lockfile @lockfile_contents = String.new @locked_bundler_version = nil @locked_ruby_version = nil @new_platform = nil if lockfile && File.exist?(lockfile) @lockfile_contents = Bundler.read_file(lockfile) @locked_gems = LockfileParser.new(@lockfile_contents) @locked_platforms = @locked_gems.platforms @platforms = @locked_platforms.dup @locked_bundler_version = @locked_gems.bundler_version @locked_ruby_version = @locked_gems.ruby_version if unlock != true @locked_deps = @locked_gems.dependencies @locked_specs = SpecSet.new(@locked_gems.specs) @locked_sources = @locked_gems.sources else @unlock = {} @locked_deps = {} @locked_specs = SpecSet.new([]) @locked_sources = [] end else @unlock = {} @platforms = [] @locked_gems = nil @locked_deps = {} @locked_specs = SpecSet.new([]) @locked_sources = [] @locked_platforms = [] end locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } @multisource_allowed = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? && Bundler.frozen_bundle? if @multisource_allowed unless sources.aggregate_global_source? msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure." Bundler::SharedHelpers.major_deprecation 2, msg end @sources.merged_gem_lockfile_sections!(locked_gem_sources.first) end @unlock[:sources] ||= [] @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object @ruby_version.diff(locked_ruby_version_object) end @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version) add_current_platform unless current_ruby_platform_locked? || Bundler.frozen_bundle? converge_path_sources_to_gemspec_sources @path_changes = converge_paths @source_changes = converge_sources if @unlock[:conservative] @unlock[:gems] ||= @dependencies.map(&:name) else eager_unlock = (@unlock[:gems] || [], true) @unlock[:gems] = @locked_specs.for(eager_unlock, false, false).map(&:name) end @dependency_changes = converge_dependencies @local_changes = converge_locals @locked_specs_incomplete_for_platform = !@locked_specs.for(requested_dependencies & (locked_dependencies), true, true) @requires = compute_requires end
Class Method Details
.build(gemfile, lockfile, unlock) ⇒ Definition
Given a gemfile and lockfile creates a ::Bundler
definition
Instance Attribute Details
#current_platform_locked? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/bundler/definition.rb', line 501
def current_platform_locked? @platforms.any? do |bundle_platform| MatchPlatform.platforms_match?(bundle_platform, Bundler.local_platform) end end
#current_ruby_platform_locked? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/bundler/definition.rb', line 495
def current_ruby_platform_locked? return false unless generic_local_platform == Gem::Platform::RUBY current_platform_locked? end
#dependencies (readonly)
[ GitHub ]# File 'lib/bundler/definition.rb', line 9
attr_reader( :dependencies, :locked_deps, :locked_gems, :platforms, :requires, :ruby_version, :lockfile, :gemfiles )
#gemfiles (readonly)
[ GitHub ]# File 'lib/bundler/definition.rb', line 9
attr_reader( :dependencies, :locked_deps, :locked_gems, :platforms, :requires, :ruby_version, :lockfile, :gemfiles )
#locked_deps (readonly)
[ GitHub ]# File 'lib/bundler/definition.rb', line 9
attr_reader( :dependencies, :locked_deps, :locked_gems, :platforms, :requires, :ruby_version, :lockfile, :gemfiles )
#locked_gems (readonly)
[ GitHub ]# File 'lib/bundler/definition.rb', line 9
attr_reader( :dependencies, :locked_deps, :locked_gems, :platforms, :requires, :ruby_version, :lockfile, :gemfiles )
#lockfile (readonly)
[ GitHub ]# File 'lib/bundler/definition.rb', line 9
attr_reader( :dependencies, :locked_deps, :locked_gems, :platforms, :requires, :ruby_version, :lockfile, :gemfiles )
#missing_specs (readonly)
[ GitHub ]# File 'lib/bundler/definition.rb', line 196
def missing_specs resolve.materialize(requested_dependencies).missing_specs end
#missing_specs? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/bundler/definition.rb', line 200
def missing_specs? missing = missing_specs return false if missing.empty? Bundler.ui.debug "The definition is missing #{missing.map(&:full_name)}" true rescue BundlerError => e @resolve = nil @specs = nil @gem_version_promoter = nil Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})" true end
#nothing_changed? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/bundler/definition.rb', line 456
def nothing_changed? !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform end
#platforms (readonly)
[ GitHub ]# File 'lib/bundler/definition.rb', line 9
attr_reader( :dependencies, :locked_deps, :locked_gems, :platforms, :requires, :ruby_version, :lockfile, :gemfiles )
#precompute_source_requirements_for_indirect_dependencies? ⇒ Boolean
(readonly, private)
[ GitHub ]
#requires (readonly)
[ GitHub ]# File 'lib/bundler/definition.rb', line 9
attr_reader( :dependencies, :locked_deps, :locked_gems, :platforms, :requires, :ruby_version, :lockfile, :gemfiles )
#ruby_version (readonly)
[ GitHub ]# File 'lib/bundler/definition.rb', line 9
attr_reader( :dependencies, :locked_deps, :locked_gems, :platforms, :requires, :ruby_version, :lockfile, :gemfiles )
#sources (readonly, private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 453
attr_reader :sources
#unlocking? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/bundler/definition.rb', line 460
def unlocking? @unlocking end
Instance Method Details
#add_current_platform (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 507
def add_current_platform add_platform(local_platform) end
#add_platform(platform)
[ GitHub ]# File 'lib/bundler/definition.rb', line 437
def add_platform(platform) @new_platform ||= !@platforms.include?(platform) @platforms |= [platform] end
#additional_base_requirements_for_resolve (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 819
def additional_base_requirements_for_resolve return [] unless @locked_gems && unlocking? && !sources.expired_sources?(@locked_gems.sources) converge_specs(@locked_gems.specs).map do |locked_spec| name = locked_spec.name dep = Gem::Dependency.new(name, ">= #{locked_spec.version}") DepProxy.get_proxy(dep, locked_spec.platform) end end
#change_reason (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 511
def change_reason if unlocking? unlock_reason = @unlock.reject {|_k, v| Array(v).empty? }.map do |k, v| if v == true k.to_s else v = Array(v) "#{k}: (#{v.join(", ")})" end end.join(", ") return "bundler is unlocking #{unlock_reason}" end [ [@source_changes, "the list of sources changed"], [@dependency_changes, "the dependencies in your gemfile changed"], [@new_platform, "you added a new platform to your gemfile"], [@path_changes, "the gemspecs for path gems changed"], [@local_changes, "the gemspecs for git local gems changed"], [@locked_specs_incomplete_for_platform, "the lockfile does not have all gems needed for the current platform"], ].select(&:first).map(&:last).join(", ") end
#compute_requires (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 808
def compute_requires dependencies.reduce({}) do |requires, dep| next requires unless dep.should_include? requires[dep.name] = Array(dep.autorequire || dep.name).map do |file| # Allow `require: true` as an alias for `require: <name>` file == true ? dep.name : file end requires end end
#converge_dependencies (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 629
def converge_dependencies changes = false @dependencies.each do |dep| if dep.source dep.source = sources.get(dep.source) end unless locked_dep = @locked_deps[dep.name] changes = true next end # Gem::Dependency#== matches Gem::Dependency#type. As the lockfile # doesn't carry a notion of the dependency type, if you use # add_development_dependency in a gemspec that's loaded with the gemspec # directive, the lockfile dependencies and resolved dependencies end up # with a mismatch on #type. Work around that by setting the type on the # dep from the lockfile. locked_dep.instance_variable_set(:@type, dep.type) # We already know the name matches from the hash lookup # so we only need to check the requirement now changes ||= dep.requirement != locked_dep.requirement end changes end
#converge_locals (private)
Get all locals and override their matching sources. Return true if any of the locals changed (for example, they point to a new revision) or depend on new specs.
# File 'lib/bundler/definition.rb', line 566
def converge_locals locals = [] Bundler.settings.local_overrides.map do |k, v| spec = @dependencies.find {|s| s.name == k } source = spec && spec.source if source && source.respond_to?(:local_override!) source.unlock! if @unlock[:gems].include?(spec.name) locals << [source, source.local_override!(v)] end end sources_with_changes = locals.select do |source, changed| changed || specs_changed?(source) end.map(&:first) !sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty? end
#converge_locked_specs (private)
Remove elements from the locked specs that are expired. This will most commonly happen if the Gemfile has changed since the lockfile was last generated
# File 'lib/bundler/definition.rb', line 661
def converge_locked_specs resolve = converge_specs(@locked_specs) diff = nil # Now, we unlock any sources that do not have anymore gems pinned to it sources.all_sources.each do |source| next unless source.respond_to?(:unlock!) unless resolve.any? {|s| s.source == source } diff ||= @locked_specs.to_a - resolve.to_a source.unlock! if diff.any? {|s| s.source == source } end end resolve end
#converge_path_source_to_gemspec_source(source) (private)
[ GitHub ]#converge_path_sources_to_gemspec_sources (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 596
def converge_path_sources_to_gemspec_sources @locked_sources.map! do |source| converge_path_source_to_gemspec_source(source) end @locked_specs.each do |spec| spec.source &&= converge_path_source_to_gemspec_source(spec.source) end @locked_deps.each do |_, dep| dep.source &&= converge_path_source_to_gemspec_source(dep.source) end end
#converge_paths (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 584
def converge_paths sources.path_sources.any? do |source| specs_changed?(source) end end
#converge_sources (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 608
def converge_sources # Replace the sources from the Gemfile with the sources from the Gemfile.lock, # if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent # source in the Gemfile.lock, use the one from the Gemfile. changes = sources.replace_sources!(@locked_sources) sources.all_sources.each do |source| # If the source is unlockable and the current command allows an unlock of # the source (for example, you are doing a `bundle update <foo>` of a git-pinned # gem), unlock it. For git sources, this means to unlock the revision, which # will cause the `ref` used to be the most recent for the branch (or master) if # an explicit `ref` is not used. if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name) source.unlock! changes = true end end changes end
#converge_specs(specs) (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 679
def converge_specs(specs) deps = [] converged = [] specs.each do |s| # Replace the locked dependency's source with the equivalent source from the Gemfile dep = @dependencies.find {|d| s.satisfies?(d) } if dep && (!dep.source || s.source.include?(dep.source)) deps << dep end s.source = (dep && dep.source) || sources.get(s.source) || sources.default_source unless Bundler.frozen_bundle? next if @unlock[:sources].include?(s.source.name) # If the spec is from a path source and it doesn't exist anymore # then we unlock it. # Path sources have special logic if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec) new_specs = begin s.source.specs rescue PathError, GitError # if we won't need the source (according to the lockfile), # don't error if the path/git source isn't available next if specs. for(requested_dependencies, false, true). none? {|locked_spec| locked_spec.source == s.source } raise end new_spec = new_specs[s].first # If the spec is no longer in the path source, unlock it. This # commonly happens if the version changed in the gemspec next unless new_spec s.dependencies.replace(new_spec.dependencies) end if dep.nil? && requested_dependencies.find {|d| s.name == d.name } @unlock[:gems] << s.name else converged << s end end resolve = SpecSet.new(converged) SpecSet.new(resolve.for( (deps, true), false, false).reject{|s| @unlock[:gems].include?(s.name) }) end
#current_dependencies
[ GitHub ]# File 'lib/bundler/definition.rb', line 222
def current_dependencies dependencies.select do |d| d.should_include? && !d.gem_platforms(@platforms).empty? end end
#dependencies_for(groups)
[ GitHub ]# File 'lib/bundler/definition.rb', line 238
def dependencies_for(groups) groups.map!(&:to_sym) deps = current_dependencies.reject do |d| (d.groups & groups).empty? end (deps) end
#dependencies_for_source_changed?(source, locked_source = source) ⇒ Boolean
(private)
# File 'lib/bundler/definition.rb', line 545
def dependencies_for_source_changed?(source, locked_source = source) deps_for_source = @dependencies.select {|s| s.source == source } locked_deps_for_source = locked_dependencies.select {|dep| dep.source == locked_source } deps_for_source.uniq.sort != locked_deps_for_source.sort end
#ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
# File 'lib/bundler/definition.rb', line 342
def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false) msg = String.new msg << "You are trying to install in deployment mode after changing\n" \ "your Gemfile. Run `bundle install` elsewhere and add the\n" \ "updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control." unless explicit_flag suggested_command = if Bundler.settings.locations("frozen").keys.&([:global, :local]).any? "bundle config unset frozen" elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any? "bundle config unset deployment" end msg << "\n\nIf this is a development machine, remove the #{Bundler.default_gemfile} " \ "freeze \nby running `#{suggested_command}`." end added = [] deleted = [] changed = [] new_platforms = @platforms - @locked_platforms deleted_platforms = @locked_platforms - @platforms added.concat new_platforms.map {|p| "* platform: #{p}" } deleted.concat deleted_platforms.map {|p| "* platform: #{p}" } new_deps = @dependencies - locked_dependencies deleted_deps = locked_dependencies - @dependencies added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any? deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } if deleted_deps.any? both_sources = Hash.new {|h, k| h[k] = [] } @dependencies.each {|d| both_sources[d.name][0] = d } locked_dependencies.each {|d| both_sources[d.name][1] = d } both_sources.each do |name, (dep, lock_dep)| next if dep.nil? || lock_dep.nil? gemfile_source = dep.source || sources.default_source lock_source = lock_dep.source || sources.default_source next if lock_source.include?(gemfile_source) gemfile_source_name = dep.source ? gemfile_source.identifier : "no specified source" lockfile_source_name = lock_dep.source ? lock_source.identifier : "no specified source" changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`" end reason = change_reason msg << "\n\n#{reason.split(", ").map(&:capitalize).join("\n")}" unless reason.strip.empty? msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any? msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any? msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any? msg << "\n" raise ProductionError, msg if added.any? || deleted.any? || changed.any? || !nothing_changed? end
#expand_dependencies(dependencies, remote = false) (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 757
def (dependencies, remote = false) deps = [] dependencies.each do |dep| dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name) next unless remote || dep.current_platform? target_platforms = dep.gem_platforms(remote ? @platforms : [generic_local_platform]) deps += (dep, target_platforms) end deps end
#expand_dependency_with_platforms(dep, platforms) (private)
[ GitHub ]#gem_version_promoter
[ GitHub ]# File 'lib/bundler/definition.rb', line 146
def gem_version_promoter @gem_version_promoter ||= begin locked_specs = if unlocking? && @locked_specs.empty? && !@lockfile_contents.empty? # Definition uses an empty set of locked_specs to indicate all gems # are unlocked, but GemVersionPromoter needs the locked_specs # for conservative comparison. Bundler::SpecSet.new(@locked_gems.specs) else @locked_specs end GemVersionPromoter.new(locked_specs, @unlock[:gems]) end end
#groups
[ GitHub ]# File 'lib/bundler/definition.rb', line 273
def groups dependencies.map(&:groups).flatten.uniq end
#lock(file, preserve_unknown_sections = false)
[ GitHub ]# File 'lib/bundler/definition.rb', line 277
def lock(file, preserve_unknown_sections = false) contents = to_lock # Convert to \r\n if the existing lock has them # i.e., Windows with `git config core.autocrlf=true` contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match("\r\n") if @locked_bundler_version locked_major = @locked_bundler_version.segments.first current_major = Gem::Version.create(Bundler::VERSION).segments.first if updating_major = locked_major < current_major Bundler.ui.warn "Warning: the lockfile is being updated to Bundler #{current_major}, " \ "after which you will be unable to return to Bundler #{@locked_bundler_version.segments.first}." end end preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler)) return if file && File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections) if Bundler.frozen_bundle? Bundler.ui.error "Cannot write a changed lockfile while frozen." return end SharedHelpers.filesystem_access(file) do |p| File.open(p, "wb") {|f| f.puts(contents) } end end
#locked_bundler_version
[ GitHub ]#locked_dependencies
[ GitHub ]# File 'lib/bundler/definition.rb', line 228
def locked_dependencies @locked_deps.values end
#locked_ruby_version
[ GitHub ]# File 'lib/bundler/definition.rb', line 316
def locked_ruby_version return unless ruby_version if @unlock[:ruby] || !@locked_ruby_version Bundler::RubyVersion.system else @locked_ruby_version end end
#locked_ruby_version_object
[ GitHub ]# File 'lib/bundler/definition.rb', line 325
def locked_ruby_version_object return unless @locked_ruby_version @locked_ruby_version_object ||= begin unless version = RubyVersion.from_string(@locked_ruby_version) raise LockfileError, "The Ruby version #{@locked_ruby_version} from " \ "#{@lockfile} could not be parsed. " \ "Try running bundle update --ruby to resolve this." end version end end
#lockfiles_equal?(current, proposed, preserve_unknown_sections) ⇒ Boolean
(private)
# File 'lib/bundler/definition.rb', line 795
def lockfiles_equal?(current, proposed, preserve_unknown_sections) if preserve_unknown_sections sections_to_ignore = LockfileParser.sections_to_ignore(@locked_bundler_version) sections_to_ignore += LockfileParser.unknown_sections_in_lockfile(current) sections_to_ignore += LockfileParser::ENVIRONMENT_VERSION_SECTIONS pattern = /#{Regexp.union(sections_to_ignore)}\n(\s{2,}.*\n)+/ whitespace_cleanup = /\n{2,}/ current = current.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip proposed = proposed.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip end current == proposed end
#materialize(dependencies) (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 466
def materialize(dependencies) specs = resolve.materialize(dependencies) missing_specs = specs.missing_specs if missing_specs.any? missing_specs.each do |s| locked_gem = @locked_specs[s.name].last next if locked_gem.nil? || locked_gem.version != s.version || !@remote raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \ "no longer be found in that source. That means the author of #{locked_gem} has removed it. " \ "You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \ "removed in order to install." end raise GemNotFound, "Could not find #{missing_specs.map(&:full_name).join(", ")} in any of the sources" end unless specs["bundler"].any? bundler = sources. .specs.search(Gem::Dependency.new("bundler", VERSION)).last specs["bundler"] = bundler end specs end
#metadata_dependencies (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 731
def @metadata_dependencies ||= begin ruby_versions = ruby_version_requirements(@ruby_version) [ Dependency.new("Ruby\0", ruby_versions), Dependency.new("RubyGems\0", Gem::VERSION), ] end end
#most_specific_locked_platform
[ GitHub ]# File 'lib/bundler/definition.rb', line 447
def most_specific_locked_platform @platforms.min_by do |bundle_platform| platform_specificity_match(bundle_platform, local_platform) end end
#new_specs
[ GitHub ]# File 'lib/bundler/definition.rb', line 188
def new_specs specs - @locked_specs end
#pretty_dep(dep, source = false) (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 533
def pretty_dep(dep, source = false) SharedHelpers.pretty_dependency(dep, source) end
#remove_platform(platform)
# File 'lib/bundler/definition.rb', line 442
def remove_platform(platform) return if @platforms.delete(Gem::Platform.new(platform)) raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}" end
#removed_specs
[ GitHub ]# File 'lib/bundler/definition.rb', line 192
def removed_specs @locked_specs - specs end
#requested_dependencies
[ GitHub ]# File 'lib/bundler/definition.rb', line 218
def requested_dependencies dependencies_for(requested_groups) end
#requested_groups (private)
[ GitHub ]#requested_specs
[ GitHub ]# File 'lib/bundler/definition.rb', line 214
def requested_specs specs_for(requested_groups) end
#resolve ⇒ SpecSet
Resolve all the dependencies specified in Gemfile. It ensures that dependencies that have been already resolved via locked file and are fresh are reused when resolving dependencies
# File 'lib/bundler/definition.rb', line 251
def resolve @resolve ||= begin last_resolve = converge_locked_specs if Bundler.frozen_bundle? Bundler.ui.debug "Frozen, using resolution from the lockfile" last_resolve elsif !unlocking? && nothing_changed? Bundler.ui.debug("Found no changes, using resolution from the lockfile") last_resolve else # Run a resolve against the locally available gems Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}") = (dependencies + , @remote) Resolver.resolve(, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) end end end
#resolve_only_locally!
[ GitHub ]#resolve_remotely!
[ GitHub ]#resolve_with_cache!
[ GitHub ]#ruby_version_requirements(ruby_version) (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 741
def ruby_version_requirements(ruby_version) return [] unless ruby_version if ruby_version.patchlevel [ruby_version.to_gem_version_with_patchlevel] else ruby_version.versions.map do |version| requirement = Gem::Requirement.new(version) if requirement.exact? "~> #{version}.0" else requirement end end end end
#source_map (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 828
def source_map @source_map ||= SourceMap.new(sources, dependencies) end
#source_requirements (private)
[ GitHub ]# File 'lib/bundler/definition.rb', line 774
def source_requirements # Record the specs available in each gem's source, so that those # specs will be available later when the resolver knows where to # look for that gemspec (or its dependencies) source_requirements = if precompute_source_requirements_for_indirect_dependencies? { :default => sources.default_source }.merge(source_map.all_requirements) else { :default => Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements) end .each do |dep| source_requirements[dep.name] = sources. end source_requirements[:default_bundler] = source_requirements["bundler"] || sources.default_source source_requirements["bundler"] = sources. # needs to come last to override source_requirements end
#spec_git_paths
[ GitHub ]# File 'lib/bundler/definition.rb', line 269
def spec_git_paths sources.git_sources.map {|s| File.realpath(s.path) if File.exist?(s.path) }.compact end
#specs ⇒ Bundler::SpecSet
For given dependency list returns a SpecSet
with Gemspec of all the required dependencies.
1. The method first resolves the dependencies specified in Gemfile
2. After that it tries and fetches gemspec of resolved dependencies
# File 'lib/bundler/definition.rb', line 184
def specs @specs ||= materialize(requested_dependencies) end
#specs_changed?(source) ⇒ Boolean
(private)
Check if the specs of the given source changed according to the locked source.
# File 'lib/bundler/definition.rb', line 539
def specs_changed?(source) locked = @locked_sources.find {|s| s == source } !locked || dependencies_for_source_changed?(source, locked) || specs_for_source_changed?(source) end
#specs_for(groups)
[ GitHub ]# File 'lib/bundler/definition.rb', line 232
def specs_for(groups) return specs if groups.empty? deps = dependencies_for(groups) materialize(deps) end
#specs_for_source_changed?(source) ⇒ Boolean
(private)
# File 'lib/bundler/definition.rb', line 552
def specs_for_source_changed?(source) locked_index = Index.new locked_index.use(@locked_specs.select {|s| source.can_lock?(s) }) # order here matters, since Index#== is checking source.specs.include?(locked_index) locked_index != source.specs rescue PathError, GitError => e Bundler.ui.debug "Assuming that #{source} has not changed since fetching its specs errored (#{e})" false end
#to_lock
[ GitHub ]# File 'lib/bundler/definition.rb', line 337
def to_lock require_relative "lockfile_generator" LockfileGenerator.generate(self) end
#validate_platforms!
# File 'lib/bundler/definition.rb', line 429
def validate_platforms! return if current_platform_locked? raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \ "but your local platform is #{Bundler.local_platform}. " \ "Add the current platform to the lockfile with `bundle lock --add-platform #{Bundler.local_platform}` and try again." end
#validate_ruby!
[ GitHub ]# File 'lib/bundler/definition.rb', line 404
def validate_ruby! return unless ruby_version if diff = ruby_version.diff(Bundler::RubyVersion.system) problem, expected, actual = diff msg = case problem when :engine "Your Ruby engine is #{actual}, but your Gemfile specified #{expected}" when :version "Your Ruby version is #{actual}, but your Gemfile specified #{expected}" when :engine_version "Your #{Bundler::RubyVersion.system.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}" when :patchlevel if !expected.is_a?(String) "The Ruby patchlevel in your Gemfile must be a string" else "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}" end end raise RubyVersionMismatch, msg end end
#validate_runtime!
[ GitHub ]# File 'lib/bundler/definition.rb', line 399
def validate_runtime! validate_ruby! validate_platforms! end