| 
									
										
										
										
											2020-10-10 14:16:11 +02:00
										 |  |  | # typed: false | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  | require "utils/bottles" | 
					
						
							| 
									
										
										
										
											2020-12-09 10:36:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  | require "formula" | 
					
						
							| 
									
										
										
										
											2018-09-03 19:39:07 +01:00
										 |  |  | require "cask/cask_loader" | 
					
						
							| 
									
										
										
										
											2018-08-10 00:54:03 +02:00
										 |  |  | require "set" | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  | module Homebrew | 
					
						
							|  |  |  |   # Helper class for cleaning up the Homebrew cache. | 
					
						
							|  |  |  |   # | 
					
						
							|  |  |  |   # @api private | 
					
						
							|  |  |  |   class Cleanup | 
					
						
							| 
									
										
										
										
											2020-12-09 10:36:02 +00:00
										 |  |  |     CLEANUP_DEFAULT_DAYS = Homebrew::EnvConfig.cleanup_periodic_full_days.to_i.freeze | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |     private_constant :CLEANUP_DEFAULT_DAYS | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |     # {Pathname} refinement with helper functions for cleaning up files. | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |     module CleanupRefinement | 
					
						
							|  |  |  |       refine Pathname do | 
					
						
							|  |  |  |         def incomplete? | 
					
						
							|  |  |  |           extname.end_with?(".incomplete") | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |         def nested_cache? | 
					
						
							|  |  |  |           directory? && %w[
 | 
					
						
							|  |  |  |             cargo_cache | 
					
						
							|  |  |  |             go_cache | 
					
						
							|  |  |  |             go_mod_cache | 
					
						
							|  |  |  |             glide_home | 
					
						
							|  |  |  |             java_cache | 
					
						
							|  |  |  |             npm_cache | 
					
						
							|  |  |  |             gclient_cache | 
					
						
							|  |  |  |           ].include?(basename.to_s) | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |         def go_cache_directory? | 
					
						
							|  |  |  |           # Go makes its cache contents read-only to ensure cache integrity, | 
					
						
							|  |  |  |           # which makes sense but is something we need to undo for cleanup. | 
					
						
							|  |  |  |           directory? && %w[go_cache go_mod_cache].include?(basename.to_s) | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |         def prune?(days) | 
					
						
							|  |  |  |           return false unless days | 
					
						
							|  |  |  |           return true if days.zero? | 
					
						
							| 
									
										
										
										
											2018-08-30 05:19:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           return true if symlink? && !exist? | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           mtime < days.days.ago && ctime < days.days.ago | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2018-09-01 06:42:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-19 17:12:32 +01:00
										 |  |  |         def stale?(scrub: false) | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           return false unless resolved_path.file? | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           if dirname.basename.to_s == "Cask" | 
					
						
							|  |  |  |             stale_cask?(scrub) | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             stale_formula?(scrub) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |         private | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |         def stale_formula?(scrub) | 
					
						
							|  |  |  |           return false unless HOMEBREW_CELLAR.directory? | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           version = if to_s.match?(Pathname::BOTTLE_EXTNAME_RX) | 
					
						
							|  |  |  |             begin | 
					
						
							|  |  |  |               Utils::Bottles.resolve_version(self) | 
					
						
							|  |  |  |             rescue | 
					
						
							|  |  |  |               nil | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           version ||= basename.to_s[/\A.*(?:--.*?)*--(.*?)#{Regexp.escape(extname)}\Z/, 1] | 
					
						
							|  |  |  |           version ||= basename.to_s[/\A.*--?(.*?)#{Regexp.escape(extname)}\Z/, 1] | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           return false unless version | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           version = Version.new(version) | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-12 18:33:37 +05:30
										 |  |  |           return false unless (formula_name = basename.to_s[/\A(.*?)(?:--.*?)*--?(?:#{Regexp.escape(version)})/, 1]) | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           formula = begin | 
					
						
							|  |  |  |             Formulary.from_rack(HOMEBREW_CELLAR/formula_name) | 
					
						
							|  |  |  |           rescue FormulaUnavailableError, TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError | 
					
						
							| 
									
										
										
										
											2020-11-10 00:11:22 +11:00
										 |  |  |             nil | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-10 00:11:22 +11:00
										 |  |  |           return false if formula.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           resource_name = basename.to_s[/\A.*?--(.*?)--?(?:#{Regexp.escape(version)})/, 1] | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           if resource_name == "patch" | 
					
						
							|  |  |  |             patch_hashes = formula.stable&.patches&.select(&:external?)&.map(&:resource)&.map(&:version) | 
					
						
							| 
									
										
										
										
											2021-01-07 08:33:57 +01:00
										 |  |  |             return true unless patch_hashes&.include?(Checksum.new(version.to_s)) | 
					
						
							| 
									
										
										
										
											2021-02-12 18:33:37 +05:30
										 |  |  |           elsif resource_name && (resource_version = formula.stable&.resources&.dig(resource_name)&.version) | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |             return true if resource_version != version | 
					
						
							|  |  |  |           elsif version.is_a?(PkgVersion) | 
					
						
							|  |  |  |             return true if formula.pkg_version > version | 
					
						
							|  |  |  |           elsif formula.version > version | 
					
						
							|  |  |  |             return true | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           return true if scrub && !formula.latest_version_installed? | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           return true if Utils::Bottles.file_outdated?(formula, self) | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           false | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |         def stale_cask?(scrub) | 
					
						
							| 
									
										
										
										
											2021-02-12 18:33:37 +05:30
										 |  |  |           return false unless (name = basename.to_s[/\A(.*?)--/, 1]) | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           cask = begin | 
					
						
							|  |  |  |             Cask::CaskLoader.load(name) | 
					
						
							|  |  |  |           rescue Cask::CaskError | 
					
						
							| 
									
										
										
										
											2020-11-10 00:11:22 +11:00
										 |  |  |             nil | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-10 00:11:22 +11:00
										 |  |  |           return false if cask.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           return true unless basename.to_s.match?(/\A#{Regexp.escape(name)}--#{Regexp.escape(cask.version)}\b/) | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-01 17:04:59 +00:00
										 |  |  |           return true if scrub && cask.versions.exclude?(cask.version) | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           if cask.version.latest? | 
					
						
							|  |  |  |             return mtime < CLEANUP_DEFAULT_DAYS.days.ago && | 
					
						
							|  |  |  |                    ctime < CLEANUP_DEFAULT_DAYS.days.ago | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |           false | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 03:52:17 +02:00
										 |  |  |     using CleanupRefinement | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 11:20:53 +02:00
										 |  |  |     extend Predicable | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-19 21:46:20 +09:00
										 |  |  |     PERIODIC_CLEAN_FILE = (HOMEBREW_CACHE/".cleaned").freeze | 
					
						
							| 
									
										
										
										
											2019-01-03 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-31 13:40:49 +00:00
										 |  |  |     attr_predicate :dry_run?, :scrub?, :prune? | 
					
						
							| 
									
										
										
										
											2020-07-07 11:29:33 +01:00
										 |  |  |     attr_reader :args, :days, :cache, :disk_cleanup_size | 
					
						
							| 
									
										
										
										
											2018-08-08 11:20:53 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def initialize(*args, dry_run: false, scrub: false, days: nil, cache: HOMEBREW_CACHE) | 
					
						
							|  |  |  |       @disk_cleanup_size = 0
 | 
					
						
							|  |  |  |       @args = args | 
					
						
							|  |  |  |       @dry_run = dry_run | 
					
						
							|  |  |  |       @scrub = scrub | 
					
						
							| 
									
										
										
										
											2020-12-31 13:40:49 +00:00
										 |  |  |       @prune = days.present? | 
					
						
							| 
									
										
										
										
											2020-04-20 10:33:15 +01:00
										 |  |  |       @days = days || Homebrew::EnvConfig.cleanup_max_age_days.to_i | 
					
						
							| 
									
										
										
										
											2018-08-08 11:20:53 +02:00
										 |  |  |       @cache = cache | 
					
						
							| 
									
										
										
										
											2018-08-10 00:54:03 +02:00
										 |  |  |       @cleaned_up_paths = Set.new | 
					
						
							| 
									
										
										
										
											2017-08-13 04:21:07 +05:30
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-03 16:23:44 +00:00
										 |  |  |     def self.install_formula_clean!(f) | 
					
						
							| 
									
										
										
										
											2020-04-05 15:44:50 +01:00
										 |  |  |       return if Homebrew::EnvConfig.no_install_cleanup? | 
					
						
							| 
									
										
										
										
											2019-01-03 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       cleanup = Cleanup.new | 
					
						
							|  |  |  |       if cleanup.periodic_clean_due? | 
					
						
							|  |  |  |         cleanup.periodic_clean! | 
					
						
							| 
									
										
										
										
											2020-05-07 09:58:27 +01:00
										 |  |  |       elsif f.latest_version_installed? | 
					
						
							| 
									
										
										
										
											2019-01-03 16:23:44 +00:00
										 |  |  |         cleanup.cleanup_formula(f) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def periodic_clean_due? | 
					
						
							| 
									
										
										
										
											2020-04-05 15:44:50 +01:00
										 |  |  |       return false if Homebrew::EnvConfig.no_install_cleanup? | 
					
						
							| 
									
										
										
										
											2020-05-07 09:58:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       unless PERIODIC_CLEAN_FILE.exist? | 
					
						
							| 
									
										
										
										
											2020-11-14 10:48:10 -05:00
										 |  |  |         HOMEBREW_CACHE.mkpath | 
					
						
							| 
									
										
										
										
											2020-05-07 09:58:27 +01:00
										 |  |  |         FileUtils.touch PERIODIC_CLEAN_FILE | 
					
						
							|  |  |  |         return false | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2019-01-03 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       PERIODIC_CLEAN_FILE.mtime < CLEANUP_DEFAULT_DAYS.days.ago | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def periodic_clean! | 
					
						
							|  |  |  |       return false unless periodic_clean_due? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       ohai "`brew cleanup` has not been run in #{CLEANUP_DEFAULT_DAYS} days, running now..." | 
					
						
							| 
									
										
										
										
											2019-02-13 12:56:36 +00:00
										 |  |  |       clean!(quiet: true, periodic: true) | 
					
						
							| 
									
										
										
										
											2019-01-03 16:23:44 +00:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-13 12:56:36 +00:00
										 |  |  |     def clean!(quiet: false, periodic: false) | 
					
						
							| 
									
										
										
										
											2018-08-08 11:20:53 +02:00
										 |  |  |       if args.empty? | 
					
						
							| 
									
										
										
										
											2018-08-11 17:23:46 +02:00
										 |  |  |         Formula.installed.sort_by(&:name).each do |formula| | 
					
						
							| 
									
										
										
										
											2020-09-11 12:56:15 +01:00
										 |  |  |           cleanup_formula(formula, quiet: quiet, ds_store: false, cache_db: false) | 
					
						
							| 
									
										
										
										
											2018-08-08 11:20:53 +02:00
										 |  |  |         end | 
					
						
							|  |  |  |         cleanup_cache | 
					
						
							|  |  |  |         cleanup_logs | 
					
						
							| 
									
										
										
										
											2018-10-14 00:13:04 +02:00
										 |  |  |         cleanup_lockfiles | 
					
						
							| 
									
										
										
										
											2019-01-02 13:21:34 +00:00
										 |  |  |         prune_prefix_symlinks_and_directories | 
					
						
							| 
									
										
										
										
											2019-02-13 12:56:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         unless dry_run? | 
					
						
							| 
									
										
										
										
											2020-09-11 12:56:15 +01:00
										 |  |  |           cleanup_cache_db | 
					
						
							| 
									
										
										
										
											2019-02-13 12:56:36 +00:00
										 |  |  |           rm_ds_store | 
					
						
							|  |  |  |           HOMEBREW_CACHE.mkpath | 
					
						
							|  |  |  |           FileUtils.touch PERIODIC_CLEAN_FILE | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Cleaning up Ruby needs to be done last to avoid requiring additional | 
					
						
							|  |  |  |         # files afterwards. Additionally, don't allow it on periodic cleans to | 
					
						
							|  |  |  |         # avoid having to try to do a `brew install` when we've just deleted | 
					
						
							|  |  |  |         # the running Ruby process... | 
					
						
							|  |  |  |         return if periodic | 
					
						
							| 
									
										
										
										
											2019-02-19 13:12:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-13 12:56:36 +00:00
										 |  |  |         cleanup_portable_ruby | 
					
						
							| 
									
										
										
										
											2021-02-02 11:51:08 +00:00
										 |  |  |         cleanup_bootsnap | 
					
						
							| 
									
										
										
										
											2018-08-08 11:20:53 +02:00
										 |  |  |       else | 
					
						
							|  |  |  |         args.each do |arg| | 
					
						
							|  |  |  |           formula = begin | 
					
						
							| 
									
										
										
										
											2018-09-11 17:44:18 +02:00
										 |  |  |             Formulary.resolve(arg) | 
					
						
							| 
									
										
										
										
											2018-08-08 11:20:53 +02:00
										 |  |  |           rescue FormulaUnavailableError, TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError | 
					
						
							|  |  |  |             nil | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           cask = begin | 
					
						
							| 
									
										
										
										
											2018-09-06 08:29:14 +02:00
										 |  |  |             Cask::CaskLoader.load(arg) | 
					
						
							| 
									
										
										
										
											2019-11-06 13:33:33 +00:00
										 |  |  |           rescue Cask::CaskError | 
					
						
							| 
									
										
										
										
											2018-08-08 11:20:53 +02:00
										 |  |  |             nil | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2017-03-21 04:13:13 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 11:20:53 +02:00
										 |  |  |           cleanup_formula(formula) if formula | 
					
						
							|  |  |  |           cleanup_cask(cask) if cask | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-21 04:13:13 -05:00
										 |  |  |     def unremovable_kegs | 
					
						
							|  |  |  |       @unremovable_kegs ||= [] | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-11 12:56:15 +01:00
										 |  |  |     def cleanup_formula(formula, quiet: false, ds_store: true, cache_db: true) | 
					
						
							| 
									
										
										
										
											2019-01-28 16:08:23 +00:00
										 |  |  |       formula.eligible_kegs_for_cleanup(quiet: quiet) | 
					
						
							|  |  |  |              .each(&method(:cleanup_keg)) | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  |       cleanup_cache(Pathname.glob(cache/"#{formula.name}--*")) | 
					
						
							| 
									
										
										
										
											2019-09-18 11:39:40 +01:00
										 |  |  |       rm_ds_store([formula.rack]) if ds_store | 
					
						
							| 
									
										
										
										
											2020-09-11 12:56:15 +01:00
										 |  |  |       cleanup_cache_db(formula.rack) if cache_db | 
					
						
							| 
									
										
										
										
											2018-08-09 16:46:39 +02:00
										 |  |  |       cleanup_lockfiles(FormulaLock.new(formula.name).path) | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-18 11:39:40 +01:00
										 |  |  |     def cleanup_cask(cask, ds_store: true) | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  |       cleanup_cache(Pathname.glob(cache/"Cask/#{cask.token}--*")) | 
					
						
							| 
									
										
										
										
											2019-09-18 11:39:40 +01:00
										 |  |  |       rm_ds_store([cask.caskroom_path]) if ds_store | 
					
						
							| 
									
										
										
										
											2018-08-09 16:46:39 +02:00
										 |  |  |       cleanup_lockfiles(CaskLock.new(cask.token).path) | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2018-08-08 11:20:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-21 04:13:13 -05:00
										 |  |  |     def cleanup_keg(keg) | 
					
						
							| 
									
										
										
										
											2021-01-21 13:03:52 +00:00
										 |  |  |       cleanup_path(keg) { keg.uninstall(raise_failures: true) } | 
					
						
							| 
									
										
										
										
											2017-03-21 04:13:13 -05:00
										 |  |  |     rescue Errno::EACCES => e | 
					
						
							|  |  |  |       opoo e.message | 
					
						
							|  |  |  |       unremovable_kegs << keg | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def cleanup_logs | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |       return unless HOMEBREW_LOGS.directory? | 
					
						
							| 
									
										
										
										
											2019-02-19 13:12:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-03 16:23:44 +00:00
										 |  |  |       logs_days = if days > CLEANUP_DEFAULT_DAYS | 
					
						
							|  |  |  |         CLEANUP_DEFAULT_DAYS | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         days | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |       HOMEBREW_LOGS.subdirs.each do |dir| | 
					
						
							| 
									
										
										
										
											2019-01-03 16:23:44 +00:00
										 |  |  |         cleanup_path(dir) { dir.rmtree } if dir.prune?(logs_days) | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-10 04:11:54 +02:00
										 |  |  |     def cleanup_unreferenced_downloads | 
					
						
							|  |  |  |       return if dry_run? | 
					
						
							|  |  |  |       return unless (cache/"downloads").directory? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-14 00:13:04 +02:00
										 |  |  |       downloads = (cache/"downloads").children | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-10 04:11:54 +02:00
										 |  |  |       referenced_downloads = [cache, cache/"Cask"].select(&:directory?) | 
					
						
							|  |  |  |                                                   .flat_map(&:children) | 
					
						
							|  |  |  |                                                   .select(&:symlink?) | 
					
						
							|  |  |  |                                                   .map(&:resolved_path) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-14 00:13:04 +02:00
										 |  |  |       (downloads - referenced_downloads).each do |download| | 
					
						
							|  |  |  |         if download.incomplete? | 
					
						
							|  |  |  |           begin | 
					
						
							|  |  |  |             LockFile.new(download.basename).with_lock do | 
					
						
							|  |  |  |               download.unlink | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |           rescue OperationInProgressError | 
					
						
							|  |  |  |             # Skip incomplete downloads which are still in progress. | 
					
						
							|  |  |  |             next | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2019-01-28 16:08:23 +00:00
										 |  |  |         elsif download.directory? | 
					
						
							|  |  |  |           FileUtils.rm_rf download | 
					
						
							| 
									
										
										
										
											2018-10-14 00:13:04 +02:00
										 |  |  |         else | 
					
						
							|  |  |  |           download.unlink | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2018-08-10 04:11:54 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 22:23:55 +02:00
										 |  |  |     def cleanup_cache(entries = nil) | 
					
						
							|  |  |  |       entries ||= [cache, cache/"Cask"].select(&:directory?).flat_map(&:children) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       entries.each do |path| | 
					
						
							| 
									
										
										
										
											2019-04-17 21:06:47 +09:00
										 |  |  |         next if path == PERIODIC_CLEAN_FILE | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-30 05:19:20 +01:00
										 |  |  |         FileUtils.chmod_R 0755, path if path.go_cache_directory? && !dry_run? | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  |         next cleanup_path(path) { path.unlink } if path.incomplete? | 
					
						
							|  |  |  |         next cleanup_path(path) { FileUtils.rm_rf path } if path.nested_cache? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 11:20:53 +02:00
										 |  |  |         if path.prune?(days) | 
					
						
							| 
									
										
										
										
											2018-08-25 22:06:24 +02:00
										 |  |  |           if path.file? || path.symlink? | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |             cleanup_path(path) { path.unlink } | 
					
						
							|  |  |  |           elsif path.directory? && path.to_s.include?("--") | 
					
						
							|  |  |  |             cleanup_path(path) { FileUtils.rm_rf path } | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           next | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-31 13:40:49 +00:00
										 |  |  |         # If we've specifed --prune don't do the (expensive) .stale? check. | 
					
						
							|  |  |  |         cleanup_path(path) { path.unlink } if !prune? && path.stale?(scrub: scrub?) | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2018-08-10 04:11:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       cleanup_unreferenced_downloads | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-21 04:13:13 -05:00
										 |  |  |     def cleanup_path(path) | 
					
						
							| 
									
										
										
										
											2020-07-10 09:32:27 +01:00
										 |  |  |       return unless path.exist? | 
					
						
							| 
									
										
										
										
											2018-08-10 00:54:03 +02:00
										 |  |  |       return unless @cleaned_up_paths.add?(path) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 09:43:38 +02:00
										 |  |  |       disk_usage = path.disk_usage | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 11:20:53 +02:00
										 |  |  |       if dry_run? | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |         puts "Would remove: #{path} (#{path.abv})" | 
					
						
							| 
									
										
										
										
											2019-02-06 22:50:17 +01:00
										 |  |  |         @disk_cleanup_size += disk_usage | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |       else | 
					
						
							|  |  |  |         puts "Removing: #{path}... (#{path.abv})" | 
					
						
							|  |  |  |         yield | 
					
						
							| 
									
										
										
										
											2019-02-06 22:50:17 +01:00
										 |  |  |         @disk_cleanup_size += disk_usage - path.disk_usage | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-09 16:46:39 +02:00
										 |  |  |     def cleanup_lockfiles(*lockfiles) | 
					
						
							| 
									
										
										
										
											2018-08-16 05:55:17 +02:00
										 |  |  |       return if dry_run? | 
					
						
							| 
									
										
										
										
											2018-08-09 16:46:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-19 13:11:32 +00:00
										 |  |  |       lockfiles = HOMEBREW_LOCKS.children.select(&:file?) if lockfiles.empty? && HOMEBREW_LOCKS.directory? | 
					
						
							| 
									
										
										
										
											2018-08-09 16:46:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |       lockfiles.each do |file| | 
					
						
							|  |  |  |         next unless file.readable? | 
					
						
							| 
									
										
										
										
											2018-08-09 16:46:39 +02:00
										 |  |  |         next unless file.open(File::RDWR).flock(File::LOCK_EX | File::LOCK_NB) | 
					
						
							| 
									
										
										
										
											2018-08-11 17:23:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         begin | 
					
						
							| 
									
										
										
										
											2018-08-16 05:55:17 +02:00
										 |  |  |           file.unlink | 
					
						
							| 
									
										
										
										
											2018-08-11 17:23:35 +02:00
										 |  |  |         ensure | 
					
						
							|  |  |  |           file.open(File::RDWR).flock(File::LOCK_UN) if file.exist? | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-03 19:26:49 +01:00
										 |  |  |     def cleanup_portable_ruby | 
					
						
							| 
									
										
										
										
											2020-09-03 09:43:41 +01:00
										 |  |  |       rubies = [which("ruby"), which("ruby", ENV["HOMEBREW_PATH"])].compact | 
					
						
							|  |  |  |       system_ruby = Pathname.new("/usr/bin/ruby") | 
					
						
							|  |  |  |       rubies << system_ruby if system_ruby.exist? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       use_system_ruby = if Homebrew::EnvConfig.force_vendor_ruby? | 
					
						
							|  |  |  |         false | 
					
						
							| 
									
										
										
										
											2020-12-09 11:50:45 +00:00
										 |  |  |       elsif OS.mac? | 
					
						
							|  |  |  |         ENV["HOMEBREW_MACOS_SYSTEM_RUBY_NEW_ENOUGH"].present? | 
					
						
							| 
									
										
										
										
											2020-09-03 09:43:41 +01:00
										 |  |  |       else | 
					
						
							|  |  |  |         check_ruby_version = HOMEBREW_LIBRARY_PATH/"utils/ruby_check_version_script.rb" | 
					
						
							|  |  |  |         rubies.uniq.any? do |ruby| | 
					
						
							| 
									
										
										
										
											2020-09-03 16:22:03 +00:00
										 |  |  |           quiet_system ruby, "--enable-frozen-string-literal", "--disable=gems,did_you_mean,rubyopt", | 
					
						
							|  |  |  |                        check_ruby_version, HOMEBREW_REQUIRED_RUBY_VERSION | 
					
						
							| 
									
										
										
										
											2020-09-03 09:43:41 +01:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2018-10-03 19:26:49 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 09:43:41 +01:00
										 |  |  |       vendor_dir = HOMEBREW_LIBRARY/"Homebrew/vendor" | 
					
						
							|  |  |  |       portable_ruby_latest_version = (vendor_dir/"portable-ruby-version").read.chomp | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-16 16:04:24 +00:00
										 |  |  |       portable_rubies_to_remove = [] | 
					
						
							| 
									
										
										
										
											2020-09-03 09:43:41 +01:00
										 |  |  |       Pathname.glob(vendor_dir/"portable-ruby/*.*").select(&:directory?).each do |path| | 
					
						
							|  |  |  |         next if !use_system_ruby && portable_ruby_latest_version == path.basename.to_s | 
					
						
							| 
									
										
										
										
											2019-02-19 13:12:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-16 16:04:24 +00:00
										 |  |  |         portable_rubies_to_remove << path | 
					
						
							|  |  |  |         puts "Would remove: #{path} (#{path.abv})" if dry_run? | 
					
						
							| 
									
										
										
										
											2018-10-03 19:26:49 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-16 16:04:24 +00:00
										 |  |  |       return if portable_rubies_to_remove.empty? | 
					
						
							| 
									
										
										
										
											2018-10-03 19:26:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 09:43:41 +01:00
										 |  |  |       bundler_path = vendor_dir/"bundle/ruby" | 
					
						
							| 
									
										
										
										
											2018-10-03 19:26:49 +01:00
										 |  |  |       if dry_run? | 
					
						
							| 
									
										
										
										
											2020-01-16 16:04:24 +00:00
										 |  |  |         puts Utils.popen_read("git", "-C", HOMEBREW_REPOSITORY, "clean", "-nx", bundler_path).chomp | 
					
						
							| 
									
										
										
										
											2018-10-03 19:26:49 +01:00
										 |  |  |       else | 
					
						
							| 
									
										
										
										
											2020-01-16 16:04:24 +00:00
										 |  |  |         puts Utils.popen_read("git", "-C", HOMEBREW_REPOSITORY, "clean", "-ffqx", bundler_path).chomp | 
					
						
							| 
									
										
										
										
											2018-10-03 19:26:49 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-01-16 16:04:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return if dry_run? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       FileUtils.rm_rf portable_rubies_to_remove | 
					
						
							| 
									
										
										
										
											2018-10-03 19:26:49 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-02 11:51:08 +00:00
										 |  |  |     def cleanup_bootsnap | 
					
						
							|  |  |  |       bootsnap = cache/"bootsnap" | 
					
						
							|  |  |  |       return unless bootsnap.exist? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if dry_run? | 
					
						
							|  |  |  |         puts "Would remove: #{bootsnap} (#{bootsnap.abv})" | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         FileUtils.rm_rf bootsnap | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-11 12:56:15 +01:00
										 |  |  |     def cleanup_cache_db(rack = nil) | 
					
						
							| 
									
										
										
										
											2018-10-13 08:22:51 -07:00
										 |  |  |       FileUtils.rm_rf [ | 
					
						
							|  |  |  |         cache/"desc_cache.json", | 
					
						
							|  |  |  |         cache/"linkage.db", | 
					
						
							|  |  |  |         cache/"linkage.db.db", | 
					
						
							|  |  |  |       ] | 
					
						
							| 
									
										
										
										
											2020-09-11 12:56:15 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       CacheStoreDatabase.use(:linkage) do |db| | 
					
						
							|  |  |  |         break unless db.created? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         db.each_key do |keg| | 
					
						
							|  |  |  |           next if rack.present? && !keg.start_with?("#{rack}/") | 
					
						
							|  |  |  |           next if File.directory?(keg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           LinkageCacheStore.new(keg, db).delete! | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2018-10-03 19:26:49 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-09 01:55:43 +02:00
										 |  |  |     def rm_ds_store(dirs = nil) | 
					
						
							| 
									
										
										
										
											2018-09-06 18:38:43 +01:00
										 |  |  |       dirs ||= begin | 
					
						
							|  |  |  |         Keg::MUST_EXIST_DIRECTORIES + [ | 
					
						
							|  |  |  |           HOMEBREW_PREFIX/"Caskroom", | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2019-09-18 11:39:40 +01:00
										 |  |  |       dirs.select(&:directory?) | 
					
						
							|  |  |  |           .flat_map { |d| Pathname.glob("#{d}/**/.DS_Store") } | 
					
						
							|  |  |  |           .each(&:unlink) | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2019-01-02 13:21:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def prune_prefix_symlinks_and_directories | 
					
						
							|  |  |  |       ObserverPathnameExtension.reset_counts! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       dirs = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       Keg::MUST_EXIST_SUBDIRECTORIES.each do |dir| | 
					
						
							|  |  |  |         next unless dir.directory? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dir.find do |path| | 
					
						
							|  |  |  |           path.extend(ObserverPathnameExtension) | 
					
						
							|  |  |  |           if path.symlink? | 
					
						
							|  |  |  |             unless path.resolved_path_exists? | 
					
						
							| 
									
										
										
										
											2020-09-01 14:05:52 +01:00
										 |  |  |               path.uninstall_info if path.to_s.match?(Keg::INFOFILE_RX) && !dry_run? | 
					
						
							| 
									
										
										
										
											2019-01-02 13:21:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |               if dry_run? | 
					
						
							|  |  |  |                 puts "Would remove (broken link): #{path}" | 
					
						
							|  |  |  |               else | 
					
						
							|  |  |  |                 path.unlink | 
					
						
							|  |  |  |               end | 
					
						
							|  |  |  |             end | 
					
						
							| 
									
										
										
										
											2020-12-01 17:04:59 +00:00
										 |  |  |           elsif path.directory? && Keg::MUST_EXIST_SUBDIRECTORIES.exclude?(path) | 
					
						
							| 
									
										
										
										
											2019-01-02 13:21:34 +00:00
										 |  |  |             dirs << path | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       dirs.reverse_each do |d| | 
					
						
							|  |  |  |         if dry_run? && d.children.empty? | 
					
						
							|  |  |  |           puts "Would remove (empty directory): #{d}" | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           d.rmdir_if_possible | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return if dry_run? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return if ObserverPathnameExtension.total.zero? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       n, d = ObserverPathnameExtension.counts | 
					
						
							|  |  |  |       print "Pruned #{n} symbolic links " | 
					
						
							|  |  |  |       print "and #{d} directories " if d.positive? | 
					
						
							|  |  |  |       puts "from #{HOMEBREW_PREFIX}" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-12-29 12:57:48 +01:00
										 |  |  |   end | 
					
						
							|  |  |  | end |