| 
									
										
										
										
											2024-08-12 10:30:59 +01:00
										 |  |  | # typed: true # rubocop:todo Sorbet/StrictSigil | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-22 03:23:50 +02:00
										 |  |  | require "lock_file" | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  | require "keg" | 
					
						
							|  |  |  | require "tab" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 19:45:33 +02:00
										 |  |  | # Helper class for migrating a formula from an old to a new name. | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  | class Migrator | 
					
						
							| 
									
										
										
										
											2020-08-02 14:32:31 +02:00
										 |  |  |   include Context | 
					
						
							| 
									
										
										
										
											2020-08-02 04:46:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 19:45:33 +02:00
										 |  |  |   # Error for when a migration is necessary. | 
					
						
							| 
									
										
										
										
											2015-08-14 14:50:26 +01:00
										 |  |  |   class MigrationNeededError < RuntimeError | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     def initialize(oldname, newname) | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |       super <<~EOS | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |         #{oldname} was renamed to #{newname} and needs to be migrated by running: | 
					
						
							|  |  |  |           brew migrate #{oldname} | 
					
						
							| 
									
										
										
										
											2015-08-14 14:50:26 +01:00
										 |  |  |       EOS | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 19:45:33 +02:00
										 |  |  |   # Error for when the old name's path does not exist. | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   class MigratorNoOldpathError < RuntimeError | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     def initialize(oldname) | 
					
						
							|  |  |  |       super "#{HOMEBREW_CELLAR/oldname} doesn't exist." | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 19:45:33 +02:00
										 |  |  |   # Error for when a formula is migrated to a different tap without explicitly using its fully-qualified name. | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   class MigratorDifferentTapsError < RuntimeError | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     def initialize(formula, oldname, tap) | 
					
						
							| 
									
										
										
										
											2016-03-08 21:53:29 +08:00
										 |  |  |       msg = if tap.core_tap? | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |         "Please try to use #{oldname} to refer to the formula.\n" | 
					
						
							| 
									
										
										
										
											2015-08-17 21:49:37 +03:00
										 |  |  |       elsif tap | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |         "Please try to use fully-qualified #{tap}/#{oldname} to refer to the formula.\n" | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2015-08-17 21:49:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |       super <<~EOS | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |         #{formula.name} from #{formula.tap} is given, but old name #{oldname} was installed from #{tap || "path or url"}. | 
					
						
							| 
									
										
										
										
											2021-01-24 21:25:12 -05:00
										 |  |  |         #{msg}To force migration, run: | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |           brew migrate --force #{oldname} | 
					
						
							| 
									
										
										
										
											2015-08-17 21:49:37 +03:00
										 |  |  |       EOS | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Instance of renamed formula. | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   attr_reader :formula | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Old name of the formula. | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |   attr_reader :oldname | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Path to oldname's cellar. | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |   attr_reader :old_cellar | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Path to oldname pin. | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |   attr_reader :old_pin_record | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Path to oldname opt. | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |   attr_reader :old_opt_records | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |   # Oldname linked kegs. | 
					
						
							|  |  |  |   attr_reader :old_linked_kegs | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |   # Oldname linked kegs that were fully linked. | 
					
						
							|  |  |  |   attr_reader :old_full_linked_kegs | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Tabs from oldname kegs. | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |   attr_reader :old_tabs | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Tap of the old name. | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |   attr_reader :old_tap | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Resolved path to oldname pin. | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   attr_reader :old_pin_link_record | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # New name of the formula. | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |   attr_reader :newname | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Path to newname cellar according to new name. | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |   attr_reader :new_cellar | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # True if new cellar existed at initialization time. | 
					
						
							| 
									
										
										
										
											2017-03-31 10:36:26 +01:00
										 |  |  |   attr_reader :new_cellar_existed | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Path to newname pin. | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |   attr_reader :new_pin_record | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Path to newname keg that will be linked if old_linked_keg isn't nil. | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |   attr_reader :new_linked_keg_record | 
					
						
							| 
									
										
										
										
											2015-08-14 20:36:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |   def self.oldnames_needing_migration(formula) | 
					
						
							|  |  |  |     formula.oldnames.select do |oldname| | 
					
						
							|  |  |  |       oldname_rack = HOMEBREW_CELLAR/oldname | 
					
						
							|  |  |  |       next false if oldname_rack.symlink? | 
					
						
							|  |  |  |       next false unless oldname_rack.directory? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |       true | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |   def self.needs_migration?(formula) | 
					
						
							|  |  |  |     !oldnames_needing_migration(formula).empty? | 
					
						
							| 
									
										
										
										
											2017-03-29 11:19:25 +01:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-31 12:27:14 -04:00
										 |  |  |   def self.migrate_if_needed(formula, force:, dry_run: false) | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     oldnames = Migrator.oldnames_needing_migration(formula) | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-29 11:19:25 +01:00
										 |  |  |     begin | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |       oldnames.each do |oldname| | 
					
						
							| 
									
										
										
										
											2023-04-08 14:10:58 +02:00
										 |  |  |         if dry_run | 
					
						
							|  |  |  |           oh1 "Would migrate formula #{Formatter.identifier(oldname)} to #{Formatter.identifier(formula.name)}" | 
					
						
							|  |  |  |           next | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |         migrator = Migrator.new(formula, oldname, force:) | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |         migrator.migrate | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2017-10-07 00:31:28 +02:00
										 |  |  |     rescue => e | 
					
						
							| 
									
										
										
										
											2017-03-29 11:19:25 +01:00
										 |  |  |       onoe e | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |   def initialize(formula, oldname, force: false) | 
					
						
							|  |  |  |     @oldname = oldname | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |     @newname = formula.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @formula = formula | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     @old_cellar = HOMEBREW_CELLAR/oldname | 
					
						
							|  |  |  |     raise MigratorNoOldpathError, oldname unless old_cellar.exist? | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-28 03:23:21 +02:00
										 |  |  |     @old_tabs = old_cellar.subdirs.map { |d| Keg.new(d).tab } | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |     @old_tap = old_tabs.first.tap | 
					
						
							| 
									
										
										
										
											2015-08-17 21:49:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     raise MigratorDifferentTapsError.new(formula, oldname, old_tap) if !force && !from_same_tap_user? | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |     @new_cellar = HOMEBREW_CELLAR/formula.name | 
					
						
							| 
									
										
										
										
											2017-03-31 10:36:26 +01:00
										 |  |  |     @new_cellar_existed = @new_cellar.exist? | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     @old_linked_kegs = linked_old_linked_kegs | 
					
						
							|  |  |  |     @old_full_linked_kegs = [] | 
					
						
							|  |  |  |     @old_opt_records = [] | 
					
						
							|  |  |  |     old_linked_kegs.each do |old_linked_keg| | 
					
						
							|  |  |  |       @old_full_linked_kegs << old_linked_keg if old_linked_keg.linked? | 
					
						
							|  |  |  |       @old_opt_records << old_linked_keg.opt_record if old_linked_keg.optlinked? | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     unless old_linked_kegs.empty? | 
					
						
							|  |  |  |       @new_linked_keg_record = HOMEBREW_CELLAR/"#{newname}/#{File.basename(old_linked_kegs.first)}" | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-15 18:28:42 +01:00
										 |  |  |     @old_pin_record = HOMEBREW_PINNED_KEGS/oldname | 
					
						
							|  |  |  |     @new_pin_record = HOMEBREW_PINNED_KEGS/newname | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |     @pinned = old_pin_record.symlink? | 
					
						
							|  |  |  |     @old_pin_link_record = old_pin_record.readlink if @pinned | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Fix `INSTALL_RECEIPT`s for tap-migrated formula. | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   def fix_tabs | 
					
						
							|  |  |  |     old_tabs.each do |tab| | 
					
						
							| 
									
										
										
										
											2015-12-06 22:50:21 +08:00
										 |  |  |       tab.tap = formula.tap | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |       tab.write | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |   sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2017-03-31 10:28:45 +01:00
										 |  |  |   def from_same_tap_user? | 
					
						
							|  |  |  |     formula_tap_user = formula.tap.user if formula.tap | 
					
						
							|  |  |  |     old_tap_user = nil | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-30 19:18:40 +01:00
										 |  |  |     new_tap = if old_tap | 
					
						
							| 
									
										
										
										
											2017-03-31 10:28:45 +01:00
										 |  |  |       old_tap_user, = old_tap.user | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |       if (migrate_tap = old_tap.tap_migrations[oldname]) | 
					
						
							| 
									
										
										
										
											2017-03-31 10:28:45 +01:00
										 |  |  |         new_tap_user, new_tap_repo = migrate_tap.split("/") | 
					
						
							| 
									
										
										
										
											2017-03-30 19:18:40 +01:00
										 |  |  |         "#{new_tap_user}/#{new_tap_repo}" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-31 10:28:45 +01:00
										 |  |  |     if formula_tap_user == old_tap_user | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |       true | 
					
						
							|  |  |  |     # Homebrew didn't use to update tabs while performing tap-migrations, | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |     # so there can be `INSTALL_RECEIPT`s containing wrong information about tap, | 
					
						
							| 
									
										
										
										
											2016-02-26 15:33:27 +08:00
										 |  |  |     # so we check if there is an entry about oldname migrated to tap and if | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |     # newname's tap is the same as tap to which oldname migrated, then we | 
					
						
							|  |  |  |     # can perform migrations and the taps for oldname and newname are the same. | 
					
						
							| 
									
										
										
										
											2017-03-30 19:18:40 +01:00
										 |  |  |     elsif formula.tap && old_tap && formula.tap == new_tap | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |       fix_tabs | 
					
						
							|  |  |  |       true | 
					
						
							| 
									
										
										
										
											2015-12-06 22:50:21 +08:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |       false | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |   def linked_old_linked_kegs | 
					
						
							| 
									
										
										
										
											2017-03-30 19:09:06 +01:00
										 |  |  |     keg_dirs = [] | 
					
						
							|  |  |  |     keg_dirs += new_cellar.subdirs if new_cellar.exist? | 
					
						
							|  |  |  |     keg_dirs += old_cellar.subdirs | 
					
						
							|  |  |  |     kegs = keg_dirs.map { |d| Keg.new(d) } | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     kegs.select { |keg| keg.linked? || keg.optlinked? } | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def pinned? | 
					
						
							|  |  |  |     @pinned | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def migrate | 
					
						
							| 
									
										
										
										
											2023-04-08 14:10:58 +02:00
										 |  |  |     oh1 "Migrating formula #{Formatter.identifier(oldname)} to #{Formatter.identifier(newname)}" | 
					
						
							| 
									
										
										
										
											2017-03-29 11:21:31 +01:00
										 |  |  |     lock | 
					
						
							|  |  |  |     unlink_oldname | 
					
						
							|  |  |  |     unlink_newname if new_cellar.exist? | 
					
						
							|  |  |  |     repin | 
					
						
							|  |  |  |     move_to_new_directory | 
					
						
							|  |  |  |     link_oldname_cellar | 
					
						
							|  |  |  |     link_oldname_opt | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     link_newname unless old_linked_kegs.empty? | 
					
						
							| 
									
										
										
										
											2017-03-29 11:21:31 +01:00
										 |  |  |     update_tabs | 
					
						
							| 
									
										
										
										
											2018-03-02 21:23:04 +00:00
										 |  |  |     return unless formula.outdated? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-02 21:23:04 +00:00
										 |  |  |     opoo <<~EOS | 
					
						
							| 
									
										
										
										
											2018-03-05 10:14:39 +00:00
										 |  |  |       #{Formatter.identifier(newname)} is outdated! | 
					
						
							|  |  |  |       To avoid broken installations, as soon as possible please run: | 
					
						
							|  |  |  |         brew upgrade | 
					
						
							|  |  |  |       Or, if you're OK with a less reliable fix: | 
					
						
							| 
									
										
										
										
											2018-03-02 21:23:04 +00:00
										 |  |  |         brew upgrade #{newname} | 
					
						
							|  |  |  |     EOS | 
					
						
							| 
									
										
										
										
											2017-03-29 11:21:31 +01:00
										 |  |  |   rescue Interrupt | 
					
						
							|  |  |  |     ignore_interrupts { backup_oldname } | 
					
						
							| 
									
										
										
										
											2017-10-07 00:31:28 +02:00
										 |  |  |   rescue Exception => e # rubocop:disable Lint/RescueException | 
					
						
							| 
									
										
										
										
											2020-07-06 15:28:50 -04:00
										 |  |  |     onoe "The migration did not complete successfully." | 
					
						
							| 
									
										
										
										
											2017-03-29 11:21:31 +01:00
										 |  |  |     puts e | 
					
						
							| 
									
										
										
										
											2024-07-15 13:44:01 -04:00
										 |  |  |     if debug? | 
					
						
							|  |  |  |       require "utils/backtrace" | 
					
						
							|  |  |  |       puts Utils::Backtrace.clean(e) | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2017-03-29 11:21:31 +01:00
										 |  |  |     puts "Backing up..." | 
					
						
							|  |  |  |     ignore_interrupts { backup_oldname } | 
					
						
							|  |  |  |   ensure | 
					
						
							|  |  |  |     unlock | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |   def remove_conflicts(directory) | 
					
						
							|  |  |  |     conflicted = T.let(false, T::Boolean) | 
					
						
							| 
									
										
										
										
											2017-03-29 11:21:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     directory.each_child do |c| | 
					
						
							|  |  |  |       if c.directory? && !c.symlink? | 
					
						
							|  |  |  |         conflicted ||= remove_conflicts(c) | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         next unless (new_cellar/c.relative_path_from(old_cellar)).exist? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-29 11:21:31 +01:00
										 |  |  |         begin | 
					
						
							|  |  |  |           FileUtils.rm_rf c | 
					
						
							|  |  |  |         rescue Errno::EACCES | 
					
						
							| 
									
										
										
										
											2017-03-17 09:21:41 -07:00
										 |  |  |           conflicted = true | 
					
						
							|  |  |  |           onoe "#{new_cellar/c.basename} already exists." | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     conflicted | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def merge_directory(directory) | 
					
						
							|  |  |  |     directory.each_child do |c| | 
					
						
							|  |  |  |       new_path = new_cellar/c.relative_path_from(old_cellar) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if c.directory? && !c.symlink? && new_path.exist? | 
					
						
							|  |  |  |         merge_directory(c) | 
					
						
							|  |  |  |         c.unlink | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         FileUtils.mv(c, new_path) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Move everything from `Cellar/oldname` to `Cellar/newname`. | 
					
						
							|  |  |  |   def move_to_new_directory | 
					
						
							|  |  |  |     return unless old_cellar.exist? | 
					
						
							| 
									
										
										
										
											2017-03-29 11:21:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     if new_cellar.exist? | 
					
						
							|  |  |  |       conflicted = remove_conflicts(old_cellar) | 
					
						
							|  |  |  |       odie "Remove #{new_cellar} and #{old_cellar} manually and run `brew reinstall #{newname}`." if conflicted | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-05 10:14:39 +00:00
										 |  |  |     oh1 "Moving #{Formatter.identifier(oldname)} versions to #{new_cellar}" | 
					
						
							| 
									
										
										
										
											2017-03-17 09:21:41 -07:00
										 |  |  |     if new_cellar.exist? | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |       merge_directory(old_cellar) | 
					
						
							| 
									
										
										
										
											2017-03-17 09:21:41 -07:00
										 |  |  |     else | 
					
						
							|  |  |  |       FileUtils.mv(old_cellar, new_cellar) | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def repin | 
					
						
							| 
									
										
										
										
											2016-09-23 22:02:23 +02:00
										 |  |  |     return unless pinned? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-26 20:55:51 +02:00
										 |  |  |     # `old_pin_record` is a relative symlink and when we try to to read it | 
					
						
							| 
									
										
										
										
											2016-09-23 22:02:23 +02:00
										 |  |  |     # from <dir> we actually try to find file | 
					
						
							|  |  |  |     # <dir>/../<...>/../Cellar/name/version. | 
					
						
							|  |  |  |     # To repin formula we need to update the link thus that it points to | 
					
						
							|  |  |  |     # the right directory. | 
					
						
							| 
									
										
										
										
											2024-04-26 20:55:51 +02:00
										 |  |  |     # | 
					
						
							|  |  |  |     # NOTE: `old_pin_record.realpath.sub(oldname, newname)` is unacceptable | 
					
						
							|  |  |  |     # here, because it resolves every symlink for `old_pin_record` and then | 
					
						
							| 
									
										
										
										
											2016-09-23 22:02:23 +02:00
										 |  |  |     # substitutes oldname with newname. It breaks things like | 
					
						
							| 
									
										
										
										
											2024-04-26 20:55:51 +02:00
										 |  |  |     # `Pathname#make_relative_symlink`, where `Pathname#relative_path_from` | 
					
						
							|  |  |  |     # is used to find the relative path from source to destination parent | 
					
						
							|  |  |  |     # and it assumes no symlinks. | 
					
						
							| 
									
										
										
										
											2017-06-01 16:06:51 +02:00
										 |  |  |     src_oldname = (old_pin_record.dirname/old_pin_link_record).expand_path | 
					
						
							| 
									
										
										
										
											2016-09-23 22:02:23 +02:00
										 |  |  |     new_pin_record.make_relative_symlink(src_oldname.sub(oldname, newname)) | 
					
						
							|  |  |  |     old_pin_record.delete | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def unlink_oldname | 
					
						
							| 
									
										
										
										
											2016-08-30 21:38:13 +02:00
										 |  |  |     oh1 "Unlinking #{Formatter.identifier(oldname)}" | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |     old_cellar.subdirs.each do |d| | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |       keg = Keg.new(d) | 
					
						
							| 
									
										
										
										
											2020-08-02 04:46:32 +02:00
										 |  |  |       keg.unlink(verbose: verbose?) | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-17 09:21:41 -07:00
										 |  |  |   def unlink_newname | 
					
						
							| 
									
										
										
										
											2018-03-05 10:14:39 +00:00
										 |  |  |     oh1 "Temporarily unlinking #{Formatter.identifier(newname)}" | 
					
						
							| 
									
										
										
										
											2017-03-17 09:21:41 -07:00
										 |  |  |     new_cellar.subdirs.each do |d| | 
					
						
							|  |  |  |       keg = Keg.new(d) | 
					
						
							| 
									
										
										
										
											2020-08-02 04:46:32 +02:00
										 |  |  |       keg.unlink(verbose: verbose?) | 
					
						
							| 
									
										
										
										
											2017-03-17 09:21:41 -07:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   def link_newname | 
					
						
							| 
									
										
										
										
											2018-03-05 10:14:39 +00:00
										 |  |  |     oh1 "Relinking #{Formatter.identifier(newname)}" | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |     new_keg = Keg.new(new_linked_keg_record) | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-12 16:21:13 +03:00
										 |  |  |     # If old_keg wasn't linked then we just optlink a keg. | 
					
						
							|  |  |  |     # If old keg wasn't optlinked and linked, we don't call this method at all. | 
					
						
							|  |  |  |     # If formula is keg-only we also optlink it. | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     if formula.keg_only? || old_full_linked_kegs.empty? | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |       begin | 
					
						
							| 
									
										
										
										
											2020-08-02 04:46:32 +02:00
										 |  |  |         new_keg.optlink(verbose: verbose?) | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |       rescue Keg::LinkError => e | 
					
						
							|  |  |  |         onoe "Failed to create #{formula.opt_prefix}" | 
					
						
							|  |  |  |         raise | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |     new_keg.remove_linked_keg_record if new_keg.linked? | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     begin | 
					
						
							| 
									
										
										
										
											2020-08-02 04:46:32 +02:00
										 |  |  |       new_keg.link(overwrite: true, verbose: verbose?) | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |     rescue Keg::ConflictError => e | 
					
						
							| 
									
										
										
										
											2020-07-06 15:28:50 -04:00
										 |  |  |       onoe "The `brew link` step did not complete successfully." | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |       puts e | 
					
						
							|  |  |  |       puts | 
					
						
							|  |  |  |       puts "Possible conflicting files are:" | 
					
						
							| 
									
										
										
										
											2020-08-02 04:46:32 +02:00
										 |  |  |       new_keg.link(dry_run: true, overwrite: true, verbose: verbose?) | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |       raise | 
					
						
							|  |  |  |     rescue Keg::LinkError => e | 
					
						
							| 
									
										
										
										
											2020-07-06 15:28:50 -04:00
										 |  |  |       onoe "The `brew link` step did not complete successfully." | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |       puts e | 
					
						
							|  |  |  |       puts | 
					
						
							|  |  |  |       puts "You can try again using:" | 
					
						
							|  |  |  |       puts "  brew link #{formula.name}" | 
					
						
							| 
									
										
										
										
											2017-10-07 00:31:28 +02:00
										 |  |  |     rescue Exception => e # rubocop:disable Lint/RescueException | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |       onoe "An unexpected error occurred during linking" | 
					
						
							|  |  |  |       puts e | 
					
						
							| 
									
										
										
										
											2024-07-15 13:44:01 -04:00
										 |  |  |       if debug? | 
					
						
							|  |  |  |         require "utils/backtrace" | 
					
						
							|  |  |  |         puts Utils::Backtrace.clean(e) | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-08-02 04:46:32 +02:00
										 |  |  |       ignore_interrupts { new_keg.unlink(verbose: verbose?) } | 
					
						
							| 
									
										
										
										
											2015-08-15 20:37:24 +08:00
										 |  |  |       raise | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Link keg to opt if it was linked before migrating. | 
					
						
							|  |  |  |   def link_oldname_opt | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     old_opt_records.each do |old_opt_record| | 
					
						
							|  |  |  |       old_opt_record.delete if old_opt_record.symlink? | 
					
						
							|  |  |  |       old_opt_record.make_relative_symlink(new_linked_keg_record) | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # After migration every `INSTALL_RECEIPT.json` has the wrong path to the formula | 
					
						
							|  |  |  |   # so we must update `INSTALL_RECEIPT`s. | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   def update_tabs | 
					
						
							| 
									
										
										
										
											2024-04-28 03:23:21 +02:00
										 |  |  |     new_tabs = new_cellar.subdirs.map { |d| Keg.new(d).tab } | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |     new_tabs.each do |tab| | 
					
						
							|  |  |  |       tab.source["path"] = formula.path.to_s if tab.source["path"] | 
					
						
							|  |  |  |       tab.write | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Remove `opt/oldname` link if it belongs to newname. | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   def unlink_oldname_opt | 
					
						
							| 
									
										
										
										
											2023-04-04 15:37:24 +01:00
										 |  |  |     return unless new_linked_keg_record.exist? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     old_opt_records.each do |old_opt_record| | 
					
						
							|  |  |  |       next unless old_opt_record.symlink? | 
					
						
							|  |  |  |       next unless old_opt_record.exist? | 
					
						
							|  |  |  |       next if new_linked_keg_record.realpath != old_opt_record.realpath | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       old_opt_record.unlink | 
					
						
							|  |  |  |       old_opt_record.parent.rmdir_if_possible | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Remove `Cellar/oldname` if it exists. | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   def link_oldname_cellar | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |     old_cellar.delete if old_cellar.symlink? || old_cellar.exist? | 
					
						
							|  |  |  |     old_cellar.make_relative_symlink(formula.rack) | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Remove `Cellar/oldname` link if it belongs to newname. | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   def unlink_oldname_cellar | 
					
						
							| 
									
										
										
										
											2024-02-29 09:26:51 -08:00
										 |  |  |     if (old_cellar.symlink? && !old_cellar.exist?) || | 
					
						
							|  |  |  |        (old_cellar.symlink? && formula.rack.exist? && formula.rack.realpath == old_cellar.realpath) | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |       old_cellar.unlink | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Backup everything if errors occur while migrating. | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   def backup_oldname | 
					
						
							|  |  |  |     unlink_oldname_opt | 
					
						
							|  |  |  |     unlink_oldname_cellar | 
					
						
							|  |  |  |     backup_oldname_cellar | 
					
						
							|  |  |  |     backup_old_tabs | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if pinned? && !old_pin_record.symlink? | 
					
						
							| 
									
										
										
										
											2017-06-01 16:06:51 +02:00
										 |  |  |       src_oldname = (old_pin_record.dirname/old_pin_link_record).expand_path | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |       old_pin_record.make_relative_symlink(src_oldname) | 
					
						
							|  |  |  |       new_pin_record.delete | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-01 18:14:10 +03:00
										 |  |  |     if new_cellar.exist? | 
					
						
							|  |  |  |       new_cellar.subdirs.each do |d| | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |         newname_keg = Keg.new(d) | 
					
						
							| 
									
										
										
										
											2020-08-02 04:46:32 +02:00
										 |  |  |         newname_keg.unlink(verbose: verbose?) | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |         newname_keg.uninstall unless new_cellar_existed | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     return if old_linked_kegs.empty? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-23 22:02:23 +02:00
										 |  |  |     # The keg used to be linked and when we backup everything we restore | 
					
						
							|  |  |  |     # Cellar/oldname, the target also gets restored, so we are able to | 
					
						
							|  |  |  |     # create a keg using its old path | 
					
						
							| 
									
										
										
										
											2023-04-27 04:09:28 +01:00
										 |  |  |     old_full_linked_kegs.each do |old_linked_keg| | 
					
						
							|  |  |  |       old_linked_keg.link(verbose: verbose?) | 
					
						
							|  |  |  |     rescue Keg::LinkError | 
					
						
							|  |  |  |       old_linked_keg.unlink(verbose: verbose?) | 
					
						
							|  |  |  |       raise | 
					
						
							|  |  |  |     rescue Keg::AlreadyLinkedError | 
					
						
							|  |  |  |       old_linked_keg.unlink(verbose: verbose?) | 
					
						
							|  |  |  |       retry | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     (old_linked_kegs - old_full_linked_kegs).each do |old_linked_keg| | 
					
						
							| 
									
										
										
										
											2020-08-02 04:46:32 +02:00
										 |  |  |       old_linked_keg.optlink(verbose: verbose?) | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def backup_oldname_cellar | 
					
						
							| 
									
										
										
										
											2016-09-23 11:01:40 +02:00
										 |  |  |     FileUtils.mv(new_cellar, old_cellar) unless old_cellar.exist? | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def backup_old_tabs | 
					
						
							|  |  |  |     old_tabs.each(&:write) | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-08-17 22:49:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   def lock | 
					
						
							|  |  |  |     @newname_lock = FormulaLock.new newname | 
					
						
							|  |  |  |     @oldname_lock = FormulaLock.new oldname | 
					
						
							|  |  |  |     @newname_lock.lock | 
					
						
							|  |  |  |     @oldname_lock.lock | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def unlock | 
					
						
							|  |  |  |     @newname_lock.unlock | 
					
						
							|  |  |  |     @oldname_lock.unlock | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-08-09 14:49:19 +03:00
										 |  |  | end |