blob: b4211c37358376a4b95554454a688a6c8bf250ac (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
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|
cleanup_path(dir) { dir.rmtree } if dir.mtime < time
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 }
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.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.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?
prune = ARGV.value "prune"
time = Time.now - 60 * 60 * 24 * prune.to_i
HOMEBREW_CACHE.children.select(&:file?).each do |file|
next cleanup_path(file) { file.unlink } if prune && file.mtime < time
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_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
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
paths = %w[Cellar Frameworks Library bin etc include lib opt sbin share var].
map { |p| HOMEBREW_PREFIX/p }.select(&:exist?)
args = paths.map(&:to_s) + %w[-name .DS_Store -delete]
quiet_system "find", *args
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 not formula.keg_only? or ARGV.force?
true
elsif formula.opt_prefix.directory?
# SHA records were added to INSTALL_RECEIPTS the same day as opt symlinks
Formula.installed.
select { |f| f.deps.any? { |d| d.name == formula.name } }.
all? { |f| f.rack.subdirs.all? { |keg| Tab.for_keg(keg).HEAD } }
end
end
end
|