| 
									
										
										
										
											2020-10-10 14:16:11 +02:00
										 |  |  | # typed: false | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-13 00:23:14 -07:00
										 |  |  | require "utils/shell" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 05:52:29 +02:00
										 |  |  | # Checks to perform on a formula's cellar. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # @api private | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  | module FormulaCellarChecks | 
					
						
							| 
									
										
										
										
											2016-09-21 09:07:04 +02:00
										 |  |  |   def check_env_path(bin) | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  |     # warn the user if stuff was installed outside of their PATH | 
					
						
							|  |  |  |     return unless bin.directory? | 
					
						
							| 
									
										
										
										
											2016-07-09 13:51:53 +01:00
										 |  |  |     return if bin.children.empty? | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-17 09:34:43 -07:00
										 |  |  |     prefix_bin = (HOMEBREW_PREFIX/bin.basename) | 
					
						
							|  |  |  |     return unless prefix_bin.directory? | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-17 09:34:43 -07:00
										 |  |  |     prefix_bin = prefix_bin.realpath | 
					
						
							|  |  |  |     return if ORIGINAL_PATHS.include? prefix_bin | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |     <<~EOS | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |       "#{prefix_bin}" is not in your PATH. | 
					
						
							| 
									
										
										
										
											2019-04-08 12:47:15 -04:00
										 |  |  |       You can amend this by altering your #{Utils::Shell.profile} file. | 
					
						
							| 
									
										
										
										
											2014-10-13 23:13:00 -05:00
										 |  |  |     EOS | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def check_manpages | 
					
						
							|  |  |  |     # Check for man pages that aren't in share/man | 
					
						
							| 
									
										
										
										
											2017-06-01 16:06:51 +02:00
										 |  |  |     return unless (formula.prefix/"man").directory? | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |     <<~EOS | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |       A top-level "man" directory was found. | 
					
						
							|  |  |  |       Homebrew requires that man pages live under "share". | 
					
						
							| 
									
										
										
										
											2021-01-24 21:40:41 -05:00
										 |  |  |       This can often be fixed by passing `--mandir=\#{man}` to `configure`. | 
					
						
							| 
									
										
										
										
											2014-10-13 23:13:00 -05:00
										 |  |  |     EOS | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def check_infopages | 
					
						
							|  |  |  |     # Check for info pages that aren't in share/info | 
					
						
							| 
									
										
										
										
											2017-06-01 16:06:51 +02:00
										 |  |  |     return unless (formula.prefix/"info").directory? | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |     <<~EOS | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |       A top-level "info" directory was found. | 
					
						
							|  |  |  |       Homebrew suggests that info pages live under "share". | 
					
						
							| 
									
										
										
										
											2021-01-24 21:40:41 -05:00
										 |  |  |       This can often be fixed by passing `--infodir=\#{info}` to `configure`. | 
					
						
							| 
									
										
										
										
											2014-10-13 23:13:00 -05:00
										 |  |  |     EOS | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def check_jars | 
					
						
							| 
									
										
										
										
											2014-10-29 22:38:49 -05:00
										 |  |  |     return unless formula.lib.directory? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-29 22:38:49 -05:00
										 |  |  |     jars = formula.lib.children.select { |g| g.extname == ".jar" } | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  |     return if jars.empty? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |     <<~EOS | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |       JARs were installed to "#{formula.lib}". | 
					
						
							| 
									
										
										
										
											2014-10-13 23:13:00 -05:00
										 |  |  |       Installing JARs to "lib" can cause conflicts between packages. | 
					
						
							|  |  |  |       For Java software, it is typically better for the formula to | 
					
						
							|  |  |  |       install to "libexec" and then symlink or wrap binaries into "bin". | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |       See formulae 'activemq', 'jruby', etc. for examples. | 
					
						
							| 
									
										
										
										
											2014-10-13 23:13:00 -05:00
										 |  |  |       The offending files are: | 
					
						
							|  |  |  |         #{jars * "\n        "} | 
					
						
							|  |  |  |     EOS | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-22 21:25:00 -05:00
										 |  |  |   VALID_LIBRARY_EXTENSIONS = %w[.a .jnilib .la .o .so .jar .prl .pm .sh].freeze | 
					
						
							| 
									
										
										
										
											2018-08-14 11:55:39 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   def valid_library_extension?(filename) | 
					
						
							|  |  |  |     VALID_LIBRARY_EXTENSIONS.include? filename.extname | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  |   alias generic_valid_library_extension? valid_library_extension? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  |   def check_non_libraries | 
					
						
							| 
									
										
										
										
											2014-10-29 22:38:49 -05:00
										 |  |  |     return unless formula.lib.directory? | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-29 18:24:52 +01:00
										 |  |  |     non_libraries = formula.lib.children.reject do |g| | 
					
						
							| 
									
										
										
										
											2017-05-29 14:06:10 -07:00
										 |  |  |       next true if g.directory? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 11:55:39 -07:00
										 |  |  |       valid_library_extension? g | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  |     end | 
					
						
							|  |  |  |     return if non_libraries.empty? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |     <<~EOS | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |       Non-libraries were installed to "#{formula.lib}". | 
					
						
							| 
									
										
										
										
											2014-10-13 23:13:00 -05:00
										 |  |  |       Installing non-libraries to "lib" is discouraged. | 
					
						
							|  |  |  |       The offending files are: | 
					
						
							|  |  |  |         #{non_libraries * "\n        "} | 
					
						
							|  |  |  |     EOS | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |   def check_non_executables(bin) | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  |     return unless bin.directory? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     non_exes = bin.children.select { |g| g.directory? || !g.executable? } | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  |     return if non_exes.empty? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |     <<~EOS | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |       Non-executables were installed to "#{bin}". | 
					
						
							| 
									
										
										
										
											2014-10-13 23:13:00 -05:00
										 |  |  |       The offending files are: | 
					
						
							| 
									
										
										
										
											2018-05-16 19:07:11 +02:00
										 |  |  |         #{non_exes * "\n  "} | 
					
						
							| 
									
										
										
										
											2014-10-13 23:13:00 -05:00
										 |  |  |     EOS | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2013-11-10 12:51:24 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |   def check_generic_executables(bin) | 
					
						
							| 
									
										
										
										
											2013-11-10 12:51:24 -08:00
										 |  |  |     return unless bin.directory? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-22 08:52:47 +01:00
										 |  |  |     generic_names = %w[service start stop] | 
					
						
							| 
									
										
										
										
											2014-05-21 10:54:24 -05:00
										 |  |  |     generics = bin.children.select { |g| generic_names.include? g.basename.to_s } | 
					
						
							| 
									
										
										
										
											2013-11-10 12:51:24 -08:00
										 |  |  |     return if generics.empty? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |     <<~EOS | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |       Generic binaries were installed to "#{bin}". | 
					
						
							|  |  |  |       Binaries with generic names are likely to conflict with other software. | 
					
						
							|  |  |  |       Homebrew suggests that this software is installed to "libexec" and then | 
					
						
							| 
									
										
										
										
											2014-10-13 23:13:00 -05:00
										 |  |  |       symlinked as needed. | 
					
						
							|  |  |  |       The offending files are: | 
					
						
							|  |  |  |         #{generics * "\n        "} | 
					
						
							|  |  |  |     EOS | 
					
						
							| 
									
										
										
										
											2013-11-10 12:51:24 -08:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2014-10-01 23:32:53 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |   def check_easy_install_pth(lib) | 
					
						
							| 
									
										
										
										
											2015-05-05 13:45:11 -07:00
										 |  |  |     pth_found = Dir["#{lib}/python{2.7,3}*/site-packages/easy-install.pth"].map { |f| File.dirname(f) } | 
					
						
							| 
									
										
										
										
											2014-10-01 18:40:04 -07:00
										 |  |  |     return if pth_found.empty? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |     <<~EOS | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |       'easy-install.pth' files were found. | 
					
						
							|  |  |  |       These '.pth' files are likely to cause link conflicts. | 
					
						
							|  |  |  |       Please invoke `setup.py` using 'Language::Python.setup_install_args'. | 
					
						
							| 
									
										
										
										
											2019-04-08 12:47:15 -04:00
										 |  |  |       The offending files are: | 
					
						
							| 
									
										
										
										
											2014-10-13 23:13:00 -05:00
										 |  |  |         #{pth_found * "\n        "} | 
					
						
							|  |  |  |     EOS | 
					
						
							| 
									
										
										
										
											2014-10-01 18:40:04 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-31 21:42:43 -07:00
										 |  |  |   def check_elisp_dirname(share, name) | 
					
						
							| 
									
										
										
										
											2015-08-01 15:42:56 -07:00
										 |  |  |     return unless (share/"emacs/site-lisp").directory? | 
					
						
							| 
									
										
										
										
											2015-10-31 21:42:43 -07:00
										 |  |  |     # Emacs itself can do what it wants | 
					
						
							|  |  |  |     return if name == "emacs" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bad_dir_name = (share/"emacs/site-lisp").children.any? do |child| | 
					
						
							|  |  |  |       child.directory? && child.basename.to_s != name | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-07-05 14:15:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-31 21:42:43 -07:00
										 |  |  |     return unless bad_dir_name | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |     <<~EOS | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |       Emacs Lisp files were installed into the wrong "site-lisp" subdirectory. | 
					
						
							| 
									
										
										
										
											2015-10-31 21:42:43 -07:00
										 |  |  |       They should be installed into: | 
					
						
							| 
									
										
										
										
											2019-04-01 16:02:13 -04:00
										 |  |  |         #{share}/emacs/site-lisp/#{name} | 
					
						
							| 
									
										
										
										
											2015-10-31 21:42:43 -07:00
										 |  |  |     EOS | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def check_elisp_root(share, name) | 
					
						
							|  |  |  |     return unless (share/"emacs/site-lisp").directory? | 
					
						
							| 
									
										
										
										
											2015-07-05 14:15:19 -07:00
										 |  |  |     # Emacs itself can do what it wants | 
					
						
							|  |  |  |     return if name == "emacs" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-11 10:29:21 +01:00
										 |  |  |     elisps = (share/"emacs/site-lisp").children.select do |file| | 
					
						
							|  |  |  |       Keg::ELISP_EXTENSIONS.include? file.extname | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-07-05 14:15:19 -07:00
										 |  |  |     return if elisps.empty? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |     <<~EOS | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |       Emacs Lisp files were linked directly to "#{HOMEBREW_PREFIX}/share/emacs/site-lisp". | 
					
						
							| 
									
										
										
										
											2015-10-31 21:42:43 -07:00
										 |  |  |       This may cause conflicts with other packages. | 
					
						
							|  |  |  |       They should instead be installed into: | 
					
						
							| 
									
										
										
										
											2019-04-01 16:02:13 -04:00
										 |  |  |         #{share}/emacs/site-lisp/#{name} | 
					
						
							| 
									
										
										
										
											2015-07-05 14:15:19 -07:00
										 |  |  |       The offending files are: | 
					
						
							|  |  |  |         #{elisps * "\n        "} | 
					
						
							|  |  |  |     EOS | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-02 17:34:28 +01:00
										 |  |  |   def check_python_packages(lib, deps) | 
					
						
							|  |  |  |     return unless lib.directory? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     lib_subdirs = lib.children | 
					
						
							|  |  |  |                      .select(&:directory?) | 
					
						
							|  |  |  |                      .map(&:basename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pythons = lib_subdirs.map do |p| | 
					
						
							|  |  |  |       match = p.to_s.match(/^python(\d+\.\d+)$/) | 
					
						
							|  |  |  |       next if match.blank? | 
					
						
							|  |  |  |       next if match.captures.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       match.captures.first | 
					
						
							|  |  |  |     end.compact | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 15:49:30 +11:00
										 |  |  |     return if pythons.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-02 17:34:28 +01:00
										 |  |  |     python_deps = deps.map(&:name) | 
					
						
							|  |  |  |                       .grep(/^python(@.*)?$/) | 
					
						
							|  |  |  |                       .map { |d| Formula[d].version.to_s[/^\d+\.\d+/] } | 
					
						
							|  |  |  |                       .compact | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return if python_deps.blank? | 
					
						
							|  |  |  |     return if pythons.any? { |v| python_deps.include? v } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pythons = pythons.map { |v| "Python #{v}" } | 
					
						
							|  |  |  |     python_deps = python_deps.map { |v| "Python #{v}" } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     <<~EOS | 
					
						
							|  |  |  |       Packages have been installed for: | 
					
						
							|  |  |  |         #{pythons * "\n        "} | 
					
						
							|  |  |  |       but this formula depends on: | 
					
						
							|  |  |  |         #{python_deps * "\n        "} | 
					
						
							|  |  |  |     EOS | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 00:57:30 +01:00
										 |  |  |   def check_shim_references(prefix) | 
					
						
							|  |  |  |     return unless prefix.directory? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     keg = Keg.new(prefix) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     matches = [] | 
					
						
							|  |  |  |     keg.each_unique_file_matching(HOMEBREW_SHIMS_PATH) do |f| | 
					
						
							|  |  |  |       match = f.relative_path_from(keg.to_path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       next if match.to_s.match? %r{^share/doc/.+?/INFO_BIN$} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       matches << match | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return if matches.empty? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     <<~EOS | 
					
						
							|  |  |  |       Files were found with references to the Homebrew shims directory. | 
					
						
							|  |  |  |       The offending files are: | 
					
						
							|  |  |  |         #{matches * "\n  "} | 
					
						
							|  |  |  |     EOS | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-03 13:59:08 +01:00
										 |  |  |   def check_plist(prefix, plist) | 
					
						
							|  |  |  |     return unless prefix.directory? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     plist = begin | 
					
						
							|  |  |  |       Plist.parse_xml(plist) | 
					
						
							|  |  |  |     rescue | 
					
						
							|  |  |  |       nil | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     return if plist.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     program_location = plist["ProgramArguments"]&.first | 
					
						
							|  |  |  |     key = "first ProgramArguments value" | 
					
						
							|  |  |  |     if program_location.blank? | 
					
						
							|  |  |  |       program_location = plist["Program"] | 
					
						
							|  |  |  |       key = "Program" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     return if program_location.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Dir.chdir("/") do | 
					
						
							|  |  |  |       unless File.exist?(program_location) | 
					
						
							|  |  |  |         return <<~EOS | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |           The plist "#{key}" does not exist: | 
					
						
							| 
									
										
										
										
											2020-05-03 13:59:08 +01:00
										 |  |  |             #{program_location} | 
					
						
							|  |  |  |         EOS | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return if File.executable?(program_location) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     <<~EOS | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |       The plist "#{key}" is not executable: | 
					
						
							| 
									
										
										
										
											2020-05-03 13:59:08 +01:00
										 |  |  |         #{program_location} | 
					
						
							|  |  |  |     EOS | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:46:23 -04:00
										 |  |  |   def check_python_symlinks(name, keg_only) | 
					
						
							|  |  |  |     return unless keg_only | 
					
						
							| 
									
										
										
										
											2020-10-20 09:44:11 -04:00
										 |  |  |     return unless name.start_with? "python" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return if %w[pip3 wheel3].none? do |l| | 
					
						
							|  |  |  |       link = HOMEBREW_PREFIX/"bin"/l | 
					
						
							|  |  |  |       link.exist? && File.realpath(link).start_with?(HOMEBREW_CELLAR/name) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |     "Python formulae that are keg-only should not create `pip3` and `wheel3` symlinks." | 
					
						
							| 
									
										
										
										
											2020-10-20 09:44:11 -04:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-13 11:25:56 +02:00
										 |  |  |   def check_service_command(formula) | 
					
						
							|  |  |  |     return unless formula.prefix.directory? | 
					
						
							|  |  |  |     return unless formula.service? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return "Service command blank" if formula.service.command.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     "Service command does not exist" unless File.exist?(formula.service.command.first) | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-03 19:23:19 +01:00
										 |  |  |   def check_cpuid_instruction(formula) | 
					
						
							|  |  |  |     return unless formula.prefix.directory? | 
					
						
							|  |  |  |     # TODO: add methods to `utils/ast` to allow checking for method use | 
					
						
							| 
									
										
										
										
											2021-09-21 00:42:40 -04:00
										 |  |  |     return unless (formula.prefix/".brew/#{formula.name}.rb").read.include? "ENV.runtime_cpu_detection" | 
					
						
							| 
									
										
										
										
											2021-07-03 19:23:19 +01:00
										 |  |  |     # Checking for `cpuid` only makes sense on Intel: | 
					
						
							|  |  |  |     # https://en.wikipedia.org/wiki/CPUID | 
					
						
							|  |  |  |     return unless Hardware::CPU.intel? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # macOS `objdump` is a bit slow, so we prioritise llvm's `llvm-objdump` (~5.7x faster) | 
					
						
							|  |  |  |     # or binutils' `objdump` (~1.8x faster) if they are installed. | 
					
						
							|  |  |  |     objdump   = Formula["llvm"].opt_bin/"llvm-objdump" if Formula["llvm"].any_version_installed? | 
					
						
							|  |  |  |     objdump ||= Formula["binutils"].opt_bin/"objdump" if Formula["binutils"].any_version_installed? | 
					
						
							|  |  |  |     objdump ||= which("objdump") | 
					
						
							|  |  |  |     objdump ||= which("objdump", ENV["HOMEBREW_PATH"]) | 
					
						
							| 
									
										
										
										
											2021-07-05 17:47:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     unless objdump | 
					
						
							|  |  |  |       return <<~EOS | 
					
						
							|  |  |  |         No `objdump` found, so cannot check for a `cpuid` instruction. Install `objdump` with | 
					
						
							|  |  |  |           brew install binutils | 
					
						
							|  |  |  |       EOS | 
					
						
							| 
									
										
										
										
											2021-07-03 19:23:19 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     keg = Keg.new(formula.prefix) | 
					
						
							| 
									
										
										
										
											2021-07-05 10:12:34 -07:00
										 |  |  |     return if keg.binary_executable_or_library_files.any? do |file| | 
					
						
							| 
									
										
										
										
											2021-07-05 17:47:20 +01:00
										 |  |  |       cpuid_instruction?(file, objdump) | 
					
						
							| 
									
										
										
										
											2021-07-03 19:23:19 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     "No `cpuid` instruction detected. #{formula} should not use `ENV.runtime_cpu_detection`." | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-18 10:48:03 +08:00
										 |  |  |   def check_binary_arches(formula) | 
					
						
							|  |  |  |     return unless formula.prefix.directory? | 
					
						
							| 
									
										
										
										
											2021-07-18 16:55:57 +08:00
										 |  |  |     # There is no `binary_executable_or_library_files` method for the generic OS | 
					
						
							|  |  |  |     return if !OS.mac? && !OS.linux? | 
					
						
							| 
									
										
										
										
											2021-07-18 10:48:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     keg = Keg.new(formula.prefix) | 
					
						
							| 
									
										
										
										
											2021-07-23 11:40:01 +08:00
										 |  |  |     mismatches = {} | 
					
						
							|  |  |  |     keg.binary_executable_or_library_files.each do |file| | 
					
						
							|  |  |  |       farch = file.arch | 
					
						
							|  |  |  |       mismatches[file] = farch unless farch == Hardware::CPU.arch | 
					
						
							| 
									
										
										
										
											2021-07-18 10:48:03 +08:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2021-07-20 12:35:09 +08:00
										 |  |  |     return if mismatches.empty? | 
					
						
							| 
									
										
										
										
											2021-07-18 10:48:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-23 11:40:01 +08:00
										 |  |  |     compatible_universal_binaries, mismatches = mismatches.partition do |file, arch| | 
					
						
							|  |  |  |       arch == :universal && file.archs.include?(Hardware::CPU.arch) | 
					
						
							|  |  |  |     end.map(&:to_h) # To prevent transformation into nested arrays | 
					
						
							| 
									
										
										
										
											2021-07-20 12:10:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-20 18:40:19 +08:00
										 |  |  |     universal_binaries_expected = if formula.tap.present? && formula.tap.core_tap? | 
					
						
							|  |  |  |       tap_audit_exception(:universal_binary_allowlist, formula.name) | 
					
						
							| 
									
										
										
										
											2021-07-20 18:48:40 +08:00
										 |  |  |     else | 
					
						
							|  |  |  |       true | 
					
						
							| 
									
										
										
										
											2021-07-20 18:40:19 +08:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2021-07-20 12:35:09 +08:00
										 |  |  |     return if mismatches.empty? && universal_binaries_expected | 
					
						
							| 
									
										
										
										
											2021-07-20 12:10:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 18:09:26 +09:00
										 |  |  |     mismatches_expected = formula.tap.blank? || tap_audit_exception(:mismatched_binary_allowlist, formula.name) | 
					
						
							|  |  |  |     return if compatible_universal_binaries.empty? && mismatches_expected | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 01:02:29 +08:00
										 |  |  |     return if universal_binaries_expected && mismatches_expected | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-20 12:10:49 +08:00
										 |  |  |     s = "" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 18:09:26 +09:00
										 |  |  |     if mismatches.present? && !mismatches_expected | 
					
						
							| 
									
										
										
										
											2021-07-20 12:10:49 +08:00
										 |  |  |       s += <<~EOS | 
					
						
							| 
									
										
										
										
											2021-07-23 11:40:01 +08:00
										 |  |  |         Binaries built for a non-native architecture were installed into #{formula}'s prefix. | 
					
						
							| 
									
										
										
										
											2021-07-20 12:10:49 +08:00
										 |  |  |         The offending files are: | 
					
						
							| 
									
										
										
										
											2021-07-23 11:40:01 +08:00
										 |  |  |           #{mismatches.map { |m| "#{m.first}\t(#{m.last})" } * "\n  "} | 
					
						
							| 
									
										
										
										
											2021-07-20 12:10:49 +08:00
										 |  |  |       EOS | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-20 18:53:53 +08:00
										 |  |  |     if compatible_universal_binaries.present? && !universal_binaries_expected | 
					
						
							| 
									
										
										
										
											2021-07-20 12:10:49 +08:00
										 |  |  |       s += <<~EOS | 
					
						
							|  |  |  |         Unexpected universal binaries were found. | 
					
						
							|  |  |  |         The offending files are: | 
					
						
							| 
									
										
										
										
											2021-07-23 11:40:01 +08:00
										 |  |  |           #{compatible_universal_binaries.keys * "\n  "} | 
					
						
							| 
									
										
										
										
											2021-07-20 12:10:49 +08:00
										 |  |  |       EOS | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s | 
					
						
							| 
									
										
										
										
											2021-07-18 10:48:03 +08:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-13 23:13:01 -05:00
										 |  |  |   def audit_installed | 
					
						
							| 
									
										
										
										
											2018-04-07 20:28:56 +01:00
										 |  |  |     @new_formula ||= false | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-18 08:17:24 +01:00
										 |  |  |     problem_if_output(check_manpages) | 
					
						
							|  |  |  |     problem_if_output(check_infopages) | 
					
						
							|  |  |  |     problem_if_output(check_jars) | 
					
						
							| 
									
										
										
										
											2021-04-13 11:25:56 +02:00
										 |  |  |     problem_if_output(check_service_command(formula)) | 
					
						
							| 
									
										
										
										
											2017-08-03 01:56:15 -07:00
										 |  |  |     problem_if_output(check_non_libraries) if @new_formula | 
					
						
							| 
									
										
										
										
											2017-04-18 08:17:24 +01:00
										 |  |  |     problem_if_output(check_non_executables(formula.bin)) | 
					
						
							|  |  |  |     problem_if_output(check_generic_executables(formula.bin)) | 
					
						
							|  |  |  |     problem_if_output(check_non_executables(formula.sbin)) | 
					
						
							|  |  |  |     problem_if_output(check_generic_executables(formula.sbin)) | 
					
						
							|  |  |  |     problem_if_output(check_easy_install_pth(formula.lib)) | 
					
						
							|  |  |  |     problem_if_output(check_elisp_dirname(formula.share, formula.name)) | 
					
						
							|  |  |  |     problem_if_output(check_elisp_root(formula.share, formula.name)) | 
					
						
							| 
									
										
										
										
											2020-04-02 17:34:28 +01:00
										 |  |  |     problem_if_output(check_python_packages(formula.lib, formula.deps)) | 
					
						
							| 
									
										
										
										
											2020-04-15 00:57:30 +01:00
										 |  |  |     problem_if_output(check_shim_references(formula.prefix)) | 
					
						
							| 
									
										
										
										
											2020-05-03 13:59:08 +01:00
										 |  |  |     problem_if_output(check_plist(formula.prefix, formula.plist)) | 
					
						
							| 
									
										
										
										
											2020-10-20 12:46:23 -04:00
										 |  |  |     problem_if_output(check_python_symlinks(formula.name, formula.keg_only?)) | 
					
						
							| 
									
										
										
										
											2021-07-03 19:23:19 +01:00
										 |  |  |     problem_if_output(check_cpuid_instruction(formula)) | 
					
						
							| 
									
										
										
										
											2021-07-18 10:48:03 +08:00
										 |  |  |     problem_if_output(check_binary_arches(formula)) | 
					
						
							| 
									
										
										
										
											2014-10-13 23:13:01 -05:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-09-23 18:13:48 +02:00
										 |  |  |   alias generic_audit_installed audit_installed | 
					
						
							| 
									
										
										
										
											2014-10-13 23:13:01 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-01 23:32:53 -05:00
										 |  |  |   private | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def relative_glob(dir, pattern) | 
					
						
							| 
									
										
										
										
											2014-10-17 12:01:27 -05:00
										 |  |  |     File.directory?(dir) ? Dir.chdir(dir) { Dir[pattern] } : [] | 
					
						
							| 
									
										
										
										
											2014-10-01 23:32:53 -05:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2021-07-03 19:23:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   def cpuid_instruction?(file, objdump = "objdump") | 
					
						
							| 
									
										
										
										
											2021-07-05 17:47:20 +01:00
										 |  |  |     @instruction_column_index ||= {} | 
					
						
							| 
									
										
										
										
											2021-07-08 01:43:34 +01:00
										 |  |  |     @instruction_column_index[objdump] ||= begin | 
					
						
							|  |  |  |       objdump_version = Utils.popen_read(objdump, "--version") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (objdump_version.match?(/^Apple LLVM/) && MacOS.version <= :mojave) || | 
					
						
							|  |  |  |          objdump_version.exclude?("LLVM") | 
					
						
							|  |  |  |         2 # Mojave `objdump` or GNU Binutils `objdump` | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         1 # `llvm-objdump` or Catalina+ `objdump` | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2021-07-05 17:47:20 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-03 19:23:19 +01:00
										 |  |  |     has_cpuid_instruction = false | 
					
						
							|  |  |  |     Utils.popen_read(objdump, "--disassemble", file) do |io| | 
					
						
							|  |  |  |       until io.eof? | 
					
						
							| 
									
										
										
										
											2021-07-05 10:12:34 -07:00
										 |  |  |         instruction = io.readline.split("\t")[@instruction_column_index[objdump]]&.strip | 
					
						
							|  |  |  |         has_cpuid_instruction = instruction == "cpuid" if instruction.present? | 
					
						
							| 
									
										
										
										
											2021-07-03 19:23:19 +01:00
										 |  |  |         break if has_cpuid_instruction | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     has_cpuid_instruction | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2013-07-15 19:28:10 -07:00
										 |  |  | end | 
					
						
							| 
									
										
										
										
											2016-07-09 13:51:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | require "extend/os/formula_cellar_checks" |