# typed: true # 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 && Bundle.upgrade_formulae.exclude?(name) "needs to be installed." else "needs to be installed or updated." end "#{self.class.const_get(: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) require "bundle/skipper" all_entries.select { |e| e.type == self.class.const_get(: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 def self.check(global: false, file: nil, exit_on_first_error: false, no_upgrade: false, verbose: false) require "bundle/brewfile" @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 def self.casks_to_install(exit_on_first_error: false, no_upgrade: false, verbose: false) require "bundle/cask_checker" Homebrew::Bundle::Checker::CaskChecker.new.find_actionable( @dsl.entries, exit_on_first_error:, no_upgrade:, verbose:, ) end def self.formulae_to_install(exit_on_first_error: false, no_upgrade: false, verbose: false) require "bundle/brew_checker" Homebrew::Bundle::Checker::BrewChecker.new.find_actionable( @dsl.entries, exit_on_first_error:, no_upgrade:, verbose:, ) end def self.taps_to_tap(exit_on_first_error: false, no_upgrade: false, verbose: false) require "bundle/tap_checker" Homebrew::Bundle::Checker::TapChecker.new.find_actionable( @dsl.entries, exit_on_first_error:, no_upgrade:, verbose:, ) end def self.apps_to_install(exit_on_first_error: false, no_upgrade: false, verbose: false) require "bundle/mac_app_store_checker" Homebrew::Bundle::Checker::MacAppStoreChecker.new.find_actionable( @dsl.entries, exit_on_first_error:, no_upgrade:, verbose:, ) end def self.extensions_to_install(exit_on_first_error: false, no_upgrade: false, verbose: false) require "bundle/vscode_extension_checker" Homebrew::Bundle::Checker::VscodeExtensionChecker.new.find_actionable( @dsl.entries, exit_on_first_error:, no_upgrade:, verbose:, ) end def self.formulae_to_start(exit_on_first_error: false, no_upgrade: false, verbose: false) require "bundle/brew_service_checker" Homebrew::Bundle::Checker::BrewServiceChecker.new.find_actionable( @dsl.entries, exit_on_first_error:, no_upgrade:, verbose:, ) end def self.reset! require "bundle/cask_dumper" require "bundle/formula_dumper" require "bundle/mac_app_store_dumper" require "bundle/tap_dumper" require "bundle/brew_services" @dsl = nil Homebrew::Bundle::CaskDumper.reset! Homebrew::Bundle::FormulaDumper.reset! Homebrew::Bundle::MacAppStoreDumper.reset! Homebrew::Bundle::TapDumper.reset! Homebrew::Bundle::BrewServices.reset! end end end end