| 
									
										
										
										
											2025-04-02 17:15:32 +01:00
										 |  |  | # typed: strict | 
					
						
							| 
									
										
										
										
											2025-03-18 17:38:37 +00:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  | require "English" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module Homebrew | 
					
						
							|  |  |  |   module Bundle | 
					
						
							|  |  |  |     class << self | 
					
						
							| 
									
										
										
										
											2025-04-02 17:15:32 +01:00
										 |  |  |       sig { params(args_upgrade_formula: T.nilable(String)).void } | 
					
						
							|  |  |  |       def upgrade_formulae=(args_upgrade_formula) | 
					
						
							|  |  |  |         @upgrade_formulae = args_upgrade_formula.to_s.split(",") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       sig { returns(T::Array[String]) } | 
					
						
							|  |  |  |       def upgrade_formulae | 
					
						
							|  |  |  |         @upgrade_formulae || [] | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       sig { params(cmd: T.any(String, Pathname), args: T.anything, verbose: T::Boolean).returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |       def system(cmd, *args, verbose: false) | 
					
						
							|  |  |  |         return super cmd, *args if verbose | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         logs = [] | 
					
						
							| 
									
										
										
										
											2025-04-02 17:15:32 +01:00
										 |  |  |         success = T.let(false, T::Boolean) | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |         IO.popen([cmd, *args], err: [:child, :out]) do |pipe| | 
					
						
							|  |  |  |           while (buf = pipe.gets) | 
					
						
							|  |  |  |             logs << buf | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           Process.wait(pipe.pid) | 
					
						
							|  |  |  |           success = $CHILD_STATUS.success? | 
					
						
							|  |  |  |           pipe.close | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |         puts logs.join unless success | 
					
						
							|  |  |  |         success | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-02 17:15:32 +01:00
										 |  |  |       sig { params(args: T.anything, verbose: T::Boolean).returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |       def brew(*args, verbose: false) | 
					
						
							|  |  |  |         system(HOMEBREW_BREW_FILE, *args, verbose:) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-02 17:15:32 +01:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |       def mas_installed? | 
					
						
							| 
									
										
										
										
											2025-07-14 14:48:08 +01:00
										 |  |  |         @mas_installed ||= which_formula?("mas") | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-02 17:15:32 +01:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |       def vscode_installed? | 
					
						
							|  |  |  |         @vscode_installed ||= which_vscode.present? | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-02 17:15:32 +01:00
										 |  |  |       sig { returns(T.nilable(Pathname)) } | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |       def which_vscode | 
					
						
							|  |  |  |         @which_vscode ||= which("code", ORIGINAL_PATHS) | 
					
						
							|  |  |  |         @which_vscode ||= which("codium", ORIGINAL_PATHS) | 
					
						
							|  |  |  |         @which_vscode ||= which("cursor", ORIGINAL_PATHS) | 
					
						
							|  |  |  |         @which_vscode ||= which("code-insiders", ORIGINAL_PATHS) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-02 17:15:32 +01:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |       def whalebrew_installed? | 
					
						
							| 
									
										
										
										
											2025-07-14 14:48:08 +01:00
										 |  |  |         @whalebrew_installed ||= which_formula?("whalebrew") | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-02 17:15:32 +01:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |       def cask_installed? | 
					
						
							|  |  |  |         @cask_installed ||= File.directory?("#{HOMEBREW_PREFIX}/Caskroom") && | 
					
						
							|  |  |  |                             (File.directory?("#{HOMEBREW_LIBRARY}/Taps/homebrew/homebrew-cask") || | 
					
						
							|  |  |  |                              !Homebrew::EnvConfig.no_install_from_api?) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-02 17:15:32 +01:00
										 |  |  |       sig { params(name: String).returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2025-07-14 14:48:08 +01:00
										 |  |  |       def which_formula?(name) | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |         formula = Formulary.factory(name) | 
					
						
							|  |  |  |         ENV["PATH"] = "#{formula.opt_bin}:#{ENV.fetch("PATH", nil)}" if formula.any_version_installed? | 
					
						
							|  |  |  |         which(name).present? | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-02 17:15:32 +01:00
										 |  |  |       sig { params(block: T.proc.returns(T.anything)).returns(T.untyped) } | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |       def exchange_uid_if_needed!(&block) | 
					
						
							|  |  |  |         euid = Process.euid | 
					
						
							|  |  |  |         uid = Process.uid | 
					
						
							|  |  |  |         return yield if euid == uid | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         old_euid = euid | 
					
						
							|  |  |  |         process_reexchangeable = Process::UID.re_exchangeable? | 
					
						
							|  |  |  |         if process_reexchangeable | 
					
						
							|  |  |  |           Process::UID.re_exchange | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           Process::Sys.seteuid(uid) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         home = T.must(Etc.getpwuid(Process.uid)).dir | 
					
						
							|  |  |  |         return_value = with_env("HOME" => home, &block) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if process_reexchangeable | 
					
						
							|  |  |  |           Process::UID.re_exchange | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           Process::Sys.seteuid(old_euid) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return_value | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2025-03-24 17:34:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-03 11:05:07 +01:00
										 |  |  |       sig { params(formula_name: String).returns(T.nilable(String)) } | 
					
						
							|  |  |  |       def formula_versions_from_env(formula_name) | 
					
						
							| 
									
										
										
										
											2025-03-24 17:34:35 +00:00
										 |  |  |         @formula_versions_from_env ||= begin | 
					
						
							|  |  |  |           formula_versions = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           ENV.each do |key, value| | 
					
						
							| 
									
										
										
										
											2025-04-01 15:35:27 +01:00
										 |  |  |             match = key.match(/^HOMEBREW_BUNDLE_FORMULA_VERSION_(.+)$/) | 
					
						
							| 
									
										
										
										
											2025-03-24 17:34:35 +00:00
										 |  |  |             next if match.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-03 11:05:07 +01:00
										 |  |  |             env_formula_name = match[1] | 
					
						
							|  |  |  |             next if env_formula_name.blank? | 
					
						
							| 
									
										
										
										
											2025-03-24 17:34:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             ENV.delete(key) | 
					
						
							| 
									
										
										
										
											2025-04-03 11:05:07 +01:00
										 |  |  |             formula_versions[env_formula_name] = value | 
					
						
							| 
									
										
										
										
											2025-03-24 17:34:35 +00:00
										 |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           formula_versions | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2025-04-03 11:05:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Fix up formula name for a valid environment variable name. | 
					
						
							|  |  |  |         formula_env_name = formula_name.upcase | 
					
						
							|  |  |  |                                        .gsub("@", "AT") | 
					
						
							|  |  |  |                                        .tr("+", "X") | 
					
						
							|  |  |  |                                        .tr("-", "_") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @formula_versions_from_env[formula_env_name] | 
					
						
							| 
									
										
										
										
											2025-03-24 17:34:35 +00:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-09 19:06:16 +01:00
										 |  |  |       sig { void } | 
					
						
							|  |  |  |       def prepend_pkgconf_path_if_needed!; end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-24 17:34:35 +00:00
										 |  |  |       sig { void } | 
					
						
							|  |  |  |       def reset! | 
					
						
							| 
									
										
										
										
											2025-04-02 17:15:32 +01:00
										 |  |  |         @mas_installed = T.let(nil, T.nilable(T::Boolean)) | 
					
						
							|  |  |  |         @vscode_installed = T.let(nil, T.nilable(T::Boolean)) | 
					
						
							| 
									
										
										
										
											2025-08-23 18:44:36 -07:00
										 |  |  |         @which_vscode = T.let(nil, T.nilable(Pathname)) | 
					
						
							| 
									
										
										
										
											2025-04-02 17:15:32 +01:00
										 |  |  |         @whalebrew_installed = T.let(nil, T.nilable(T::Boolean)) | 
					
						
							|  |  |  |         @cask_installed = T.let(nil, T.nilable(T::Boolean)) | 
					
						
							|  |  |  |         @formula_versions_from_env = T.let(nil, T.nilable(T::Hash[String, String])) | 
					
						
							|  |  |  |         @upgrade_formulae = T.let(nil, T.nilable(T::Array[String])) | 
					
						
							| 
									
										
										
										
											2025-03-24 17:34:35 +00:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require "extend/os/bundle/bundle" |