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
Improve consistency between Git and API formula handling #12936
Conversation
Review period will end on 2022-03-01 at 14:36:56 UTC. |
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 is amazing. A bunch of comments but would really like to land this sooner rather than later.
@@ -758,7 +758,7 @@ then | |||
export HOMEBREW_DEVELOPER_MODE="1" | |||
fi | |||
|
|||
if [[ -n "${HOMEBREW_INSTALL_FROM_API}" && -n "${HOMEBREW_DEVELOPER_COMMAND}" ]] | |||
if [[ -n "${HOMEBREW_INSTALL_FROM_API}" && -n "${HOMEBREW_DEVELOPER_COMMAND}" && "${HOMEBREW_COMMAND}" != "irb" ]] |
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.
Wondering if we should turn this into a more explicit denylist or just remove this entirely?
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.
Could probably remove this, since I want to allow brew ruby
too. @Rylan12 will have a better idea about this.
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.
Yeh, that makes sense to me. bump
, command
, dispatch-build-bottle
, generate-man-completions
, install-bundler-gems
, irb
, linkage
, pr-publish
, prof
, release
, rubocop
, ruby
, sh
, sponsors
, style
, tap-new
, tests
, typecheck
, unpack
, update-license-data
, update-maintainers
, update-test
, vendor-gems
all look like they should work without a tapped homebrew/core.
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, there's no reason to exclude HOMEBREW_INSTALL_FROM_API
from devs for those commands (except maybe brew style formula
and unpack
), it's just easier to maintain that developers shouldn't use it. Otherwise, we need to maintain this list to make sure that if commands get an online component they are removed from the list (and vice versa).
Another, better option, is probably just to complain on a per-command basis. We can remove the restriction on developers and just fail immediately in brew bump-formula-pr
and friends if the user has HOMEBREW_INSTALL_FROM_API
.
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.
brew style formula
could still work for non-core formulae and brew unpack
could still be useful to unpack even without a local formula IMO.
We can remove the restriction on developers and just fail immediately in brew bump-formula-pr and friends if the user has HOMEBREW_INSTALL_FROM_API.
This would work for me 👍🏻
if !CoreTap.instance.installed? && | ||
Homebrew::EnvConfig.install_from_api? && |
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 wonder whether we want a testing mode where you can always install from the API, even if the CoreTap is installed?
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 makes sense, though I'm not sure if it should be a part of this PR or not.
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.
Yeh, can punt on that being part of this PR if necessary. Just think it'd be a nice decoupling at some point.
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.
This looks really good to me!
Have you tested this with an install yet? I feel like something is missing still. Before, the bottles were downloaded using Homebrew::API::Bottle.fetch_bottles
. This added some caching thing to Formulary
so that BottleLoader
would recognize the ref (I'm pretty sure) and load there. The API load happens last in Formulary::laoder_for
, so I worry that there will be some unexpected consequences of that.
Also, we can probably remove Formulary.map_formula_name_to_local_bottle_path
and the methods in Homebrew::API::Bottle
(and maybe the entire API), right?
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've spent today taking a much more thorough look at this PR for the API project. Here are a few questions.
One thing that I'm still looking into is caching in Formulary
. Currently, when you load a formula from a path, the formula class is cached in Formulary#cache
under the path name. However, when loading from the API (as is currently set up), the class is still cached but in a different way. Instead of caching in Formulary#cache
, we simply check the Formulary::FormulaNamespaceAPI
module to see if the class is already defined and, if so, return it (although only after re-updating the build flags). I think this has the same effect, but I wonder if we should be consistent and cache in Formulary#cache
like we do "normally."
Caching is something I've largely ignored. I feel like we should probably investigate what we have as we currently have three caching mechanisms: factory caching, One thing to remember: we should make sure a formula loaded from file and a formula created via API is not seen as the same cache entry. The scenario where this might happen is a build-from-source flow (theoretically, as this doesn't actually exist yet). |
Agreed that this is worth investigating 👍🏻 |
I've looked a bit more into the caching and it looks like we do two things:
I'd suggest that we scope the cache to be type-dependent. Meaning, having a separate cache for loading from path and from the API. That way, there's no risk of accidental overlap if we somehow try to load the same formula from the API and a file. We also could add caching when loading from a bottle, potentially using the bottle path as a cache key. We could also use e.g. a hash of the contents as a cache key. This might help speed up loading from a bottle since we won't need to read the file contents each time, but is also probably outside the scope of this PR. |
Okay, I think I'm done with this for today. At the moment, loading from the API does work. I was successfully able to uninstall and reinstall formulae. For consistency, one important thing to note is that loading formulae and casks from the API will take precedence over loading from an installed keg/cask. This is intentional since it mimics the way things work without the API: the most recent version is loaded, even if an installed version is older. Doing this will allow lots of I'm still working through all of those changes, and I'll mark this PR as "ready" once I've made those and have done more testing. But, I'll gladly accept feedback on what's been done so far since I've made some more substantial changes to the original commits. With these changes, I've also been able to remove the Overall, I'm very pleased with how this approach is looking since I've been able to remove a ton of those conditionals. It makes everything feel much more integrated and less like an add-on. |
Yeah I agree. Formula files in kegs can get stale. Casks use their equivalent a lot more than the formula side and there have been countless bugs caused by that due to our deprecation turnover. One of the goals here was to avoid needing to use them. + we need the latest information anyway for
Excellent. That's exactly what I wanted to see the API code become. It's a lot easier to maintain not having to have two different code paths everywhere. The idea was to fix |
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 PR is now ready to move out of the draft stage. I've done some testing locally, and haven't encountered any issues. It feels super seamless and much more stable. Plus, a ton of code was able to be removed so that the only places where we need to check whether HOMEBREW_INSTALL_FROM_API
is set are in Formulary
, Cask::CaskLoader
, Caskroom
, and a few places only to make sure that having homebrew/core and homebrew/cask untapped isn't an issue.
There are still a few things that I want to work on that should happen in separate PRs:
- Removing the restrictions on
HOMEBREW_INSTALL_FROM_API
for developers (except for certain commands that need full clones) - The new
brew update
process will need to be looked at to make sure that things like tap/formula migrations still are noticed, and potentially failingbrew update
if the cachedformula.json
file can't be downloaded - There are certain commands (e.g.
brew update
) that feel like they run slower now since they need to parse the hugeformula.json
file. I'm not sure yet what the best solution is, but I wonder if we can further improve performance for some of these commands. - Adding a way to test without needing to move homebrew/cask and homebrew/cask so that they aren't installed
Is there even an API endpoint for that yet?
How long does parsing the file take? One thing to address at some point (not now) is download integrity. This could be using standards like JWS, or potentially something more custom if we really want to shoehorn it into existing endpoints. |
Nope
Here are the results of some tests I just ran using
I wonder if there's something else going on in
Good point, thanks for bringing it up. I don't really know anything about this kind of thing so I'll have to look into it more in the future |
I know about JWS at least so if we go that route feel free to ask me about it at the time. |
Also agreed 👍🏻
Tried playing with |
@@ -764,7 +764,7 @@ then | |||
export HOMEBREW_DEVELOPER_MODE="1" | |||
fi | |||
|
|||
if [[ -n "${HOMEBREW_INSTALL_FROM_API}" && -n "${HOMEBREW_DEVELOPER_COMMAND}" ]] | |||
if [[ -n "${HOMEBREW_INSTALL_FROM_API}" && -n "${HOMEBREW_DEVELOPER_COMMAND}" && "${HOMEBREW_COMMAND}" != "irb" ]] |
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.
👍🏻 for now. I'm thinking we may want to have a longer list of commands we allow here.
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 already have a PR in the works for this
Co-authored-by: Mike McQuaid <mike@mikemcquaid.com>
Great! Thanks for getting this started and helping out, @Bo98! |
I intended to open a PR for this a while back but never did.
It's WIP and I'll hopefully revisit it within the next month. There's been minimal changes since I last presented this (main change is
keg_only_reason
being now supported).