From 5e4dba4d6beb1e0f96c5e4a8427366fb85f3b6fe Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Thu, 6 Aug 2026 08:30:57 +0100 Subject: [PATCH] Remove the formula install-step var default Formula install-step paths now serialise only a base that was explicitly specified. RuboCop prevents relative official-tap paths from relying on the current working directory. Run structured-only API post-installs from the current JSON data so old formula snapshots embedded in bottles cannot restore the removed default. Keep using bottle snapshots for formulae that still have Ruby hooks. --- Library/Homebrew/formula.rb | 3 -- Library/Homebrew/formula_installer.rb | 10 +++++-- .../Homebrew/test/formula_installer_spec.rb | 29 +++++++++++++++++++ Library/Homebrew/test/formula_spec.rb | 19 ++++++++++-- 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index bd84b0cffd..89608994bf 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -4086,9 +4086,6 @@ class Formula current_steps.concat( if block Homebrew::InstallSteps::DSL.build( - # TODO: Remove the undocumented `default_base: :var` compatibility default after official taps use - # explicit bases. - default_base: :var, default_source_base: :prefix, default_target_base: :prefix, &block diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index 22c1a5af36..40565acf92 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -1354,10 +1354,10 @@ on_request: installed_on_request?, options:) @show_summary_heading = true end - sig { returns(Pathname) } + sig { returns(T.any(String, Pathname)) } def post_install_formula_path # Use the formula from the keg when any of the following is true: - # * We're installing from the JSON API + # * We're installing from the JSON API and it has a Ruby post-install hook # * We're installing a local bottle file # * We're building from source # * The formula doesn't exist in the tap (or the tap isn't installed) @@ -1372,7 +1372,11 @@ on_request: installed_on_request?, options:) return tap_formula_path if installed_prefix.nil? keg_formula_path = installed_prefix/".brew/#{formula.name}.rb" - return keg_formula_path if formula.loaded_from_api? + if formula.loaded_from_api? + return formula.full_name unless formula.post_install_defined? + + return keg_formula_path + end return keg_formula_path if formula.local_bottle_path return keg_formula_path if build_from_source? diff --git a/Library/Homebrew/test/formula_installer_spec.rb b/Library/Homebrew/test/formula_installer_spec.rb index 4cb761fbc1..4185782d12 100644 --- a/Library/Homebrew/test/formula_installer_spec.rb +++ b/Library/Homebrew/test/formula_installer_spec.rb @@ -181,6 +181,35 @@ RSpec.describe FormulaInstaller do end end + describe "#post_install_formula_path" do + it "uses the API formula for structured-only post-installs" do + formula = formula("api-install-steps") do + T.bind(self, T.class_of(Formula)) + url "foo-1.0" + end + installer = described_class.new(formula) + + allow(formula).to receive_messages(any_installed_prefix: mktmpdir, loaded_from_api?: true, + post_install_defined?: false) + + expect(installer.post_install_formula_path).to eq(formula.full_name) + end + + it "uses the keg formula for API post-installs with Ruby hooks" do + formula = formula("api-post-install-hook") do + T.bind(self, T.class_of(Formula)) + url "foo-1.0" + end + installer = described_class.new(formula) + installed_prefix = mktmpdir + + allow(formula).to receive_messages(any_installed_prefix: installed_prefix, loaded_from_api?: true, + post_install_defined?: true) + + expect(installer.post_install_formula_path).to eq(installed_prefix/".brew/api-post-install-hook.rb") + end + end + describe "#pour" do let(:f) do formula("missing-bottle-tab") do diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb index 25ea05b31c..c6d9775e79 100644 --- a/Library/Homebrew/test/formula_spec.rb +++ b/Library/Homebrew/test/formula_spec.rb @@ -1193,8 +1193,8 @@ RSpec.describe Formula do url "foo-1.0" post_install_steps do - mkdir_p "log/foo" - touch "foo/marker" + mkdir_p "log/foo", base: :var + touch "foo/marker", base: :var move "move-source", "move-target" move_contents "children-source", "children-target" symlink "move-target", "linked-target", source_base: :relative, remove_on_uninstall: true @@ -1226,6 +1226,21 @@ RSpec.describe Formula do expect(f.to_hash["post_install_steps"]).to eq(f.post_install_steps) end + specify "#post_install_steps does not default paths to var" do + f = formula do + T.bind(self, T.class_of(Formula)) + url "foo-1.0" + + post_install_steps do + touch "foo/marker" + end + end + + expect(f.post_install_steps).to eq([ + { "type" => "touch", "path" => { "path" => "foo/marker" } }, + ]) + end + specify "#post_install_steps_defined? with an empty block" do f = formula do T.bind(self, T.class_of(Formula))