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 loader improvements #14472
Cask loader improvements #14472
Conversation
This allows homebrew/cask/caskname to work with the FromAPILoader. Also, creates new constant to hold the regex to validate main tap casks.
Review period will end on 2023-02-02 at 03:47:46 UTC. |
# Match main cask taps' casks, e.g. `homebrew/cask/somecask` or `somecask` | ||
HOMEBREW_MAIN_TAP_CASK_REGEX = %r{^(homebrew/cask/)?[a-z0-9\-_]+$}.freeze |
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.
Not sure if this is the best place to put this but I couldn't find anywhere else that made more sense.
@@ -356,18 +361,12 @@ def self.for(ref, need_path: false) | |||
FromInstanceLoader, | |||
FromContentLoader, | |||
FromURILoader, | |||
FromAPILoader, |
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.
Run before FromTapLoader
to preserve the same intended behavior as before.
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.
Currently, if the main cask tap is specified but the cask doesn't exist from the API it will skip the FromAPILoader
and will try the FromTapLoader
which will throw an error.
~ [1]$ brew install -n homebrew/cask/1passwordless --cask --debug
/usr/local/Homebrew/Library/Homebrew/shims/shared/curl --disable --cookie /dev/null --globoff --show-error --user-agent Homebrew/3.6.20-148-gaa35cc5-dirty\ \(Macintosh\;\ Intel\ Mac\ OS\ X\ 10.15.7\)\ curl/7.64.1 --header Accept-Language:\ en --fail --progress-bar --max-time 5 --retry 3 --location --remote-time --output /Users/kevinrobell/Library/Caches/Homebrew/api/cask.json --time-cond /Users/kevinrobell/Library/Caches/Homebrew/api/cask.json --compressed --silent https://formulae.brew.sh/api/cask.json
Warning: Cask 'homebrew/cask/1passwordless' is unavailable.
Please tap it and then try again: brew tap homebrew/cask
Maybe it'd be better to just try to load all cask references that start with the homebrew/cask/
in the FromAPILoader
so that we can throw an error that doesn't suggest tapping the main cask tap (the same casks should be available from both places, right?). This is the current behavior though so I didn't want to change it without some discussion.
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.
Maybe it'd be better to just try to load all cask references that start with the homebrew/cask/ in the FromAPILoader so that we can throw an error that doesn't suggest tapping the main cask tap (the same casks should be available from both places, right?).
This makes sense to me (but can wait until another PR if easier).
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.
In that case, this can be simplified even further.
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.
Not sure I'm brave enough to make that change in this PR. 😁
Review period ended. |
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.
Great work here! Happy to merge as-is.
@@ -356,18 +361,12 @@ def self.for(ref, need_path: false) | |||
FromInstanceLoader, | |||
FromContentLoader, | |||
FromURILoader, | |||
FromAPILoader, |
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.
Maybe it'd be better to just try to load all cask references that start with the homebrew/cask/ in the FromAPILoader so that we can throw an error that doesn't suggest tapping the main cask tap (the same casks should be available from both places, right?).
This makes sense to me (but can wait until another PR if easier).
I'm wondering if the second check for the brew/Library/Homebrew/cask/cask_loader.rb Lines 373 to 375 in 7a5f614
This will only get triggered if the cask was not in the Edit: It seems to get regenerated every hour so there is the possibility that a cask exists but isn't in the |
I'll merge this in tomorrow. |
After 32a0877 this logic has been changed so it's now always covered by `FromAPILoader.can_load?`.
Thanks again @apainintheneck! |
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, this looks great, @apainintheneck!
brew style
with your changes locally?brew typecheck
with your changes locally?brew tests
with your changes locally?This PR includes two little improvements to the cask loader that are tangentially related to some of the cask upgrade problems that we've seen in the last few days. I don't think they will necessarily solve all of those problems but I did find some things that could be improved.
Sanity Check for Cask Token
Essentially, we hit the API here without any validation of the cask token. This means that when this is called with a value that is clearly wrong like a file path it decides to hit the API anyway which is unnecessary. The regex is based on the
HOMEBREW_TAP_CASK_REGEX
.brew/Library/Homebrew/tap_constants.rb
Line 7 in 7a5f614
The
CaskSource.available?
method is used in theCaskLoader
when deciding whether or not to try and load the cask by downloading the cask source from the API.brew/Library/Homebrew/cask/cask_loader.rb
Lines 373 to 375 in 7a5f614
This should eliminate problems where an obviously invalid token is interpolated into then cask url path which is noticeable when using the debug flag.
Before
This url interpolation issue can be seen in #14463 for example. This shouldn't change behavior but will save a call to the API when we try to load a cask from a path.
Fix
FromAPILoader.can_load?
LogicThe previous logic didn't work as expected.
brew/Library/Homebrew/cask/cask_loader.rb
Lines 365 to 368 in 7a5f614
It's impossible for a cask reference to start with
homebrew/cask/
and satisfy the requirements forFromAPILoader.can_load?
brew/Library/Homebrew/cask/cask_loader.rb
Lines 195 to 197 in 7a5f614
brew/Library/Homebrew/api/cask.rb
Lines 19 to 28 in 7a5f614
FromAPILoader.can_load?
eventually ends up checking the cask reference against the keys incask.json
loaded as a hash which are thetoken
attributes in the JSON. The tokens in thecask.json
file are not prefixed withhomebrew/cask/
so it's impossible to have that prefix and pass the.can_load?
check.So if that bit of code cannot possibly be called right now, where are the casks getting loaded from when
HOMEBREW_INSTALL_FROM_API
is set? There is a backup call to the API that is doing all the heavy lifting.brew/Library/Homebrew/cask/cask_loader.rb
Lines 373 to 375 in 7a5f614
This changes the logic to first validate that the token seems plausible, second delete the prefix "homebrew/cask/" if it's there and then third check if the token exists in the JSON. It also moves that into
FromAPILoader.can_load?
to try and clean upCaskLoader.for
a little bit.Before
After