Allow pinning casks
Verification
- [x] I understand that if I ignore these instructions, my issue may be closed without review.
- [x] I have retried my command with
--force. - [x] I ran
brew update-reset && brew updateand retried my command. - [x] I ran
brew doctor, fixed as many issues as possible and retried my command. - [x] I have checked the instructions for reporting bugs.
- [x] I made doubly sure this is not a checksum does not match / SHA256 mismatch error (do not open an issue before trying to open a PR to fix first).
Description of issue
I'd like to re-raise #49127 and other tickets filed for this. I believe the original justification given doesn't address the problems that pinning would solve. Therefore, the topic requires a reconsideration.
@vitorgalvao
A huge chunk of casks auto-update and we can’t stop that. So pin would at best be inconsistent and not work in a lot of cases.
If you do a search you’ll see we’ve discussed this in the past, especially in the upgrade issues on brew’s repository.
Argument 1: a counter-argument to "pin would at best be inconsistent and not work in a lot of cases"
Casks with auto_updates are effectively pinned. brew upgrade will not update them, unless --greedy-auto-updates is passed. They may be upgraded externally by the application itself, and Homebrew won't know the actual version installed over time or what files were modified...
...so how is this different from an explicit pin on the package? auto_updates and latest markers are pins. Permanent ones that prevent them from being upgraded on brew upgrade - but still pins. They just can't be arbitrarily removed or added by the user to achieve their own goals.
Argument 2: auto-update feature is often optional, let brew do it
Out of all my auto_updates casks listed with brew info --json=v2 --installed --casks | jq -r '.casks[] | select(.auto_updates) | .token', most have optional auto-updates:
- Check optional: iterm2, menumeters, nextcloud, orbstack, teamviewer, visual-studio-code, vlc, wireshark, witch
- Check mandatory but update optional: firefox, imageoptim, macfuse, pika, sublime-text, xee, spectacle
- Check and update mandatory: adobe-acrobat-reader, discord, dropbox, google-chrome, onedrive, signal
How do I update all packages except these listed in "Check and update mandatory" category, without this kind of trickery? brew upgrade --cask --greedy-auto-updates $(brew info --json=v2 --installed --casks | jq -r '.casks[] | select(.auto_updates) | .token' | grep -vE '^(adobe-acrobat-reader|discord|dropbox|onedrive|signal)$')
There is absolutely nothing wrong about brew pin adobe-acrobat-reader discord dropbox google-chrome onedrive signal so we can brew update --greedy-auto-updates and get everything up-to-date except the ones we pinned.
Argument 3: the fundamental issue
All package manager in existence - except pkgin/pksrc and Homebrew (for casks) - allow their users to "upgrade all except these":
pacman -Syu --ignore <pkg1>,<pkg2>apt-mark hold <pkg1> <pkg2>; apt upgrade; apt-mark unhold <pkg1> <pkg2>dnf upgrade --refresh --exclude=<pkg1>,<pkg2>- or
dnf versionlock add <pkg1> <pkg2>; dnf upgrade --refresh; dnf versionlock delete <pkg1> <pkg2>
- or
yum update --exclude=<pkg1>,<pkg2>- or
yum versionlock add <pkg1>-* <pkg2>-*; yum update; yum versionlock delete <pkg1>-* <pkg2>-*
- or
zypper up --exclude <pkg1>,<pkg2>- or
zypper addlock <pkg>; zypper up; zypper removelock <pkg>
- or
emerge -avuD --exclude <pkg1>,<pkg2> @world- or add
=<pkg>-*to/etc/portage/package.mask
- or add
choco upgrade all --except=<pkg1>,<pkg2>- or
choco pin add -n=<pkg>; choco upgrade all; choco pin remove -n=<pkg>
- or
winget pin add --id <PackageID>; winget upgrade --all; winget pin remove --id <PackageID>scoop hold <pkg1> <pkg2>; scoop update *; scoop unhold <pkg1> <pkg2>port upgrade outdated and not <port>brew pin something; brew upgrade; brew unpin something- (except for casks)
Why would one want to "upgrade all except these"? Every user has their own reasons. For me:
- I do it to skip large packages when my download speed is limited at that time. I tend to run
pacman -Syu --ignore libreoffice-fresh,signalquite a bit. - There are certain packages that I update myself. On Arch, I never update
linuxandlinux-ltspackages at the same time.linux-ltsstays inIgnorePkg(it's pinned). - For Homebrew specifically, I'd like to execute
brew update --greedy-auto-updatesand get everything upgraded except for those that perform mandatory updates. Whether that's via a permanent pinbrew pin signal; brew update --greedy-auto-updates, or a one-time exclusionbrew update --greedy-auto-updates --ignore pkg1,pkg2, it's all good. - ...But most importantly: why not? All other package manager do it, and there must be many good reasons why.
Argument 4: by popular vote
Users have been requesting it all the time:
- #150045 by @edpichler
- #100700 by @alexreg
- #97285 by @nopdotcom
- #90242 by @ericbn
- #49127 by @boobaa
- https://github.com/Homebrew/brew/issues/12425 by @rafalkrupinski
- https://github.com/Homebrew/brew/issues/11860 by @cglong
- https://github.com/Homebrew/brew/issues/4898 by @ondrejfuhrer
Users simply want this feature.
Thank you in advance for reconsidering this.
Command that failed
brew pin nextcloud
Output of command with --verbose --debug
nowaker@nwkr-m1pro ~ % brew pin nextcloud --verbose --debug
/opt/homebrew/Library/Homebrew/brew.rb (Formulary::NullLoader): loading nextcloud
/opt/homebrew/Library/Homebrew/brew.rb (Formulary::NullLoader): loading nextcloud
Error: No available formula with the name "nextcloud".
/opt/homebrew/Library/Homebrew/formulary.rb:826:in 'Formulary::NullLoader#get_formula'
/opt/homebrew/Library/Homebrew/formulary.rb:931:in 'Formulary.factory'
...not relevant
Output of brew doctor and brew config
irrelevant
Output of brew tap
homebrew/cask-versions
homebrew/services
@Nowaker, Thanks for the detailed background here. I think it is definitely something that could be beneficial for users and a worthwhile consideration.
Generally, with feature requests within Homebrew, they are moved forward when a contributor opens a pull request to get the process started. Is this something that you would have the capacity to have a look at?
@bevanjkay I could try my best, for sure. But in my view, the biggest issue with brew pin for casks wasn't lack of contributors, but rather, it was a direct disapproval of the feature itself. So it would be best to secure support from the Homebrew Cask's higher ups before investing time in coding. :-)
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
This issue was just brought up in our maintainer Slack, so I'll weigh in. In short: I'm not convinced this is necessary, but I won't block someone wanting to work on it.
I do it to skip large packages when my download speed is limited at that time. I tend to run pacman -Syu --ignore libreoffice-fresh,signal quite a bit.
I just pulled down the latest releases of LibreOffice and Signal. LibreOffice is ~300 MB, and Signal is ~150 MB. LibreOffice has been updated 5 times this year, though Signal is updated roughly once per week. How often is your download speed so constrained that you would need to routinely skip these upgrades?
There are certain packages that I update myself. On Arch, I never update linux and linux-lts packages at the same time. linux-lts stays in IgnorePkg (it's pinned).
I can't think of any cask as critical linux and linux-lts though. Can you provide some examples of casks that need to be upgraded by hand and why?
For Homebrew specifically, I'd like to execute brew update --greedy-auto-updates and get everything upgraded except for those that perform mandatory updates. Whether that's via a permanent pin brew pin signal; brew update --greedy-auto-updates, or a one-time exclusion brew update --greedy-auto-updates --ignore pkg1,pkg2, it's all good.
What do you mean by 'mandatory updates'? Homebrew is a rolling release package manager designed to provide the latest versions of software. The goal of the Homebrew project is not to provide this kind of granular control over every single package. I'm struggling to see the purpose of installing Signal via a package manager and not letting the package manager update it.
...But most importantly: why not? All other package manager do it, and there must be many good reasons why.
This is the easiest one to answer. No maintainer wants this. No maintainer has wanted to put in the work to implement this, and likewise no community member has stepped up to do it either. We run this project as volunteers. No one is working on Homebrew as a full-time job. We implement things we want to see in the project, and accept community contributions.
I do it to skip large packages when my download speed is limited at that time. I tend to run pacman -Syu --ignore libreoffice-fresh,signal quite a bit.
I just pulled down the latest releases of LibreOffice and Signal. LibreOffice is ~300 MB, and Signal is ~150 MB. LibreOffice has been updated 5 times this year, though Signal is updated roughly once per week. How often is your download speed so constrained that you would need to routinely skip these upgrades?
There are certain packages that I update myself. On Arch, I never update linux and linux-lts packages at the same time. linux-lts stays in IgnorePkg (it's pinned).
I can't think of any cask as critical
linuxandlinux-ltsthough. Can you provide some examples of casks that need to be upgraded by hand and why?
The two above are just two different reasons why someone would want to skip an update ad-hoc. Whether that is because of download speed constraints (I have a 4G hotspot that's limited to 24 mbit - and I use it when I travel, and I travel quite a lot), life circumstances (running updates before shutting down, but not wanting to wait for Libreoffice), or just not having the patience for annoyingly slow download of Nextcloud due to their snail servers, it doesn't matter. Every other package manager in existence - except pkgin/pksrc and Homebrew (for casks) - allow their users to "upgrade all except these", for whatever reasons the user may have. Even Homebrew allows me to do that using brew pin - but for formulae only.
And another annoying thing about these snail speed upgrades like Nextcloud is the fact that previous sudo cookie will expire by the time Nextcloud download finishes, so my intended upgrade of everything will instead sleep on sudo prompt for Nextcloud installation. It happened so many times I simply wanted to brew pin nextcloud but it's not allowed.
For Homebrew specifically, I'd like to execute brew update --greedy-auto-updates and get everything upgraded except for those that perform mandatory updates. Whether that's via a permanent pin brew pin signal; brew update --greedy-auto-updates, or a one-time exclusion brew update --greedy-auto-updates --ignore pkg1,pkg2, it's all good.
What do you mean by 'mandatory updates'? Homebrew is a rolling release package manager designed to provide the latest versions of software. The goal of the Homebrew project is not to provide this kind of granular control over every single package. I'm struggling to see the purpose of installing Signal via a package manager and not letting the package manager update it.
You didn't understand my point, but provided a totally valid argument FOR this feature by mistake. ;-) I'm too struggling to see the purpose of installing Signal via a package manager (Homebrew) and not letting the package manager update it (with brew upgrade)! 😆
It's not clear to me if you know that brew upgrade will not upgrade Signal because of its :auto_updates flag. Only an explicit brew upgrade signal will (but this requires an explicit call with the package name - not convenient when I want another 10 casks with :auto_updates flag updated), or brew upgrade --cask --greedy-auto-updates - which will upgrade everything, including for example Discord, which is useless to upgrade via Homebrew since Discord has mandatory auto-updates built-in. "Mandatory updates", as in, Discord downloads and upgrades itself automatically without asking and you cannot disable this behavior.
I want to upgrade all application, except those that have mandatory updates. These include: adobe-acrobat-reader, discord, dropbox, google-chrome, onedrive, ~~signal~~ for me. Currently, the only way to upgrade all :auto_updates packages except those with mandatory updates is by using this beauty: brew upgrade --cask --greedy-auto-updates $(brew info --json=v2 --installed --casks | jq -r '.casks[] | select(.auto_updates) | .token' | grep -vE '^(adobe-acrobat-reader|discord|dropbox|onedrive)$').
My feature request asks for a mechanism to execute it as either:
brew upgrade --cask --greedy-auto-updates --exclude adobe-acrobat-reader,discord,dropbox,onedrive, orbrew pin adobe-acrobat-reader discord dropbox onedrive; brew upgrade --cask --greedy-auto-updates
For a complete list of packages with :auto_updates flag, see brew info --json=v2 --casks --eval-all | jq -r '.casks[] | select(.auto_updates) | .token'. There's plenty of them. All packages returned by this command will not get upgraded without --greedy-auto-updates flag. And when you use --greedy-auto-updates, you will cause an unnecessary upgrade of Discord, Adobe Reader, and other applications that have mandatory upgrades.
...But most importantly: why not? All other package manager do it, and there must be many good reasons why.
This is the easiest one to answer. No maintainer wants this. No maintainer has wanted to put in the work to implement this, and likewise no community member has stepped up to do it either. We run this project as volunteers. No one is working on Homebrew as a full-time job. We implement things we want to see in the project, and accept community contributions.
Like I already said, I'm open to contribute, but in my view, the biggest issue with brew pin for casks wasn't lack of contributors, but rather, it was a direct disapproval of the feature itself. Some Homebrew community members (unsure if official maintainers, or random infrequent contributors) actively opposed brew pin, I provided multiple reasons why one would actually want this feature. So it would be best to secure support from the Homebrew Cask's higher ups before investing time in coding. Being a volunteer isn't a full-time job either, so it's understandable I'm treading carefully before I put any real work towards something historically opposed by the community and closed a number of times so I don't waste my time on something no maintainer wants to see in the project.
The two above are just two different reasons why someone would want to skip an update ad-hoc. Whether that is because of download speed constraints (I have a 4G hotspot that's limited to 24 mbit - and I use it when I travel, and I travel quite a lot), life circumstances (running updates before shutting down, but not wanting to wait for Libreoffice), or just not having the patience for annoyingly slow download of Nextcloud due to their snail servers, it doesn't matter. Every other package manager in existence - except
pkgin/pksrcand Homebrew (for casks) - allow their users to "upgrade all except these", for whatever reasons the user may have. Even Homebrew allows me to do that usingbrew pin- but for formulae only.And another annoying thing about these snail speed upgrades like Nextcloud is the fact that previous sudo cookie will expire by the time Nextcloud download finishes, so my intended upgrade of everything will instead sleep on sudo prompt for Nextcloud installation. It happened so many times I simply wanted to
brew pin nextcloudbut it's not allowed.
If you open an issue on the main Homebrew/brew repository for suggesting a feature request (where the code to support this would actually go) it asks how the feature would be beneficial to 90% of Homebrew users. I find this to very much be an edge case, and not something that would apply to most users.
You're also missing the historical context of Homebrew/cask being its own project ran by different people prior to it being brought into the main Homebrew project. That is one reason there are often differences between formulae and casks. There was never a 'we have to introduce full feature parity before we officially support casks'. We've been adding things as they make sense over the years.
You didn't understand my point, but provided a totally valid argument FOR this feature by mistake. ;-) I'm too struggling to see the purpose of installing Signal via a package manager (Homebrew) and not letting the package manager update it (with
brew upgrade)! 😆It's not clear to me if you know that
brew upgradewill not upgrade Signal because of its:auto_updatesflag. Only an explicitbrew upgrade signalwill (but this requires an explicit call with the package name - not convenient when I want another 10 casks with:auto_updatesflag updated), orbrew upgrade --cask --greedy-auto-updates- which will upgrade everything, including for example Discord, which is useless to upgrade via Homebrew since Discord has mandatory auto-updates built-in. "Mandatory updates", as in, Discord downloads and upgrades itself automatically without asking and you cannot disable this behavior.I want to upgrade all application, except those that have mandatory updates. These include: adobe-acrobat-reader, discord, dropbox, google-chrome, onedrive, ~signal~ for me. Currently, the only way to upgrade all
:auto_updatespackages except those with mandatory updates is by using this beauty:brew upgrade --cask --greedy-auto-updates $(brew info --json=v2 --installed --casks | jq -r '.casks[] | select(.auto_updates) | .token' | grep -vE '^(adobe-acrobat-reader|discord|dropbox|onedrive)$').My feature request asks for a mechanism to execute it as either:
brew upgrade --cask --greedy-auto-updates --exclude adobe-acrobat-reader,discord,dropbox,onedrive, orbrew pin adobe-acrobat-reader discord dropbox onedrive; brew upgrade --cask --greedy-auto-updatesFor a complete list of packages with
:auto_updatesflag, seebrew info --json=v2 --casks --eval-all | jq -r '.casks[] | select(.auto_updates) | .token'. There's plenty of them. All packages returned by this command will not get upgraded without--greedy-auto-updatesflag. And when you use--greedy-auto-updates, you will cause an unnecessary upgrade of Discord, Adobe Reader, and other applications that have mandatory upgrades.
I'm quite aware of how brew upgrade works, having been a maintainer for this project for years. It seems you're not understanding MY point. I have HOMEBREW_UPGRADE_GREEDY set on my system, which passes --greedy to all upgrade commands. When I install a cask, I disable autoupdates from within the app, and upgrade it only via brew upgrade. I install software with my package manager, and upgrade it all with my package manager. This whole 'pick and choose random packages to selectively upgrade sometimes' scenario seems pointlessly complex. Install and upgrade stuff with your package manager, or let autoupdates take over. This feels like needling in on very niche scenarios, as I stated above. 90% of users do not need this.
Like I already said, I'm open to contribute, but in my view, the biggest issue with
brew pinfor casks wasn't lack of contributors, but rather, it was a direct disapproval of the feature itself. Some Homebrew community members (unsure if official maintainers, or random infrequent contributors) actively opposedbrew pin, I provided multiple reasons why one would actually want this feature. So it would be best to secure support from the Homebrew Cask's higher ups before investing time in coding. Being a volunteer isn't a full-time job either, so it's understandable I'm treading carefully before I put any real work towards something historically opposed by the community and closed a number of times so I don't waste my time on something no maintainer wants to see in the project.
If it were up to me alone, brew pin wouldn't exist at all. It makes no sense to me in a rolling release package manager like Homebrew. However, no single person unilaterally makes decisions for this project. If you open a PR, with well written and working code, and can explain how this won't break existing functionality, the odds of it getting merged are good. We just don't want PR's that are thrown together and require lots of maintainer work to get over the line.
Bottom line: if you want to see this, and are willing to submit a working PR for review, please do. My personal ideological disagreement with this feature is not a showstopper, and I know that at least fellow maintainer @bevanjkay would find this useful, which is good enough for me.
It seems to me like what you're describing would be much better suited for a flag to exclude certain packages from an upgrade invocation, rather than limiting all updates of a certain cask.
In addition to that I'm not very convinced by the "everyone else has it so Homebrew should too" everyone makes different design choices along the way and I'm not sure the pinning system makes sense in Homebrew at all.
Either way, I'm fairly certain a well written PR will still be merged. Since in the end people contributing is the biggest driving factor.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
Sorry, I've been busy and didn't get to respond yet. I'll address all the feedback soon.
@Nowaker Maybe https://github.com/buo/homebrew-cask-upgrade?tab=readme-ov-file#version-pinning is a working solution to your problem?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.