2019-04-19 15:38:03 +09:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-04-25 17:57:51 +01:00
|
|
|
require "utils/bottles"
|
2019-02-21 15:52:42 +00:00
|
|
|
require "utils/gems"
|
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
|
|
|
|
2019-01-03 16:23:44 +00:00
|
|
|
CLEANUP_DEFAULT_DAYS = 30
|
|
|
|
CLEANUP_MAX_AGE_DAYS = 120
|
2018-08-08 22:23:55 +02:00
|
|
|
|
2019-01-03 16:23:44 +00:00
|
|
|
module CleanupRefinement
|
2018-08-08 09:43:38 +02:00
|
|
|
refine Pathname do
|
|
|
|
def incomplete?
|
|
|
|
extname.end_with?(".incomplete")
|
|
|
|
end
|
|
|
|
|
|
|
|
def nested_cache?
|
2018-09-03 18:59:53 +10:00
|
|
|
directory? && %w[cargo_cache go_cache glide_home java_cache npm_cache gclient_cache].include?(basename.to_s)
|
2018-08-08 09:43:38 +02:00
|
|
|
end
|
|
|
|
|
2018-08-30 05:19:20 +01: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].include?(basename.to_s)
|
|
|
|
end
|
|
|
|
|
2018-08-08 09:43:38 +02:00
|
|
|
def prune?(days)
|
|
|
|
return false unless days
|
|
|
|
return true if days.zero?
|
|
|
|
|
2018-09-01 06:42:47 +02:00
|
|
|
return true if symlink? && !exist?
|
|
|
|
|
2019-01-21 21:35:24 +00:00
|
|
|
mtime < days.days.ago && ctime < days.days.ago
|
2018-08-08 09:43:38 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def stale?(scrub = false)
|
2018-08-29 01:34:40 +02:00
|
|
|
return false unless resolved_path.file?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2019-03-05 19:41:58 -08:00
|
|
|
if dirname.basename.to_s == "Cask"
|
|
|
|
stale_cask?(scrub)
|
|
|
|
else
|
|
|
|
stale_formula?(scrub)
|
|
|
|
end
|
2018-08-08 09:43:38 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def stale_formula?(scrub)
|
|
|
|
return false unless HOMEBREW_CELLAR.directory?
|
|
|
|
|
|
|
|
version = if to_s.match?(Pathname::BOTTLE_EXTNAME_RX)
|
|
|
|
begin
|
|
|
|
Utils::Bottles.resolve_version(self)
|
|
|
|
rescue
|
2018-08-08 22:23:55 +02:00
|
|
|
nil
|
2018-08-08 09:43:38 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-08-10 05:08:50 +02:00
|
|
|
version ||= basename.to_s[/\A.*(?:\-\-.*?)*\-\-(.*?)#{Regexp.escape(extname)}\Z/, 1]
|
2018-08-10 00:54:03 +02:00
|
|
|
version ||= basename.to_s[/\A.*\-\-?(.*?)#{Regexp.escape(extname)}\Z/, 1]
|
2018-08-08 22:23:55 +02:00
|
|
|
|
2018-08-08 09:43:38 +02:00
|
|
|
return false unless version
|
2018-08-08 22:23:55 +02:00
|
|
|
|
2018-08-10 00:54:03 +02:00
|
|
|
version = Version.new(version)
|
2018-08-08 22:23:55 +02:00
|
|
|
|
2018-08-10 05:08:50 +02:00
|
|
|
return false unless formula_name = basename.to_s[/\A(.*?)(?:\-\-.*?)*\-\-?(?:#{Regexp.escape(version)})/, 1]
|
2018-08-08 09:43:38 +02:00
|
|
|
|
|
|
|
formula = begin
|
2018-08-10 00:54:03 +02:00
|
|
|
Formulary.from_rack(HOMEBREW_CELLAR/formula_name)
|
2018-08-08 09:43:38 +02:00
|
|
|
rescue FormulaUnavailableError, TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2018-08-10 00:54:03 +02:00
|
|
|
resource_name = basename.to_s[/\A.*?\-\-(.*?)\-\-?(?:#{Regexp.escape(version)})/, 1]
|
|
|
|
|
2018-08-10 05:08:50 +02:00
|
|
|
if resource_name == "patch"
|
2018-08-12 19:54:08 +02:00
|
|
|
patch_hashes = formula.stable&.patches&.select(&:external?)&.map(&:resource)&.map(&:version)
|
2018-08-10 05:08:50 +02:00
|
|
|
return true unless patch_hashes&.include?(Checksum.new(:sha256, version.to_s))
|
|
|
|
elsif resource_name && resource_version = formula.stable&.resources&.dig(resource_name)&.version
|
|
|
|
return true if resource_version != version
|
2018-08-10 00:54:03 +02:00
|
|
|
elsif version.is_a?(PkgVersion)
|
2018-08-08 09:43:38 +02:00
|
|
|
return true if formula.pkg_version > version
|
|
|
|
elsif formula.version > version
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
return true if scrub && !formula.installed?
|
|
|
|
|
|
|
|
return true if Utils::Bottles.file_outdated?(formula, self)
|
|
|
|
|
|
|
|
false
|
|
|
|
end
|
2018-08-08 22:23:55 +02:00
|
|
|
|
|
|
|
def stale_cask?(scrub)
|
|
|
|
return false unless name = basename.to_s[/\A(.*?)\-\-/, 1]
|
|
|
|
|
|
|
|
cask = begin
|
2018-09-06 08:29:14 +02:00
|
|
|
Cask::CaskLoader.load(name)
|
2019-11-06 13:33:33 +00:00
|
|
|
rescue Cask::CaskError
|
2018-08-08 22:23:55 +02:00
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2019-02-19 13:11:32 +00: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
|
|
|
|
|
|
|
return true if scrub && !cask.versions.include?(cask.version)
|
|
|
|
|
2019-01-21 21:35:24 +00: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
|
|
|
|
|
|
|
false
|
|
|
|
end
|
2018-08-08 09:43:38 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using CleanupRefinement
|
|
|
|
|
2015-12-29 12:57:48 +01:00
|
|
|
module Homebrew
|
2018-08-08 11:20:53 +02:00
|
|
|
class Cleanup
|
|
|
|
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
|
|
|
|
2018-08-08 11:20:53 +02:00
|
|
|
attr_predicate :dry_run?, :scrub?
|
|
|
|
attr_reader :args, :days, :cache
|
|
|
|
attr_reader :disk_cleanup_size
|
|
|
|
|
|
|
|
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
|
2019-01-03 16:23:44 +00:00
|
|
|
@days = days || CLEANUP_MAX_AGE_DAYS
|
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)
|
|
|
|
return if ENV["HOMEBREW_NO_INSTALL_CLEANUP"]
|
|
|
|
|
|
|
|
cleanup = Cleanup.new
|
|
|
|
if cleanup.periodic_clean_due?
|
|
|
|
cleanup.periodic_clean!
|
|
|
|
elsif f.installed?
|
|
|
|
cleanup.cleanup_formula(f)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def periodic_clean_due?
|
|
|
|
return false if ENV["HOMEBREW_NO_INSTALL_CLEANUP"]
|
|
|
|
return true unless PERIODIC_CLEAN_FILE.exist?
|
|
|
|
|
|
|
|
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|
|
2019-09-18 11:39:40 +01:00
|
|
|
cleanup_formula(formula, quiet: quiet, ds_store: 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?
|
|
|
|
cleanup_old_cache_db
|
|
|
|
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
|
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
|
|
|
|
|
2019-09-18 11:39:40 +01:00
|
|
|
def cleanup_formula(formula, quiet: false, ds_store: 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
|
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)
|
|
|
|
cleanup_path(keg) { keg.uninstall }
|
|
|
|
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
|
|
|
|
|
2018-08-08 22:23:55 +02:00
|
|
|
next cleanup_path(path) { path.unlink } if path.stale?(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)
|
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
|
|
|
|
system_ruby_version =
|
|
|
|
Utils.popen_read("/usr/bin/ruby", "-e", "puts RUBY_VERSION")
|
|
|
|
.chomp
|
|
|
|
use_system_ruby = (
|
|
|
|
Gem::Version.new(system_ruby_version) >= Gem::Version.new(RUBY_VERSION)
|
|
|
|
) && ENV["HOMEBREW_FORCE_VENDOR_RUBY"].nil?
|
|
|
|
vendor_path = HOMEBREW_LIBRARY/"Homebrew/vendor"
|
|
|
|
portable_ruby_version_file = vendor_path/"portable-ruby-version"
|
|
|
|
portable_ruby_version = if portable_ruby_version_file.exist?
|
|
|
|
portable_ruby_version_file.read
|
|
|
|
.chomp
|
|
|
|
end
|
|
|
|
|
|
|
|
portable_ruby_path = vendor_path/"portable-ruby"
|
|
|
|
portable_ruby_glob = "#{portable_ruby_path}/*.*"
|
2020-01-16 16:04:24 +00:00
|
|
|
portable_rubies_to_remove = []
|
2018-10-03 19:26:49 +01:00
|
|
|
Pathname.glob(portable_ruby_glob).each do |path|
|
|
|
|
next if !use_system_ruby && portable_ruby_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
|
|
|
|
2018-10-04 15:08:38 +01:00
|
|
|
bundler_path = vendor_path/"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
|
|
|
|
|
2018-10-13 08:22:51 -07:00
|
|
|
def cleanup_old_cache_db
|
|
|
|
FileUtils.rm_rf [
|
|
|
|
cache/"desc_cache.json",
|
|
|
|
cache/"linkage.db",
|
|
|
|
cache/"linkage.db.db",
|
|
|
|
]
|
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?
|
2019-10-13 19:26:39 +01:00
|
|
|
if path.to_s.match?(Keg::INFOFILE_RX)
|
2019-01-02 13:21:34 +00:00
|
|
|
path.uninstall_info unless dry_run?
|
|
|
|
end
|
|
|
|
|
|
|
|
if dry_run?
|
|
|
|
puts "Would remove (broken link): #{path}"
|
|
|
|
else
|
|
|
|
path.unlink
|
|
|
|
end
|
|
|
|
end
|
|
|
|
elsif path.directory? && !Keg::MUST_EXIST_SUBDIRECTORIES.include?(path)
|
|
|
|
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
|