@@ -94,7 +94,7 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti
9494
9595 @locked_ruby_version = nil
9696 @new_platforms = [ ]
97- @removed_platform = nil
97+ @removed_platforms = [ ]
9898
9999 if lockfile_exists?
100100 @lockfile_contents = Bundler . read_file ( lockfile )
@@ -330,7 +330,7 @@ def resolve
330330 SpecSet . new ( filter_specs ( @locked_specs , @dependencies - deleted_deps ) )
331331 else
332332 Bundler . ui . debug "Found no changes, using resolution from the lockfile"
333- if @removed_platform || @locked_gems . may_include_redundant_platform_specific_gems?
333+ if @removed_platforms . any? || @locked_gems . may_include_redundant_platform_specific_gems?
334334 SpecSet . new ( filter_specs ( @locked_specs , @dependencies ) )
335335 else
336336 @locked_specs
@@ -412,41 +412,8 @@ def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
412412
413413 raise ProductionError , "Frozen mode is set, but there's no lockfile" unless lockfile_exists?
414414
415- added = [ ]
416- deleted = [ ]
417- changed = [ ]
418-
419- new_platforms = @platforms - @locked_platforms
420- deleted_platforms = @locked_platforms - @platforms
421- added . concat new_platforms . map { |p | "* platform: #{ p } " }
422- deleted . concat deleted_platforms . map { |p | "* platform: #{ p } " }
423-
424- added . concat new_deps . map { |d | "* #{ pretty_dep ( d ) } " } if new_deps . any?
425- deleted . concat deleted_deps . map { |d | "* #{ pretty_dep ( d ) } " } if deleted_deps . any?
426-
427- both_sources = Hash . new { |h , k | h [ k ] = [ ] }
428- current_dependencies . each { |d | both_sources [ d . name ] [ 0 ] = d }
429- current_locked_dependencies . each { |d | both_sources [ d . name ] [ 1 ] = d }
430-
431- both_sources . each do |name , ( dep , lock_dep ) |
432- next if dep . nil? || lock_dep . nil?
433-
434- gemfile_source = dep . source || default_source
435- lock_source = lock_dep . source || default_source
436- next if lock_source . include? ( gemfile_source )
437-
438- gemfile_source_name = dep . source ? gemfile_source . to_gemfile : "no specified source"
439- lockfile_source_name = lock_dep . source ? lock_source . to_gemfile : "no specified source"
440- changed << "* #{ name } from `#{ lockfile_source_name } ` to `#{ gemfile_source_name } `"
441- end
442-
443- reason = resolve_needed? ? change_reason : "some dependencies were deleted from your gemfile"
444- msg = String . new
445- msg << "#{ reason . capitalize . strip } , but the lockfile can't be updated because frozen mode is set"
446- msg << "\n \n You have added to the Gemfile:\n " << added . join ( "\n " ) if added . any?
447- msg << "\n \n You have deleted from the Gemfile:\n " << deleted . join ( "\n " ) if deleted . any?
448- msg << "\n \n You have changed in the Gemfile:\n " << changed . join ( "\n " ) if changed . any?
449- msg << "\n \n Run `bundle install` elsewhere and add the updated #{ SharedHelpers . relative_gemfile_path } to version control.\n " unless unlocking?
415+ msg = lockfile_changes_summary ( "frozen mode is set" )
416+ return unless msg
450417
451418 unless explicit_flag
452419 suggested_command = unless Bundler . settings . locations ( "frozen" ) . keys . include? ( :env )
@@ -456,7 +423,7 @@ def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
456423 "freeze by running `#{ suggested_command } `." if suggested_command
457424 end
458425
459- raise ProductionError , msg if added . any? || deleted . any? || changed . any? || resolve_needed?
426+ raise ProductionError , msg
460427 end
461428
462429 def validate_runtime!
@@ -511,10 +478,10 @@ def add_platform(platform)
511478 end
512479
513480 def remove_platform ( platform )
514- removed_platform = @platforms . delete ( Gem :: Platform . new ( platform ) )
515- @removed_platform ||= removed_platform
516- return if removed_platform
517- raise InvalidOption , "Unable to remove the platform ` #{ platform } ` since the only platforms are #{ @platforms . join ", " } "
481+ raise InvalidOption , "Unable to remove the platform ` #{ platform } ` since the only platforms are #{ @platforms . join ", " } " unless @platforms . include? ( platform )
482+
483+ @removed_platforms << platform
484+ @platforms . delete ( platform )
518485 end
519486
520487 def nothing_changed?
@@ -541,6 +508,46 @@ def add_checksums
541508
542509 private
543510
511+ def lockfile_changes_summary ( update_refused_reason )
512+ added = [ ]
513+ deleted = [ ]
514+ changed = [ ]
515+
516+ added . concat @new_platforms . map { |p | "* platform: #{ p } " }
517+ deleted . concat @removed_platforms . map { |p | "* platform: #{ p } " }
518+
519+ added . concat new_deps . map { |d | "* #{ pretty_dep ( d ) } " } if new_deps . any?
520+ deleted . concat deleted_deps . map { |d | "* #{ pretty_dep ( d ) } " } if deleted_deps . any?
521+
522+ both_sources = Hash . new { |h , k | h [ k ] = [ ] }
523+ current_dependencies . each { |d | both_sources [ d . name ] [ 0 ] = d }
524+ current_locked_dependencies . each { |d | both_sources [ d . name ] [ 1 ] = d }
525+
526+ both_sources . each do |name , ( dep , lock_dep ) |
527+ next if dep . nil? || lock_dep . nil?
528+
529+ gemfile_source = dep . source || default_source
530+ lock_source = lock_dep . source || default_source
531+ next if lock_source . include? ( gemfile_source )
532+
533+ gemfile_source_name = dep . source ? gemfile_source . to_gemfile : "no specified source"
534+ lockfile_source_name = lock_dep . source ? lock_source . to_gemfile : "no specified source"
535+ changed << "* #{ name } from `#{ lockfile_source_name } ` to `#{ gemfile_source_name } `"
536+ end
537+
538+ return unless added . any? || deleted . any? || changed . any? || resolve_needed?
539+
540+ reason = resolve_needed? ? change_reason : "some dependencies were deleted from your gemfile"
541+
542+ msg = String . new
543+ msg << "#{ reason . capitalize . strip } , but the lockfile can't be updated because #{ update_refused_reason } "
544+ msg << "\n \n You have added to the Gemfile:\n " << added . join ( "\n " ) if added . any?
545+ msg << "\n \n You have deleted from the Gemfile:\n " << deleted . join ( "\n " ) if deleted . any?
546+ msg << "\n \n You have changed in the Gemfile:\n " << changed . join ( "\n " ) if changed . any?
547+ msg << "\n \n Run `bundle install` elsewhere and add the updated #{ SharedHelpers . relative_gemfile_path } to version control.\n " unless unlocking?
548+ msg
549+ end
550+
544551 def install_needed?
545552 resolve_needed? || missing_specs?
546553 end
@@ -601,8 +608,12 @@ def write_lock(file, preserve_unknown_sections)
601608 return
602609 end
603610
604- SharedHelpers . filesystem_access ( file ) do |p |
605- File . open ( p , "wb" ) { |f | f . puts ( contents ) }
611+ begin
612+ SharedHelpers . filesystem_access ( file ) do |p |
613+ File . open ( p , "wb" ) { |f | f . puts ( contents ) }
614+ end
615+ rescue ReadOnlyFileSystemError
616+ raise ProductionError , lockfile_changes_summary ( "file system is read-only" )
606617 end
607618 end
608619
@@ -625,7 +636,8 @@ def resolution_packages
625636 @resolution_packages ||= begin
626637 last_resolve = converge_locked_specs
627638 remove_invalid_platforms!
628- packages = Resolver ::Base . new ( source_requirements , expanded_dependencies , last_resolve , @platforms , locked_specs : @originally_locked_specs , unlock : @unlocking_all || @gems_to_unlock , prerelease : gem_version_promoter . pre? , prefer_local : @prefer_local , new_platforms : @new_platforms )
639+ new_resolution_platforms = @current_platform_missing ? @new_platforms + [ local_platform ] : @new_platforms
640+ packages = Resolver ::Base . new ( source_requirements , expanded_dependencies , last_resolve , @platforms , locked_specs : @originally_locked_specs , unlock : @unlocking_all || @gems_to_unlock , prerelease : gem_version_promoter . pre? , prefer_local : @prefer_local , new_platforms : new_resolution_platforms )
629641 packages = additional_base_requirements_to_prevent_downgrades ( packages )
630642 packages = additional_base_requirements_to_force_updates ( packages )
631643 packages
@@ -768,7 +780,6 @@ def add_current_platform
768780 @most_specific_non_local_locked_platform = find_most_specific_locked_platform
769781 return if @most_specific_non_local_locked_platform
770782
771- @new_platforms << local_platform
772783 @platforms << local_platform
773784 true
774785 end
@@ -799,7 +810,7 @@ def change_reason
799810 [ @source_changes , "the list of sources changed" ] ,
800811 [ @dependency_changes , "the dependencies in your gemfile changed" ] ,
801812 [ @current_platform_missing , "your lockfile does not include the current platform" ] ,
802- [ @new_platforms . any? , "you added a new platform to your gemfile " ] ,
813+ [ @new_platforms . any? , "you are adding a new platform to your lockfile " ] ,
803814 [ @path_changes , "the gemspecs for path gems changed" ] ,
804815 [ @local_changes , "the gemspecs for git local gems changed" ] ,
805816 [ @missing_lockfile_dep , "your lock file is missing \" #{ @missing_lockfile_dep } \" " ] ,
0 commit comments