2010-09-11 20:22:54 +01:00
|
|
|
require 'formula'
|
2012-08-10 16:33:47 -04:00
|
|
|
require 'keg'
|
2012-04-30 15:10:51 -05:00
|
|
|
require 'bottles'
|
2010-09-11 20:22:54 +01:00
|
|
|
|
2014-06-18 22:41:47 -05:00
|
|
|
module Homebrew
|
2010-09-11 20:22:54 +01:00
|
|
|
def cleanup
|
2014-05-17 16:59:14 -07:00
|
|
|
# individual cleanup_ methods should also check for the existence of the
|
|
|
|
# appropriate directories before assuming they exist
|
2013-05-15 12:45:39 -05:00
|
|
|
return unless HOMEBREW_CELLAR.directory?
|
|
|
|
|
2010-09-11 20:22:54 +01:00
|
|
|
if ARGV.named.empty?
|
2013-05-15 12:45:39 -05:00
|
|
|
cleanup_cellar
|
|
|
|
cleanup_cache
|
2014-05-14 12:12:30 -05:00
|
|
|
cleanup_logs
|
2013-06-21 15:42:14 -05:00
|
|
|
unless ARGV.dry_run?
|
|
|
|
cleanup_lockfiles
|
|
|
|
rm_DS_Store
|
|
|
|
end
|
2010-09-11 20:22:54 +01:00
|
|
|
else
|
2013-05-15 12:45:35 -05:00
|
|
|
ARGV.formulae.each { |f| cleanup_formula(f) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-05-14 12:12:30 -05:00
|
|
|
def cleanup_logs
|
2014-05-17 16:59:14 -07:00
|
|
|
return unless HOMEBREW_LOGS.directory?
|
2014-05-14 12:12:30 -05:00
|
|
|
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
|
|
|
|
|
2013-05-15 12:45:39 -05:00
|
|
|
def cleanup_cellar
|
2013-05-15 12:45:36 -05:00
|
|
|
HOMEBREW_CELLAR.subdirs.each do |rack|
|
2013-05-15 12:45:36 -05:00
|
|
|
begin
|
2014-06-22 15:00:15 -05:00
|
|
|
cleanup_formula Formulary.factory(rack.basename.to_s)
|
2013-05-15 12:45:36 -05:00
|
|
|
rescue FormulaUnavailableError
|
|
|
|
# Don't complain about directories from DIY installs
|
2010-09-11 20:22:54 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def cleanup_formula f
|
2013-05-15 12:45:36 -05:00
|
|
|
if f.installed?
|
2014-03-05 20:12:51 -06:00
|
|
|
eligible_kegs = f.rack.subdirs.map { |d| Keg.new(d) }.select { |k| f.pkg_version > k.version }
|
2013-05-15 12:45:38 -05:00
|
|
|
eligible_kegs.each do |keg|
|
|
|
|
if f.can_cleanup?
|
|
|
|
cleanup_keg(keg)
|
|
|
|
else
|
|
|
|
opoo "Skipping (old) keg-only: #{keg}"
|
2010-09-11 20:22:54 +01:00
|
|
|
end
|
|
|
|
end
|
2013-05-15 12:45:36 -05:00
|
|
|
elsif f.rack.subdirs.length > 1
|
2010-09-11 20:22:54 +01:00
|
|
|
# If the cellar only has one version installed, don't complain
|
|
|
|
# that we can't tell which one to keep.
|
2011-03-11 13:36:26 -08:00
|
|
|
opoo "Skipping #{f.name}: most recent version #{f.version} not installed"
|
2010-09-11 20:22:54 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-05-15 12:45:38 -05:00
|
|
|
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}..."
|
2014-06-24 09:54:26 -05:00
|
|
|
keg.uninstall
|
2013-05-15 12:45:38 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-05-15 12:45:36 -05:00
|
|
|
def cleanup_cache
|
2013-05-15 12:45:38 -05:00
|
|
|
HOMEBREW_CACHE.children.select(&:file?).each do |file|
|
2013-06-06 12:34:47 -05:00
|
|
|
next unless (version = file.version)
|
|
|
|
next unless (name = file.basename.to_s[/(.*)-(?:#{Regexp.escape(version)})/, 1])
|
2013-05-15 12:45:39 -05:00
|
|
|
|
|
|
|
begin
|
2014-06-22 15:00:15 -05:00
|
|
|
f = Formulary.factory(name)
|
2013-05-15 12:45:39 -05:00
|
|
|
rescue FormulaUnavailableError
|
|
|
|
next
|
2012-03-06 20:12:42 +00:00
|
|
|
end
|
2013-05-15 12:45:39 -05:00
|
|
|
|
2014-03-06 09:50:44 -06:00
|
|
|
spec = f.stable || f.devel || f.head
|
|
|
|
if spec.version > version || ARGV.switch?('s') && !f.installed? || bottle_file_outdated?(f, file)
|
2013-05-15 12:45:39 -05:00
|
|
|
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
|
2012-03-06 20:12:42 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-06-21 15:42:14 -05:00
|
|
|
def cleanup_lockfiles
|
2013-06-21 18:37:52 -05:00
|
|
|
return unless HOMEBREW_CACHE_FORMULA.directory?
|
2013-06-21 15:42:14 -05:00
|
|
|
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
|
|
|
|
|
2012-08-10 16:06:24 -04:00
|
|
|
def rm_DS_Store
|
2013-01-26 14:11:03 +00:00
|
|
|
system "find #{HOMEBREW_PREFIX} -name .DS_Store -delete 2>/dev/null"
|
2012-08-10 16:06:24 -04:00
|
|
|
end
|
|
|
|
|
2010-09-11 20:22:54 +01:00
|
|
|
end
|
2012-08-10 16:33:47 -04:00
|
|
|
|
|
|
|
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.
|
2012-09-11 14:22:56 -05:00
|
|
|
if not keg_only? or ARGV.force?
|
2012-08-10 16:33:47 -04:00
|
|
|
true
|
|
|
|
elsif opt_prefix.directory?
|
|
|
|
# SHA records were added to INSTALL_RECEIPTS the same day as opt symlinks
|
|
|
|
!Formula.installed.
|
2012-12-19 12:00:05 -06:00
|
|
|
select{ |ff| ff.deps.map{ |d| d.to_s }.include? name }.
|
2013-05-15 12:45:36 -05:00
|
|
|
map{ |ff| ff.rack.subdirs rescue [] }.
|
2012-08-10 16:33:47 -04:00
|
|
|
flatten.
|
2014-03-22 13:16:16 -05:00
|
|
|
map{ |keg_path| Tab.for_keg(keg_path).HEAD }.
|
2012-08-10 16:33:47 -04:00
|
|
|
include? nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|