-
-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Refine ask‐option dependency resolution and strengthen tests #20033
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
…h dependencies and dependants is upgraded as expected
I saw a problem, with this example, I don't know if it's the expected behaviour. |
@tyuwags Not sure I understand the question. It's expected that some dependencies may need to be upgraded and others may not. Does that answer your question? |
Thanks for the reply! Let me clarify the issue a bit: In this example:
However, during the actual upgrade, Homebrew skips sqlite because its direct parent (python@3.13) is not being rebuilt. So my actual question is: Should my function consider only the outdated recursive dependencies whose parent will also be rebuilt? |
This is expected.
Thanks for this. Ideally this would be done by using the same code rather than having two code paths that have to mirror each other. |
That was my initial thought as well. However, from what I’ve seen, brew doesn’t seem to know upfront which formulae will need to be upgraded. Instead, it determines the necessary dependencies and dependents dynamically using: Upgrade.upgrade_formulae formulae_to_install
Upgrade.check_installed_dependents formulae_to_install What I'd like is for these functions to return the full list of formulae that need to be upgraded, without performing the upgrade yet. Then, I could pass that list to a separate function that handles the actual upgrade logic. This way, I could reuse the existing resolution logic and keep everything consistent, without duplicating or mirroring code paths. |
@tyuwags I'm open to seeing PR(s) to modify those functions to the logic can be shared. Let me know when this one is ready for review and maybe make it draft until then? |
# Conflicts: # Library/Homebrew/test/cmd/upgrade_spec.rb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR refactors how upgrade, install, and reinstall commands resolve and act on dependencies when --ask
is used, and strengthens integration tests to cover full dependency hierarchies.
- Split dependency resolution from execution by introducing
get_formulae_dependencies
,get_dependants
,upgrade_dependents
, andget_hierarchy
. - Refactored
Reinstall
andInstall
modules to parallelUpgrade
’s two-phase flow. - Enhanced test helpers and added end-to-end integration tests covering nested formula dependency trees.
Reviewed Changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated no comments.
Show a summary per file
File | Description |
---|---|
Library/Homebrew/upgrade.rb | Extracted dependency-gathering into get_formulae_dependencies and get_dependants ; separated upgrade execution into upgrade_formulae and upgrade_dependents . |
Library/Homebrew/install.rb | Renamed first install_formulae to get_formulae_dependencies ; added two-phase flow and get_hierarchy for ask-mode. |
Library/Homebrew/reinstall.rb | Introduced get_formula_to_reinstall and a Formula_keg struct; moved prelude/fetch into new reinstall_formula . |
Library/Homebrew/cmd/upgrade.rb | Updated CLI to use new dependency resolution methods and only call ask_formulae when appropriate. |
Library/Homebrew/cmd/install.rb | Mirrored upgrade changes: using get_formulae_dependencies , ask_formulae , upgrade_dependents . |
Library/Homebrew/cmd/reinstall.rb | Adjusted to call get_formula_to_reinstall and adopt two-phase ask-mode. |
Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb | Extended setup_test_formula to handle bottled testballs and generalized program names. |
Library/Homebrew/test/cmd/upgrade_spec.rb | Updated descriptions, test setup, and added a new integration test for full dependant hierarchy. |
Library/Homebrew/test/cmd/install_spec.rb | Aligned expected output regex and test formulas to new ask-mode behavior. |
Comments suppressed due to low confidence (2)
Library/Homebrew/reinstall.rb:10
- [nitpick] The constant
Formula_keg
does not follow Ruby’s CamelCase naming convention. Consider renaming it toFormulaKeg
for consistency with typical Ruby style.
Formula_keg = Struct.new(:formula_installer, :keg, :formula, :options)
Library/Homebrew/upgrade.rb:98
- In the rescue block you reference an undefined variable
formula
. You should reference the installer’s formula, for examplefi.formula.full_name
, to report the correct formula name.
ofail "#{formula}: #{e}"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @tyuwags! Looking good so far.
Library/Homebrew/cmd/install.rb
Outdated
dry_run: args.dry_run?, | ||
) | ||
if args.ask? | ||
dependants = Upgrade.get_dependants( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to have a single call to this rather than two? Does Install.install_formulae
change the output here always/sometimes/maybe/never?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I have to make two calls or change the behaviour of this method
In the flow, I have this line
installed_formulae = (dry_run ? formulae : FormulaInstaller.installed.to_a).dup
which used formulae or FormulaInstaller.installed.to_a
the problem is that I have to get the dependants to print them out before installing
so I must call this function before installing or upgrading and use formulae rather than FormulaInstaller.installed.to_a as its empty for now
I could refactor to only use formulae but the original flow was to install formulae and get the dependants of the freshly installed formulae so I keep both flow depending of the option
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the problem is that I have to get the dependants to print them out before installing
Yeh, makes sense. I guess the question I have is: can you get these dependents and use them regardless of whether ask?
is used. If not: can you explain why not and what needs to be different/breaks/etc.?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can but I will get the dépendants based on formulae that I want to install instead of which formulae brew really installed. Normally, it shouldn't have any difference but im not sure about that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tyuwags Can you try it out and see? Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tests are all running as expected after just using formulae.dup
and I didn't see any problems when using brew locally without ask
Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb
Outdated
Show resolved
Hide resolved
@tyuwags ☝🏻 these both seem correct |
@MikeMcQuaid, everything is ready, everything is resolved |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few suggested style tweaks but the bulk of this looks great, thanks @tyuwags! Feel like we're really close now. Gonna ask a few other maintainers to review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall. Mostly some naming comments here, though with a couple of logic comments at the end which are more important.
@@ -95,34 +95,4 @@ def install | |||
|
|||
expect(HOMEBREW_CELLAR/"testball1/0.1/bin/test").to be_a_file | |||
end | |||
|
|||
it "installs with asking for user prompts with installed dependent checks", :integration_test do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these tests deleted? If they're redundant, it's probably better to handle in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created those tests to make sure all the new methods created ran correctly. As @MikeMcQuaid said before, those tests are too long so I deleted them
Library/Homebrew/upgrade.rb
Outdated
if !dry_run && dependents && fi.bottle_tab_runtime_dependencies.presence&.all? do |dependency, hash| | ||
minimum_version = Version.new(hash["version"]) if hash["version"].present? | ||
Dependency.new(dependency).installed?(minimum_version:, minimum_revision: hash["revision"]) | ||
end | ||
# Don't need to install this bottle if all of the runtime | ||
# dependencies have the same or newer version already installed. | ||
next if dependents && fi.bottle_tab_runtime_dependencies.presence&.all? do |dependency, hash| | ||
minimum_version = Version.new(hash["version"]) if hash["version"].present? | ||
Dependency.new(dependency).installed?(minimum_version:, minimum_revision: hash["revision"]) | ||
end | ||
|
||
fi.fetch | ||
next | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The double end
here is a bit confusing. I'd move things about a bit so the first end
doesn't look like it's ending the if
block.
Ideally go for next if
if possible.
Library/Homebrew/upgrade.rb
Outdated
fi.prelude | ||
|
||
if !dry_run && dependents && fi.bottle_tab_runtime_dependencies.presence&.all? do |dependency, hash| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this logic is correct. fi.bottle_tab_runtime_dependencies
requires fi.fetch_bottle_tab
to have run first, which was previously called by fi.prelude
that we're removing here.
Library/Homebrew/upgrade.rb
Outdated
installed_formulae = (dry_run ? formulae : FormulaInstaller.installed.to_a).dup | ||
installed_formulae = formulae.dup | ||
installed_formulae.reject! { |f| f.core_formula? && f.versioned_formula? } | ||
return if installed_formulae.empty? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds like it'll now upgrade dependents of things that failed to upgrade.
We may need to group dependents by formula and then filter out those that didn't actually install later.
Co-authored-by: Bo Anderson <mail@boanderson.me>
Co-authored-by: Bo Anderson <mail@boanderson.me>
brew style
with your changes locally?brew typecheck
with your changes locally?brew tests
with your changes locally?These changes resolve an error a finding the whole hierarchy for the ask option, pruning the build dependencies and be able to find the whole dependants hierarchy of the formula.
These changes also create and update tests to make sure the whole hierarchy is displayed in the ask prompt.