aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Library/Homebrew/cleanup.rb156
-rw-r--r--Library/Homebrew/cmd/cleanup.rb189
-rw-r--r--Library/Homebrew/cmd/upgrade.rb6
-rw-r--r--Library/Homebrew/formula.rb44
-rw-r--r--Library/Homebrew/test/test_cleanup.rb76
-rw-r--r--Library/Homebrew/test/test_cmd_cleanup.rb30
-rw-r--r--Library/Homebrew/test/test_formula.rb22
7 files changed, 307 insertions, 216 deletions
diff --git a/Library/Homebrew/cleanup.rb b/Library/Homebrew/cleanup.rb
new file mode 100644
index 000000000..15805ae8e
--- /dev/null
+++ b/Library/Homebrew/cleanup.rb
@@ -0,0 +1,156 @@
+require "bottles"
+require "formula"
+require "thread"
+
+module Homebrew
+ module Cleanup
+ @@disk_cleanup_size = 0
+
+ def self.cleanup
+ cleanup_cellar
+ cleanup_cache
+ cleanup_logs
+ unless ARGV.dry_run?
+ cleanup_lockfiles
+ rm_DS_Store
+ end
+ end
+
+ def self.update_disk_cleanup_size(path_size)
+ @@disk_cleanup_size += path_size
+ end
+
+ def self.disk_cleanup_size
+ @@disk_cleanup_size
+ end
+
+ def self.cleanup_formula(formula)
+ formula.eligible_kegs_for_cleanup.each do |keg|
+ cleanup_path(keg) { keg.uninstall }
+ end
+ end
+
+ def self.cleanup_logs
+ return unless HOMEBREW_LOGS.directory?
+ HOMEBREW_LOGS.subdirs.each do |dir|
+ cleanup_path(dir) { dir.rmtree } if prune?(dir, :days_default => 14)
+ end
+ end
+
+ def self.cleanup_cellar
+ Formula.installed.each do |formula|
+ cleanup_formula formula
+ end
+ end
+
+ def self.cleanup_cache
+ return unless HOMEBREW_CACHE.directory?
+ HOMEBREW_CACHE.children.each do |path|
+ if path.to_s.end_with? ".incomplete"
+ cleanup_path(path) { path.unlink }
+ next
+ end
+ if path.basename.to_s == "java_cache" && path.directory?
+ cleanup_path(path) { FileUtils.rm_rf path }
+ next
+ end
+ if prune?(path)
+ if path.file?
+ cleanup_path(path) { path.unlink }
+ elsif path.directory? && path.to_s.include?("--")
+ cleanup_path(path) { FileUtils.rm_rf path }
+ end
+ next
+ end
+
+ next unless path.file?
+ file = path
+
+ if Pathname::BOTTLE_EXTNAME_RX === file.to_s
+ version = bottle_resolve_version(file) rescue file.version
+ else
+ version = file.version
+ end
+ next unless version
+ next unless (name = file.basename.to_s[/(.*)-(?:#{Regexp.escape(version)})/, 1])
+
+ next unless HOMEBREW_CELLAR.directory?
+
+ begin
+ f = Formulary.from_rack(HOMEBREW_CELLAR/name)
+ rescue FormulaUnavailableError, TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError
+ next
+ end
+
+ file_is_stale = if PkgVersion === version
+ f.pkg_version > version
+ else
+ f.version > version
+ end
+
+ if file_is_stale || ARGV.switch?("s") && !f.installed? || bottle_file_outdated?(f, file)
+ cleanup_path(file) { file.unlink }
+ end
+ end
+ end
+
+ def self.cleanup_path(path)
+ if ARGV.dry_run?
+ puts "Would remove: #{path} (#{path.abv})"
+ else
+ puts "Removing: #{path}... (#{path.abv})"
+ yield
+ end
+
+ update_disk_cleanup_size(path.disk_usage)
+ end
+
+ def self.cleanup_lockfiles
+ return unless HOMEBREW_CACHE_FORMULA.directory?
+ candidates = HOMEBREW_CACHE_FORMULA.children
+ lockfiles = candidates.select { |f| f.file? && f.extname == ".brewing" }
+ lockfiles.each do |file|
+ next unless file.readable?
+ file.open.flock(File::LOCK_EX | File::LOCK_NB) && file.unlink
+ end
+ end
+
+ def self.rm_DS_Store
+ paths = Queue.new
+ %w[Cellar Frameworks Library bin etc include lib opt sbin share var].
+ map { |p| HOMEBREW_PREFIX/p }.each { |p| paths << p if p.exist? }
+ workers = (0...Hardware::CPU.cores).map do
+ Thread.new do
+ begin
+ while p = paths.pop(true)
+ quiet_system "find", p, "-name", ".DS_Store", "-delete"
+ end
+ rescue ThreadError # ignore empty queue error
+ end
+ end
+ end
+ workers.map(&:join)
+ end
+
+ def self.prune?(path, options = {})
+ @time ||= Time.now
+
+ path_modified_time = path.mtime
+ days_default = options[:days_default]
+
+ prune = ARGV.value "prune"
+
+ return true if prune == "all"
+
+ prune_time = if prune
+ @time - 60 * 60 * 24 * prune.to_i
+ elsif days_default
+ @time - 60 * 60 * 24 * days_default.to_i
+ end
+
+ return false unless prune_time
+
+ path_modified_time < prune_time
+ end
+ end
+end
diff --git a/Library/Homebrew/cmd/cleanup.rb b/Library/Homebrew/cmd/cleanup.rb
index e01a809b5..7d891787a 100644
--- a/Library/Homebrew/cmd/cleanup.rb
+++ b/Library/Homebrew/cmd/cleanup.rb
@@ -1,31 +1,16 @@
-require "formula"
-require "keg"
-require "bottles"
-require "thread"
+require "cleanup"
require "utils"
module Homebrew
- @@disk_cleanup_size = 0
-
- def update_disk_cleanup_size(path_size)
- @@disk_cleanup_size += path_size
- end
-
def cleanup
if ARGV.named.empty?
- cleanup_cellar
- cleanup_cache
- cleanup_logs
- unless ARGV.dry_run?
- cleanup_lockfiles
- rm_DS_Store
- end
+ Cleanup.cleanup
else
- ARGV.resolved_formulae.each { |f| cleanup_formula(f) }
+ ARGV.resolved_formulae.each { |f| Cleanup.cleanup_formula f }
end
- if @@disk_cleanup_size > 0
- disk_space = disk_usage_readable(@@disk_cleanup_size)
+ if Cleanup.disk_cleanup_size > 0
+ disk_space = disk_usage_readable(Cleanup.disk_cleanup_size)
if ARGV.dry_run?
ohai "This operation would free approximately #{disk_space} of disk space."
else
@@ -33,168 +18,4 @@ module Homebrew
end
end
end
-
- def cleanup_logs
- return unless HOMEBREW_LOGS.directory?
- HOMEBREW_LOGS.subdirs.each do |dir|
- cleanup_path(dir) { dir.rmtree } if prune?(dir, :days_default => 14)
- end
- end
-
- def cleanup_cellar
- Formula.installed.each do |formula|
- cleanup_formula formula
- end
- end
-
- def cleanup_formula(f)
- if f.installed?
- eligible_kegs = f.installed_kegs.select { |k| f.pkg_version > k.version }
- if eligible_kegs.any? && eligible_for_cleanup?(f)
- eligible_kegs.each { |keg| cleanup_keg(keg) }
- else
- eligible_kegs.each { |keg| opoo "Skipping (old) keg-only: #{keg}" }
- end
- elsif f.installed_prefixes.any? && !f.pinned?
- # If the cellar only has one version installed, don't complain
- # that we can't tell which one to keep. Don't complain at all if the
- # only installed version is a pinned formula.
- opoo "Skipping #{f.full_name}: most recent version #{f.pkg_version} not installed"
- end
- end
-
- def cleanup_keg(keg)
- if keg.linked?
- opoo "Skipping (old) #{keg} due to it being linked"
- else
- cleanup_path(keg) { keg.uninstall }
- end
- end
-
- def cleanup_cache
- return unless HOMEBREW_CACHE.directory?
- HOMEBREW_CACHE.children.each do |path|
- if path.to_s.end_with? ".incomplete"
- cleanup_path(path) { path.unlink }
- next
- end
- if path.basename.to_s == "java_cache" && path.directory?
- cleanup_path(path) { FileUtils.rm_rf path }
- next
- end
- if prune?(path)
- if path.file?
- cleanup_path(path) { path.unlink }
- elsif path.directory? && path.to_s.include?("--")
- cleanup_path(path) { FileUtils.rm_rf path }
- end
- next
- end
-
- next unless path.file?
- file = path
-
- if Pathname::BOTTLE_EXTNAME_RX === file.to_s
- version = bottle_resolve_version(file) rescue file.version
- else
- version = file.version
- end
- next unless version
- next unless (name = file.basename.to_s[/(.*)-(?:#{Regexp.escape(version)})/, 1])
-
- next unless HOMEBREW_CELLAR.directory?
-
- begin
- f = Formulary.from_rack(HOMEBREW_CELLAR/name)
- rescue FormulaUnavailableError, TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError
- next
- end
-
- file_is_stale = if PkgVersion === version
- f.pkg_version > version
- else
- f.version > version
- end
-
- if file_is_stale || ARGV.switch?("s") && !f.installed? || bottle_file_outdated?(f, file)
- cleanup_path(file) { file.unlink }
- end
- end
- end
-
- def cleanup_path(path)
- if ARGV.dry_run?
- puts "Would remove: #{path} (#{path.abv})"
- else
- puts "Removing: #{path}... (#{path.abv})"
- yield
- end
- update_disk_cleanup_size(path.disk_usage)
- 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.each do |file|
- next unless file.readable?
- file.open.flock(File::LOCK_EX | File::LOCK_NB) && file.unlink
- end
- end
-
- def rm_DS_Store
- paths = Queue.new
- %w[Cellar Frameworks Library bin etc include lib opt sbin share var].
- map { |p| HOMEBREW_PREFIX/p }.each { |p| paths << p if p.exist? }
- workers = (0...Hardware::CPU.cores).map do
- Thread.new do
- begin
- while p = paths.pop(true)
- quiet_system "find", p, "-name", ".DS_Store", "-delete"
- end
- rescue ThreadError # ignore empty queue error
- end
- end
- end
- workers.map(&:join)
- end
-
- def prune?(path, options = {})
- @time ||= Time.now
-
- path_modified_time = path.mtime
- days_default = options[:days_default]
-
- prune = ARGV.value "prune"
-
- return true if prune == "all"
-
- prune_time = if prune
- @time - 60 * 60 * 24 * prune.to_i
- elsif days_default
- @time - 60 * 60 * 24 * days_default.to_i
- end
-
- return false unless prune_time
-
- path_modified_time < prune_time
- end
-
- def eligible_for_cleanup?(formula)
- # 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 !formula.keg_only? || ARGV.force?
- true
- elsif formula.opt_prefix.directory?
- # SHA records were added to INSTALL_RECEIPTS the same day as opt symlinks
- Formula.installed.select do |f|
- f.deps.any? do |d|
- d.to_formula.full_name == formula.full_name rescue d.name == formula.name
- end
- end.all? { |f| f.installed_prefixes.all? { |keg| Tab.for_keg(keg).HEAD } }
- end
- end
end
diff --git a/Library/Homebrew/cmd/upgrade.rb b/Library/Homebrew/cmd/upgrade.rb
index 9c71d4057..62ef0bf81 100644
--- a/Library/Homebrew/cmd/upgrade.rb
+++ b/Library/Homebrew/cmd/upgrade.rb
@@ -1,5 +1,5 @@
require "cmd/install"
-require "cmd/cleanup"
+require "cleanup"
module Homebrew
def upgrade
@@ -44,7 +44,9 @@ module Homebrew
outdated.each do |f|
upgrade_formula(f)
- cleanup_formula(f) if ARGV.include?("--cleanup") && f.installed?
+ next unless ARGV.include?("--cleanup")
+ next unless f.installed?
+ Homebrew::Cleanup.cleanup_formula f
end
end
diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb
index b12b9c01b..e2f5bd961 100644
--- a/Library/Homebrew/formula.rb
+++ b/Library/Homebrew/formula.rb
@@ -1475,6 +1475,50 @@ class Formula
end
end
+ # @private
+ def eligible_kegs_for_cleanup
+ eligible_for_cleanup = []
+ if installed?
+ eligible_kegs = installed_kegs.select { |k| pkg_version > k.version }
+ if eligible_kegs.any? && eligible_for_cleanup?
+ eligible_kegs.each do |keg|
+ if keg.linked?
+ opoo "Skipping (old) #{keg} due to it being linked"
+ else
+ eligible_for_cleanup << keg
+ end
+ end
+ else
+ eligible_kegs.each { |keg| opoo "Skipping (old) keg-only: #{keg}" }
+ end
+ elsif installed_prefixes.any? && !pinned?
+ # If the cellar only has one version installed, don't complain
+ # that we can't tell which one to keep. Don't complain at all if the
+ # only installed version is a pinned formula.
+ opoo "Skipping #{full_name}: most recent version #{f.pkg_version} not installed"
+ end
+ eligible_for_cleanup
+ end
+
+ # @private
+ def eligible_for_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 !keg_only? || ARGV.force?
+ true
+ elsif opt_prefix.directory?
+ # SHA records were added to INSTALL_RECEIPTS the same day as opt symlinks
+ Formula.installed.select do |f|
+ f.deps.any? do |d|
+ d.to_formula.full_name == full_name rescue d.name == name
+ end
+ end.all? { |f| f.installed_prefixes.all? { |keg| Tab.for_keg(keg).HEAD } }
+ end
+ end
+
private
def exec_cmd(cmd, args, out, logfn)
diff --git a/Library/Homebrew/test/test_cleanup.rb b/Library/Homebrew/test/test_cleanup.rb
new file mode 100644
index 000000000..bccfa1e54
--- /dev/null
+++ b/Library/Homebrew/test/test_cleanup.rb
@@ -0,0 +1,76 @@
+require "testing_env"
+require "testball"
+require "cleanup"
+require "fileutils"
+require "pathname"
+
+class CleanupTests < Homebrew::TestCase
+ def setup
+ @ds_store = Pathname.new "#{HOMEBREW_PREFIX}/Library/.DS_Store"
+ FileUtils.touch @ds_store
+ end
+
+ def teardown
+ FileUtils.rm_f @ds_store
+ ARGV.delete "--dry-run"
+ ARGV.delete "--prune=all"
+ end
+
+ def test_cleanup
+ shutup { Homebrew::Cleanup.cleanup }
+ refute_predicate @ds_store, :exist?
+ end
+
+ def test_cleanup_dry_run
+ ARGV << "--dry-run"
+ shutup { Homebrew::Cleanup.cleanup }
+ assert_predicate @ds_store, :exist?
+ end
+
+ def test_cleanup_formula
+ f1 = Class.new(Testball) { version "0.1" }.new
+ f2 = Class.new(Testball) { version "0.2" }.new
+ f3 = Class.new(Testball) { version "0.3" }.new
+
+ shutup do
+ f1.brew { f1.install }
+ f2.brew { f2.install }
+ f3.brew { f3.install }
+ end
+
+ assert_predicate f1, :installed?
+ assert_predicate f2, :installed?
+ assert_predicate f3, :installed?
+
+ shutup { Homebrew::Cleanup.cleanup_formula f3 }
+
+ refute_predicate f1, :installed?
+ refute_predicate f2, :installed?
+ assert_predicate f3, :installed?
+ ensure
+ [f1, f2, f3].each(&:clear_cache)
+ f3.rack.rmtree
+ end
+
+ def test_cleanup_logs
+ path = (HOMEBREW_LOGS/"delete_me")
+ path.mkpath
+ ARGV << "--prune=all"
+ shutup { Homebrew::Cleanup.cleanup_logs }
+ refute_predicate path, :exist?
+ end
+
+ def test_cleanup_cache_incomplete_downloads
+ incomplete = (HOMEBREW_CACHE/"something.incomplete")
+ incomplete.mkpath
+ shutup { Homebrew::Cleanup.cleanup_cache }
+ refute_predicate incomplete, :exist?
+ end
+
+ def test_cleanup_cache_java_cache
+ java_cache = (HOMEBREW_CACHE/"java_cache")
+ java_cache.mkpath
+ shutup { Homebrew::Cleanup.cleanup_cache }
+ refute_predicate java_cache, :exist?
+ end
+end
diff --git a/Library/Homebrew/test/test_cmd_cleanup.rb b/Library/Homebrew/test/test_cmd_cleanup.rb
deleted file mode 100644
index 109f27eba..000000000
--- a/Library/Homebrew/test/test_cmd_cleanup.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require "testing_env"
-require "testball"
-require "cmd/cleanup"
-
-class CleanupTests < Homebrew::TestCase
- def test_cleanup
- f1 = Class.new(Testball) { version "0.1" }.new
- f2 = Class.new(Testball) { version "0.2" }.new
- f3 = Class.new(Testball) { version "0.3" }.new
-
- shutup do
- f1.brew { f1.install }
- f2.brew { f2.install }
- f3.brew { f3.install }
- end
-
- assert_predicate f1, :installed?
- assert_predicate f2, :installed?
- assert_predicate f3, :installed?
-
- shutup { Homebrew.cleanup_formula(f3) }
-
- refute_predicate f1, :installed?
- refute_predicate f2, :installed?
- assert_predicate f3, :installed?
- ensure
- [f1, f2, f3].each(&:clear_cache)
- f3.rack.rmtree
- end
-end
diff --git a/Library/Homebrew/test/test_formula.rb b/Library/Homebrew/test/test_formula.rb
index e6b5396b8..8f372f6f7 100644
--- a/Library/Homebrew/test/test_formula.rb
+++ b/Library/Homebrew/test/test_formula.rb
@@ -1,5 +1,6 @@
require "testing_env"
require "testball"
+require "formula"
class FormulaTests < Homebrew::TestCase
def test_formula_instantiation
@@ -345,4 +346,25 @@ class FormulaTests < Homebrew::TestCase
assert h.is_a?(Hash), "Formula#to_hash should return a Hash"
assert h["versions"]["bottle"], "The hash should say the formula is bottled"
end
+
+ def test_eligible_kegs_for_cleanup
+ f1 = Class.new(Testball) { version "0.1" }.new
+ f2 = Class.new(Testball) { version "0.2" }.new
+ f3 = Class.new(Testball) { version "0.3" }.new
+
+ shutup do
+ f1.brew { f1.install }
+ f2.brew { f2.install }
+ f3.brew { f3.install }
+ end
+
+ assert_predicate f1, :installed?
+ assert_predicate f2, :installed?
+ assert_predicate f3, :installed?
+
+ assert_equal f3.installed_kegs[0..1], f3.eligible_kegs_for_cleanup
+ ensure
+ [f1, f2, f3].each(&:clear_cache)
+ f3.rack.rmtree
+ end
end