зеркало из https://github.com/github/ruby.git
Родитель
d928ebacb2
Коммит
a4e14b9d9d
|
@ -524,13 +524,22 @@ module Bundler
|
|||
raise GemNotFound, "Could not find #{missing_specs_list.join(" nor ")}"
|
||||
end
|
||||
|
||||
incomplete_specs = specs.incomplete_specs
|
||||
loop do
|
||||
incomplete_specs = specs.incomplete_specs
|
||||
break if incomplete_specs.empty?
|
||||
|
||||
Bundler.ui.debug("The lockfile does not have all gems needed for the current platform though, Bundler will still re-resolve dependencies")
|
||||
@resolve = start_resolution(:exclude_specs => incomplete_specs)
|
||||
specs = resolve.materialize(dependencies)
|
||||
|
||||
still_incomplete_specs = specs.incomplete_specs
|
||||
|
||||
if still_incomplete_specs == incomplete_specs
|
||||
package = resolution_packages[incomplete_specs.first.name]
|
||||
resolver.raise_not_found! package
|
||||
end
|
||||
|
||||
incomplete_specs = still_incomplete_specs
|
||||
end
|
||||
|
||||
bundler = sources.metadata_source.specs.search(["bundler", Bundler.gem_version]).last
|
||||
|
|
|
@ -75,7 +75,7 @@ module Bundler
|
|||
end
|
||||
|
||||
def self.git_version
|
||||
Bundler::Source::Git::GitProxy.new(nil, nil, nil).full_version
|
||||
Bundler::Source::Git::GitProxy.new(nil, nil).full_version
|
||||
rescue Bundler::Source::Git::GitNotInstalledError
|
||||
"not installed"
|
||||
end
|
||||
|
|
|
@ -29,9 +29,7 @@ module Bundler
|
|||
" is a chance you are experiencing a man-in-the-middle attack, but" \
|
||||
" most likely your system doesn't have the CA certificates needed" \
|
||||
" for verification. For information about OpenSSL certificates, see" \
|
||||
" https://railsapps.github.io/openssl-certificate-verify-failed.html." \
|
||||
" To connect without using SSL, edit your Gemfile" \
|
||||
" sources and change 'https' to 'http'."
|
||||
" https://railsapps.github.io/openssl-certificate-verify-failed.html."
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -39,8 +37,7 @@ module Bundler
|
|||
class SSLError < HTTPError
|
||||
def initialize(msg = nil)
|
||||
super msg || "Could not load OpenSSL.\n" \
|
||||
"You must recompile Ruby with OpenSSL support or change the sources in your " \
|
||||
"Gemfile from 'https' to 'http'."
|
||||
"You must recompile Ruby with OpenSSL support."
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ It will display the ruby directive information, so you don\'t have to parse it f
|
|||
.SH "SEE ALSO"
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
bundle\-lock(1) \fIbundle\-lock\.1\.ronn\fR
|
||||
bundle\-lock(1) \fIbundle\-lock\.1\.html\fR
|
||||
.
|
||||
.IP "" 0
|
||||
|
||||
|
|
|
@ -46,4 +46,4 @@ match the running Ruby VM, it tells you what part does not.
|
|||
|
||||
## SEE ALSO
|
||||
|
||||
* [bundle-lock(1)](bundle-lock.1.ronn)
|
||||
* [bundle-lock(1)](bundle-lock.1.html)
|
||||
|
|
|
@ -11,6 +11,7 @@ module Bundler
|
|||
require_relative "resolver/base"
|
||||
require_relative "resolver/package"
|
||||
require_relative "resolver/candidate"
|
||||
require_relative "resolver/incompatibility"
|
||||
require_relative "resolver/root"
|
||||
|
||||
include GemHelpers
|
||||
|
@ -29,6 +30,10 @@ module Bundler
|
|||
root = Resolver::Root.new(name_for_explicit_dependency_source)
|
||||
root_version = Resolver::Candidate.new(0)
|
||||
|
||||
@all_specs = Hash.new do |specs, name|
|
||||
specs[name] = source_for(name).specs.search(name).sort_by {|s| [s.version, s.platform.to_s] }
|
||||
end
|
||||
|
||||
@sorted_versions = Hash.new do |candidates, package|
|
||||
candidates[package] = if package.root?
|
||||
[root_version]
|
||||
|
@ -60,7 +65,7 @@ module Bundler
|
|||
incompatibility = e.incompatibility
|
||||
|
||||
names_to_unlock = []
|
||||
conflict_on_bundler = nil
|
||||
extended_explanation = nil
|
||||
|
||||
while incompatibility.conflict?
|
||||
cause = incompatibility.cause
|
||||
|
@ -69,12 +74,11 @@ module Bundler
|
|||
incompatibility.terms.each do |term|
|
||||
name = term.package.name
|
||||
names_to_unlock << name if base_requirements[name]
|
||||
next unless name == "bundler"
|
||||
|
||||
no_versions_incompat = [cause.incompatibility, cause.satisfier].find {|incompat| incompat.cause.is_a?(PubGrub::Incompatibility::NoVersions) }
|
||||
next unless no_versions_incompat
|
||||
|
||||
conflict_on_bundler ||= Gem::Requirement.new(no_versions_incompat.cause.constraint.constraint.constraint_string.split(","))
|
||||
extended_explanation = no_versions_incompat.extended_explanation
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -85,9 +89,9 @@ module Bundler
|
|||
|
||||
explanation = e.message
|
||||
|
||||
if conflict_on_bundler
|
||||
if extended_explanation
|
||||
explanation << "\n\n"
|
||||
explanation << bundler_not_found_message(conflict_on_bundler)
|
||||
explanation << extended_explanation
|
||||
end
|
||||
|
||||
raise SolveFailure.new(explanation)
|
||||
|
@ -111,14 +115,25 @@ module Bundler
|
|||
|
||||
def no_versions_incompatibility_for(package, unsatisfied_term)
|
||||
cause = PubGrub::Incompatibility::NoVersions.new(unsatisfied_term)
|
||||
name = package.name
|
||||
constraint = unsatisfied_term.constraint
|
||||
requirement = Gem::Requirement.new(constraint.constraint_string.split(","))
|
||||
|
||||
custom_explanation = if package.name == "bundler"
|
||||
"the current Bundler version (#{Bundler::VERSION}) does not satisfy #{cause.constraint}"
|
||||
if name == "bundler"
|
||||
custom_explanation = "the current Bundler version (#{Bundler::VERSION}) does not satisfy #{constraint}"
|
||||
extended_explanation = bundler_not_found_message(requirement)
|
||||
else
|
||||
"#{cause.constraint} could not be found in #{repository_for(package)}"
|
||||
specs_matching_other_platforms = filter_matching_specs(@all_specs[name], requirement)
|
||||
|
||||
platforms_explanation = specs_matching_other_platforms.any? ? " for any resolution platforms (#{package.platforms.join(", ")})" : ""
|
||||
custom_explanation = "#{constraint} could not be found in #{repository_for(package)}#{platforms_explanation}"
|
||||
|
||||
dependency = Dependency.new(name, requirement)
|
||||
label = SharedHelpers.pretty_dependency(dependency)
|
||||
extended_explanation = other_specs_matching_message(specs_matching_other_platforms, label) if specs_matching_other_platforms.any?
|
||||
end
|
||||
|
||||
PubGrub::Incompatibility.new([unsatisfied_term], :cause => cause, :custom_explanation => custom_explanation)
|
||||
Incompatibility.new([unsatisfied_term], :cause => cause, :custom_explanation => custom_explanation, :extended_explanation => extended_explanation)
|
||||
end
|
||||
|
||||
def debug?
|
||||
|
@ -187,9 +202,9 @@ module Bundler
|
|||
|
||||
def all_versions_for(package)
|
||||
name = package.name
|
||||
results = @base[name] + results_for(name)
|
||||
results = @base[name] + @all_specs[name]
|
||||
locked_requirement = base_requirements[name]
|
||||
results = results.select {|spec| requirement_satisfied_by?(locked_requirement, spec) } if locked_requirement
|
||||
results = filter_matching_specs(results, locked_requirement) if locked_requirement
|
||||
|
||||
versions = results.group_by(&:version).reduce([]) do |groups, (version, specs)|
|
||||
platform_specs = package.platforms.flat_map {|platform| select_best_platform_match(specs, platform) }
|
||||
|
@ -208,30 +223,56 @@ module Bundler
|
|||
sort_versions(package, versions)
|
||||
end
|
||||
|
||||
def index_for(name)
|
||||
source_for(name).specs
|
||||
end
|
||||
|
||||
def source_for(name)
|
||||
@source_requirements[name] || @source_requirements[:default]
|
||||
end
|
||||
|
||||
def results_for(name)
|
||||
index_for(name).search(name)
|
||||
end
|
||||
|
||||
def name_for_explicit_dependency_source
|
||||
Bundler.default_gemfile.basename.to_s
|
||||
rescue StandardError
|
||||
"Gemfile"
|
||||
end
|
||||
|
||||
def requirement_satisfied_by?(requirement, spec)
|
||||
requirement.satisfied_by?(spec.version) || spec.source.is_a?(Source::Gemspec)
|
||||
def raise_not_found!(package)
|
||||
name = package.name
|
||||
source = source_for(name)
|
||||
specs = @all_specs[name]
|
||||
matching_part = name
|
||||
requirement_label = SharedHelpers.pretty_dependency(package.dependency)
|
||||
cache_message = begin
|
||||
" or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist?
|
||||
rescue GemfileNotFound
|
||||
nil
|
||||
end
|
||||
specs_matching_requirement = filter_matching_specs(specs, package.dependency.requirement)
|
||||
|
||||
if specs_matching_requirement.any?
|
||||
specs = specs_matching_requirement
|
||||
matching_part = requirement_label
|
||||
platforms = package.platforms
|
||||
platform_label = platforms.size == 1 ? "platform '#{platforms.first}" : "platforms '#{platforms.join("', '")}"
|
||||
requirement_label = "#{requirement_label}' with #{platform_label}"
|
||||
end
|
||||
|
||||
message = String.new("Could not find gem '#{requirement_label}' in #{source}#{cache_message}.\n")
|
||||
|
||||
if specs.any?
|
||||
message << "\n#{other_specs_matching_message(specs, matching_part)}"
|
||||
end
|
||||
|
||||
raise GemNotFound, message
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def filter_matching_specs(specs, requirement)
|
||||
specs.select {| spec| requirement_satisfied_by?(requirement, spec) }
|
||||
end
|
||||
|
||||
def requirement_satisfied_by?(requirement, spec)
|
||||
requirement.satisfied_by?(spec.version) || spec.source.is_a?(Source::Gemspec)
|
||||
end
|
||||
|
||||
def sort_versions(package, versions)
|
||||
if versions.size > 1
|
||||
@gem_version_promoter.sort_versions(package, versions).reverse
|
||||
|
@ -260,38 +301,13 @@ module Bundler
|
|||
next [dep_package, dep_constraint] unless versions_for(dep_package, dep_constraint.range).empty?
|
||||
next unless dep_package.current_platform?
|
||||
|
||||
raise GemNotFound, gem_not_found_message(dep_package, dep_constraint)
|
||||
raise_not_found!(dep_package)
|
||||
end.compact.to_h
|
||||
end
|
||||
|
||||
def gem_not_found_message(package, requirement)
|
||||
name = package.name
|
||||
source = source_for(name)
|
||||
specs = source.specs.search(name).sort_by {|s| [s.version, s.platform.to_s] }
|
||||
matching_part = name
|
||||
requirement_label = SharedHelpers.pretty_dependency(package.dependency)
|
||||
cache_message = begin
|
||||
" or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist?
|
||||
rescue GemfileNotFound
|
||||
nil
|
||||
end
|
||||
specs_matching_requirement = specs.select {| spec| requirement_satisfied_by?(package.dependency.requirement, spec) }
|
||||
|
||||
if specs_matching_requirement.any?
|
||||
specs = specs_matching_requirement
|
||||
matching_part = requirement_label
|
||||
platforms = package.platforms
|
||||
platform_label = platforms.size == 1 ? "platform '#{platforms.first}" : "platforms '#{platforms.join("', '")}"
|
||||
requirement_label = "#{requirement_label}' with #{platform_label}"
|
||||
end
|
||||
|
||||
message = String.new("Could not find gem '#{requirement_label}' in #{source}#{cache_message}.\n")
|
||||
|
||||
if specs.any?
|
||||
message << "\nThe source contains the following gems matching '#{matching_part}':\n"
|
||||
message << specs.map {|s| " * #{s.full_name}" }.join("\n")
|
||||
end
|
||||
|
||||
def other_specs_matching_message(specs, requirement)
|
||||
message = String.new("The source contains the following gems matching '#{requirement}':\n")
|
||||
message << specs.map {|s| " * #{s.full_name}" }.join("\n")
|
||||
message
|
||||
end
|
||||
|
||||
|
@ -342,7 +358,7 @@ module Bundler
|
|||
end
|
||||
|
||||
def bundler_not_found_message(conflict_dependency)
|
||||
candidate_specs = source_for(:default_bundler).specs.search("bundler").select {|spec| requirement_satisfied_by?(conflict_dependency, spec) }
|
||||
candidate_specs = filter_matching_specs(source_for(:default_bundler).specs.search("bundler"), conflict_dependency)
|
||||
if candidate_specs.any?
|
||||
target_version = candidate_specs.last.version
|
||||
new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ")
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Bundler
|
||||
class Resolver
|
||||
class Incompatibility < PubGrub::Incompatibility
|
||||
attr_reader :extended_explanation
|
||||
|
||||
def initialize(terms, cause:, custom_explanation: nil, extended_explanation: nil)
|
||||
@extended_explanation = extended_explanation
|
||||
|
||||
super(terms, :cause => cause, :custom_explanation => custom_explanation)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -13,14 +13,14 @@ module Bundler
|
|||
# * The dependency explicit set in the Gemfile for this gem (if any).
|
||||
#
|
||||
class Package
|
||||
attr_reader :name, :platforms, :dependency
|
||||
attr_reader :name, :platforms, :dependency, :locked_version
|
||||
|
||||
def initialize(name, platforms, locked_specs, unlock, dependency: nil)
|
||||
@name = name
|
||||
@platforms = platforms
|
||||
@locked_specs = locked_specs
|
||||
@locked_version = locked_specs[name].first&.version
|
||||
@unlock = unlock
|
||||
@dependency = dependency
|
||||
@dependency = dependency || Dependency.new(name, @locked_version)
|
||||
end
|
||||
|
||||
def to_s
|
||||
|
@ -43,24 +43,20 @@ module Bundler
|
|||
@name.hash
|
||||
end
|
||||
|
||||
def locked_version
|
||||
@locked_specs[name].first&.version
|
||||
end
|
||||
|
||||
def unlock?
|
||||
@unlock.empty? || @unlock.include?(name)
|
||||
end
|
||||
|
||||
def prerelease_specified?
|
||||
@dependency&.prerelease?
|
||||
@dependency.prerelease?
|
||||
end
|
||||
|
||||
def force_ruby_platform?
|
||||
@dependency&.force_ruby_platform
|
||||
@dependency.force_ruby_platform
|
||||
end
|
||||
|
||||
def current_platform?
|
||||
@dependency&.current_platform?
|
||||
@dependency.current_platform?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -72,7 +72,7 @@ module Bundler
|
|||
elsif ref
|
||||
ref
|
||||
else
|
||||
git_proxy.branch
|
||||
current_branch
|
||||
end
|
||||
|
||||
rev = "at #{at}@#{shortref_for_display(revision)}"
|
||||
|
@ -126,7 +126,7 @@ module Bundler
|
|||
path = Pathname.new(path)
|
||||
path = path.expand_path(Bundler.root) unless path.relative?
|
||||
|
||||
unless options["branch"] || Bundler.settings[:disable_local_branch_check]
|
||||
unless branch || Bundler.settings[:disable_local_branch_check]
|
||||
raise GitError, "Cannot use local override for #{name} at #{path} because " \
|
||||
":branch is not specified in Gemfile. Specify a branch or run " \
|
||||
"`bundle config unset local.#{override_for(original_path)}` to remove the local override"
|
||||
|
@ -141,11 +141,11 @@ module Bundler
|
|||
|
||||
# Create a new git proxy without the cached revision
|
||||
# so the Gemfile.lock always picks up the new revision.
|
||||
@git_proxy = GitProxy.new(path, uri, ref)
|
||||
@git_proxy = GitProxy.new(path, uri, options)
|
||||
|
||||
if git_proxy.branch != options["branch"] && !Bundler.settings[:disable_local_branch_check]
|
||||
if current_branch != branch && !Bundler.settings[:disable_local_branch_check]
|
||||
raise GitError, "Local override for #{name} at #{path} is using branch " \
|
||||
"#{git_proxy.branch} but Gemfile specifies #{options["branch"]}"
|
||||
"#{current_branch} but Gemfile specifies #{branch}"
|
||||
end
|
||||
|
||||
changed = cached_revision && cached_revision != git_proxy.revision
|
||||
|
@ -228,6 +228,10 @@ module Bundler
|
|||
git_proxy.revision
|
||||
end
|
||||
|
||||
def current_branch
|
||||
git_proxy.current_branch
|
||||
end
|
||||
|
||||
def allow_git_ops?
|
||||
@allow_remote || @allow_cached
|
||||
end
|
||||
|
@ -313,7 +317,7 @@ module Bundler
|
|||
end
|
||||
|
||||
def git_proxy
|
||||
@git_proxy ||= GitProxy.new(cache_path, uri, ref, cached_revision, self)
|
||||
@git_proxy ||= GitProxy.new(cache_path, uri, options, cached_revision, self)
|
||||
end
|
||||
|
||||
def fetch
|
||||
|
|
|
@ -47,13 +47,15 @@ module Bundler
|
|||
# All actions required by the Git source is encapsulated in this
|
||||
# object.
|
||||
class GitProxy
|
||||
attr_accessor :path, :uri, :ref
|
||||
attr_accessor :path, :uri, :branch, :tag, :ref
|
||||
attr_writer :revision
|
||||
|
||||
def initialize(path, uri, ref, revision = nil, git = nil)
|
||||
def initialize(path, uri, options = {}, revision = nil, git = nil)
|
||||
@path = path
|
||||
@uri = uri
|
||||
@ref = ref
|
||||
@branch = options["branch"]
|
||||
@tag = options["tag"]
|
||||
@ref = options["ref"]
|
||||
@revision = revision
|
||||
@git = git
|
||||
end
|
||||
|
@ -62,8 +64,8 @@ module Bundler
|
|||
@revision ||= find_local_revision
|
||||
end
|
||||
|
||||
def branch
|
||||
@branch ||= allowed_with_path do
|
||||
def current_branch
|
||||
@current_branch ||= allowed_with_path do
|
||||
git("rev-parse", "--abbrev-ref", "HEAD", :dir => path).strip
|
||||
end
|
||||
end
|
||||
|
@ -76,36 +78,33 @@ module Bundler
|
|||
end
|
||||
|
||||
def version
|
||||
git("--version").match(/(git version\s*)?((\.?\d+)+).*/)[2]
|
||||
@version ||= full_version.match(/((\.?\d+)+).*/)[1]
|
||||
end
|
||||
|
||||
def full_version
|
||||
git("--version").sub("git version", "").strip
|
||||
@full_version ||= git("--version").sub(/git version\s*/, "").strip
|
||||
end
|
||||
|
||||
def checkout
|
||||
return if path.exist? && has_revision_cached?
|
||||
extra_ref = "#{ref}:#{ref}" if ref && ref.start_with?("refs/")
|
||||
return if has_revision_cached?
|
||||
|
||||
Bundler.ui.info "Fetching #{URICredentialsFilter.credential_filtered_uri(uri)}"
|
||||
|
||||
configured_uri = configured_uri_for(uri).to_s
|
||||
Bundler.ui.info "Fetching #{credential_filtered_uri}"
|
||||
|
||||
unless path.exist?
|
||||
SharedHelpers.filesystem_access(path.dirname) do |p|
|
||||
FileUtils.mkdir_p(p)
|
||||
end
|
||||
git_retry "clone", "--bare", "--no-hardlinks", "--quiet", "--", configured_uri, path.to_s
|
||||
git_retry "clone", "--bare", "--no-hardlinks", "--quiet", *extra_clone_args, "--", configured_uri, path.to_s
|
||||
return unless extra_ref
|
||||
end
|
||||
|
||||
with_path do
|
||||
git_retry(*["fetch", "--force", "--quiet", "--tags", "--", configured_uri, "refs/heads/*:refs/heads/*", extra_ref].compact, :dir => path)
|
||||
end
|
||||
fetch_args = extra_fetch_args
|
||||
fetch_args.unshift("--unshallow") if path.join("shallow").exist? && full_clone?
|
||||
|
||||
git_retry(*["fetch", "--force", "--quiet", "--no-tags", *fetch_args, "--", configured_uri, refspec].compact, :dir => path)
|
||||
end
|
||||
|
||||
def copy_to(destination, submodules = false)
|
||||
# method 1
|
||||
unless File.exist?(destination.join(".git"))
|
||||
begin
|
||||
SharedHelpers.filesystem_access(destination.dirname) do |p|
|
||||
|
@ -114,7 +113,7 @@ module Bundler
|
|||
SharedHelpers.filesystem_access(destination) do |p|
|
||||
FileUtils.rm_rf(p)
|
||||
end
|
||||
git_retry "clone", "--no-checkout", "--quiet", path.to_s, destination.to_s
|
||||
git "clone", "--no-checkout", "--quiet", path.to_s, destination.to_s
|
||||
File.chmod(((File.stat(destination).mode | 0o777) & ~File.umask), destination)
|
||||
rescue Errno::EEXIST => e
|
||||
file_path = e.message[%r{.*?((?:[a-zA-Z]:)?/.*)}, 1]
|
||||
|
@ -123,14 +122,10 @@ module Bundler
|
|||
"this file and try again."
|
||||
end
|
||||
end
|
||||
# method 2
|
||||
git_retry "fetch", "--force", "--quiet", "--tags", path.to_s, :dir => destination
|
||||
|
||||
begin
|
||||
git "reset", "--hard", @revision, :dir => destination
|
||||
rescue GitCommandError => e
|
||||
raise MissingGitRevisionError.new(e.command, destination, @revision, URICredentialsFilter.credential_filtered_uri(uri))
|
||||
end
|
||||
git(*["fetch", "--force", "--quiet", *extra_fetch_args, path.to_s, revision_refspec].compact, :dir => destination)
|
||||
|
||||
git "reset", "--hard", @revision, :dir => destination
|
||||
|
||||
if submodules
|
||||
git_retry "submodule", "update", "--init", "--recursive", :dir => destination
|
||||
|
@ -142,6 +137,69 @@ module Bundler
|
|||
|
||||
private
|
||||
|
||||
def extra_ref
|
||||
return false if not_pinned?
|
||||
return true unless full_clone?
|
||||
|
||||
ref.start_with?("refs/")
|
||||
end
|
||||
|
||||
def depth
|
||||
return @depth if defined?(@depth)
|
||||
|
||||
@depth = if legacy_locked_revision? || !supports_fetching_unreachable_refs?
|
||||
nil
|
||||
elsif not_pinned?
|
||||
1
|
||||
elsif ref.include?("~")
|
||||
parsed_depth = ref.split("~").last
|
||||
parsed_depth.to_i + 1
|
||||
elsif abbreviated_ref?
|
||||
nil
|
||||
else
|
||||
1
|
||||
end
|
||||
end
|
||||
|
||||
def refspec
|
||||
if fully_qualified_ref
|
||||
"#{fully_qualified_ref}:#{fully_qualified_ref}"
|
||||
elsif ref.include?("~")
|
||||
parsed_ref = ref.split("~").first
|
||||
"#{parsed_ref}:#{parsed_ref}"
|
||||
elsif ref.start_with?("refs/")
|
||||
"#{ref}:#{ref}"
|
||||
elsif abbreviated_ref?
|
||||
nil
|
||||
else
|
||||
ref
|
||||
end
|
||||
end
|
||||
|
||||
def fully_qualified_ref
|
||||
return @fully_qualified_ref if defined?(@fully_qualified_ref)
|
||||
|
||||
@fully_qualified_ref = if branch
|
||||
"refs/heads/#{branch}"
|
||||
elsif tag
|
||||
"refs/tags/#{tag}"
|
||||
elsif ref.nil?
|
||||
"refs/heads/#{current_branch}"
|
||||
end
|
||||
end
|
||||
|
||||
def not_pinned?
|
||||
branch || tag || ref.nil?
|
||||
end
|
||||
|
||||
def abbreviated_ref?
|
||||
ref =~ /\A\h+\z/ && ref !~ /\A\h{40}\z/
|
||||
end
|
||||
|
||||
def legacy_locked_revision?
|
||||
!@revision.nil? && @revision =~ /\A\h{7}\z/
|
||||
end
|
||||
|
||||
def git_null(*command, dir: nil)
|
||||
check_allowed(command)
|
||||
|
||||
|
@ -175,37 +233,40 @@ module Bundler
|
|||
end
|
||||
|
||||
def has_revision_cached?
|
||||
return unless @revision
|
||||
with_path { git("cat-file", "-e", @revision, :dir => path) }
|
||||
return unless @revision && path.exist?
|
||||
git("cat-file", "-e", @revision, :dir => path)
|
||||
true
|
||||
rescue GitError
|
||||
false
|
||||
end
|
||||
|
||||
def remove_cache
|
||||
FileUtils.rm_rf(path)
|
||||
end
|
||||
|
||||
def find_local_revision
|
||||
allowed_with_path do
|
||||
git("rev-parse", "--verify", ref || "HEAD", :dir => path).strip
|
||||
git("rev-parse", "--verify", branch || tag || ref || "HEAD", :dir => path).strip
|
||||
end
|
||||
rescue GitCommandError => e
|
||||
raise MissingGitRevisionError.new(e.command, path, ref, URICredentialsFilter.credential_filtered_uri(uri))
|
||||
raise MissingGitRevisionError.new(e.command, path, branch || tag || ref, credential_filtered_uri)
|
||||
end
|
||||
|
||||
# Adds credentials to the URI as Fetcher#configured_uri_for does
|
||||
def configured_uri_for(uri)
|
||||
# Adds credentials to the URI
|
||||
def configured_uri
|
||||
if /https?:/ =~ uri
|
||||
remote = Bundler::URI(uri)
|
||||
config_auth = Bundler.settings[remote.to_s] || Bundler.settings[remote.host]
|
||||
remote.userinfo ||= config_auth
|
||||
remote.to_s
|
||||
elsif File.exist?(uri)
|
||||
"file://#{uri}"
|
||||
else
|
||||
uri
|
||||
uri.to_s
|
||||
end
|
||||
end
|
||||
|
||||
# Removes credentials from the URI
|
||||
def credential_filtered_uri
|
||||
URICredentialsFilter.credential_filtered_uri(uri)
|
||||
end
|
||||
|
||||
def allow?
|
||||
allowed = @git ? @git.allow_git_ops? : true
|
||||
|
||||
|
@ -254,9 +315,43 @@ module Bundler
|
|||
end
|
||||
end
|
||||
|
||||
def extra_clone_args
|
||||
return [] if full_clone?
|
||||
|
||||
args = ["--depth", depth.to_s, "--single-branch"]
|
||||
args.unshift("--no-tags") if supports_cloning_with_no_tags?
|
||||
|
||||
args += ["--branch", branch || tag] if branch || tag
|
||||
args
|
||||
end
|
||||
|
||||
def extra_fetch_args
|
||||
return [] if full_clone?
|
||||
|
||||
["--depth", depth.to_s]
|
||||
end
|
||||
|
||||
def revision_refspec
|
||||
return if legacy_locked_revision?
|
||||
|
||||
revision
|
||||
end
|
||||
|
||||
def full_clone?
|
||||
depth.nil?
|
||||
end
|
||||
|
||||
def supports_minus_c?
|
||||
@supports_minus_c ||= Gem::Version.new(version) >= Gem::Version.new("1.8.5")
|
||||
end
|
||||
|
||||
def supports_fetching_unreachable_refs?
|
||||
@supports_fetching_unreachable_refs ||= Gem::Version.new(version) >= Gem::Version.new("2.5.0")
|
||||
end
|
||||
|
||||
def supports_cloning_with_no_tags?
|
||||
@supports_cloning_with_no_tags ||= Gem::Version.new(version) >= Gem::Version.new("2.14.0-rc0")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ require "bundler/settings"
|
|||
require "openssl"
|
||||
|
||||
RSpec.describe Bundler::Env do
|
||||
let(:git_proxy_stub) { Bundler::Source::Git::GitProxy.new(nil, nil, nil) }
|
||||
let(:git_proxy_stub) { Bundler::Source::Git::GitProxy.new(nil, nil) }
|
||||
|
||||
describe "#report" do
|
||||
it "prints the environment" do
|
||||
|
|
|
@ -11,21 +11,24 @@ RSpec.describe Bundler::Source::Git::GitProxy do
|
|||
context "with configured credentials" do
|
||||
it "adds username and password to URI" do
|
||||
Bundler.settings.temporary(uri => "u:p") do
|
||||
expect(subject).to receive(:git_retry).with("clone", "--bare", "--no-hardlinks", "--quiet", "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s)
|
||||
allow(subject).to receive(:git).with("--version").and_return("git version 2.14.0")
|
||||
expect(subject).to receive(:git_retry).with("clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--depth", "1", "--single-branch", "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s)
|
||||
subject.checkout
|
||||
end
|
||||
end
|
||||
|
||||
it "adds username and password to URI for host" do
|
||||
Bundler.settings.temporary("github.com" => "u:p") do
|
||||
expect(subject).to receive(:git_retry).with("clone", "--bare", "--no-hardlinks", "--quiet", "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s)
|
||||
allow(subject).to receive(:git).with("--version").and_return("git version 2.14.0")
|
||||
expect(subject).to receive(:git_retry).with("clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--depth", "1", "--single-branch", "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s)
|
||||
subject.checkout
|
||||
end
|
||||
end
|
||||
|
||||
it "does not add username and password to mismatched URI" do
|
||||
Bundler.settings.temporary("https://u:p@github.com/rubygems/rubygems-mismatch.git" => "u:p") do
|
||||
expect(subject).to receive(:git_retry).with("clone", "--bare", "--no-hardlinks", "--quiet", "--", uri, path.to_s)
|
||||
allow(subject).to receive(:git).with("--version").and_return("git version 2.14.0")
|
||||
expect(subject).to receive(:git_retry).with("clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--depth", "1", "--single-branch", "--", uri, path.to_s)
|
||||
subject.checkout
|
||||
end
|
||||
end
|
||||
|
@ -34,7 +37,8 @@ RSpec.describe Bundler::Source::Git::GitProxy do
|
|||
Bundler.settings.temporary("github.com" => "u:p") do
|
||||
original = "https://orig:info@github.com/rubygems/rubygems.git"
|
||||
subject = described_class.new(Pathname("path"), original, "HEAD")
|
||||
expect(subject).to receive(:git_retry).with("clone", "--bare", "--no-hardlinks", "--quiet", "--", original, path.to_s)
|
||||
allow(subject).to receive(:git).with("--version").and_return("git version 2.14.0")
|
||||
expect(subject).to receive(:git_retry).with("clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--depth", "1", "--single-branch", "--", original, path.to_s)
|
||||
subject.checkout
|
||||
end
|
||||
end
|
||||
|
@ -122,33 +126,6 @@ RSpec.describe Bundler::Source::Git::GitProxy do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#copy_to" do
|
||||
let(:cache) { tmpdir("cache_path") }
|
||||
let(:destination) { tmpdir("copy_to_path") }
|
||||
let(:submodules) { false }
|
||||
|
||||
context "when given a SHA as a revision" do
|
||||
let(:revision) { "abcd" * 10 }
|
||||
let(:command) { ["reset", "--hard", revision] }
|
||||
let(:command_for_display) { "git #{command.shelljoin}" }
|
||||
|
||||
it "fails gracefully when resetting to the revision fails" do
|
||||
expect(subject).to receive(:git_retry).with("clone", any_args) { destination.mkpath }
|
||||
expect(subject).to receive(:git_retry).with("fetch", any_args, :dir => destination)
|
||||
expect(subject).to receive(:git).with(*command, :dir => destination).and_raise(Bundler::Source::Git::GitCommandError.new(command_for_display, destination))
|
||||
expect(subject).not_to receive(:git)
|
||||
|
||||
expect { subject.copy_to(destination, submodules) }.
|
||||
to raise_error(
|
||||
Bundler::Source::Git::MissingGitRevisionError,
|
||||
"Git error: command `#{command_for_display}` in directory #{destination} has failed.\n" \
|
||||
"Revision #{revision} does not exist in the repository #{uri}. Maybe you misspelled it?\n" \
|
||||
"If this error persists you could try removing the cache directory '#{destination}'"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "doesn't allow arbitrary code execution through Gemfile uris with a leading dash" do
|
||||
gemfile <<~G
|
||||
gem "poc", git: "-u./pay:load.sh"
|
||||
|
|
|
@ -90,7 +90,6 @@ RSpec.describe "bundle cache with git" do
|
|||
expect(ref).not_to eq(old_ref)
|
||||
|
||||
bundle "update", :all => true
|
||||
bundle "config set cache_all true"
|
||||
bundle :cache
|
||||
|
||||
expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist
|
||||
|
|
|
@ -595,4 +595,74 @@ RSpec.describe "bundle lock" do
|
|||
expect(read_lockfile).to eq(@lockfile.sub("foo (1.0)", "foo (2.0)").sub(/foo$/, "foo (= 2.0)"))
|
||||
end
|
||||
end
|
||||
|
||||
context "when a system gem has incorrect dependencies, different from the lockfile" do
|
||||
before do
|
||||
build_repo4 do
|
||||
build_gem "debug", "1.6.3" do |s|
|
||||
s.add_dependency "irb", ">= 1.3.6"
|
||||
end
|
||||
|
||||
build_gem "irb", "1.5.0"
|
||||
end
|
||||
|
||||
system_gems "irb-1.5.0", :gem_repo => gem_repo4
|
||||
system_gems "debug-1.6.3", :gem_repo => gem_repo4
|
||||
|
||||
# simulate gemspec with wrong empty dependencies
|
||||
debug_gemspec_path = system_gem_path("specifications/debug-1.6.3.gemspec")
|
||||
debug_gemspec = Gem::Specification.load(debug_gemspec_path.to_s)
|
||||
debug_gemspec.dependencies.clear
|
||||
File.write(debug_gemspec_path, debug_gemspec.to_ruby)
|
||||
end
|
||||
|
||||
it "respects the existing lockfile, even when reresolving" do
|
||||
gemfile <<~G
|
||||
source "#{file_uri_for(gem_repo4)}"
|
||||
|
||||
gem "debug"
|
||||
G
|
||||
|
||||
lockfile <<~L
|
||||
GEM
|
||||
remote: #{file_uri_for(gem_repo4)}/
|
||||
specs:
|
||||
debug (1.6.3)
|
||||
irb (>= 1.3.6)
|
||||
irb (1.5.0)
|
||||
|
||||
PLATFORMS
|
||||
x86_64-linux
|
||||
|
||||
DEPENDENCIES
|
||||
debug
|
||||
|
||||
BUNDLED WITH
|
||||
#{Bundler::VERSION}
|
||||
L
|
||||
|
||||
simulate_platform "arm64-darwin-22" do
|
||||
bundle "lock"
|
||||
end
|
||||
|
||||
expect(lockfile).to eq <<~L
|
||||
GEM
|
||||
remote: #{file_uri_for(gem_repo4)}/
|
||||
specs:
|
||||
debug (1.6.3)
|
||||
irb (>= 1.3.6)
|
||||
irb (1.5.0)
|
||||
|
||||
PLATFORMS
|
||||
arm64-darwin-22
|
||||
x86_64-linux
|
||||
|
||||
DEPENDENCIES
|
||||
debug
|
||||
|
||||
BUNDLED WITH
|
||||
#{Bundler::VERSION}
|
||||
L
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -53,7 +53,10 @@ RSpec.describe "bundle install with :allow_offline_install" do
|
|||
File.open(tmp("broken_path/git"), "w", 0o755) do |f|
|
||||
f.puts strip_whitespace(<<-RUBY)
|
||||
#!/usr/bin/env ruby
|
||||
if %w(fetch --force --quiet --tags refs/heads/*:refs/heads/*).-(ARGV).empty? || %w(clone --bare --no-hardlinks --quiet).-(ARGV).empty?
|
||||
fetch_args = %w(fetch --force --quiet)
|
||||
clone_args = %w(clone --bare --no-hardlinks --quiet)
|
||||
|
||||
if (fetch_args.-(ARGV).empty? || clone_args.-(ARGV).empty?) && ARGV.any? {|arg| arg.start_with?("file://") }
|
||||
warn "git remote ops have been disabled"
|
||||
exit 1
|
||||
end
|
||||
|
|
|
@ -52,8 +52,9 @@ RSpec.describe "bundle install with git sources" do
|
|||
bundle "update foo"
|
||||
|
||||
sha = git.ref_for("main", 11)
|
||||
spec_file = default_bundle_path.join("bundler/gems/foo-1.0-#{sha}/foo.gemspec").to_s
|
||||
ruby_code = Gem::Specification.load(spec_file).to_ruby
|
||||
spec_file = default_bundle_path.join("bundler/gems/foo-1.0-#{sha}/foo.gemspec")
|
||||
expect(spec_file).to exist
|
||||
ruby_code = Gem::Specification.load(spec_file.to_s).to_ruby
|
||||
file_code = File.read(spec_file)
|
||||
expect(file_code).to eq(ruby_code)
|
||||
end
|
||||
|
@ -218,6 +219,22 @@ RSpec.describe "bundle install with git sources" do
|
|||
expect(out).to eq("WIN")
|
||||
end
|
||||
|
||||
it "works when an abbreviated revision is added after an initial, potentially shallow clone" do
|
||||
install_gemfile <<-G
|
||||
source "#{file_uri_for(gem_repo1)}"
|
||||
git "#{lib_path("foo-1.0")}" do
|
||||
gem "foo"
|
||||
end
|
||||
G
|
||||
|
||||
install_gemfile <<-G
|
||||
source "#{file_uri_for(gem_repo1)}"
|
||||
git "#{lib_path("foo-1.0")}", :ref => #{@revision[0..7].inspect} do
|
||||
gem "foo"
|
||||
end
|
||||
G
|
||||
end
|
||||
|
||||
it "works when the revision is a non-head ref" do
|
||||
# want to ensure we don't fallback to main
|
||||
update_git "foo", :path => lib_path("foo-1.0") do |s|
|
||||
|
|
|
@ -363,23 +363,19 @@ RSpec.describe "bundle install with specific platforms" do
|
|||
G
|
||||
|
||||
error_message = <<~ERROR.strip
|
||||
Could not find gem 'sorbet-static (= 0.5.6433)' with platform 'arm64-darwin-21', which is required by gem 'sorbet (= 0.5.6433)', in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally.
|
||||
Could not find compatible versions
|
||||
|
||||
Because every version of sorbet depends on sorbet-static = 0.5.6433
|
||||
and sorbet-static = 0.5.6433 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally for any resolution platforms (arm64-darwin-21),
|
||||
every version of sorbet is forbidden.
|
||||
So, because Gemfile depends on sorbet = 0.5.6433,
|
||||
version solving has failed.
|
||||
|
||||
The source contains the following gems matching 'sorbet-static (= 0.5.6433)':
|
||||
* sorbet-static-0.5.6433-universal-darwin-20
|
||||
* sorbet-static-0.5.6433-x86_64-linux
|
||||
ERROR
|
||||
|
||||
error_message = <<~ERROR.strip
|
||||
Could not find compatible versions
|
||||
|
||||
Because every version of sorbet depends on sorbet-static = 0.5.6433
|
||||
and sorbet-static = 0.5.6433 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally,
|
||||
every version of sorbet is forbidden.
|
||||
So, because Gemfile depends on sorbet = 0.5.6433,
|
||||
version solving has failed.
|
||||
ERROR
|
||||
|
||||
simulate_platform "arm64-darwin-21" do
|
||||
bundle "lock", :raise_on_error => false
|
||||
end
|
||||
|
|
|
@ -374,6 +374,57 @@ RSpec.describe "bundle install with install-time dependencies" do
|
|||
end
|
||||
end
|
||||
|
||||
context "with a Gemfile and lock file that don't resolve under the current platform" do
|
||||
before do
|
||||
build_repo4 do
|
||||
build_gem "sorbet", "0.5.10554" do |s|
|
||||
s.add_dependency "sorbet-static", "0.5.10554"
|
||||
end
|
||||
|
||||
build_gem "sorbet-static", "0.5.10554" do |s|
|
||||
s.platform = "universal-darwin-21"
|
||||
end
|
||||
end
|
||||
|
||||
gemfile <<~G
|
||||
source "#{file_uri_for(gem_repo4)}"
|
||||
gem 'sorbet', '= 0.5.10554'
|
||||
G
|
||||
|
||||
lockfile <<~L
|
||||
GEM
|
||||
remote: #{file_uri_for(gem_repo4)}/
|
||||
specs:
|
||||
sorbet (0.5.10554)
|
||||
sorbet-static (= 0.5.10554)
|
||||
sorbet-static (0.5.10554-universal-darwin-21)
|
||||
|
||||
PLATFORMS
|
||||
arm64-darwin-21
|
||||
|
||||
DEPENDENCIES
|
||||
sorbet (= 0.5.10554)
|
||||
|
||||
BUNDLED WITH
|
||||
#{Bundler::VERSION}
|
||||
L
|
||||
end
|
||||
|
||||
it "raises a proper error" do
|
||||
simulate_platform "aarch64-linux" do
|
||||
bundle "install", :raise_on_error => false
|
||||
end
|
||||
|
||||
nice_error = strip_whitespace(<<-E).strip
|
||||
Could not find gem 'sorbet-static (= 0.5.10554)' with platforms 'arm64-darwin-21', 'aarch64-linux' in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally.
|
||||
|
||||
The source contains the following gems matching 'sorbet-static (= 0.5.10554)':
|
||||
* sorbet-static-0.5.10554-universal-darwin-21
|
||||
E
|
||||
expect(err).to end_with(nice_error)
|
||||
end
|
||||
end
|
||||
|
||||
it "gives a meaningful error on ruby version mismatches between dependencies" do
|
||||
build_repo4 do
|
||||
build_gem "requires-old-ruby" do |s|
|
||||
|
|
|
@ -14,6 +14,14 @@ RSpec.describe "bundle lock with git gems" do
|
|||
expect(the_bundle).to include_gems "foo 1.0.0"
|
||||
end
|
||||
|
||||
it "doesn't print errors even if running lock after removing the cache" do
|
||||
FileUtils.rm_rf(Dir[default_cache_path("git/foo-1.0-*")].first)
|
||||
|
||||
bundle "lock --verbose"
|
||||
|
||||
expect(err).to be_empty
|
||||
end
|
||||
|
||||
it "locks a git source to the current ref" do
|
||||
update_git "foo"
|
||||
bundle :install
|
||||
|
|
|
@ -21,7 +21,7 @@ end
|
|||
RSpec.configure do |config|
|
||||
config.filter_run_excluding :realworld => true
|
||||
|
||||
git_version = Bundler::Source::Git::GitProxy.new(nil, nil, nil).version
|
||||
git_version = Bundler::Source::Git::GitProxy.new(nil, nil).version
|
||||
|
||||
config.filter_run_excluding :git => RequirementChecker.against(git_version)
|
||||
config.filter_run_excluding :bundler => RequirementChecker.against(Bundler::VERSION.split(".")[0])
|
||||
|
|
|
@ -118,6 +118,14 @@ module Spec
|
|||
end
|
||||
end
|
||||
|
||||
def default_cache_path(*path)
|
||||
if Bundler.feature_flag.global_gem_cache?
|
||||
home(".bundle/cache", *path)
|
||||
else
|
||||
default_bundle_path("cache/bundler", *path)
|
||||
end
|
||||
end
|
||||
|
||||
def bundled_app(*path)
|
||||
root = tmp.join("bundled_app")
|
||||
FileUtils.mkdir_p(root)
|
||||
|
|
|
@ -120,6 +120,7 @@ RSpec.describe "bundle update" do
|
|||
G
|
||||
|
||||
bundle "update", :all => true
|
||||
expect(err).to be_empty
|
||||
end
|
||||
|
||||
describe "with submodules" do
|
||||
|
|
Загрузка…
Ссылка в новой задаче