From 844e865363b2280b681d30edeea34f87ad3a329d Mon Sep 17 00:00:00 2001 From: Kenneth Chew Date: Sun, 14 Mar 2021 17:30:25 -0400 Subject: [PATCH 1/3] audit: check for installed empty files Empty files sometimes indicate that problems occurred during building or installation. --- Library/Homebrew/formula_cellar_checks.rb | 42 +++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/Library/Homebrew/formula_cellar_checks.rb b/Library/Homebrew/formula_cellar_checks.rb index 2059ebbeba..1c742d4aea 100644 --- a/Library/Homebrew/formula_cellar_checks.rb +++ b/Library/Homebrew/formula_cellar_checks.rb @@ -275,6 +275,47 @@ module FormulaCellarChecks "Python formulae that are keg-only should not create `pip3` and `wheel3` symlinks." end + INVALID_EMPTY_FILE_NAMES = %w[AUTHORS ChangeLog changes COPYING NEWS README TODO].freeze + INVALID_EMPTY_FILE_EXTENSIONS = %w[.html .md .rst .txt].freeze + INVALID_EMPTY_FILE_LOCATIONS = %w[bin libexec share/man share/doc].freeze + # Names and extensions to ignore, even if they are in a location within prefix given above + VALID_EMPTY_FILE_NAMES = %w[__init__.py REQUESTED].freeze + VALID_EMPTY_FILE_EXTENSIONS = %w[.stamp].freeze + + def check_empty_files(prefix) + return unless prefix.directory? + + empty_files = [] + prefix.children.each do |f| + next if INVALID_EMPTY_FILE_NAMES.none?(File.basename(f)) && + INVALID_EMPTY_FILE_EXTENSIONS.none?(File.extname(f)) + next unless File.zero?(f) + + empty_files << f + end + + INVALID_EMPTY_FILE_LOCATIONS.each do |loc| + next unless (prefix/loc).directory? + + # search all directories in INVALID_EMPTY_FILE_LOCATIONS and their subdirectories + Dir.glob(prefix/loc/"**/*").each do |f| + next if VALID_EMPTY_FILE_NAMES.any?(File.basename(f)) || + VALID_EMPTY_FILE_EXTENSIONS.any?(File.extname(f)) + next unless File.zero?(f) + + empty_files << f + end + end + + return if empty_files.empty? + + <<~EOS + Suspicious empty files were installed. + The offending files are: + #{empty_files * "\n "} + EOS + end + def audit_installed @new_formula ||= false @@ -293,6 +334,7 @@ module FormulaCellarChecks problem_if_output(check_shim_references(formula.prefix)) problem_if_output(check_plist(formula.prefix, formula.plist)) problem_if_output(check_python_symlinks(formula.name, formula.keg_only?)) + problem_if_output(check_empty_files(formula.prefix)) end alias generic_audit_installed audit_installed From 5adf8cbe7b908574de4a688d1b5c825975166271 Mon Sep 17 00:00:00 2001 From: Kenneth Chew Date: Mon, 15 Mar 2021 14:34:05 -0400 Subject: [PATCH 2/3] audit: add additional (in)valid empty files, refactor empty file check --- Library/Homebrew/formula_cellar_checks.rb | 35 ++++++++++++----------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/Library/Homebrew/formula_cellar_checks.rb b/Library/Homebrew/formula_cellar_checks.rb index 1c742d4aea..4b21a8a714 100644 --- a/Library/Homebrew/formula_cellar_checks.rb +++ b/Library/Homebrew/formula_cellar_checks.rb @@ -275,42 +275,43 @@ module FormulaCellarChecks "Python formulae that are keg-only should not create `pip3` and `wheel3` symlinks." end - INVALID_EMPTY_FILE_NAMES = %w[AUTHORS ChangeLog changes COPYING NEWS README TODO].freeze + INVALID_EMPTY_FILE_NAMES = %w[AUTHORS ChangeLog changes COPYING LICENSE NEWS README TODO].freeze INVALID_EMPTY_FILE_EXTENSIONS = %w[.html .md .rst .txt].freeze - INVALID_EMPTY_FILE_LOCATIONS = %w[bin libexec share/man share/doc].freeze + INVALID_EMPTY_FILE_DIRECTORIES = %w[bin libexec share/man share/doc].freeze # Names and extensions to ignore, even if they are in a location within prefix given above - VALID_EMPTY_FILE_NAMES = %w[__init__.py REQUESTED].freeze - VALID_EMPTY_FILE_EXTENSIONS = %w[.stamp].freeze + VALID_EMPTY_FILE_NAMES = %w[__init__ empty REQUESTED].freeze + VALID_EMPTY_FILE_EXTENSIONS = %w[.gitkeep .keep .keepme .stamp .typed].freeze def check_empty_files(prefix) return unless prefix.directory? - empty_files = [] - prefix.children.each do |f| - next if INVALID_EMPTY_FILE_NAMES.none?(File.basename(f)) && - INVALID_EMPTY_FILE_EXTENSIONS.none?(File.extname(f)) + empty_files = prefix.children.select do |f| + next if INVALID_EMPTY_FILE_NAMES.exclude?(f.basename(".*").to_s) && + INVALID_EMPTY_FILE_EXTENSIONS.exclude?(f.extname) next unless File.zero?(f) - empty_files << f + true end - INVALID_EMPTY_FILE_LOCATIONS.each do |loc| - next unless (prefix/loc).directory? + INVALID_EMPTY_FILE_DIRECTORIES.each do |dir| + path = prefix/dir + next unless path.directory? # search all directories in INVALID_EMPTY_FILE_LOCATIONS and their subdirectories - Dir.glob(prefix/loc/"**/*").each do |f| - next if VALID_EMPTY_FILE_NAMES.any?(File.basename(f)) || - VALID_EMPTY_FILE_EXTENSIONS.any?(File.extname(f)) - next unless File.zero?(f) + Pathname.glob(path/"**/*").each do |p| + # Any files in the "valid" list should be skipped because they are expected to be empty + next if VALID_EMPTY_FILE_NAMES.include?(p.basename(".*").to_s) + next if VALID_EMPTY_FILE_EXTENSIONS.include?(p.extname) + next unless File.zero?(p) - empty_files << f + empty_files << p end end return if empty_files.empty? <<~EOS - Suspicious empty files were installed. + Unexpected empty files were installed. The offending files are: #{empty_files * "\n "} EOS From 9d6bfa59659fd3497bc1e2a07eb8b1adc6c26aa9 Mon Sep 17 00:00:00 2001 From: Kenneth Chew Date: Fri, 26 Mar 2021 20:31:09 -0400 Subject: [PATCH 3/3] pathname: do not install empty metafiles --- Library/Homebrew/extend/pathname.rb | 1 + Library/Homebrew/test/formula_installer_spec.rb | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/extend/pathname.rb b/Library/Homebrew/extend/pathname.rb index 3930deb3bc..0582e55e86 100644 --- a/Library/Homebrew/extend/pathname.rb +++ b/Library/Homebrew/extend/pathname.rb @@ -432,6 +432,7 @@ class Pathname def install_metafiles(from = Pathname.pwd) Pathname(from).children.each do |p| next if p.directory? + next if File.zero?(p) next unless Metafiles.copy?(p.basename.to_s) # Some software symlinks these files (see help2man.rb) diff --git a/Library/Homebrew/test/formula_installer_spec.rb b/Library/Homebrew/test/formula_installer_spec.rb index 0e84ed74a5..674c57948a 100644 --- a/Library/Homebrew/test/formula_installer_spec.rb +++ b/Library/Homebrew/test/formula_installer_spec.rb @@ -51,7 +51,8 @@ describe FormulaInstaller do specify "basic installation" do temporary_install(Testball.new) do |f| # Test that things made it into the Keg - expect(f.prefix/"readme").to exist + # "readme" is empty, so it should not be installed + expect(f.prefix/"readme").not_to exist expect(f.bin).to be_a_directory expect(f.bin.children.count).to eq(3)