lib/bundler/definition.rb in bundler-1.13.7 vs lib/bundler/definition.rb in bundler-1.14.0.pre.1
- old
+ new
@@ -60,18 +60,20 @@
@optional_groups = optional_groups
@remote = false
@specs = nil
@ruby_version = ruby_version
+ @lockfile = lockfile
@lockfile_contents = String.new
@locked_bundler_version = nil
@locked_ruby_version = nil
if lockfile && File.exist?(lockfile)
@lockfile_contents = Bundler.read_file(lockfile)
@locked_gems = LockfileParser.new(@lockfile_contents)
- @platforms = @locked_gems.platforms
+ @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
@@ -88,30 +90,29 @@
@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
- unless locked_ruby_version_object = RubyVersion.from_string(@locked_ruby_version)
- raise LockfileError, "Failed to create a `RubyVersion` object from " \
- "`#{@locked_ruby_version}` found in #{lockfile} -- try running `bundle update --ruby`."
- end
+ @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)
- current_platform = Bundler.rubygems.platforms.map {|p| generic(p) }.compact.last
- add_platform(current_platform)
+ add_current_platform unless Bundler.settings[:frozen]
@path_changes = converge_paths
- eager_unlock = expand_dependencies(@unlock[:gems])
- @unlock[:gems] = @locked_specs.for(eager_unlock).map(&:name)
+ unless @unlock[:lock_shared_dependencies]
+ eager_unlock = expand_dependencies(@unlock[:gems])
+ @unlock[:gems] = @locked_specs.for(eager_unlock).map(&:name)
+ end
+
@gem_version_promoter = create_gem_version_promoter
@source_changes = converge_sources
@dependency_changes = converge_dependencies
@local_changes = converge_locals
@@ -173,11 +174,11 @@
begin
specs = resolve.materialize(Bundler.settings[:cache_all_platforms] ? dependencies : 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
+ 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 different version of #{locked_gem} that hasn't been removed in order to install."
end
@@ -245,11 +246,11 @@
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, ruby_version, gem_version_promoter, additional_base_requirements_for_resolve)
+ last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve)
end
end
end
def index
@@ -260,10 +261,12 @@
source.dependency_names = dependency_names.dup
idx.add_source source.specs
dependency_names -= pinned_spec_names(source.specs)
dependency_names.concat(source.unmet_deps).uniq!
end
+ idx << Gem::Specification.new("ruby\0", RubyVersion.system.to_gem_version_with_patchlevel)
+ idx << Gem::Specification.new("rubygems\0", Gem::VERSION)
end
end
# used when frozen is enabled so we can find the bundler
# spec, even if (say) a git gem is not checked out.
@@ -336,10 +339,22 @@
else
@locked_ruby_version
end
end
+ 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
+
def to_lock
out = String.new
sources.lock_sources.each do |source|
# Add the source header
@@ -399,10 +414,15 @@
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
@@ -447,10 +467,15 @@
msg << "\n"
raise ProductionError, msg if added.any? || deleted.any? || changed.any?
end
+ def validate_runtime!
+ validate_ruby!
+ validate_platforms!
+ end
+
def validate_ruby!
return unless ruby_version
if diff = ruby_version.diff(Bundler::RubyVersion.system)
problem, expected, actual = diff
@@ -472,20 +497,46 @@
raise RubyVersionMismatch, msg
end
end
+ 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
+
def add_platform(platform)
@new_platform ||= !@platforms.include?(platform)
@platforms |= [platform]
end
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
+ def add_current_platform
+ current_platform = Bundler.local_platform
+ add_platform(current_platform) if Bundler.settings[:specific_platform]
+ add_platform(generic(current_platform))
+ end
+
+ def find_resolved_spec(current_spec)
+ specs.find_by_name_and_platform(current_spec.name, current_spec.platform)
+ end
+
+ def find_indexed_specs(current_spec)
+ index[current_spec.name].select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version)
+ end
+
attr_reader :sources
private :sources
private
@@ -724,20 +775,58 @@
def satisfies_locked_spec?(dep)
@locked_specs.any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
end
+ # This list of dependencies is only used in #resolve, so it's OK to add
+ # the metadata dependencies here
def expanded_dependencies
- @expanded_dependencies ||= expand_dependencies(dependencies, @remote)
+ @expanded_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
+
+ metadata_dependencies = [
+ Dependency.new("ruby\0", ruby_versions),
+ Dependency.new("rubygems\0", Gem::VERSION),
+ ]
+ expand_dependencies(dependencies + metadata_dependencies, @remote)
+ end
end
+ 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
+
def expand_dependencies(dependencies, remote = false)
deps = []
dependencies.each do |dep|
dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name)
- next unless remote || dep.current_platform?
- dep.gem_platforms(@platforms).each do |p|
+ next if !remote && !dep.current_platform?
+ platforms = dep.gem_platforms(@platforms)
+ if platforms.empty?
+ 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 #{dep.platforms.map {|p| Dependency::PLATFORM_MAP[p] }.join ", "}. " \
+ "To add those platforms to the bundle, run `bundle lock --add-platform #{dep.platforms.join ", "}`."
+ end
+ platforms.each do |p|
deps << DepProxy.new(dep, p) if remote || p == generic_local_platform
end
end
deps
end
@@ -810,12 +899,13 @@
requires
end
end
def additional_base_requirements_for_resolve
- return [] unless @locked_gems && Bundler.settings[:only_update_to_newer_versions]
+ return [] unless @locked_gems && Bundler.feature_flag.only_update_to_newer_versions?
@locked_gems.specs.reduce({}) do |requirements, locked_spec|
- requirements[locked_spec.name] = Gem::Dependency.new(locked_spec.name, ">= #{locked_spec.version}")
+ dep = Gem::Dependency.new(locked_spec.name, ">= #{locked_spec.version}")
+ requirements[locked_spec.name] = DepProxy.new(dep, locked_spec.platform)
requirements
end.values
end
end
end