| 
									
										
										
										
											2025-03-18 17:38:37 +00:00
										 |  |  | # typed: false # rubocop:todo Sorbet/TrueSigil | 
					
						
							|  |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module Homebrew | 
					
						
							|  |  |  |   module Bundle | 
					
						
							|  |  |  |     module Checker | 
					
						
							|  |  |  |       class Base | 
					
						
							|  |  |  |         # Implement these in any subclass | 
					
						
							|  |  |  |         # PACKAGE_TYPE = :pkg | 
					
						
							|  |  |  |         # PACKAGE_TYPE_NAME = "Package" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def exit_early_check(packages, no_upgrade:) | 
					
						
							|  |  |  |           work_to_be_done = packages.find do |pkg| | 
					
						
							|  |  |  |             !installed_and_up_to_date?(pkg, no_upgrade:) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           Array(work_to_be_done) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def failure_reason(name, no_upgrade:) | 
					
						
							|  |  |  |           reason = if no_upgrade | 
					
						
							|  |  |  |             "needs to be installed." | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             "needs to be installed or updated." | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           "#{self.class::PACKAGE_TYPE_NAME} #{name} #{reason}" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def full_check(packages, no_upgrade:) | 
					
						
							|  |  |  |           packages.reject { |pkg| installed_and_up_to_date?(pkg, no_upgrade:) } | 
					
						
							|  |  |  |                   .map { |pkg| failure_reason(pkg, no_upgrade:) } | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def checkable_entries(all_entries) | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |           require "bundle/skipper" | 
					
						
							| 
									
										
										
										
											2025-03-18 17:38:37 +00:00
										 |  |  |           all_entries.select { |e| e.type == self.class::PACKAGE_TYPE } | 
					
						
							|  |  |  |                      .reject(&Bundle::Skipper.method(:skip?)) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def format_checkable(entries) | 
					
						
							|  |  |  |           checkable_entries(entries).map(&:name) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def installed_and_up_to_date?(_pkg, no_upgrade: false) | 
					
						
							|  |  |  |           raise NotImplementedError | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def find_actionable(entries, exit_on_first_error: false, no_upgrade: false, verbose: false) | 
					
						
							|  |  |  |           requested = format_checkable entries | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if exit_on_first_error | 
					
						
							|  |  |  |             exit_early_check(requested, no_upgrade:) | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             full_check(requested, no_upgrade:) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       CheckResult = Struct.new :work_to_be_done, :errors | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       CHECKS = { | 
					
						
							|  |  |  |         taps_to_tap:           "Taps", | 
					
						
							|  |  |  |         casks_to_install:      "Casks", | 
					
						
							|  |  |  |         extensions_to_install: "VSCode Extensions", | 
					
						
							|  |  |  |         apps_to_install:       "Apps", | 
					
						
							|  |  |  |         formulae_to_install:   "Formulae", | 
					
						
							|  |  |  |         formulae_to_start:     "Services", | 
					
						
							|  |  |  |       }.freeze | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-21 04:24:55 +00:00
										 |  |  |       def self.check(global: false, file: nil, exit_on_first_error: false, no_upgrade: false, verbose: false) | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |         require "bundle/brewfile" | 
					
						
							| 
									
										
										
										
											2025-03-18 17:38:37 +00:00
										 |  |  |         @dsl ||= Brewfile.read(global:, file:) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         check_method_names = CHECKS.keys | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         errors = [] | 
					
						
							|  |  |  |         enumerator = exit_on_first_error ? :find : :map | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         work_to_be_done = check_method_names.public_send(enumerator) do |check_method| | 
					
						
							|  |  |  |           check_errors = | 
					
						
							|  |  |  |             send(check_method, exit_on_first_error:, no_upgrade:, verbose:) | 
					
						
							|  |  |  |           any_errors = check_errors.any? | 
					
						
							|  |  |  |           errors.concat(check_errors) if any_errors | 
					
						
							|  |  |  |           any_errors | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         work_to_be_done = Array(work_to_be_done).flatten.any? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         CheckResult.new work_to_be_done, errors | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-21 04:24:55 +00:00
										 |  |  |       def self.casks_to_install(exit_on_first_error: false, no_upgrade: false, verbose: false) | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |         require "bundle/cask_checker" | 
					
						
							| 
									
										
										
										
											2025-03-18 17:38:37 +00:00
										 |  |  |         Homebrew::Bundle::Checker::CaskChecker.new.find_actionable( | 
					
						
							|  |  |  |           @dsl.entries, | 
					
						
							|  |  |  |           exit_on_first_error:, no_upgrade:, verbose:, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-21 04:24:55 +00:00
										 |  |  |       def self.formulae_to_install(exit_on_first_error: false, no_upgrade: false, verbose: false) | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |         require "bundle/brew_checker" | 
					
						
							| 
									
										
										
										
											2025-03-18 17:38:37 +00:00
										 |  |  |         Homebrew::Bundle::Checker::BrewChecker.new.find_actionable( | 
					
						
							|  |  |  |           @dsl.entries, | 
					
						
							|  |  |  |           exit_on_first_error:, no_upgrade:, verbose:, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-21 04:24:55 +00:00
										 |  |  |       def self.taps_to_tap(exit_on_first_error: false, no_upgrade: false, verbose: false) | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |         require "bundle/tap_checker" | 
					
						
							| 
									
										
										
										
											2025-03-18 17:38:37 +00:00
										 |  |  |         Homebrew::Bundle::Checker::TapChecker.new.find_actionable( | 
					
						
							|  |  |  |           @dsl.entries, | 
					
						
							|  |  |  |           exit_on_first_error:, no_upgrade:, verbose:, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-21 04:24:55 +00:00
										 |  |  |       def self.apps_to_install(exit_on_first_error: false, no_upgrade: false, verbose: false) | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |         require "bundle/mac_app_store_checker" | 
					
						
							| 
									
										
										
										
											2025-03-18 17:38:37 +00:00
										 |  |  |         Homebrew::Bundle::Checker::MacAppStoreChecker.new.find_actionable( | 
					
						
							|  |  |  |           @dsl.entries, | 
					
						
							|  |  |  |           exit_on_first_error:, no_upgrade:, verbose:, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-21 04:24:55 +00:00
										 |  |  |       def self.extensions_to_install(exit_on_first_error: false, no_upgrade: false, verbose: false) | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |         require "bundle/vscode_extension_checker" | 
					
						
							| 
									
										
										
										
											2025-03-18 17:38:37 +00:00
										 |  |  |         Homebrew::Bundle::Checker::VscodeExtensionChecker.new.find_actionable( | 
					
						
							|  |  |  |           @dsl.entries, | 
					
						
							|  |  |  |           exit_on_first_error:, no_upgrade:, verbose:, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-21 04:24:55 +00:00
										 |  |  |       def self.formulae_to_start(exit_on_first_error: false, no_upgrade: false, verbose: false) | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |         require "bundle/brew_service_checker" | 
					
						
							| 
									
										
										
										
											2025-03-18 17:38:37 +00:00
										 |  |  |         Homebrew::Bundle::Checker::BrewServiceChecker.new.find_actionable( | 
					
						
							|  |  |  |           @dsl.entries, | 
					
						
							|  |  |  |           exit_on_first_error:, no_upgrade:, verbose:, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-21 04:24:55 +00:00
										 |  |  |       def self.reset! | 
					
						
							| 
									
										
										
										
											2025-03-24 21:55:47 +08:00
										 |  |  |         require "bundle/cask_dumper" | 
					
						
							|  |  |  |         require "bundle/brew_dumper" | 
					
						
							|  |  |  |         require "bundle/mac_app_store_dumper" | 
					
						
							|  |  |  |         require "bundle/tap_dumper" | 
					
						
							|  |  |  |         require "bundle/brew_services" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-18 17:38:37 +00:00
										 |  |  |         @dsl = nil | 
					
						
							|  |  |  |         Homebrew::Bundle::CaskDumper.reset! | 
					
						
							|  |  |  |         Homebrew::Bundle::BrewDumper.reset! | 
					
						
							|  |  |  |         Homebrew::Bundle::MacAppStoreDumper.reset! | 
					
						
							|  |  |  |         Homebrew::Bundle::TapDumper.reset! | 
					
						
							|  |  |  |         Homebrew::Bundle::BrewServices.reset! | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |