Skip to content

Commit

Permalink
Use option parser for brew cleanup.
Browse files Browse the repository at this point in the history
  • Loading branch information
reitermarkus committed Aug 8, 2018
1 parent 6ae2246 commit 03b93da
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 78 deletions.
71 changes: 49 additions & 22 deletions Library/Homebrew/cleanup.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "utils/bottles"
require "formula"
require "hbc/cask_loader"

module CleanupRefinement
refine Pathname do
Expand Down Expand Up @@ -67,22 +68,50 @@ def stale_formula?(scrub)
using CleanupRefinement

module Homebrew
module Cleanup
@disk_cleanup_size = 0

class << self
attr_reader :disk_cleanup_size
end
class Cleanup
extend Predicable

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
@days = days
@cache = cache
end

def clean!
if args.empty?
Formula.installed.each do |formula|
cleanup_formula(formula)
end
cleanup_cache
cleanup_logs
return if dry_run?
cleanup_lockfiles
rm_ds_store
else
args.each do |arg|
formula = begin
Formula[arg]
rescue FormulaUnavailableError, TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError
nil
end

module_function
cask = begin
Hbc::CaskLoader.load(arg)
rescue Hbc::CaskUnavailableError
nil
end

def cleanup
cleanup_cellar
cleanup_cache
cleanup_logs
return if ARGV.dry_run?
cleanup_lockfiles
rm_ds_store
cleanup_formula(formula) if formula
cleanup_cask(cask) if cask
end
end
end

def update_disk_cleanup_size(path_size)
Expand All @@ -93,14 +122,12 @@ def unremovable_kegs
@unremovable_kegs ||= []
end

def cleanup_cellar(formulae = Formula.installed)
formulae.each(&method(:cleanup_formula))
end

def cleanup_formula(formula)
formula.eligible_kegs_for_cleanup.each(&method(:cleanup_keg))
end

def cleanup_cask(cask); end

def cleanup_keg(keg)
cleanup_path(keg) { keg.uninstall }
rescue Errno::EACCES => e
Expand All @@ -113,17 +140,17 @@ def cleanup_keg(keg)
def cleanup_logs
return unless HOMEBREW_LOGS.directory?
HOMEBREW_LOGS.subdirs.each do |dir|
cleanup_path(dir) { dir.rmtree } if dir.prune?(ARGV.value("prune")&.to_i || DEFAULT_LOG_DAYS)
cleanup_path(dir) { dir.rmtree } if dir.prune?(days || DEFAULT_LOG_DAYS)
end
end

def cleanup_cache(cache = HOMEBREW_CACHE)
def cleanup_cache
return unless cache.directory?
cache.children.each do |path|
next cleanup_path(path) { path.unlink } if path.incomplete?
next cleanup_path(path) { FileUtils.rm_rf path } if path.nested_cache?

if path.prune?(ARGV.value("prune")&.to_i)
if path.prune?(days)
if path.file?
cleanup_path(path) { path.unlink }
elsif path.directory? && path.to_s.include?("--")
Expand All @@ -139,7 +166,7 @@ def cleanup_cache(cache = HOMEBREW_CACHE)
def cleanup_path(path)
disk_usage = path.disk_usage

if ARGV.dry_run?
if dry_run?
puts "Would remove: #{path} (#{path.abv})"
else
puts "Removing: #{path}... (#{path.abv})"
Expand Down
34 changes: 18 additions & 16 deletions Library/Homebrew/cmd/cleanup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,36 @@
#: deleted. If you want to delete those too: `rm -rf $(brew --cache)`

require "cleanup"
require "cli_parser"

module Homebrew
module_function

def cleanup
if ARGV.named.empty?
Cleanup.cleanup
else
Cleanup.cleanup_cellar(ARGV.resolved_formulae)
CLI::Parser.parse do
switch "-n", "--dry-run"
switch "-s"
flag "--prune="
end

report_disk_usage unless Cleanup.disk_cleanup_size.zero?
report_unremovable_kegs unless Cleanup.unremovable_kegs.empty?
end
cleanup = Cleanup.new(*args.remaining, dry_run: args.dry_run?, scrub: args.s?, days: args.prune&.to_i)

cleanup.clean!

def report_disk_usage
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
ohai "This operation has freed approximately #{disk_space} of disk space."
unless cleanup.disk_cleanup_size.zero?
disk_space = disk_usage_readable(cleanup.disk_cleanup_size)
if args.dry_run?
ohai "This operation would free approximately #{disk_space} of disk space."
else
ohai "This operation has freed approximately #{disk_space} of disk space."
end
end
end

def report_unremovable_kegs
return if cleanup.unremovable_kegs.empty?

ofail <<~EOS
Could not cleanup old kegs! Fix your permissions on:
#{Cleanup.unremovable_kegs.join "\n "}
#{cleanup.unremovable_kegs.join "\n "}
EOS
end
end
4 changes: 0 additions & 4 deletions Library/Homebrew/cmd/update-report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,6 @@ def migrate_legacy_cache_if_necessary
return unless legacy_cache.writable_real?
FileUtils.touch migration_attempted_file

# Cleanup to avoid copying files unnecessarily
ohai "Cleaning up #{legacy_cache}..."
Cleanup.cleanup_cache legacy_cache

# This directory could have been compromised if it's world-writable/
# a symlink/owned by another user so don't copy files in those cases.
world_writable = legacy_cache.stat.mode & 0777 == 0777
Expand Down
2 changes: 1 addition & 1 deletion Library/Homebrew/cmd/upgrade.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def upgrade
upgrade_formula(f)
next if !ARGV.include?("--cleanup") && !ENV["HOMEBREW_UPGRADE_CLEANUP"]
next unless f.installed?
Homebrew::Cleanup.cleanup_formula f
Cleanup.new.cleanup_formula(f)
rescue UnsatisfiedRequirements => e
Homebrew.failed = true
onoe "#{f}: #{e}"
Expand Down
59 changes: 24 additions & 35 deletions Library/Homebrew/test/cleanup_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,14 @@

describe "::cleanup" do
it "removes .DS_Store and lock files" do
described_class.cleanup
subject.clean!

expect(ds_store).not_to exist
expect(lock_file).not_to exist
end

it "doesn't remove anything if `--dry-run` is specified" do
ARGV << "--dry-run"

described_class.cleanup
it "doesn't remove anything if `dry_run` is true" do
described_class.new(dry_run: true).clean!

expect(ds_store).to exist
expect(lock_file).to exist
Expand All @@ -61,18 +59,16 @@
it "doesn't remove the lock file if it is locked" do
lock_file.open(File::RDWR | File::CREAT).flock(File::LOCK_EX | File::LOCK_NB)

described_class.cleanup
subject.clean!

expect(lock_file).to exist
end

context "when it can't remove a keg" do
let(:f1) { Class.new(Testball) { version "0.1" }.new }
let(:f2) { Class.new(Testball) { version "0.2" }.new }
let(:unremovable_kegs) { [] }

before do
described_class.instance_variable_set(:@unremovable_kegs, [])
[f1, f2].each do |f|
f.brew do
f.install
Expand All @@ -87,13 +83,13 @@
end

it "doesn't remove any kegs" do
described_class.cleanup_formula f2
subject.cleanup_formula f2
expect(f1.installed_kegs.size).to eq(2)
end

it "lists the unremovable kegs" do
described_class.cleanup_formula f2
expect(described_class.unremovable_kegs).to contain_exactly(f1.installed_kegs[0])
subject.cleanup_formula f2
expect(subject.unremovable_kegs).to contain_exactly(f1.installed_kegs[0])
end
end
end
Expand Down Expand Up @@ -131,7 +127,7 @@
expect(f3).to be_installed
expect(f4).to be_installed

described_class.cleanup_formula f3
subject.cleanup_formula f3

expect(f1).not_to be_installed
expect(f2).not_to be_installed
Expand All @@ -146,21 +142,20 @@
path.mkpath
end

it "cleans all logs if prune all" do
ARGV << "--prune=all"
described_class.cleanup_logs
it "cleans all logs if prune is 0" do
described_class.new(days: 0).cleanup_logs
expect(path).not_to exist
end

it "cleans up logs if older than 14 days" do
allow_any_instance_of(Pathname).to receive(:mtime).and_return(Time.now - 15 * 60 * 60 * 24)
described_class.cleanup_logs
subject.cleanup_logs
expect(path).not_to exist
end

it "does not clean up logs less than 14 days old" do
allow_any_instance_of(Pathname).to receive(:mtime).and_return(Time.now - 2 * 60 * 60 * 24)
described_class.cleanup_logs
subject.cleanup_logs
expect(path).to exist
end
end
Expand All @@ -170,7 +165,7 @@
incomplete = (HOMEBREW_CACHE/"something.incomplete")
incomplete.mkpath

described_class.cleanup_cache
subject.cleanup_cache

expect(incomplete).not_to exist
end
Expand All @@ -179,7 +174,7 @@
glide_home = (HOMEBREW_CACHE/"glide_home")
glide_home.mkpath

described_class.cleanup_cache
subject.cleanup_cache

expect(glide_home).not_to exist
end
Expand All @@ -188,7 +183,7 @@
java_cache = (HOMEBREW_CACHE/"java_cache")
java_cache.mkpath

described_class.cleanup_cache
subject.cleanup_cache

expect(java_cache).not_to exist
end
Expand All @@ -197,7 +192,7 @@
npm_cache = (HOMEBREW_CACHE/"npm_cache")
npm_cache.mkpath

described_class.cleanup_cache
subject.cleanup_cache

expect(npm_cache).not_to exist
end
Expand All @@ -211,9 +206,7 @@
gist.mkpath
FileUtils.touch svn

allow(ARGV).to receive(:value).with("prune").and_return("all")

described_class.cleanup_cache
described_class.new(days: 0).cleanup_cache

expect(git).not_to exist
expect(gist).to exist
Expand All @@ -223,27 +216,24 @@
it "does not clean up directories that are not VCS checkouts" do
git = (HOMEBREW_CACHE/"git")
git.mkpath
allow(ARGV).to receive(:value).with("prune").and_return("all")

described_class.cleanup_cache
described_class.new(days: 0).cleanup_cache

expect(git).to exist
end

it "cleans up VCS checkout directories with modified time < prune time" do
foo = (HOMEBREW_CACHE/"--foo")
foo.mkpath
allow(ARGV).to receive(:value).with("prune").and_return("1")
allow_any_instance_of(Pathname).to receive(:mtime).and_return(Time.now - 2 * 60 * 60 * 24)
described_class.cleanup_cache
described_class.new(days: 1).cleanup_cache
expect(foo).not_to exist
end

it "does not clean up VCS checkout directories with modified time >= prune time" do
foo = (HOMEBREW_CACHE/"--foo")
foo.mkpath
allow(ARGV).to receive(:value).with("prune").and_return("1")
described_class.cleanup_cache
described_class.new(days: 1).cleanup_cache
expect(foo).to exist
end

Expand All @@ -260,20 +250,19 @@

it "cleans up file if outdated" do
allow(Utils::Bottles).to receive(:file_outdated?).with(any_args).and_return(true)
described_class.cleanup_cache
subject.cleanup_cache
expect(bottle).not_to exist
expect(testball).not_to exist
end

it "cleans up file if ARGV has -s and formula not installed" do
ARGV << "-s"
described_class.cleanup_cache
it "cleans up file if `scrub` is true and formula not installed" do
described_class.new(scrub: true).cleanup_cache
expect(bottle).not_to exist
expect(testball).not_to exist
end

it "cleans up file if stale" do
described_class.cleanup_cache
subject.cleanup_cache
expect(bottle).not_to exist
expect(testball).not_to exist
end
Expand Down

0 comments on commit 03b93da

Please sign in to comment.