| 
									
										
										
										
											2024-08-12 10:30:59 +01:00
										 |  |  |  | # typed: true # rubocop:todo Sorbet/StrictSigil | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-26 14:50:34 +00:00
										 |  |  |  | # Contains shorthand Homebrew utility methods like `ohai`, `opoo`, `odisabled`. | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  | # TODO: move these out of `Kernel` into `Homebrew::GlobalMethods` and add | 
					
						
							|  |  |  |  | # necessary Sorbet and global Kernel inclusions. | 
					
						
							| 
									
										
										
										
											2024-07-14 08:49:39 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  | module Kernel | 
					
						
							| 
									
										
										
										
											2025-06-09 19:06:16 +01:00
										 |  |  |  |   sig { params(env: T.nilable(String)).returns(T::Boolean) } | 
					
						
							|  |  |  |  |   def superenv?(env) | 
					
						
							|  |  |  |  |     return false if env == "std" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     !Superenv.bin.nil? | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  |   private :superenv? | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { params(path: T.nilable(T.any(String, Pathname))).returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def require?(path) | 
					
						
							|  |  |  |  |     return false if path.nil? | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-27 08:42:49 +00:00
										 |  |  |  |     if defined?(Warnings) | 
					
						
							|  |  |  |  |       # Work around require warning when done repeatedly: | 
					
						
							|  |  |  |  |       # https://bugs.ruby-lang.org/issues/21091 | 
					
						
							|  |  |  |  |       Warnings.ignore(/already initialized constant/, /previous definition of/) do | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |         require path.to_s | 
					
						
							| 
									
										
										
										
											2025-01-27 08:42:49 +00:00
										 |  |  |  |       end | 
					
						
							|  |  |  |  |     else | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |       require path.to_s | 
					
						
							| 
									
										
										
										
											2025-01-27 08:42:49 +00:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     true | 
					
						
							| 
									
										
										
										
											2025-07-14 17:32:09 +01:00
										 |  |  |  |   rescue LoadError | 
					
						
							|  |  |  |  |     false | 
					
						
							| 
									
										
										
										
											2017-10-29 14:44:43 +00:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2017-06-01 17:45:07 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { params(title: String).returns(String) } | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def ohai_title(title) | 
					
						
							| 
									
										
										
										
											2020-08-02 03:22:22 +02:00
										 |  |  |  |     verbose = if respond_to?(:verbose?) | 
					
						
							| 
									
										
										
										
											2023-02-27 11:43:16 -08:00
										 |  |  |  |       T.unsafe(self).verbose? | 
					
						
							| 
									
										
										
										
											2020-08-02 03:22:22 +02:00
										 |  |  |  |     else | 
					
						
							| 
									
										
										
										
											2020-08-02 14:32:31 +02:00
										 |  |  |  |       Context.current.verbose? | 
					
						
							| 
									
										
										
										
											2020-08-02 03:22:22 +02:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-02 09:22:15 -04:00
										 |  |  |  |     title = Tty.truncate(title.to_s) if $stdout.tty? && !verbose | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     Formatter.headline(title, color: :blue) | 
					
						
							| 
									
										
										
										
											2017-10-29 14:44:43 +00:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-08-01 04:07:59 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def ohai(title, *sput) | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |     puts ohai_title(title.to_s) | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     puts sput | 
					
						
							|  |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-02 03:22:22 +02:00
										 |  |  |  |   def odebug(title, *sput, always_display: false) | 
					
						
							| 
									
										
										
										
											2020-08-02 14:32:31 +02:00
										 |  |  |  |     debug = if respond_to?(:debug) | 
					
						
							| 
									
										
										
										
											2023-02-27 11:43:16 -08:00
										 |  |  |  |       T.unsafe(self).debug? | 
					
						
							| 
									
										
										
										
											2020-08-02 03:22:22 +02:00
										 |  |  |  |     else | 
					
						
							| 
									
										
										
										
											2020-08-02 14:32:31 +02:00
										 |  |  |  |       Context.current.debug? | 
					
						
							| 
									
										
										
										
											2020-08-02 03:22:22 +02:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-07 13:49:05 -08:00
										 |  |  |  |     return if !debug && !always_display | 
					
						
							| 
									
										
										
										
											2010-01-13 09:00:51 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |     $stderr.puts Formatter.headline(title.to_s, color: :magenta) | 
					
						
							| 
									
										
										
										
											2023-10-10 01:54:54 +02:00
										 |  |  |  |     $stderr.puts sput unless sput.empty? | 
					
						
							| 
									
										
										
										
											2009-11-09 17:44:29 +00:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2009-08-11 12:20:55 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { params(title: String, truncate: T.any(Symbol, T::Boolean)).returns(String) } | 
					
						
							| 
									
										
										
										
											2022-08-12 23:44:45 -07:00
										 |  |  |  |   def oh1_title(title, truncate: :auto) | 
					
						
							| 
									
										
										
										
											2020-08-02 03:22:22 +02:00
										 |  |  |  |     verbose = if respond_to?(:verbose?) | 
					
						
							| 
									
										
										
										
											2023-02-27 11:43:16 -08:00
										 |  |  |  |       T.unsafe(self).verbose? | 
					
						
							| 
									
										
										
										
											2020-08-02 03:22:22 +02:00
										 |  |  |  |     else | 
					
						
							| 
									
										
										
										
											2020-08-02 14:32:31 +02:00
										 |  |  |  |       Context.current.verbose? | 
					
						
							| 
									
										
										
										
											2020-08-02 03:22:22 +02:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-02 09:22:15 -04:00
										 |  |  |  |     title = Tty.truncate(title.to_s) if $stdout.tty? && !verbose && truncate == :auto | 
					
						
							| 
									
										
										
										
											2022-08-12 23:44:45 -07:00
										 |  |  |  |     Formatter.headline(title, color: :green) | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { params(title: String, truncate: T.any(Symbol, T::Boolean)).void } | 
					
						
							| 
									
										
										
										
											2022-08-12 23:44:45 -07:00
										 |  |  |  |   def oh1(title, truncate: :auto) | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |  |     puts oh1_title(title, truncate:) | 
					
						
							| 
									
										
										
										
											2014-03-16 11:52:11 -07:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2012-03-03 15:50:24 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-22 21:05:48 +02:00
										 |  |  |  |   # Print a warning message. | 
					
						
							|  |  |  |  |   # | 
					
						
							|  |  |  |  |   # @api public | 
					
						
							| 
									
										
										
										
											2024-05-10 14:12:19 +01:00
										 |  |  |  |   sig { params(message: T.any(String, Exception)).void } | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def opoo(message) | 
					
						
							| 
									
										
										
										
											2024-10-16 03:58:05 +01:00
										 |  |  |  |     require "utils/github/actions" | 
					
						
							| 
									
										
										
										
											2025-07-14 14:48:08 +01:00
										 |  |  |  |     return if GitHub::Actions.puts_annotation_if_env_set!(:warning, message.to_s) | 
					
						
							| 
									
										
										
										
											2024-10-14 12:15:24 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-16 03:58:05 +01:00
										 |  |  |  |     require "utils/formatter" | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-17 04:18:13 +05:30
										 |  |  |  |     Tty.with($stderr) do |stderr| | 
					
						
							| 
									
										
										
										
											2024-09-16 16:52:03 +01:00
										 |  |  |  |       stderr.puts Formatter.warning(message, label: "Warning") | 
					
						
							| 
									
										
										
										
											2020-09-17 04:18:13 +05:30
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-09 09:25:28 +01:00
										 |  |  |  |   # Print a warning message only if not running in GitHub Actions. | 
					
						
							|  |  |  |  |   # | 
					
						
							|  |  |  |  |   # @api public | 
					
						
							|  |  |  |  |   sig { params(message: T.any(String, Exception)).void } | 
					
						
							|  |  |  |  |   def opoo_outside_github_actions(message) | 
					
						
							|  |  |  |  |     require "utils/github/actions" | 
					
						
							|  |  |  |  |     return if GitHub::Actions.env_set? | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     opoo(message) | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-22 21:05:48 +02:00
										 |  |  |  |   # Print an error message. | 
					
						
							|  |  |  |  |   # | 
					
						
							|  |  |  |  |   # @api public | 
					
						
							| 
									
										
										
										
											2024-05-10 14:12:19 +01:00
										 |  |  |  |   sig { params(message: T.any(String, Exception)).void } | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def onoe(message) | 
					
						
							| 
									
										
										
										
											2024-07-14 08:49:39 -04:00
										 |  |  |  |     require "utils/github/actions" | 
					
						
							| 
									
										
										
										
											2025-07-14 14:48:08 +01:00
										 |  |  |  |     return if GitHub::Actions.puts_annotation_if_env_set!(:error, message.to_s) | 
					
						
							| 
									
										
										
										
											2024-10-14 12:15:24 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     require "utils/formatter" | 
					
						
							| 
									
										
										
										
											2024-07-14 08:49:39 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-17 04:18:13 +05:30
										 |  |  |  |     Tty.with($stderr) do |stderr| | 
					
						
							| 
									
										
										
										
											2024-09-16 16:52:03 +01:00
										 |  |  |  |       stderr.puts Formatter.error(message, label: "Error") | 
					
						
							| 
									
										
										
										
											2020-09-17 04:18:13 +05:30
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-22 21:05:48 +02:00
										 |  |  |  |   # Print an error message and fail at the end of the program. | 
					
						
							|  |  |  |  |   # | 
					
						
							|  |  |  |  |   # @api public | 
					
						
							| 
									
										
										
										
											2024-05-10 14:12:19 +01:00
										 |  |  |  |   sig { params(error: T.any(String, Exception)).void } | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def ofail(error) | 
					
						
							|  |  |  |  |     onoe error | 
					
						
							|  |  |  |  |     Homebrew.failed = true | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-22 21:05:48 +02:00
										 |  |  |  |   # Print an error message and fail immediately. | 
					
						
							|  |  |  |  |   # | 
					
						
							|  |  |  |  |   # @api public | 
					
						
							| 
									
										
										
										
											2023-03-13 18:31:26 -07:00
										 |  |  |  |   sig { params(error: T.any(String, Exception)).returns(T.noreturn) } | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def odie(error) | 
					
						
							|  |  |  |  |     onoe error | 
					
						
							|  |  |  |  |     exit 1
 | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-22 21:05:48 +02:00
										 |  |  |  |   # Output a deprecation warning/error message. | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { | 
					
						
							|  |  |  |  |     params(method: String, replacement: T.nilable(T.any(String, Symbol)), disable: T::Boolean, | 
					
						
							|  |  |  |  |            disable_on: T.nilable(Time), disable_for_developers: T::Boolean, caller: T::Array[String]).void | 
					
						
							|  |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-04-18 16:41:39 +01:00
										 |  |  |  |   def odeprecated(method, replacement = nil, | 
					
						
							|  |  |  |  |                   disable:                false, | 
					
						
							|  |  |  |  |                   disable_on:             nil, | 
					
						
							|  |  |  |  |                   disable_for_developers: true, | 
					
						
							|  |  |  |  |                   caller:                 send(:caller)) | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     replacement_message = if replacement | 
					
						
							|  |  |  |  |       "Use #{replacement} instead." | 
					
						
							|  |  |  |  |     else | 
					
						
							|  |  |  |  |       "There is no replacement." | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     unless disable_on.nil? | 
					
						
							|  |  |  |  |       if disable_on > Time.now | 
					
						
							|  |  |  |  |         will_be_disabled_message = " and will be disabled on #{disable_on.strftime("%Y-%m-%d")}" | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         disable = true | 
					
						
							|  |  |  |  |       end | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     verb = if disable | 
					
						
							|  |  |  |  |       "disabled" | 
					
						
							|  |  |  |  |     else | 
					
						
							|  |  |  |  |       "deprecated#{will_be_disabled_message}" | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     # Try to show the most relevant location in message, i.e. (if applicable): | 
					
						
							|  |  |  |  |     # - Location in a formula. | 
					
						
							|  |  |  |  |     # - Location of caller of deprecated method (if all else fails). | 
					
						
							|  |  |  |  |     backtrace = caller | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     # Don't throw deprecations at all for cached, .brew or .metadata files. | 
					
						
							|  |  |  |  |     return if backtrace.any? do |line| | 
					
						
							| 
									
										
										
										
											2021-03-24 09:04:49 +01:00
										 |  |  |  |       next true if line.include?(HOMEBREW_CACHE.to_s) | 
					
						
							| 
									
										
										
										
											2020-12-15 12:04:28 +00:00
										 |  |  |  |       next true if line.include?("/.brew/") | 
					
						
							|  |  |  |  |       next true if line.include?("/.metadata/") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       next false unless line.match?(HOMEBREW_TAP_PATH_REGEX) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       path = Pathname(line.split(":", 2).first) | 
					
						
							|  |  |  |  |       next false unless path.file? | 
					
						
							|  |  |  |  |       next false unless path.readable? | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       formula_contents = path.read | 
					
						
							|  |  |  |  |       formula_contents.include?(" deprecate! ") || formula_contents.include?(" disable! ") | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-23 18:15:48 +01:00
										 |  |  |  |     tap_message = T.let(nil, T.nilable(String)) | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     backtrace.each do |line| | 
					
						
							| 
									
										
										
										
											2021-02-12 18:33:37 +05:30
										 |  |  |  |       next unless (match = line.match(HOMEBREW_TAP_PATH_REGEX)) | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 08:49:39 -04:00
										 |  |  |  |       require "tap" | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-02 10:01:03 -07:00
										 |  |  |  |       tap = Tap.fetch(match[:user], match[:repository]) | 
					
						
							| 
									
										
										
										
											2024-09-04 10:05:50 -07:00
										 |  |  |  |       tap_message = "\nPlease report this issue to the #{tap.full_name} tap" | 
					
						
							| 
									
										
										
										
											2025-03-31 09:53:19 +01:00
										 |  |  |  |       tap_message += " (not Homebrew/* repositories)" unless tap.official? | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |       tap_message += ", or even better, submit a PR to fix it" if replacement | 
					
						
							| 
									
										
										
										
											2020-06-02 09:49:23 +01:00
										 |  |  |  |       tap_message << ":\n  #{line.sub(/^(.*:\d+):.*$/, '\1')}\n\n" | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |       break | 
					
						
							| 
									
										
										
										
											2016-01-02 23:08:51 +08:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2024-05-09 13:19:14 +01:00
										 |  |  |  |     file, line, = backtrace.first.split(":") | 
					
						
							|  |  |  |  |     line = line.to_i if line.present? | 
					
						
							| 
									
										
										
										
											2016-01-02 23:08:51 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-04 10:05:50 -07:00
										 |  |  |  |     message = "Calling #{method} is #{verb}! #{replacement_message}" | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     message << tap_message if tap_message | 
					
						
							|  |  |  |  |     message.freeze | 
					
						
							| 
									
										
										
										
											2017-06-07 16:07:40 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-18 16:41:39 +01:00
										 |  |  |  |     disable = true if disable_for_developers && Homebrew::EnvConfig.developer? | 
					
						
							|  |  |  |  |     if disable || Homebrew.raise_deprecation_exceptions? | 
					
						
							| 
									
										
										
										
											2024-08-09 17:35:40 -07:00
										 |  |  |  |       require "utils/github/actions" | 
					
						
							| 
									
										
										
										
											2025-07-14 14:48:08 +01:00
										 |  |  |  |       GitHub::Actions.puts_annotation_if_env_set!(:error, message, file:, line:) | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |       exception = MethodDeprecatedError.new(message) | 
					
						
							|  |  |  |  |       exception.set_backtrace(backtrace) | 
					
						
							|  |  |  |  |       raise exception | 
					
						
							|  |  |  |  |     elsif !Homebrew.auditing? | 
					
						
							|  |  |  |  |       opoo message | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2017-04-24 08:49:11 +01:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-01-05 15:23:35 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { | 
					
						
							| 
									
										
										
										
											2025-08-01 08:47:38 +01:00
										 |  |  |  |     params(method: String, replacement: T.nilable(T.any(String, Symbol)), | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |            disable_on: T.nilable(Time), disable_for_developers: T::Boolean, caller: T::Array[String]).void | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   def odisabled(method, replacement = nil, | 
					
						
							|  |  |  |  |                 disable_on:             nil, | 
					
						
							|  |  |  |  |                 disable_for_developers: true, | 
					
						
							|  |  |  |  |                 caller:                 send(:caller)) | 
					
						
							| 
									
										
										
										
											2023-07-06 16:47:09 +01:00
										 |  |  |  |     # This odeprecated should stick around indefinitely. | 
					
						
							| 
									
										
										
										
											2025-08-01 08:47:38 +01:00
										 |  |  |  |     odeprecated(method, replacement, disable: true, disable_on:, disable_for_developers:, caller:) | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-01-05 15:23:35 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-02 01:59:46 +08:00
										 |  |  |  |   sig { params(string: String).returns(String) } | 
					
						
							| 
									
										
										
										
											2025-08-02 02:11:12 +08:00
										 |  |  |  |   def pretty_installed(string) | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     if !$stdout.tty? | 
					
						
							| 
									
										
										
										
											2025-08-02 01:59:46 +08:00
										 |  |  |  |       string | 
					
						
							| 
									
										
										
										
											2020-04-05 15:44:50 +01:00
										 |  |  |  |     elsif Homebrew::EnvConfig.no_emoji? | 
					
						
							| 
									
										
										
										
											2025-08-02 01:59:46 +08:00
										 |  |  |  |       Formatter.success("#{Tty.bold}#{string} (installed)#{Tty.reset}") | 
					
						
							| 
									
										
										
										
											2020-04-05 15:44:50 +01:00
										 |  |  |  |     else | 
					
						
							| 
									
										
										
										
											2025-08-02 01:59:46 +08:00
										 |  |  |  |       "#{Tty.bold}#{string} #{Formatter.success("✔")}#{Tty.reset}" | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2011-12-16 14:27:58 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-02 01:59:46 +08:00
										 |  |  |  |   sig { params(string: String).returns(String) } | 
					
						
							| 
									
										
										
										
											2025-08-02 02:11:12 +08:00
										 |  |  |  |   def pretty_outdated(string) | 
					
						
							| 
									
										
										
										
											2022-06-03 19:16:15 +01:00
										 |  |  |  |     if !$stdout.tty? | 
					
						
							| 
									
										
										
										
											2025-08-02 01:59:46 +08:00
										 |  |  |  |       string | 
					
						
							| 
									
										
										
										
											2022-06-03 19:16:15 +01:00
										 |  |  |  |     elsif Homebrew::EnvConfig.no_emoji? | 
					
						
							| 
									
										
										
										
											2025-08-02 01:59:46 +08:00
										 |  |  |  |       Formatter.error("#{Tty.bold}#{string} (outdated)#{Tty.reset}") | 
					
						
							| 
									
										
										
										
											2022-06-03 19:16:15 +01:00
										 |  |  |  |     else | 
					
						
							| 
									
										
										
										
											2025-08-02 01:59:46 +08:00
										 |  |  |  |       "#{Tty.bold}#{string} #{Formatter.warning("⚠")}#{Tty.reset}" | 
					
						
							| 
									
										
										
										
											2022-06-03 19:16:15 +01:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-02 01:59:46 +08:00
										 |  |  |  |   sig { params(string: String).returns(String) } | 
					
						
							| 
									
										
										
										
											2025-08-02 02:11:12 +08:00
										 |  |  |  |   def pretty_uninstalled(string) | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     if !$stdout.tty? | 
					
						
							| 
									
										
										
										
											2025-08-02 01:59:46 +08:00
										 |  |  |  |       string | 
					
						
							| 
									
										
										
										
											2020-04-05 15:44:50 +01:00
										 |  |  |  |     elsif Homebrew::EnvConfig.no_emoji? | 
					
						
							| 
									
										
										
										
											2025-08-02 01:59:46 +08:00
										 |  |  |  |       Formatter.error("#{Tty.bold}#{string} (uninstalled)#{Tty.reset}") | 
					
						
							| 
									
										
										
										
											2020-04-05 15:44:50 +01:00
										 |  |  |  |     else | 
					
						
							| 
									
										
										
										
											2025-08-02 01:59:46 +08:00
										 |  |  |  |       "#{Tty.bold}#{string} #{Formatter.error("✘")}#{Tty.reset}" | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2012-12-27 23:34:29 -06:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { params(seconds: T.nilable(T.any(Integer, Float))).returns(String) } | 
					
						
							| 
									
										
										
										
											2023-03-07 23:55:16 +00:00
										 |  |  |  |   def pretty_duration(seconds) | 
					
						
							|  |  |  |  |     seconds = seconds.to_i | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     res = +"" | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-07 23:55:16 +00:00
										 |  |  |  |     if seconds > 59
 | 
					
						
							|  |  |  |  |       minutes = seconds / 60
 | 
					
						
							|  |  |  |  |       seconds %= 60
 | 
					
						
							| 
									
										
										
										
											2023-03-20 07:23:17 -04:00
										 |  |  |  |       res = +Utils.pluralize("minute", minutes, include_count: true) | 
					
						
							| 
									
										
										
										
											2023-03-07 23:55:16 +00:00
										 |  |  |  |       return res.freeze if seconds.zero? | 
					
						
							| 
									
										
										
										
											2019-02-10 23:30:54 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |       res << " " | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2009-09-08 15:31:28 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 07:23:17 -04:00
										 |  |  |  |     res << Utils.pluralize("second", seconds, include_count: true) | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     res.freeze | 
					
						
							| 
									
										
										
										
											2010-09-12 22:55:52 +02:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2010-01-29 10:15:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { params(formula: T.nilable(Formula)).void } | 
					
						
							| 
									
										
										
										
											2023-03-10 23:46:07 +00:00
										 |  |  |  |   def interactive_shell(formula = nil) | 
					
						
							|  |  |  |  |     unless formula.nil? | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |       ENV["HOMEBREW_DEBUG_PREFIX"] = formula.prefix.to_s | 
					
						
							| 
									
										
										
										
											2023-03-10 23:46:07 +00:00
										 |  |  |  |       ENV["HOMEBREW_DEBUG_INSTALL"] = formula.full_name | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-30 05:07:42 +01:00
										 |  |  |  |     if Utils::Shell.preferred == :zsh && (home = Dir.home).start_with?(HOMEBREW_TEMP.resolved_path.to_s) | 
					
						
							| 
									
										
										
										
											2020-11-23 18:15:48 +01:00
										 |  |  |  |       FileUtils.mkdir_p home | 
					
						
							|  |  |  |  |       FileUtils.touch "#{home}/.zshrc" | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-28 15:02:06 +00:00
										 |  |  |  |     Process.wait fork { exec Utils::Shell.preferred_path(default: "/bin/bash") } | 
					
						
							| 
									
										
										
										
											2009-10-15 12:36:09 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     return if $CHILD_STATUS.success? | 
					
						
							|  |  |  |  |     raise "Aborted due to non-zero exit status (#{$CHILD_STATUS.exitstatus})" if $CHILD_STATUS.exited? | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     raise $CHILD_STATUS.inspect | 
					
						
							| 
									
										
										
										
											2012-09-11 20:59:59 -04:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2009-11-09 18:24:36 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-19 17:12:32 +01:00
										 |  |  |  |   def with_homebrew_path(&block) | 
					
						
							| 
									
										
										
										
											2022-06-15 05:40:43 +01:00
										 |  |  |  |     with_env(PATH: PATH.new(ORIGINAL_PATHS), &block) | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-11-11 20:08:26 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-19 17:12:32 +01:00
										 |  |  |  |   def with_custom_locale(locale, &block) | 
					
						
							|  |  |  |  |     with_env(LC_ALL: locale, &block) | 
					
						
							| 
									
										
										
										
											2009-11-09 18:24:36 +00:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2010-04-07 21:01:12 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |  |   # Kernel.system but with exceptions. | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def safe_system(cmd, *args, **options) | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |     # TODO: migrate to utils.rb Homebrew.safe_system | 
					
						
							| 
									
										
										
										
											2024-07-26 19:48:51 +01:00
										 |  |  |  |     require "utils" | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     return if Homebrew.system(cmd, *args, **options) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     raise ErrorDuringExecution.new([cmd, *args], status: $CHILD_STATUS) | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-13 14:30:06 -07:00
										 |  |  |  |   # Run a system command without any output. | 
					
						
							| 
									
										
										
										
											2024-04-23 19:10:33 +02:00
										 |  |  |  |   # | 
					
						
							|  |  |  |  |   # @api internal | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def quiet_system(cmd, *args) | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |     # TODO: migrate to utils.rb Homebrew.quiet_system | 
					
						
							| 
									
										
										
										
											2024-07-26 19:48:51 +01:00
										 |  |  |  |     require "utils" | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     Homebrew._system(cmd, *args) do | 
					
						
							|  |  |  |  |       # Redirect output streams to `/dev/null` instead of closing as some programs | 
					
						
							|  |  |  |  |       # will fail to execute if they can't write to an open stream. | 
					
						
							| 
									
										
										
										
											2024-11-26 11:50:45 -08:00
										 |  |  |  |       $stdout.reopen(File::NULL) | 
					
						
							|  |  |  |  |       $stderr.reopen(File::NULL) | 
					
						
							| 
									
										
										
										
											2013-09-15 20:11:17 -07:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2013-09-15 20:11:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-22 21:05:48 +02:00
										 |  |  |  |   # Find a command. | 
					
						
							|  |  |  |  |   # | 
					
						
							|  |  |  |  |   # @api public | 
					
						
							| 
									
										
										
										
											2022-06-15 05:40:43 +01:00
										 |  |  |  |   def which(cmd, path = ENV.fetch("PATH")) | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     PATH.new(path).each do |p| | 
					
						
							|  |  |  |  |       begin | 
					
						
							|  |  |  |  |         pcmd = File.expand_path(cmd, p) | 
					
						
							|  |  |  |  |       rescue ArgumentError | 
					
						
							|  |  |  |  |         # File.expand_path will raise an ArgumentError if the path is malformed. | 
					
						
							|  |  |  |  |         # See https://github.com/Homebrew/legacy-homebrew/issues/32789 | 
					
						
							|  |  |  |  |         next | 
					
						
							|  |  |  |  |       end | 
					
						
							|  |  |  |  |       return Pathname.new(pcmd) if File.file?(pcmd) && File.executable?(pcmd) | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  |     nil | 
					
						
							| 
									
										
										
										
											2015-11-17 16:12:31 +05:30
										 |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-15 05:40:43 +01:00
										 |  |  |  |   def which_all(cmd, path = ENV.fetch("PATH")) | 
					
						
							| 
									
										
										
										
											2024-02-22 23:29:55 +00:00
										 |  |  |  |     PATH.new(path).filter_map do |p| | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |       begin | 
					
						
							|  |  |  |  |         pcmd = File.expand_path(cmd, p) | 
					
						
							|  |  |  |  |       rescue ArgumentError | 
					
						
							|  |  |  |  |         # File.expand_path will raise an ArgumentError if the path is malformed. | 
					
						
							|  |  |  |  |         # See https://github.com/Homebrew/legacy-homebrew/issues/32789 | 
					
						
							|  |  |  |  |         next | 
					
						
							|  |  |  |  |       end | 
					
						
							|  |  |  |  |       Pathname.new(pcmd) if File.file?(pcmd) && File.executable?(pcmd) | 
					
						
							| 
									
										
										
										
											2024-02-22 23:29:55 +00:00
										 |  |  |  |     end.uniq | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-07-05 08:45:17 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-11 00:16:11 -08:00
										 |  |  |  |   def which_editor(silent: false) | 
					
						
							| 
									
										
										
										
											2020-04-05 15:44:50 +01:00
										 |  |  |  |     editor = Homebrew::EnvConfig.editor | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     return editor if editor | 
					
						
							| 
									
										
										
										
											2016-08-24 11:06:20 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-19 11:42:37 +00:00
										 |  |  |  |     # Find VS Code variants, Sublime Text, Textmate, BBEdit, or vim | 
					
						
							|  |  |  |  |     editor = %w[code codium cursor code-insiders subl mate bbedit vim].find do |candidate| | 
					
						
							| 
									
										
										
										
											2022-06-15 05:40:43 +01:00
										 |  |  |  |       candidate if which(candidate, ORIGINAL_PATHS) | 
					
						
							| 
									
										
										
										
											2017-07-13 17:14:21 -07:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     editor ||= "vim" | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-11 00:16:11 -08:00
										 |  |  |  |     unless silent | 
					
						
							|  |  |  |  |       opoo <<~EOS | 
					
						
							|  |  |  |  |         Using #{editor} because no editor was set in the environment. | 
					
						
							| 
									
										
										
										
											2025-08-02 23:27:59 -04:00
										 |  |  |  |         This may change in the future, so we recommend setting `$EDITOR` | 
					
						
							|  |  |  |  |         or `$HOMEBREW_EDITOR` to your preferred text editor. | 
					
						
							| 
									
										
										
										
											2023-02-11 00:16:11 -08:00
										 |  |  |  |       EOS | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     editor | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-03 16:35:53 +01:00
										 |  |  |  |   sig { params(filenames: T.any(String, Pathname)).void } | 
					
						
							|  |  |  |  |   def exec_editor(*filenames) | 
					
						
							|  |  |  |  |     puts "Editing #{filenames.join "\n"}" | 
					
						
							|  |  |  |  |     with_homebrew_path { safe_system(*which_editor.shellsplit, *filenames) } | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { params(args: T.any(String, Pathname)).void } | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def exec_browser(*args) | 
					
						
							| 
									
										
										
										
											2020-04-05 15:44:50 +01:00
										 |  |  |  |     browser = Homebrew::EnvConfig.browser | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     browser ||= OS::PATH_OPEN if defined?(OS::PATH_OPEN) | 
					
						
							|  |  |  |  |     return unless browser | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-05 15:44:50 +01:00
										 |  |  |  |     ENV["DISPLAY"] = Homebrew::EnvConfig.display | 
					
						
							| 
									
										
										
										
											2017-07-13 17:14:21 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-30 04:37:09 +01:00
										 |  |  |  |     with_env(DBUS_SESSION_BUS_ADDRESS: ENV.fetch("HOMEBREW_DBUS_SESSION_BUS_ADDRESS", nil)) do | 
					
						
							| 
									
										
										
										
											2022-02-17 11:55:04 +08:00
										 |  |  |  |       safe_system(browser, *args) | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   IGNORE_INTERRUPTS_MUTEX = T.let(Thread::Mutex.new.freeze, Thread::Mutex) | 
					
						
							| 
									
										
										
										
											2020-12-17 15:45:50 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 15:08:37 -04:00
										 |  |  |  |   def ignore_interrupts | 
					
						
							| 
									
										
										
										
											2024-07-14 11:41:38 -04:00
										 |  |  |  |     IGNORE_INTERRUPTS_MUTEX.synchronize do | 
					
						
							| 
									
										
										
										
											2024-07-14 14:32:17 -04:00
										 |  |  |  |       interrupted = T.let(false, T::Boolean) | 
					
						
							| 
									
										
										
										
											2024-07-14 11:41:38 -04:00
										 |  |  |  |       old_sigint_handler = trap(:INT) do | 
					
						
							| 
									
										
										
										
											2024-07-14 13:36:43 -04:00
										 |  |  |  |         interrupted = true | 
					
						
							| 
									
										
										
										
											2024-07-14 13:18:33 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 15:08:37 -04:00
										 |  |  |  |         $stderr.print "\n" | 
					
						
							|  |  |  |  |         $stderr.puts "One sec, cleaning up..." | 
					
						
							| 
									
										
										
										
											2024-07-14 11:41:38 -04:00
										 |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-12-17 15:45:50 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 11:41:38 -04:00
										 |  |  |  |       begin | 
					
						
							|  |  |  |  |         yield | 
					
						
							|  |  |  |  |       ensure | 
					
						
							|  |  |  |  |         trap(:INT, old_sigint_handler) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 13:36:43 -04:00
										 |  |  |  |         raise Interrupt if interrupted | 
					
						
							| 
									
										
										
										
											2020-12-17 15:45:50 +01:00
										 |  |  |  |       end | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2017-07-13 17:14:21 -07:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2017-07-14 17:03:33 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-23 00:24:15 +08:00
										 |  |  |  |   def redirect_stdout(file) | 
					
						
							|  |  |  |  |     out = $stdout.dup | 
					
						
							|  |  |  |  |     $stdout.reopen(file) | 
					
						
							|  |  |  |  |     yield | 
					
						
							|  |  |  |  |   ensure | 
					
						
							|  |  |  |  |     $stdout.reopen(out) | 
					
						
							|  |  |  |  |     out.close | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-23 23:29:05 +08:00
										 |  |  |  |   # Ensure the given executable is exist otherwise install the brewed version | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { params(name: String, formula_name: T.nilable(String), reason: String, latest: T::Boolean).returns(T.nilable(Pathname)) } | 
					
						
							| 
									
										
										
										
											2024-07-29 12:59:29 -04:00
										 |  |  |  |   def ensure_executable!(name, formula_name = nil, reason: "", latest: false) | 
					
						
							| 
									
										
										
										
											2021-11-23 23:29:05 +08:00
										 |  |  |  |     formula_name ||= name | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     executable = [ | 
					
						
							|  |  |  |  |       which(name), | 
					
						
							| 
									
										
										
										
											2022-06-15 05:40:43 +01:00
										 |  |  |  |       which(name, ORIGINAL_PATHS), | 
					
						
							| 
									
										
										
										
											2024-04-18 11:11:26 -07:00
										 |  |  |  |       # We prefer the opt_bin path to a formula's executable over the prefix | 
					
						
							|  |  |  |  |       # path where available, since the former is stable during upgrades. | 
					
						
							|  |  |  |  |       HOMEBREW_PREFIX/"opt/#{formula_name}/bin/#{name}", | 
					
						
							| 
									
										
										
										
											2021-11-23 23:29:05 +08:00
										 |  |  |  |       HOMEBREW_PREFIX/"bin/#{name}", | 
					
						
							|  |  |  |  |     ].compact.first | 
					
						
							|  |  |  |  |     return executable if executable.exist? | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-02 02:34:56 +08:00
										 |  |  |  |     require "formula" | 
					
						
							| 
									
										
										
										
											2025-08-02 03:37:31 +08:00
										 |  |  |  |     Formula[formula_name].ensure_installed!(reason:, latest:).opt_bin/name | 
					
						
							| 
									
										
										
										
											2021-11-23 23:29:05 +08:00
										 |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { returns(T::Array[Pathname]) } | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def paths | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |     @paths ||= T.let(ORIGINAL_PATHS.uniq.map(&:to_s), T.nilable(T::Array[Pathname])) | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2019-06-28 14:50:38 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { params(size_in_bytes: T.any(Integer, Float)).returns(String) } | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def disk_usage_readable(size_in_bytes) | 
					
						
							| 
									
										
										
										
											2025-03-04 20:01:07 -05:00
										 |  |  |  |     if size_in_bytes.abs >= 1_073_741_824
 | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |       size = size_in_bytes.to_f / 1_073_741_824
 | 
					
						
							|  |  |  |  |       unit = "GB" | 
					
						
							| 
									
										
										
										
											2025-03-04 20:01:07 -05:00
										 |  |  |  |     elsif size_in_bytes.abs >= 1_048_576
 | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |       size = size_in_bytes.to_f / 1_048_576
 | 
					
						
							|  |  |  |  |       unit = "MB" | 
					
						
							| 
									
										
										
										
											2025-03-04 20:01:07 -05:00
										 |  |  |  |     elsif size_in_bytes.abs >= 1_024
 | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |       size = size_in_bytes.to_f / 1_024
 | 
					
						
							|  |  |  |  |       unit = "KB" | 
					
						
							|  |  |  |  |     else | 
					
						
							|  |  |  |  |       size = size_in_bytes | 
					
						
							|  |  |  |  |       unit = "B" | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     # avoid trailing zero after decimal point | 
					
						
							|  |  |  |  |     if ((size * 10).to_i % 10).zero? | 
					
						
							|  |  |  |  |       "#{size.to_i}#{unit}" | 
					
						
							|  |  |  |  |     else | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |  |       "#{format("%<size>.1f", size:)}#{unit}" | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   def number_readable(number) | 
					
						
							|  |  |  |  |     numstr = number.to_i.to_s | 
					
						
							|  |  |  |  |     (numstr.size - 3).step(1, -3) { |i| numstr.insert(i, ",") } | 
					
						
							|  |  |  |  |     numstr | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   # Truncates a text string to fit within a byte size constraint, | 
					
						
							|  |  |  |  |   # preserving character encoding validity. The returned string will | 
					
						
							|  |  |  |  |   # be not much longer than the specified max_bytes, though the exact | 
					
						
							|  |  |  |  |   # shortfall or overrun may vary. | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { params(str: String, max_bytes: Integer, options: T::Hash[Symbol, T.untyped]).returns(String) } | 
					
						
							| 
									
										
										
										
											2023-03-07 23:55:16 +00:00
										 |  |  |  |   def truncate_text_to_approximate_size(str, max_bytes, options = {}) | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     front_weight = options.fetch(:front_weight, 0.5) | 
					
						
							|  |  |  |  |     raise "opts[:front_weight] must be between 0.0 and 1.0" if front_weight < 0.0 || front_weight > 1.0
 | 
					
						
							| 
									
										
										
										
											2023-03-07 23:55:16 +00:00
										 |  |  |  |     return str if str.bytesize <= max_bytes | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     glue = "\n[...snip...]\n" | 
					
						
							|  |  |  |  |     max_bytes_in = [max_bytes - glue.bytesize, 1].max | 
					
						
							| 
									
										
										
										
											2023-03-07 23:55:16 +00:00
										 |  |  |  |     bytes = str.dup.force_encoding("BINARY") | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     glue_bytes = glue.encode("BINARY") | 
					
						
							|  |  |  |  |     n_front_bytes = (max_bytes_in * front_weight).floor | 
					
						
							|  |  |  |  |     n_back_bytes = max_bytes_in - n_front_bytes | 
					
						
							|  |  |  |  |     if n_front_bytes.zero? | 
					
						
							|  |  |  |  |       front = bytes[1..0] | 
					
						
							| 
									
										
										
										
											2020-05-21 10:15:34 +01:00
										 |  |  |  |       back = bytes[-max_bytes_in..] | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     elsif n_back_bytes.zero? | 
					
						
							|  |  |  |  |       front = bytes[0..(max_bytes_in - 1)] | 
					
						
							|  |  |  |  |       back = bytes[1..0] | 
					
						
							|  |  |  |  |     else | 
					
						
							|  |  |  |  |       front = bytes[0..(n_front_bytes - 1)] | 
					
						
							| 
									
										
										
										
											2020-05-21 10:15:34 +01:00
										 |  |  |  |       back = bytes[-n_back_bytes..] | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |     out = T.must(front) + glue_bytes + T.must(back) | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |     out.force_encoding("UTF-8") | 
					
						
							|  |  |  |  |     out.encode!("UTF-16", invalid: :replace) | 
					
						
							|  |  |  |  |     out.encode!("UTF-8") | 
					
						
							|  |  |  |  |     out | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   # Calls the given block with the passed environment variables | 
					
						
							| 
									
										
										
										
											2024-04-26 20:55:51 +02:00
										 |  |  |  |   # added to `ENV`, then restores `ENV` afterwards. | 
					
						
							|  |  |  |  |   # | 
					
						
							|  |  |  |  |   # NOTE: This method is **not** thread-safe – other threads | 
					
						
							|  |  |  |  |   #       which happen to be scheduled during the block will also | 
					
						
							|  |  |  |  |   #       see these environment variables. | 
					
						
							|  |  |  |  |   # | 
					
						
							|  |  |  |  |   # ### Example | 
					
						
							|  |  |  |  |   # | 
					
						
							|  |  |  |  |   # ```ruby | 
					
						
							|  |  |  |  |   # with_env(PATH: "/bin") do | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   #   system "echo $PATH" | 
					
						
							| 
									
										
										
										
											2024-04-26 20:55:51 +02:00
										 |  |  |  |   # end | 
					
						
							|  |  |  |  |   # ``` | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   # | 
					
						
							| 
									
										
										
										
											2020-11-26 16:11:33 -08:00
										 |  |  |  |   # @api public | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def with_env(hash) | 
					
						
							|  |  |  |  |     old_values = {} | 
					
						
							|  |  |  |  |     begin | 
					
						
							|  |  |  |  |       hash.each do |key, value| | 
					
						
							|  |  |  |  |         key = key.to_s | 
					
						
							|  |  |  |  |         old_values[key] = ENV.delete(key) | 
					
						
							|  |  |  |  |         ENV[key] = value | 
					
						
							|  |  |  |  |       end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       yield if block_given? | 
					
						
							|  |  |  |  |     ensure | 
					
						
							|  |  |  |  |       ENV.update(old_values) | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { returns(T.proc.params(a: String, b: String).returns(Integer)) } | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def tap_and_name_comparison | 
					
						
							|  |  |  |  |     proc do |a, b| | 
					
						
							| 
									
										
										
										
											2020-12-01 17:04:59 +00:00
										 |  |  |  |       if a.include?("/") && b.exclude?("/") | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |         1
 | 
					
						
							| 
									
										
										
										
											2020-12-01 17:04:59 +00:00
										 |  |  |  |       elsif a.exclude?("/") && b.include?("/") | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |         -1
 | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         a <=> b | 
					
						
							|  |  |  |  |       end | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 17:31:27 +01:00
										 |  |  |  |   sig { params(input: String, secrets: T::Array[String]).returns(String) } | 
					
						
							| 
									
										
										
										
											2019-08-15 09:12:21 +02:00
										 |  |  |  |   def redact_secrets(input, secrets) | 
					
						
							|  |  |  |  |     secrets.compact | 
					
						
							|  |  |  |  |            .reduce(input) { |str, secret| str.gsub secret, "******" } | 
					
						
							|  |  |  |  |            .freeze | 
					
						
							|  |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2019-06-28 14:50:38 +08:00
										 |  |  |  | end |