diff --git a/Library/Homebrew/cask_dependent.rb b/Library/Homebrew/cask_dependent.rb index 74b7419714..bf9a57c23f 100644 --- a/Library/Homebrew/cask_dependent.rb +++ b/Library/Homebrew/cask_dependent.rb @@ -15,8 +15,8 @@ class CaskDependent @cask.full_name end - def runtime_dependencies - recursive_dependencies + def runtime_dependencies(ignore_missing: false) + recursive_dependencies ignore_missing: ignore_missing end def deps @@ -43,8 +43,8 @@ class CaskDependent end end - def recursive_dependencies(&block) - Dependency.expand(self, &block) + def recursive_dependencies(ignore_missing: false, &block) + Dependency.expand(self, ignore_missing: ignore_missing, &block) end def recursive_requirements(&block) diff --git a/Library/Homebrew/cmd/untap.rb b/Library/Homebrew/cmd/untap.rb index 888d768e47..02ba88f316 100644 --- a/Library/Homebrew/cmd/untap.rb +++ b/Library/Homebrew/cmd/untap.rb @@ -25,7 +25,7 @@ module Homebrew args = untap_args.parse args.named.to_installed_taps.each do |tap| - odie "Untapping #{tap} is not allowed" if tap.core_tap? + odie "Untapping #{tap} is not allowed" if tap.core_tap? && ENV["HOMEBREW_JSON_CORE"].blank? installed_tap_formulae = Formula.installed.select { |formula| formula.tap == tap } installed_tap_casks = Cask::Caskroom.casks.select { |cask| cask.tap == tap } diff --git a/Library/Homebrew/cmd/update-report.rb b/Library/Homebrew/cmd/update-report.rb index cc83b687b6..cdc44a7e72 100644 --- a/Library/Homebrew/cmd/update-report.rb +++ b/Library/Homebrew/cmd/update-report.rb @@ -207,6 +207,7 @@ module Homebrew def install_core_tap_if_necessary return if ENV["HOMEBREW_UPDATE_TEST"] + return if ENV["HOMEBREW_JSON_CORE"].present? core_tap = CoreTap.instance return if core_tap.installed? diff --git a/Library/Homebrew/dependency.rb b/Library/Homebrew/dependency.rb index 7ac088dc16..aa5375112a 100644 --- a/Library/Homebrew/dependency.rb +++ b/Library/Homebrew/dependency.rb @@ -46,6 +46,15 @@ class Dependency formula end + def unavailable_core_formula? + to_formula + false + rescue CoreTapFormulaUnavailableError + true + rescue + false + end + def installed? to_formula.latest_version_installed? end @@ -89,7 +98,7 @@ class Dependency # the list. # The default filter, which is applied when a block is not given, omits # optionals and recommendeds based on what the dependent has asked for - def expand(dependent, deps = dependent.deps, cache_key: nil, &block) + def expand(dependent, deps = dependent.deps, cache_key: nil, ignore_missing: false, &block) # Keep track dependencies to avoid infinite cyclic dependency recursion. @expand_stack ||= [] @expand_stack.push dependent.name @@ -104,19 +113,19 @@ class Dependency deps.each do |dep| next if dependent.name == dep.name - case action(dependent, dep, &block) + case action(dependent, dep, ignore_missing: ignore_missing, &block) when :prune next when :skip next if @expand_stack.include? dep.name - expanded_deps.concat(expand(dep.to_formula, cache_key: cache_key, &block)) + expanded_deps.concat(expand(dep.to_formula, cache_key: cache_key, ignore_missing: ignore_missing, &block)) when :keep_but_prune_recursive_deps expanded_deps << dep else next if @expand_stack.include? dep.name - expanded_deps.concat(expand(dep.to_formula, cache_key: cache_key, &block)) + expanded_deps.concat(expand(dep.to_formula, cache_key: cache_key, ignore_missing: ignore_missing, &block)) expanded_deps << dep end end @@ -128,8 +137,10 @@ class Dependency @expand_stack.pop end - def action(dependent, dep, &block) + def action(dependent, dep, ignore_missing: false, &block) catch(:action) do + prune if ignore_missing && dep.unavailable_core_formula? + if block yield dependent, dep elsif dep.optional? || dep.recommended? diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb index 06e58d3962..09765e0068 100644 --- a/Library/Homebrew/exceptions.rb +++ b/Library/Homebrew/exceptions.rb @@ -221,6 +221,13 @@ class TapFormulaUnavailableError < FormulaUnavailableError end end +# Raised when a formula in a the core tap is unavailable. +class CoreTapFormulaUnavailableError < TapFormulaUnavailableError + def initialize(name) + super CoreTap.instance, name + end +end + # Raised when a formula in a specific tap does not contain a formula class. class TapFormulaClassUnavailableError < TapFormulaUnavailableError include FormulaClassUnavailableErrorModule diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index 867d7237ee..45b6136723 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -361,6 +361,8 @@ module Formulary end def get_formula(*) + raise CoreTapFormulaUnavailableError, name if !CoreTap.instance.installed? && ENV["HOMEBREW_JSON_CORE"].present? + raise FormulaUnavailableError, name end end @@ -395,7 +397,7 @@ module Formulary ) raise ArgumentError, "Formulae must have a ref!" unless ref - if ENV["HOMEBREW_BOTTLE_JSON"].present? && + if ENV["HOMEBREW_JSON_CORE"].present? && @formula_name_local_bottle_path_map.present? && @formula_name_local_bottle_path_map.key?(ref) ref = @formula_name_local_bottle_path_map[ref] @@ -427,9 +429,7 @@ module Formulary # @param formula_name the formula name string to map. # @param local_bottle_path a path pointing to the target bottle archive. def self.map_formula_name_to_local_bottle_path(formula_name, local_bottle_path) - if ENV["HOMEBREW_BOTTLE_JSON"].blank? - raise UsageError, "HOMEBREW_BOTTLE_JSON not set but required for #{__method__}!" - end + raise UsageError, "HOMEBREW_JSON_CORE not set but required for #{__method__}!" if ENV["HOMEBREW_JSON_CORE"].blank? @formula_name_local_bottle_path_map ||= {} @formula_name_local_bottle_path_map[formula_name] = Pathname(local_bottle_path).realpath diff --git a/Library/Homebrew/installed_dependents.rb b/Library/Homebrew/installed_dependents.rb index 20a7440e7d..7d231943e7 100644 --- a/Library/Homebrew/installed_dependents.rb +++ b/Library/Homebrew/installed_dependents.rb @@ -50,7 +50,8 @@ module InstalledDependents when Formula dependent.missing_dependencies(hide: keg_names) when Cask::Cask - CaskDependent.new(dependent).runtime_dependencies.map(&:to_formula) + # When checking for cask dependents, we don't care about missing dependencies + CaskDependent.new(dependent).runtime_dependencies(ignore_missing: true).map(&:to_formula) end required_kegs = required.map do |f| diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index ae604f1a72..99d0081059 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -734,6 +734,7 @@ class CoreTap < Tap def self.ensure_installed! return if instance.installed? + return if ENV["HOMEBREW_JSON_CORE"].present? safe_system HOMEBREW_BREW_FILE, "tap", instance.name end @@ -748,9 +749,11 @@ class CoreTap < Tap end # @private - sig { void } - def uninstall - raise "Tap#uninstall is not available for CoreTap" + sig { params(manual: T::Boolean).void } + def uninstall(manual: false) + raise "Tap#uninstall is not available for CoreTap" if ENV["HOMEBREW_JSON_CORE"].blank? + + super end # @private diff --git a/Library/Homebrew/test/formulary_spec.rb b/Library/Homebrew/test/formulary_spec.rb index c98916820a..7370a04d13 100644 --- a/Library/Homebrew/test/formulary_spec.rb +++ b/Library/Homebrew/test/formulary_spec.rb @@ -216,12 +216,12 @@ describe Formulary do described_class.factory("formula-to-map") }.to raise_error(FormulaUnavailableError) - ENV["HOMEBREW_BOTTLE_JSON"] = nil + ENV["HOMEBREW_JSON_CORE"] = nil expect { described_class.map_formula_name_to_local_bottle_path "formula-to-map", formula_path - }.to raise_error(UsageError, /HOMEBREW_BOTTLE_JSON not set/) + }.to raise_error(UsageError, /HOMEBREW_JSON_CORE not set/) - ENV["HOMEBREW_BOTTLE_JSON"] = "1" + ENV["HOMEBREW_JSON_CORE"] = "1" described_class.map_formula_name_to_local_bottle_path "formula-to-map", formula_path expect(described_class.factory("formula-to-map")).to be_kind_of(Formula)