brew/Library/Homebrew/cmd/cleanup.rb
Jack Nagel ba48d8c5b9 Use version attribute directly in cache comparisons
The bug that prompted the two relevant commits has since been addressed.

Squashed commit of the following:

commit ecca17ede8324efd1175a42300ace8e1e2df30fa
Author: Jack Nagel <jacknagel@gmail.com>
Date:   Sat Dec 27 16:16:12 2014 -0500

    Revert "Don't use pkg_version when cleaning the cache"

    This reverts commit 4d511b5169d78a5d44bbf6c36c17f0c28014a614.

commit e8935de08f6440ae1874ce523f93b19da6b68df3
Author: Jack Nagel <jacknagel@gmail.com>
Date:   Sat Dec 27 16:16:12 2014 -0500

    Revert "Fix cleanup for head-only formulae"

    This reverts commit 510267ffd314c296c0b0969dd27d130a249f16e2.
2014-12-27 16:16:16 -05:00

139 lines
3.7 KiB
Ruby

require 'formula'
require 'keg'
require 'bottles'
module Homebrew
def cleanup
# individual cleanup_ methods should also check for the existence of the
# appropriate directories before assuming they exist
return unless HOMEBREW_CELLAR.directory?
if ARGV.named.empty?
cleanup_cellar
cleanup_cache
cleanup_logs
unless ARGV.dry_run?
cleanup_lockfiles
rm_DS_Store
end
else
ARGV.formulae.each { |f| cleanup_formula(f) }
end
end
def cleanup_logs
return unless HOMEBREW_LOGS.directory?
time = Time.now - 2 * 7 * 24 * 60 * 60 # two weeks
HOMEBREW_LOGS.subdirs.each do |dir|
if dir.mtime < time
if ARGV.dry_run?
puts "Would remove: #{dir}"
else
puts "Removing: #{dir}..."
dir.rmtree
end
end
end
end
def cleanup_cellar
HOMEBREW_CELLAR.subdirs.each do |rack|
begin
cleanup_formula Formulary.factory(rack.basename.to_s)
rescue FormulaUnavailableError
# Don't complain about directories from DIY installs
end
end
end
def cleanup_formula f
if f.installed?
eligible_kegs = f.rack.subdirs.map { |d| Keg.new(d) }.select { |k| f.pkg_version > k.version }
eligible_kegs.each do |keg|
if f.can_cleanup?
cleanup_keg(keg)
else
opoo "Skipping (old) keg-only: #{keg}"
end
end
elsif f.rack.subdirs.length > 1
# If the cellar only has one version installed, don't complain
# that we can't tell which one to keep.
opoo "Skipping #{f.name}: most recent version #{f.version} not installed"
end
end
def cleanup_keg keg
if keg.linked?
opoo "Skipping (old) #{keg} due to it being linked"
elsif ARGV.dry_run?
puts "Would remove: #{keg}"
else
puts "Removing: #{keg}..."
keg.uninstall
end
end
def cleanup_cache
return unless HOMEBREW_CACHE.directory?
HOMEBREW_CACHE.children.select(&:file?).each do |file|
next unless (version = file.version)
next unless (name = file.basename.to_s[/(.*)-(?:#{Regexp.escape(version)})/, 1])
begin
f = Formulary.factory(name)
rescue FormulaUnavailableError
next
end
if f.version > version || ARGV.switch?('s') && !f.installed? || bottle_file_outdated?(f, file)
cleanup_cached_file(file)
end
end
end
def cleanup_cached_file file
if ARGV.dry_run?
puts "Would remove: #{file}"
else
puts "Removing: #{file}..."
file.unlink
end
end
def cleanup_lockfiles
return unless HOMEBREW_CACHE_FORMULA.directory?
candidates = HOMEBREW_CACHE_FORMULA.children
lockfiles = candidates.select { |f| f.file? && f.extname == '.brewing' }
lockfiles.select(&:readable?).each do |file|
file.open.flock(File::LOCK_EX | File::LOCK_NB) and file.unlink
end
end
def rm_DS_Store
quiet_system "find", HOMEBREW_PREFIX.to_s, "-name", ".DS_Store", "-delete"
end
end
class Formula
def can_cleanup?
# It used to be the case that keg-only kegs could not be cleaned up, because
# older brews were built against the full path to the keg-only keg. Then we
# introduced the opt symlink, and built against that instead. So provided
# no brew exists that was built against an old-style keg-only keg, we can
# remove it.
if not keg_only? or ARGV.force?
true
elsif opt_prefix.directory?
# SHA records were added to INSTALL_RECEIPTS the same day as opt symlinks
!Formula.installed.
select{ |ff| ff.deps.map{ |d| d.to_s }.include? name }.
map{ |ff| ff.rack.subdirs rescue [] }.
flatten.
map{ |keg_path| Tab.for_keg(keg_path).HEAD }.
include? nil
end
end
end