Spec-Zone.ru › Ruby 2.7

класс Bundler::Definition

Родитель:
Объект
Включенные модули:
Bundler::GemHelpers

Атрибуты

dependencies[Ч]
gemfiles[Ч]
locked_deps[Ч]
locked_gems[Ч]
lockfile[Ч]
platforms[Ч]
requires[Ч]
ruby_version[Ч]
sources[Ч]

Публичные методы класса

build(gemfile, lockfile, unlock) Показать исходный код
# File lib/bundler/definition.rb, line 28
def self.build(gemfile, lockfile, unlock)
  unlock ||= {}
  gemfile = Pathname.new(gemfile).expand_path

  raise GemfileNotFound, "#{gemfile} not found" unless gemfile.file?

  Dsl.evaluate(gemfile, lockfile, unlock)
end

На основе файла Gemfile и lockfile создаёт определение Bundler

@param gemfile [Pathname] Путь к файлу Gemfile @param lockfile [Pathname,nil] Путь к файлу Gemfile.lock @param unlock [Hash, Boolean, nil] Запрошенные gem-пакеты

to be updated or true if all gems should be updated

@return [Bundler::Definition]

new(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = []) Показать исходный код
# File lib/bundler/definition.rb, line 55
def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = [])
  if [true, false].include?(unlock)
    @unlocking_bundler = false
    @unlocking = unlock
  else
    unlock = unlock.dup
    @unlocking_bundler = unlock.delete(:bundler)
    unlock.delete_if {|_k, v| Array(v).empty? }
    @unlocking = !unlock.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
  @locked_specs_incomplete_for_platform = false

  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

  @unlock[:gems] ||= []
  @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 Bundler.frozen_bundle?

  converge_path_sources_to_gemspec_sources
  @path_changes = converge_paths
  @source_changes = converge_sources

  unless @unlock[:lock_shared_dependencies]
    eager_unlock = expand_dependencies(@unlock[:gems], true)
    @unlock[:gems] = @locked_specs.for(eager_unlock, [], false, false, false).map(&:name)
  end

  @dependency_changes = converge_dependencies
  @local_changes = converge_locals

  @requires = compute_requires
end

Как работает новая система?

  • Загрузка информации из Gemfile и Lockfile

  • Отмена устаревших заблокированных спецификаций

  • Все спецификации из устаревшего источника устарели

  • Все спецификации, доступные только через устаревшую зависимость, устарели.

  • Если все новые зависимости удовлетворяются заблокированными

specs, then we can try to resolve locally.

@param lockfile [Pathname] Путь к файлу Gemfile.lock @param dependencies [Array(Bundler::Dependency)] массив зависимостей из Gemfile @param sources [Bundler::SourceList] @param unlock [Hash, Boolean, nil] Запрошенные gem-пакеты

to be updated or true if all gems should be updated

@param ruby_version [Bundler::RubyVersion, nil] Запрошенная версия Ruby @param optional_groups [Array(String)] Список необязательных групп

Публичные методы экземпляра

add_current_platform() Показать исходный код
# File lib/bundler/definition.rb, line 521
def add_current_platform
  current_platforms.each {|platform| add_platform(platform) }
end
add_platform(platform) Показать исходный код
# File lib/bundler/definition.rb, line 511
def add_platform(platform)
  @new_platform ||= !@platforms.include?(platform)
  @platforms |= [platform]
end
current_dependencies() Показать исходный код
# File lib/bundler/definition.rb, line 230
def current_dependencies
  dependencies.select(&:should_include?)
end
ensure_equivalent_gemfile_and_lockfile(explicit_flag = false) Показать исходный код
# File lib/bundler/definition.rb, line 392
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")[:global]
      "bundle config unset frozen"
    elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any?
      "bundle config unset deployment"
    else
      "bundle install --no-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}" }

  gemfile_sources = sources.lock_sources

  new_sources = gemfile_sources - @locked_sources
  deleted_sources = @locked_sources - gemfile_sources

  new_deps = @dependencies - @locked_deps.values
  deleted_deps = @locked_deps.values - @dependencies

  # Check if it is possible that the source is only changed thing
  if (new_deps.empty? && deleted_deps.empty?) && (!new_sources.empty? && !deleted_sources.empty?)
    new_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
    deleted_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
  end

  if @locked_sources != gemfile_sources
    if new_sources.any?
      added.concat new_sources.map {|source| "* source: #{source}" }
    end

    if deleted_sources.any?
      deleted.concat deleted_sources.map {|source| "* source: #{source}" }
    end
  end

  added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any?
  if deleted_deps.any?
    deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" }
  end

  both_sources = Hash.new {|h, k| h[k] = [] }
  @dependencies.each {|d| both_sources[d.name][0] = d }
  @locked_deps.each  {|name, d| both_sources[name][1] = d.source }

  both_sources.each do |name, (dep, lock_source)|
    next unless (dep.nil? && !lock_source.nil?) || (!dep.nil? && !lock_source.nil? && !lock_source.can_lock?(dep))
    gemfile_source_name = (dep && dep.source) || "no specified source"
    lockfile_source_name = lock_source || "no specified source"
    changed << "* #{name} from `#{gemfile_source_name}` to `#{lockfile_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
find_indexed_specs(current_spec) Показать исходный код
# File lib/bundler/definition.rb, line 529
def find_indexed_specs(current_spec)
  index[current_spec.name].select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version)
end
find_resolved_spec(current_spec) Показать исходный код
# File lib/bundler/definition.rb, line 525
def find_resolved_spec(current_spec)
  specs.find_by_name_and_platform(current_spec.name, current_spec.platform)
end
gem_version_promoter() Показать исходный код
# File lib/bundler/definition.rb, line 133
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() Показать исходный код
# File lib/bundler/definition.rb, line 323
def groups
  dependencies.map(&:groups).flatten.uniq
end
has_local_dependencies?() Показать исходный код
# File lib/bundler/definition.rb, line 315
def has_local_dependencies?
  !sources.path_sources.empty? || !sources.git_sources.empty?
end
has_rubygems_remotes?() Показать исходный код
# File lib/bundler/definition.rb, line 311
def has_rubygems_remotes?
  sources.rubygems_sources.any? {|s| s.remotes.any? }
end
index() Показать исходный код
# File lib/bundler/definition.rb, line 267
def index
  @index ||= Index.build do |idx|
    dependency_names = @dependencies.map(&:name)

    sources.all_sources.each do |source|
      source.dependency_names = dependency_names - pinned_spec_names(source)
      idx.add_source source.specs
      dependency_names.concat(source.unmet_deps).uniq!
    end

    double_check_for_index(idx, dependency_names)
  end
end
lock(file, preserve_unknown_sections = false) Показать исходный код
# File lib/bundler/definition.rb, line 327
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() Показать исходный код
# File lib/bundler/definition.rb, line 358
def locked_bundler_version
  if @locked_bundler_version && @locked_bundler_version < Gem::Version.new(Bundler::VERSION)
    new_version = Bundler::VERSION
  end

  new_version || @locked_bundler_version || Bundler::VERSION
end
locked_ruby_version() Показать исходный код
# File lib/bundler/definition.rb, line 366
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() Показать исходный код
# File lib/bundler/definition.rb, line 375
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
missing_specs() Показать исходный код
# File lib/bundler/definition.rb, line 201
def missing_specs
  missing = []
  resolve.materialize(requested_dependencies, missing)
  missing
end
missing_specs?() Показать исходный код
# File lib/bundler/definition.rb, line 207
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
  @index = nil
  @resolve = nil
  @specs = nil
  @gem_version_promoter = nil

  Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})"
  true
end
new_platform?() Показать исходный код
# File lib/bundler/definition.rb, line 197
def new_platform?
  @new_platform
end
new_specs() Показать исходный код
# File lib/bundler/definition.rb, line 189
def new_specs
  specs - @locked_specs
end
nothing_changed?() Показать исходный код
# File lib/bundler/definition.rb, line 536
def nothing_changed?
  !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform
end
remove_platform(platform) Показать исходный код
# File lib/bundler/definition.rb, line 516
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() Показать исходный код
# File lib/bundler/definition.rb, line 193
def removed_specs
  @locked_specs - specs
end
requested_specs() Показать исходный код
# File lib/bundler/definition.rb, line 222
def requested_specs
  @requested_specs ||= begin
    groups = requested_groups
    groups.map!(&:to_sym)
    specs_for(groups)
  end
end
resolve() Показать исходный код
# File lib/bundler/definition.rb, line 245
def resolve
  @resolve ||= begin
    last_resolve = converge_locked_specs
    resolve =
      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}")
        last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms)
      end

    # filter out gems that _can_ be installed on multiple platforms, but don't need
    # to be
    resolve.for(expand_dependencies(dependencies, true), [], false, false, false)
  end
end

Разрешает все зависимости, указанные в Gemfile. Гарантирует, что зависимости, которые уже были разрешены через файл с зафиксированными значениями и являются актуальными, повторно используются при разрешении зависимостей

@return [SpecSet] разрешённые зависимости

resolve_remotely!() Показать исходный код
# File lib/bundler/definition.rb, line 154
def resolve_remotely!
  raise "Specs already loaded" if @specs
  @remote = true
  sources.remote!
  specs
end
resolve_with_cache!() Показать исходный код
# File lib/bundler/definition.rb, line 148
def resolve_with_cache!
  raise "Specs already loaded" if @specs
  sources.cached!
  specs
end
spec_git_paths() Показать исходный код
# File lib/bundler/definition.rb, line 319
def spec_git_paths
  sources.git_sources.map {|s| File.realpath(s.path) if File.exist?(s.path) }.compact
end
specs() Показать исходный код
# File lib/bundler/definition.rb, line 167
def specs
  @specs ||= begin
    begin
      specs = resolve.materialize(requested_dependencies)
    rescue GemNotFound => e # Handle yanked gem
      gem_name, gem_version = extract_gem_info(e)
      locked_gem = @locked_specs[gem_name].last
      raise if locked_gem.nil? || locked_gem.version.to_s != gem_version || !@remote
      raise GemNotFound, "Your bundle is locked to #{locked_gem}, but that version could not " \
                         "be found in any of the sources listed in your Gemfile. If you haven't changed sources, " \
                         "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
    unless specs["bundler"].any?
      bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last
      specs["bundler"] = bundler
    end

    specs
  end
end

Для данного списка зависимостей возвращает SpecSet с Gemspec всех необходимых зависимостей.

1. The method first resolves the dependencies specified in Gemfile
2. After that it tries and fetches gemspec of resolved dependencies

@return [Bundler::SpecSet]

specs_for(groups) Показать исходный код
# File lib/bundler/definition.rb, line 234
def specs_for(groups)
  deps = dependencies.select {|d| (d.groups & groups).any? }
  deps.delete_if {|d| !d.should_include? }
  specs.for(expand_dependencies(deps))
end
to_lock() Показать исходный код
# File lib/bundler/definition.rb, line 387
def to_lock
  require_relative "lockfile_generator"
  LockfileGenerator.generate(self)
end
unlocking?() Показать исходный код
# File lib/bundler/definition.rb, line 540
def unlocking?
  @unlocking
end
validate_platforms!() Показать исходный код
# File lib/bundler/definition.rb, line 499
def validate_platforms!
  return if @platforms.any? do |bundle_platform|
    Bundler.rubygems.platforms.any? do |local_platform|
      MatchPlatform.platforms_match?(bundle_platform, local_platform)
    end
  end

  raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \
    "but your local platforms are #{Bundler.rubygems.platforms.map(&:to_s)}, and " \
    "there's no compatible match between those two lists."
end
validate_ruby!() Показать исходный код
# File lib/bundler/definition.rb, line 474
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!() Показать исходный код
# File lib/bundler/definition.rb, line 469
def validate_runtime!
  validate_ruby!
  validate_platforms!
end

Приватные методы экземпляра

additional_base_requirements_for_resolve() Показать исходный код
# File lib/bundler/definition.rb, line 982
def additional_base_requirements_for_resolve
  return [] unless @locked_gems && Bundler.feature_flag.only_update_to_newer_versions?
  dependencies_by_name = dependencies.inject({}) {|memo, dep| memo.update(dep.name => dep) }
  @locked_gems.specs.reduce({}) do |requirements, locked_spec|
    name = locked_spec.name
    dependency = dependencies_by_name[name]
    next requirements if @locked_gems.dependencies[name] != dependency
    next requirements if dependency && dependency.source.is_a?(Source::Path)
    dep = Gem::Dependency.new(name, ">= #{locked_spec.version}")
    requirements[name] = DepProxy.new(dep, locked_spec.platform)
    requirements
  end.values
end
change_reason() Показать исходный код
# File lib/bundler/definition.rb, line 554
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() Показать исходный код
# File lib/bundler/definition.rb, line 971
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
concat_ruby_version_requirements(ruby_version, ruby_versions = []) Показать исходный код
# File lib/bundler/definition.rb, line 871
def concat_ruby_version_requirements(ruby_version, ruby_versions = [])
  return ruby_versions unless ruby_version
  if ruby_version.patchlevel
    ruby_versions << ruby_version.to_gem_version_with_patchlevel
  else
    ruby_versions.concat(ruby_version.versions.map do |version|
      requirement = Gem::Requirement.new(version)
      if requirement.exact?
        "~> #{version}.0"
      else
        requirement
      end
    end)
  end
end
converge_dependencies() Показать исходный код
# File lib/bundler/definition.rb, line 697
def converge_dependencies
  frozen = Bundler.frozen_bundle?
  (@dependencies + @locked_deps.values).each do |dep|
    locked_source = @locked_deps[dep.name]
    # This is to make sure that if bundler is installing in deployment mode and
    # after locked_source and sources don't match, we still use locked_source.
    if frozen && !locked_source.nil? &&
        locked_source.respond_to?(:source) && locked_source.source.instance_of?(Source::Path) && locked_source.source.path.exist?
      dep.source = locked_source.source
    elsif dep.source
      dep.source = sources.get(dep.source)
    end
    if dep.source.is_a?(Source::Gemspec)
      dep.platforms.concat(@platforms.map {|p| Dependency::REVERSE_PLATFORM_MAP[p] }.flatten(1)).uniq!
    end
  end

  changes = false
  # We want to know if all match, but don't want to check all entries
  # This means we need to return false if any dependency doesn't match
  # the lock or doesn't exist in the lock.
  @dependencies.each do |dependency|
    unless locked_dep = @locked_deps[dependency.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, dependency.type)

    # We already know the name matches from the hash lookup
    # so we only need to check the requirement now
    changes ||= dependency.requirement != locked_dep.requirement
  end

  changes
end
converge_locals() Показать исходный код
# File lib/bundler/definition.rb, line 609
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

Получить все локальные переменные и переопределить соответствующие источники. Возвращает true, если какие-либо локальные переменные были изменены (например, они указывают на новую ревизию) или зависят от новых спецификаций.

converge_locked_specs() Показать исходный код
# File lib/bundler/definition.rb, line 743
def converge_locked_specs
  deps = []

  # Build a list of dependencies that are the same in the Gemfile
  # and Gemfile.lock. If the Gemfile modified a dependency, but
  # the gem in the Gemfile.lock still satisfies it, this is fine
  # too.
  @dependencies.each do |dep|
    locked_dep = @locked_deps[dep.name]

    # If the locked_dep doesn't match the dependency we're looking for then we ignore the locked_dep
    locked_dep = nil unless locked_dep == dep

    if in_locked_deps?(dep, locked_dep) || satisfies_locked_spec?(dep)
      deps << dep
    elsif dep.source.is_a?(Source::Path) && dep.current_platform? && (!locked_dep || dep.source != locked_dep.source)
      @locked_specs.each do |s|
        @unlock[:gems] << s.name if s.source == dep.source
      end

      dep.source.unlock! if dep.source.respond_to?(:unlock!)
      dep.source.specs.each {|s| @unlock[:gems] << s.name }
    end
  end

  unlock_source_unlocks_spec = Bundler.feature_flag.unlock_source_unlocks_spec?

  converged = []
  @locked_specs.each do |s|
    # Replace the locked dependency's source with the equivalent source from the Gemfile
    dep = @dependencies.find {|d| s.satisfies?(d) }
    s.source = (dep && dep.source) || sources.get(s.source)

    # Don't add a spec to the list if its source is expired. For example,
    # if you change a Git gem to RubyGems.
    next if s.source.nil?
    next if @unlock[:sources].include?(s.source.name)

    # XXX This is a backwards-compatibility fix to preserve the ability to
    # unlock a single gem by passing its name via `--source`. See issue #3759
    # TODO: delete in Bundler 2
    next if unlock_source_unlocks_spec && @unlock[:sources].include?(s.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 @locked_specs.
                for(requested_dependencies, [], false, true, false).
                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

      new_runtime_deps = new_spec.dependencies.select {|d| d.type != :development }
      old_runtime_deps = s.dependencies.select {|d| d.type != :development }
      # If the dependencies of the path source have changed and locked spec can't satisfy new dependencies, unlock it
      next unless new_runtime_deps.sort == old_runtime_deps.sort || new_runtime_deps.all? {|d| satisfies_locked_spec?(d) }

      s.dependencies.replace(new_spec.dependencies)
    end

    converged << s
  end

  resolve = SpecSet.new(converged)
  @locked_specs_incomplete_for_platform = !resolve.for(expand_dependencies(deps), @unlock[:gems], true, true)
  resolve = resolve.for(expand_dependencies(deps, true), @unlock[:gems], false, false, false)
  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

Удаляет элементы из заблокированных спецификаций, которые истекли. Это чаще всего происходит, если файл Gemfile изменился с момента последнего создания файла lockfile.

converge_path_source_to_gemspec_source(source) Показать исходный код
# File lib/bundler/definition.rb, line 633
def converge_path_source_to_gemspec_source(source)
  return source unless source.instance_of?(Source::Path)
  gemspec_source = sources.path_sources.find {|s| s.is_a?(Source::Gemspec) && s.as_path_source == source }
  gemspec_source || source
end
converge_path_sources_to_gemspec_sources() Показать исходный код
# File lib/bundler/definition.rb, line 639
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() Показать исходный код
# File lib/bundler/definition.rb, line 627
def converge_paths
  sources.path_sources.any? do |source|
    specs_changed?(source)
  end
end
converge_rubygems_sources() Показать исходный код
# File lib/bundler/definition.rb, line 651
def converge_rubygems_sources
  return false if Bundler.feature_flag.disable_multisource?

  changes = false

  # Get the RubyGems sources from the Gemfile.lock
  locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
  # Get the RubyGems remotes from the Gemfile
  actual_remotes = sources.rubygems_remotes

  # If there is a RubyGems source in both
  if !locked_gem_sources.empty? && !actual_remotes.empty?
    locked_gem_sources.each do |locked_gem|
      # Merge the remotes from the Gemfile into the Gemfile.lock
      changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes])
    end
  end

  changes
end
converge_sources() Показать исходный код
# File lib/bundler/definition.rb, line 672
def converge_sources
  changes = false

  changes |= converge_rubygems_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
current_platforms() Показать исходный код
# File lib/bundler/definition.rb, line 546
def current_platforms
  current_platform = Bundler.local_platform
  [].tap do |platforms|
    platforms << current_platform if Bundler.feature_flag.specific_platform?
    platforms << generic(current_platform)
  end
end
dependencies_for_source_changed?(source, locked_source = source) Показать исходный код
# File lib/bundler/definition.rb, line 588
def dependencies_for_source_changed?(source, locked_source = source)
  deps_for_source = @dependencies.select {|s| s.source == source }
  locked_deps_for_source = @locked_deps.values.select {|dep| dep.source == locked_source }

  Set.new(deps_for_source) != Set.new(locked_deps_for_source)
end
double_check_for_index(idx, dependency_names) Показать исходный код
# File lib/bundler/definition.rb, line 286
def double_check_for_index(idx, dependency_names)
  pinned_names = pinned_spec_names
  loop do
    idxcount = idx.size

    names = :names # do this so we only have to traverse to get dependency_names from the index once
    unmet_dependency_names = lambda do
      return names unless names == :names
      new_names = sources.all_sources.map(&:dependency_names_to_double_check)
      return names = nil if new_names.compact!
      names = new_names.flatten(1).concat(dependency_names)
      names.uniq!
      names -= pinned_names
      names
    end

    sources.all_sources.each do |source|
      source.double_check_for(unmet_dependency_names)
    end

    break if idxcount == idx.size
  end
end

Предположим, что драгоценный камень Foo зависит от драгоценного камня Bar. Foo существует в Source A. Bar имеет некоторые версии, которые существуют как в источниках A, так и в B. На этом этапе запрос API нашел все версии Bar в источнике A, но не нашел никаких версий Bar из источника B, что является проблемой, если запрошенная версия Foo конкретно зависит от версии Bar, которая найдена только в источнике B. Это гарантирует, что для каждой найденной спецификации мы добавляем все возможные версии из всех источников в индекс.

equivalent_rubygems_remotes?(source) Показать исходный код
# File lib/bundler/definition.rb, line 996
def equivalent_rubygems_remotes?(source)
  return false unless source.is_a?(Source::Rubygems)

  Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes)
end
expand_dependencies(dependencies, remote = false) Показать исходный код
# File lib/bundler/definition.rb, line 887
def expand_dependencies(dependencies, remote = false)
  sorted_platforms = Resolver.sort_platforms(@platforms)
  deps = []
  dependencies.each do |dep|
    dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name)
    next if !remote && !dep.current_platform?
    platforms = dep.gem_platforms(sorted_platforms)
    if platforms.empty? && !Bundler.settings[:disable_platform_warnings]
      mapped_platforms = dep.expanded_platforms
      Bundler.ui.warn \
        "The dependency #{dep} will be unused by any of the platforms Bundler is installing for. " \
        "Bundler is installing for #{@platforms.join ", "} but the dependency " \
        "is only for #{mapped_platforms.join ", "}. " \
        "To add those platforms to the bundle, " \
        "run `bundle lock --add-platform #{mapped_platforms.join " "}`."
    end
    platforms.each do |p|
      deps << DepProxy.new(dep, p) if remote || p == generic_local_platform
    end
  end
  deps
end
expanded_dependencies() Показать исходный код
# File lib/bundler/definition.rb, line 851
def expanded_dependencies
  @expanded_dependencies ||= begin
    expand_dependencies(dependencies + metadata_dependencies, @remote)
  end
end

Этот список зависимостей используется только в resolve, поэтому добавление зависимостей метаданных здесь допустимо.

extract_gem_info(error) Показать исходный код
# File lib/bundler/definition.rb, line 965
def extract_gem_info(error)
  # This method will extract the error message like "Could not find foo-1.2.3 in any of the sources"
  # to an array. The first element will be the gem name (e.g. foo), the second will be the version number.
  error.message.scan(/Could not find (\w+)-(\d+(?:\.\d+)+)/).flatten
end
in_locked_deps?(dep, locked_dep) Показать исходный код
# File lib/bundler/definition.rb, line 838
def in_locked_deps?(dep, locked_dep)
  # Because the lockfile can't link a dep to a specific remote, we need to
  # treat sources as equivalent anytime the locked dep has all the remotes
  # that the Gemfile dep does.
  locked_dep && locked_dep.source && dep.source && locked_dep.source.include?(dep.source)
end
lockfiles_equal?(current, proposed, preserve_unknown_sections) Показать исходный код
# File lib/bundler/definition.rb, line 952
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
metadata_dependencies() Показать исходный код
# File lib/bundler/definition.rb, line 857
def metadata_dependencies
  @metadata_dependencies ||= begin
    ruby_versions = concat_ruby_version_requirements(@ruby_version)
    if ruby_versions.empty? || !@ruby_version.exact?
      concat_ruby_version_requirements(RubyVersion.system)
      concat_ruby_version_requirements(locked_ruby_version_object) unless @unlock[:ruby]
    end
    [
      Dependency.new("Ruby\0", ruby_versions),
      Dependency.new("RubyGems\0", Gem::VERSION),
    ]
  end
end
pinned_spec_names(skip = nil) Показать исходный код
# File lib/bundler/definition.rb, line 937
def pinned_spec_names(skip = nil)
  pinned_names = []
  default = Bundler.feature_flag.disable_multisource? && sources.default_source
  @dependencies.each do |dep|
    next unless dep_source = dep.source || default
    next if dep_source == skip
    pinned_names << dep.name
  end
  pinned_names
end
pretty_dep(dep, source = false) Показать исходный код
# File lib/bundler/definition.rb, line 576
def pretty_dep(dep, source = false)
  SharedHelpers.pretty_dependency(dep, source)
end
requested_dependencies() Показать исходный код
# File lib/bundler/definition.rb, line 910
def requested_dependencies
  groups = requested_groups
  groups.map!(&:to_sym)
  dependencies.reject {|d| !d.should_include? || (d.groups & groups).empty? }
end
requested_groups() Показать исходный код
# File lib/bundler/definition.rb, line 948
def requested_groups
  groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with]
end
satisfies_locked_spec?(dep) Показать исходный код
# File lib/bundler/definition.rb, line 845
def satisfies_locked_spec?(dep)
  @locked_specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
end
END_OF_DOCUMENT_MARKER
source_requirements() Показать исходный код
# File lib/bundler/definition.rb, line 916
def source_requirements
  # Load all specs from remote sources
  index

  # 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)
  default = sources.default_source
  source_requirements = { :default => default }
  default = nil unless Bundler.feature_flag.disable_multisource?
  dependencies.each do |dep|
    next unless source = dep.source || default
    source_requirements[dep.name] = source
  end
  metadata_dependencies.each do |dep|
    source_requirements[dep.name] = sources.metadata_source
  end
  source_requirements["bundler"] = sources.metadata_source # needs to come last to override
  source_requirements
end
specs_changed?(source) Показать исходный код
# File lib/bundler/definition.rb, line 582
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_source_changed?(source) Показать исходный код
# File lib/bundler/definition.rb, line 595
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

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API