diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb index 41120b0b04..27b78a0acd 100644 --- a/Library/Homebrew/brew.rb +++ b/Library/Homebrew/brew.rb @@ -107,6 +107,24 @@ begin end end + developer_mode = if cmd == "developer" && ARGV.include?("on") + true + elsif cmd == "developer" && ARGV.include?("off") + false + else + Homebrew::EnvConfig.developer? || Homebrew::Settings.read("devcmdrun") == "true" + end + + if internal_dev_cmd && Homebrew::EnvConfig.install_from_api? + odie "Developer commands cannot be run while HOMEBREW_INSTALL_FROM_API is set!" + elsif Homebrew::EnvConfig.install_from_api? && developer_mode + opoo <<~MESSAGE + Developers should not have HOMEBREW_INSTALL_FROM_API set! + Please unset HOMEBREW_INSTALL_FROM_API or turn developer mode off by running: + brew developer off + MESSAGE + end + unless internal_cmd # Add contributed commands to PATH before checking. homebrew_path.append(Tap.cmd_directories) diff --git a/Library/Homebrew/cask/cask.rb b/Library/Homebrew/cask/cask.rb index bf274ec823..616a7bff43 100644 --- a/Library/Homebrew/cask/cask.rb +++ b/Library/Homebrew/cask/cask.rb @@ -149,7 +149,7 @@ module Cask return [] end - latest_version = if ENV["HOMEBREW_INSTALL_FROM_API"].present? && + latest_version = if Homebrew::EnvConfig.install_from_api? && (latest_cask_version = Homebrew::API::Versions.latest_cask_version(token)) DSL::Version.new latest_cask_version.to_s else diff --git a/Library/Homebrew/cli/named_args.rb b/Library/Homebrew/cli/named_args.rb index 9a53f77cb5..bab7899a98 100644 --- a/Library/Homebrew/cli/named_args.rb +++ b/Library/Homebrew/cli/named_args.rb @@ -94,7 +94,7 @@ module Homebrew unreadable_error = nil if only != :cask - if prefer_loading_from_api && ENV["HOMEBREW_INSTALL_FROM_API"].present? && + if prefer_loading_from_api && Homebrew::EnvConfig.install_from_api? && Homebrew::API::Bottle.available?(name) Homebrew::API::Bottle.fetch_bottles(name) end @@ -132,7 +132,7 @@ module Homebrew end if only != :formula - if prefer_loading_from_api && ENV["HOMEBREW_INSTALL_FROM_API"].present? && + if prefer_loading_from_api && Homebrew::EnvConfig.install_from_api? && Homebrew::API::CaskSource.available?(name) contents = Homebrew::API::CaskSource.fetch(name) end diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb index bcba02b574..0c36d9b9d0 100644 --- a/Library/Homebrew/cmd/info.rb +++ b/Library/Homebrew/cmd/info.rb @@ -252,7 +252,7 @@ module Homebrew def info_formula(f, args:) specs = [] - if ENV["HOMEBREW_INSTALL_FROM_API"].present? && Homebrew::API::Bottle.available?(f.name) + if Homebrew::EnvConfig.install_from_api? && Homebrew::API::Bottle.available?(f.name) info = Homebrew::API::Bottle.fetch(f.name) latest_version = info["pkg_version"].split("_").first diff --git a/Library/Homebrew/cmd/outdated.rb b/Library/Homebrew/cmd/outdated.rb index 17f52b1f68..80013e1856 100644 --- a/Library/Homebrew/cmd/outdated.rb +++ b/Library/Homebrew/cmd/outdated.rb @@ -98,7 +98,7 @@ module Homebrew if verbose? outdated_kegs = f.outdated_kegs(fetch_head: args.fetch_HEAD?) - current_version = if !f.head? && ENV["HOMEBREW_INSTALL_FROM_API"].present? && + current_version = if !f.head? && Homebrew::EnvConfig.install_from_api? && (f.core_formula? || f.tap.blank?) Homebrew::API::Versions.latest_formula_version(f.name)&.to_s || f.pkg_version.to_s elsif f.alias_changed? && !f.latest_formula.latest_version_installed? diff --git a/Library/Homebrew/cmd/reinstall.rb b/Library/Homebrew/cmd/reinstall.rb index 08e197b5e3..c29675f3f7 100644 --- a/Library/Homebrew/cmd/reinstall.rb +++ b/Library/Homebrew/cmd/reinstall.rb @@ -88,7 +88,7 @@ module Homebrew # We need to use the bottle API instead of just using the formula file # from an installed keg because it will not contain bottle information. # As a consequence, `brew reinstall` will also upgrade outdated formulae - if ENV["HOMEBREW_INSTALL_FROM_API"].present? + if Homebrew::EnvConfig.install_from_api? args.named.each do |name| formula = Formulary.factory(name) next unless formula.any_version_installed? diff --git a/Library/Homebrew/cmd/untap.rb b/Library/Homebrew/cmd/untap.rb index 6e076bba81..3c51d60dfa 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? && ENV["HOMEBREW_INSTALL_FROM_API"].blank? + odie "Untapping #{tap} is not allowed" if tap.core_tap? && !Homebrew::EnvConfig.install_from_api? 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 49fa06d917..15baa2695f 100644 --- a/Library/Homebrew/cmd/update-report.rb +++ b/Library/Homebrew/cmd/update-report.rb @@ -136,9 +136,7 @@ module Homebrew updated_taps = [] Tap.each do |tap| next unless tap.git? - if (tap.core_tap? || tap == "homebrew/cask") && ENV["HOMEBREW_INSTALL_FROM_API"].present? && args.preinstall? - next - end + next if (tap.core_tap? || tap == "homebrew/cask") && Homebrew::EnvConfig.install_from_api? && args.preinstall? if ENV["HOMEBREW_MIGRATE_LINUXBREW_FORMULAE"].present? && tap.core_tap? && Settings.read("linuxbrewmigrated") != "true" @@ -266,7 +264,7 @@ module Homebrew def install_core_tap_if_necessary return if ENV["HOMEBREW_UPDATE_TEST"] - return if ENV["HOMEBREW_INSTALL_FROM_API"].present? + return if Homebrew::EnvConfig.install_from_api? core_tap = CoreTap.instance return if core_tap.installed? diff --git a/Library/Homebrew/cmd/upgrade.rb b/Library/Homebrew/cmd/upgrade.rb index aad5f5aa4a..6c4514acd1 100644 --- a/Library/Homebrew/cmd/upgrade.rb +++ b/Library/Homebrew/cmd/upgrade.rb @@ -158,7 +158,7 @@ module Homebrew puts pinned.map { |f| "#{f.full_specified_name} #{f.pkg_version}" } * ", " end - if ENV["HOMEBREW_INSTALL_FROM_API"].present? + if Homebrew::EnvConfig.install_from_api? formulae_to_install.map! do |formula| next formula if formula.head? next formula if formula.tap.present? && !formula.core_formula? @@ -223,7 +223,7 @@ module Homebrew def upgrade_outdated_casks(casks, args:) return false if args.formula? - if ENV["HOMEBREW_INSTALL_FROM_API"].present? + if Homebrew::EnvConfig.install_from_api? casks = casks.map do |cask| next cask if cask.tap.present? && cask.tap != "homebrew/cask" next cask unless Homebrew::API::CaskSource.available?(cask.token) diff --git a/Library/Homebrew/env_config.rb b/Library/Homebrew/env_config.rb index 8d85b31197..b0039ae23f 100644 --- a/Library/Homebrew/env_config.rb +++ b/Library/Homebrew/env_config.rb @@ -189,6 +189,11 @@ module Homebrew default_text: 'The "Beer Mug" emoji.', default: "🍺", }, + HOMEBREW_INSTALL_FROM_API: { + description: "If set, install formulae and casks in homebrew/core and homebrew/cask taps using Homebrew's " \ + "API instead of needing (large, slow) local checkouts of these repositories.", + boolean: true, + }, HOMEBREW_LIVECHECK_WATCHLIST: { description: "Consult this file for the list of formulae to check by default when no formula argument " \ "is passed to `brew livecheck`.", diff --git a/Library/Homebrew/extend/os/mac/tap.rb b/Library/Homebrew/extend/os/mac/tap.rb index d88902a1d3..b6a9e7b63e 100644 --- a/Library/Homebrew/extend/os/mac/tap.rb +++ b/Library/Homebrew/extend/os/mac/tap.rb @@ -4,7 +4,7 @@ class Tap def self.install_default_cask_tap_if_necessary(force: false) return false if default_cask_tap.installed? - return false if ENV["HOMEBREW_INSTALL_FROM_API"].present? + return false if Homebrew::EnvConfig.install_from_api? return false if !force && Tap.untapped_official_taps.include?(default_cask_tap.name) default_cask_tap.install diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 6573a85262..2c8a856e3a 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -529,7 +529,7 @@ class Formula # exists and is not empty. # @private def latest_version_installed? - latest_prefix = if !head? && ENV["HOMEBREW_INSTALL_FROM_API"].present? && + latest_prefix = if !head? && Homebrew::EnvConfig.install_from_api? && (latest_pkg_version = Homebrew::API::Versions.latest_formula_version(name)) prefix latest_pkg_version else @@ -1349,7 +1349,7 @@ class Formula Formula.cache[:outdated_kegs][cache_key] ||= begin all_kegs = [] current_version = T.let(false, T::Boolean) - latest_version = if !head? && ENV["HOMEBREW_INSTALL_FROM_API"].present? && (core_formula? || tap.blank?) + latest_version = if !head? && Homebrew::EnvConfig.install_from_api? && (core_formula? || tap.blank?) Homebrew::API::Versions.latest_formula_version(name) || pkg_version else pkg_version diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index dc88595f48..589fa5373b 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -361,7 +361,7 @@ module Formulary end def get_formula(*) - if !CoreTap.instance.installed? && ENV["HOMEBREW_INSTALL_FROM_API"].present? + if !CoreTap.instance.installed? && Homebrew::EnvConfig.install_from_api? raise CoreTapFormulaUnavailableError, name end @@ -399,7 +399,7 @@ module Formulary ) raise ArgumentError, "Formulae must have a ref!" unless ref - if ENV["HOMEBREW_INSTALL_FROM_API"].present? && + if Homebrew::EnvConfig.install_from_api? && @formula_name_local_bottle_path_map.present? && @formula_name_local_bottle_path_map.key?(ref) ref = @formula_name_local_bottle_path_map[ref] @@ -431,7 +431,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_INSTALL_FROM_API"].blank? + unless Homebrew::EnvConfig.install_from_api? raise UsageError, "HOMEBREW_INSTALL_FROM_API not set but required for #{__method__}!" end diff --git a/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi b/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi index fd59852672..2cd77dd314 100644 --- a/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi +++ b/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi @@ -4588,6 +4588,8 @@ module Homebrew::EnvConfig def self.install_badge(); end + def self.install_from_api?(); end + def self.livecheck_watchlist(); end def self.logs(); end diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index 01eb2a37c4..671272713f 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -772,7 +772,7 @@ class CoreTap < Tap def self.ensure_installed! return if instance.installed? - return if ENV["HOMEBREW_INSTALL_FROM_API"].present? + return if Homebrew::EnvConfig.install_from_api? safe_system HOMEBREW_BREW_FILE, "tap", instance.name end @@ -795,7 +795,7 @@ class CoreTap < Tap # @private sig { params(manual: T::Boolean).void } def uninstall(manual: false) - raise "Tap#uninstall is not available for CoreTap" if ENV["HOMEBREW_INSTALL_FROM_API"].blank? + raise "Tap#uninstall is not available for CoreTap" unless Homebrew::EnvConfig.install_from_api? super end diff --git a/docs/Manpage.md b/docs/Manpage.md index 53be4196d4..2a564d6bd1 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -2029,6 +2029,9 @@ example, run `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just *Default:* The "Beer Mug" emoji. +- `HOMEBREW_INSTALL_FROM_API` +
If set, install formulae and casks using Homebrew's formulae.brew.sh API instead of using local definitions. This allows formulae and casks in homebrew/core and homebrew/cask to be installed even if their respective tap is not installed locally. + - `HOMEBREW_LIVECHECK_WATCHLIST`
Consult this file for the list of formulae to check by default when no formula argument is passed to `brew livecheck`. diff --git a/manpages/brew.1 b/manpages/brew.1 index 41bcc00e10..dabd715357 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -2928,6 +2928,12 @@ Print this text before the installation summary of each successful build\. \fIDefault:\fR The "Beer Mug" emoji\. . .TP +\fBHOMEBREW_INSTALL_FROM_API\fR +. +.br +If set, install formulae and casks using Homebrew\'s formulae\.brew\.sh API instead of using local definitions\. This allows formulae and casks in homebrew/core and homebrew/cask to be installed even if their respective tap is not installed locally\. +. +.TP \fBHOMEBREW_LIVECHECK_WATCHLIST\fR . .br