-
-
Notifications
You must be signed in to change notification settings - Fork 9.3k
/
cleaner.rb
167 lines (142 loc) 路 4.8 KB
/
cleaner.rb
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# typed: true
# frozen_string_literal: true
# Cleans a newly installed keg.
# By default:
#
# * removes `.la` files
# * removes `perllocal.pod` files
# * removes `.packlist` files
# * removes empty directories
# * sets permissions on executables
# * removes unresolved symlinks
class Cleaner
include Context
# Create a cleaner for the given formula.
def initialize(formula)
@formula = formula
end
# Clean the keg of the formula.
def clean
ObserverPathnameExtension.reset_counts!
# Many formulae include 'lib/charset.alias', but it is not strictly needed
# and will conflict if more than one formula provides it
observe_file_removal @formula.lib/"charset.alias"
[@formula.bin, @formula.sbin, @formula.lib].each { |dir| clean_dir(dir) if dir.exist? }
# Get rid of any info 'dir' files, so they don't conflict at the link stage
#
# The 'dir' files come in at least 3 locations:
#
# 1. 'info/dir'
# 2. 'info/#{name}/dir'
# 3. 'info/#{arch}/dir'
#
# Of these 3 only 'info/#{name}/dir' is safe to keep since the rest will
# conflict with other formulae because they use a shared location.
#
# See [cleaner: recursively delete info `dir`s by gromgit 路 Pull Request
# #11597][1], [emacs 28.1 bottle does not contain `dir` file 路 Issue
# #100190][2], and [Keep `info/#{f.name}/dir` files in cleaner by
# timvisher][3] for more info.
#
# [1]: https://github.com/Homebrew/brew/pull/11597
# [2]: https://github.com/Homebrew/homebrew-core/issues/100190
# [3]: https://github.com/Homebrew/brew/pull/13215
Dir.glob(@formula.info/"**/dir").each do |file|
info_dir_file = Pathname(file)
next unless info_dir_file.file?
next if info_dir_file == @formula.info/@formula.name/"dir"
next if @formula.skip_clean?(info_dir_file)
observe_file_removal info_dir_file
end
rewrite_shebangs
prune
end
private
def observe_file_removal(path)
path.extend(ObserverPathnameExtension).unlink if path.exist?
end
# Removes any empty directories in the formula's prefix subtree
# Keeps any empty directories protected by skip_clean
# Removes any unresolved symlinks
def prune
dirs = []
symlinks = []
@formula.prefix.find do |path|
if path == @formula.libexec || @formula.skip_clean?(path)
Find.prune
elsif path.symlink?
symlinks << path
elsif path.directory?
dirs << path
end
end
# Remove directories opposite from traversal, so that a subtree with no
# actual files gets removed correctly.
dirs.reverse_each do |d|
if d.children.empty?
puts "rmdir: #{d} (empty)" if verbose?
d.rmdir
end
end
# Remove unresolved symlinks
symlinks.reverse_each do |s|
s.unlink unless s.resolved_path_exists?
end
end
def executable_path?(path)
path.text_executable? || path.executable?
end
# Both these files are completely unnecessary to package and cause
# pointless conflicts with other formulae. They are removed by Debian,
# Arch & MacPorts amongst other packagers as well. The files are
# created as part of installing any Perl module.
PERL_BASENAMES = Set.new(%w[perllocal.pod .packlist]).freeze
# Clean a top-level (bin, sbin, lib) directory, recursively, by fixing file
# permissions and removing .la files, unless the files (or parent
# directories) are protected by skip_clean.
#
# bin and sbin should not have any subdirectories; if either do that is
# caught as an audit warning
#
# lib may have a large directory tree (see Erlang for instance), and
# clean_dir applies cleaning rules to the entire tree
def clean_dir(directory)
directory.find do |path|
path.extend(ObserverPathnameExtension)
Find.prune if @formula.skip_clean? path
next if path.directory?
if path.extname == ".la" || PERL_BASENAMES.include?(path.basename.to_s)
path.unlink
elsif path.symlink?
# Skip it.
else
# Set permissions for executables and non-executables
perms = if executable_path?(path)
0555
else
0444
end
if debug?
old_perms = path.stat.mode & 0777
odebug "Fixing #{path} permissions from #{old_perms.to_s(8)} to #{perms.to_s(8)}" if perms != old_perms
end
path.chmod perms
end
end
end
def rewrite_shebangs
require "language/perl"
require "utils/shebang"
basepath = @formula.prefix.realpath
basepath.find do |path|
Find.prune if @formula.skip_clean? path
next if path.directory? || path.symlink?
begin
Utils::Shebang.rewrite_shebang Language::Perl::Shebang.detected_perl_shebang(@formula), path
rescue ShebangDetectionError
break
end
end
end
end
require "extend/os/cleaner"