-
-
Notifications
You must be signed in to change notification settings - Fork 10.1k
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
cask: always return short cask tokens from core cask tap #16867
cask: always return short cask tokens from core cask tap #16867
Conversation
This is a follow-up to #16798 that I discovered while trying to write the loader code. |
It's also interesting how the behavior is different when using the API. brew(main):008:0> ENV.delete("HOMEBREW_NO_INSTALL_FROM_API")
=> "1"
brew(main):009:0> CoreCaskTap.instance.cask_tokens.sample(5)
=> ["mediainfo", "movist-pro", "fluor", "opendnsupdater", "wavebox"] |
Would it be reasonable to tweak |
I also noticed that $ export HOMEBREW_NO_INSTALL_FROM_API=1
$ brew developer off
$ brew untap homebrew/cask
Untapping homebrew/cask...
Untapped 4397 casks (6,488 files, 423.9MB). But with the following change (the same override exists in diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb
index 8e779c6ec..68058e7f5 100644
--- a/Library/Homebrew/tap.rb
+++ b/Library/Homebrew/tap.rb
@@ -1337,6 +1337,12 @@ class CoreCaskTap < AbstractCoreTap
Homebrew::API::Cask.all_casks.keys
end
+ # @private
+ sig { params(file: Pathname).returns(String) }
+ def formula_file_to_name(file)
+ file.basename(".rb").to_s
+ end
+
# @private
sig { override.returns(T::Hash[String, Pathname]) }
def cask_files_by_name (After I have $ brew untap homebrew/cask
Error: Refusing to untap homebrew/cask because it contains the following installed formulae or casks:
[list of casks installed] |
Yeah, that's probably a better approach especially since the behavior in |
2f1e1cd
to
2fdb268
Compare
This seems to be a bug with how we handle name shortening for the core cask tap. The core tap always returns short formula names and returning long names from the core cask tap when not using the API leads to unexpected behavior. Specifically this can trick the `brew untap` command into thinking that there aren't any installed casks in the core cask tap and that it can be removed even when that is not the case. One risk here is that the full names were used when caching descriptions so descriptions could be out of date for people in the short term though hopefully that's not the end of the world.
2fdb268
to
6e0e78c
Compare
It was possible for the cask tokens to be included twice in the cask_tokens array. This was cancelled out by the fact that we |= the arrays together but still it was unnecessary work that is best avoided and makes the code harder to reason about. This is simpler.
Now that I look at it a bit more I think that the bug in diff --git a/Library/Homebrew/cmd/untap.rb b/Library/Homebrew/cmd/untap.rb
index 90696f7f55..d087c1cc17 100644
--- a/Library/Homebrew/cmd/untap.rb
+++ b/Library/Homebrew/cmd/untap.rb
@@ -52,7 +52,7 @@ module Homebrew
next unless installed_cask_tokens.include?(cask_token)
cask = begin
- Cask::CaskLoader.load("#{tap.name}/#{cask_token}")
+ Cask::CaskLoader.load(cask_token)
rescue
# Don't blow up because of a single unavailable cask.
next We also should probably warn here at the very least because we've seemingly been swallowing this error for months now. |
brew/Library/Homebrew/cmd/untap.rb Line 37 in cd1f040
It looks like it's broken for formula too for everything except the core tap and it seems like it was changed in December 2023. |
|
@Bo98 You beat me to it. I think that brew/Library/Homebrew/cmd/untap.rb Lines 49 to 52 in cd1f040
brew/Library/Homebrew/cmd/untap.rb Lines 31 to 34 in cd1f040
Both of the open rescue blocks for loading casks and formulae in the loop are unreachable because we're comparing full cask or formula names to Is it fine if that gets handled in a follow-up PR since it doesn't seem to be related to what I'm trying to do here? |
Not really given we already check the tap part here: brew/Library/Homebrew/cmd/untap.rb Lines 43 to 45 in cd1f040
So the logic seems right, just not handling We don't for casks purely because that information is simply not available at all. It is impossible to check which tap a cask was installed from, unless it's a JSON file but that's core-only anyway. So we just assume token shadowing doesn't happen at the moment.
Sure. This PR already improves things rather than regresses. |
That should still be unreachable for all non-core taps since it will never get past the I'm also not really sure why we check every formula and cask in each named tap to see if it's installed. It seems like it'd be simpler to check every installed formula and cask to see if it's included in one of the named taps. But I guess that's an implementation detail. |
Not if you do next unless installed_formula_names.include?(formula_name.split("/").last) In the end, |
I'm fine with keeping the current logic intact and making the small changes mentioned here to get it working again. I do want to refactor it into a method or module so that I can add some regression tests though. I'll take a stab at that tomorrow. |
To me it makes more sense to eventually make all these methods only return short names/tokens instead of doing That said, I think it's fine to fix the logic as-is for now. |
@reitermarkus That sounds like an interesting refactoring opportunity. Do you want to jump on that or should I create an issue for it? |
I agree with the stance that short tokens make sense, but the problem is that is definitely a backwards incompatible change to a public API and we've already disrupted third party code enough. It's also not a very obvious break as well if they pass it immediately to say I'm less concerned with cask-only API changes as there's significantly less third-party taps around that, so in the scenario where we have to break one then we usually side on casks. |
Since the untap command bugs will be handled in a separate PR now, is this fine as is or are their more changes that need to be made? |
cask_tokens = Tap.each_with_object([]) do |tap, array| | ||
# We can exclude the core cask tap because `CoreCaskTap#cask_tokens` returns short names by default. | ||
if tap.official? && !tap.core_cask_tap? | ||
tap.cask_tokens.each { |token| array << token.sub(%r{^homebrew/cask.*/}, "") } |
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 know it was there before, but what's the point of this sub?
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'm guessing that we want to only search by cask token for internal taps so that brew search version
doesn't return all cask-versions
casks.
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.
Feels like this is kinda begging for something like Formula#name
vs. Formula#full_name
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 @apainintheneck!
brew style
with your changes locally?brew typecheck
with your changes locally?brew tests
with your changes locally?For some reason
Tap#formula_names
returns the short name whileTap#cask_tokens
returns the full name for some reason. I'd overlooked that when generating the internal JSON.This just gets the short name for casks from the casks themselves.Edit: Based on code review we've decided to change the behavior of
CoreCaskTap.instance.cask_tokens
to always return the short tokens. This matches the behavior when the core cask tap is loaded from the API. The other bug withbrew untap
is being handled in a separate PR: #16875