At this point I should know better than to install postgres via homebrew, but unwanted/unasked-for upgrades is not a feature I'm looking for in a package manager.
What's your experience with other package managers for macOS? Currently looking into macports & nix and not sure which one to choose...
---
Homebrew upgrades dependencies and dependents of those dependencies (which, admittedly, can feel like unrelated) on installation and upgrade. As mentioned in other comments, you can customise this behaviour with `HOMEBREW_NO_INSTALL_UPGRADE` or `HOMEBREW_NO_AUTO_UPDATE`.
Homebrew does this because the alternative is sometimes breaking things. An example:
- you want to install `virtualenv` that depends on `python@3.10`
- the binary package for `virtualenv` you want requires the newest `python@3.10`
- this upgrades `python@3.10` on installation
Now, Homebrew has a choice. Either we upgrade _everything_ that depends on `python@3.10` that you have installed or we knowingly break some of the things you have installed that depend on `python@3.10`. We choose the safer option by default.
The more time left between updating/upgrading, the more likely to have more dependencies updated which requires more dependents to be updated.
---
Regardless, I appreciate this is a problem and we're still figuring out potential solutions for this problem. A reminder that we're a volunteer run project so it's not always as easy as we'd like it to be to get these changes out quickly.
Perhaps in situations like this Homebrew could alert the user "Hey, this package hasn't been updated in a while and 40 other packages depend on it so this is going to take a while. Press enter to confirm or cancel and use an alternative method (HOMEBREW_NO_INSTALL_UPGRADE) to just upgrade the one package. Caveat - this may break things."
My only point (and a source of confusion) here is that I never anticipated the cascading effect that installing a single package can have on seemingly unrelated parts of the system. I've been using homebrew for many years and as far as I remember, the only time anything broke like this was when I explicitly ran update/upgrade.
I'm going to try HOMEBREW_NO_INSTALL_UPGRADE/HOMEBREW_NO_AUTO_UPDATE — it does seem like a more intuitive default, but again, I don't know anything about how homebrew works under the hood.
Thanks again!
Personally, I have moved to downloading large things (Python, Postgres by your example) as standalone apps, and only use Homebrew for small libraries and CLI tools. I think that makes more sense.
You can download all of the Mac Python versions you want from python.org and you can get Postgres from postgresapp.com which provides a nice toolbar interface to start and shutdown servers of various versions.
With homebrew, I never know how many packages will be updated and how long it will take, so sometimes when I just need a small utility, suddenly it'll update a bunch of packages and it takes 45 minutes.
It's a UI problem.
brew outdated will list outdated app/dependencies that need to be updated. If you want to know the app's dependencies, use the info argument. For example brew info ffmpeg will list the information about FFmpeg and list the dependencies that it uses along with status indication if the dependencies is installed or not.
Am I missing something here? I am not sure if it is a UI problem since Homebrew have those functions with a few arguments here and there. Look like you are using a utility that have so much dependencies that it needs or you have habit of using brew upgrade which will prompt to upgrade everything expect pinned apps/dependencies.
If Postgres has an unversioned dependency to PackageX, the only time I might expect Postgres to be updated automatically is if I update PackageX across a major version boundary, risking breaking changes. Even then, I'm not sure I'd want that behavior by default - I'd at least like to be prompted - since often this still won't break anything, or it will likely cause less damage than updating every package with a dependency to PackageX. And if Postgres breaks after I update PackageX I can easily reason about what just happened. The alternative can be incredibly hard to troubleshoot because so many changes have occurred.
Overall, Homebrew feels far too aggressive here, and I think the result, for people who have some understanding of Homebrew behavior, is that they're afraid to touch anything.
Homebrew doesn't meaningfully have versioned or unversioned dependencies, because it doesn't incorporate any notion of version into its dependency solver. When you declare a dependency on `python@3.9`, you're not telling `brew` that ‘I need a copy of the package `python` which satisfies the constraint “version is 3.9.x”.’ Homebrew just treats `python@3.9` as the name of a package which is a whole copy of python, and it can exist alongside other, similar packages like `python@3.8` and `python@3.10`.
Homebrew only incorporates this kind of `@` syntax for select packages of which maintainers have elected to maintain multiple versions. By my count, there are 81 such packages in homebrew-core, and the following is a complete list of all of those which appear in a `depends_on` declaration:
antlr
atkmm
autoconf
cairomm
db
elasticsearch
erlang
gcc
ghc
glibmm
go
gradle
guile
hdf5
headers
helm
isl
libfuse
llvm
lua
mbedtls
mysql
node
numpy
openexr
openjdk
openssl
pangomm
php
proj
pyqt
pyside
python
qt
ruby
swig
synth
tbb
vtk
wxwidgets
So when you look at a Postgres formula in the Homebrew repos and see that it declares an ‘unversioned’ dependency on openldap, for example[1], that does not mean that the formula author has declared ‘any version is fine’, i.e., it does not mean that the dependency is unversioned. It just means that the dependency's version constraints are totally unspecified except implicitly as ‘the only version of that package which is simultaneously present in the glorious monorepo of build recipes’.This is a feature it shares with some source-based package management systems, like Nix and Guix. Those package managers solve this problem by basically vendorizing everything, so installing a new package never upgrades anything else you have installed.
Other source-based package management systems, like Portage and Pkgsrc, have extended their model to include some handling of version constraints, but they also sometimes declare dependencies without specifying a version. That seems dubious to me, since in reality there pretty much always are version constraints that ought to be specified there, but maybe those two projects are mature enough that they've hammered out the problematic cases by now.
—
https://github.com/Homebrew/homebrew-core/blob/master/Formul...
That said, I did notice recently the same effects as the OP. I.e. I try to install something small and it depends on something like python, which triggers "upgrade the whole universe" loop, which breaks a ton of things (e.g. python upgrade doesn't carry over installed modules, but does change current version - which breaks many local python scripts since their dependency modules are now in the old version). Auto-cleanup tends to break a lot of things too - especially bad for commonly-used things like openssl or ICU which commonly are linked as shared libs.
I think there are settings for changing all of this, but you only find out once you've already been bit. Maybe it's worth considering making it somehow explicit - e.g. ask the user "do you really want to upgrade the whole universe" before going in? In many cases, I'm completely fine with using python 3.7 even if python 3.10 is already out. And most of the tools that depend on python would be fine with it too. It would be nicer if low-friction mode would be the default.
> Now, Homebrew has a choice. Either we upgrade _everything_ that depends on `python@3.10` that you have installed or we knowingly break some of the things you have installed that depend on `python@3.10`. We choose the safer option by default.
A look at the formulae in homebrew-core shows that Homebrew basically doesn't consider versions in its dependency management at all, so formula are just using the ‘@x.y.z’ in place of all manner of version constraints. So you get wild stuff like this line here[1]:
depends_on "curl" # curl >= 7.55 is required
wat.Of course the recursive update policy is going to be weirdly painful for some users! Homebrew doesn't even attempt to encode some very basic aspects of dependency, so now (a) you can't know what you're going to break if you do upgrade a common dependency and (b) you can't know when you can afford not to upgrade a dependency shared by a package you're about to install and the already-installed system. The choice you outline above is one that is not faced by most package managers, because they don't make this mistake. The naive wheel reinvention with Homebrew is so eternally disappointing, and it explains a lot of the pain users experience with it.
> Homebrew upgrades dependencies and dependents of those dependencies (which, admittedly, can feel like unrelated)
One relatively non-disruptive thing you might be able to do to make this behavior less surprising to users is (offer a way to?) print the dependency tree for package installations/upgrades that pull in upgrades of their ‘siblings’. You'd probably want to just do it in a textual way, but this project seems to model the kind of logic you'd want for printing dependency trees with Homebrew as it exists.[2]
—
1: https://github.com/Homebrew/homebrew-core/blob/master/Formul...
2: https://github.com/martido/homebrew-graph/blob/master/cmd/br...
What’s the difference in what Homebrew is doing from what normally happens with something like Pacman or Apt? My impression is that “core” binaries, like Python might be, don’t get updated as often as they would on Homebrew, and perhaps those dependency chains are less frequent. Is it because (e.g.) python versions change rarely on linux package managers? Or something about how the binaries are compiled?
Homebrew is a source-based package manager, where packages are built from a single shared source of build recipes, and distribution of software happens by distributing the whole collection of recipes. Support for a binary cache is added through the identification of build recipes with the hashes of archives of binaries.
APT is what's called a binary package management system. While build recipes can be stored in a central repository, they don't have to be, as binary package management systems typically identify two kinds of packages: source packages and binary packages, which can be distributed separately. (Some repositories may not even include source packages.) Source packages contain metadata like build recipes, but things like archives of the upstream source code, patches, and sometimes helper scripts that might be usd in building. Binary packages include the actual built artifacts; they're installable packages.
In the source-based package management world, if packages can be added to the main collection through external sources, this is typically done by pretending that those packages were embedded in (some particular version of) the main repository of build recipes. Collections of packages that are ‘injected’ into the main package collection like this are typically called ‘overlays’.
In binary package management systems, an external package is not expected to have access to some copy of a complete collection of build recipes from some ‘master’ repository. Instead, source packages are distributed individually using the same mechanisms as binary packages. This means that the global namespace of terms which refer to packages can't be navigated implicitly at build time like on source-based systems, the identification of actual source code and build instructions with some package name happens both at build time and at install time. And in both cases, explicit metadata (package names, package versions, equivalency classes, lists of conflicting packages, etc.) is used to determine what versions of dependencies get pulled in.
As a result, binary package management systems always include dependency solving at install time, and usually include some explicit version constraint for every single dependency declared in a package's build recipe. This means they have the resources to look at what's going to be installed, what's already installed, and say ‘oh, the new installee requires Python <= 3.10.4, and since your installed packages together only need Python >= 3.10.2 and you already have python-3.10.3 installed, we don't have to touch Python to install this new package unless you ask us to’.
Pacman is somewhat atypical. The build system is essentially source-based and monolithic (there's no source package format) and the AUR is essentially an overlay, but the high-level CLI tool acts like a binary packager and uses the language of repositories to describe dealing with multiple package sources. Pacman's dependency resolution behavior is also unusually unreliable, and probably closer to what `brew` does than what `apt` does. Pacman has the resources to describe and test version constraints, both in its build system and in its CLI tools, but they're underutilized in a way that's more typical of source-based package management systems than binary ones. Homebrew is similar in that such constraints are radically underutilized (they're totally absent).
The main difference between Homebrew's behavior and Pacman's in this instance is that by default, just `pacman -S` doesn't update pacman's collection of package definitions (pacman -Sy does) and Homebrew always tries to install from the latest build recipes.
I imagine that Pacman's capacity for handling version constraints means that the story with `pacman` will usually be a bit better than with `brew`, but that otherwise `brew install` will be similar to `pacman -Sy` and `HOMEBREW_NO_INSTALL_UPGRADE=1 brew install` will be similar to `pacman -S`. (Pacman also sometimes makes the opposite tradeoff that Howell describes for Homebrew sometimes; it's not unheard of for installing new software or updating software using Pacman to break installed software.)
The irony is that poster was trying to install a solution to this very problem (virtualenv).
The broader problem is that, at this point, python is effectively its own OS. Coupled with macOS being schizophrenic between "We want to provide a posix environment for users" and "No user should ever look under the hood, so no need to tell them about all the duct taped bits."
Which brew attempts to bridge. Admirably, but never perfectly.
Obligatory: https://xkcd.com/1987/
AFAIK homebrew cannot automatically modify $PATH before starting a program such that $PATH points to the correct dependencies for that program. If you have multiple versions of some dependency installed, it is up to you to run `brew switch` before running your program to manually set the correct versions for each dependency.
Thanks for all the work you put in homebrew, I really appreciate it. Just upgraded to Monte Rey a few days ago and I was kind of fearful that some of the things that I needed where not going to work... nop, every singe package that I've needed so far was installed successfully.
Thanks!
My life became much better after setting this.
I wouldn't be averse to a HOMEBREW_AUTO_UPDATE_INTERVAL=180d either, or HOMEBREW_AUTO_UPDATE_ASK=y .
I think we need a new package manager since its not the fault of homebrew that many packages have hardcoded stuff in there.
Anyway, I just wanted to say you guys are doing a great job!
1. Nix has very limited support for GUI applications of the kind that you'd find in `brew cask`. Not no support, some of them are there, but limited support compared to brew. If you use brew as an out-of-the-box install-everything setup like me, you'll not be able to replicate that easily with Nix.
2. Nix can't currently build Swift applications because of some Xcode something I didn't fully understand.
3. I found a small number of packages that are broken on Nix on my aarch64 / M1 MacBook Air (and marked broken, so when you try to install it complains) and a small number that are broken without being marked broken. In specific, I think R was one that surprised me -- this is a major programming language and although the build requirements are onerous (it's a mix of C and Fortran), I would think it would work.
That being said the actual process of installing, updating, and upgrading seems much faster and dramatically less shitty than homebrew, and so I recommend migrating stuff off of brew anyway.
For anyone who remembers the year 2000 and having to compile everything from scratch, Homebrew is brilliant - but there are complexities and quirks. For Python I’d go with pyenv. Postgres - well, watch your step and maybe use Docker instead.
I'm reaching the tipping point to adopt Nix, after seeing Nix as an alternative for supporting project after project. The unstated subtext always seems to be "Nix is what the smart kids are using, but it's harder to learn."
Haskell? Same religion. But the joke is that one needs a PhD in category theory to use Haskell at all, and package management has long been a Haskell sore point, yet Nix hasn't taken over.
The Lean Theorem Prover?
https://leanprover.github.io/lean4/doc/make/nix.html
A century ago, Hilbert's program to formalize and automate mathematics was stopped in its tracks by developments in logic such as Gödel's incompleteness theorems. There is a new push involving many leading mathematicians, using the Lean theorem prover. While some imagine computers replacing people, a better model is how a chess grandmaster checks their analysis using computers. Even as the experience of observing computer Go games leads to moments of amazement, as if observing an alien tournament, the role of a human to appreciate and generalize is preserved. Primates have long used tools; our future is to coevolve with machines.
Dependency hell and Gödel's incompleteness are cut of the same fabric. This is where I first read about Nix flakes.
That said, I'm sticking to Homebrew. Not really sure about this auto-upgrading, maybe it can be deactivated, on the other hand probably it's a good way to keep packages updated.
Sure, you will eventually need to use the Nix language if you want to have complex and reusable configurations, but this is actually not needed for beginners! To install packages, you need the Nix package manager (with channels already setup) and use `nix-env` to install for the current user. You can just search for the package in https://search.nixos.org/packages and use the command directly.
If you want to have user configurations, use home-manager, just modify the example to add other options, you seldom need complicated Nix expressions unless you need to build a package by yourself.
When you really need to do so, you may want to have a look at other's build script, and make sure you understand everything in the build process, including compile dependencies and runtime dependencies, environment variables, etc. You may want to read Nix Pills at some point, but maybe you can get away with reading just the relevant section (incomplete knowledge, but usually enough to get the work done).
I still run Homebrew for a couple of services and casks, but I'm down to less than 20 packages still installed that way.
There have been a few points of friction (which I'm used to as a polyglot with lots of active projects), but the community has been very helpful with ironing those out.
I use the following Nix function to install GUI applications https://github.com/cmacrae/.nixpkgs/blob/d4b51eb414b0edaffae...
It doesn't work for everything, but I use it at the moment for Amethyst, DBeaver, DockerDesktop, Emacs, Firefox, iTerm2, Postman, Slack and VNCViewer.
One question: How do you properly install things like R on the M1 Macs, then? Do you use a 'backup' package manager?
Homebrew is old and it needs to be replaced. It has served its time.
You are more than welcome to build your own alternative. Homebrew is open source and volunteer run. I'm sure there is a very valid reason requests like this get shot down.
No wonder open source maintainers hate dealing with people like you.
Counterpoint: I've spent serious time (years) with, oh, six or seven package managers, in a couple decades of using package managers. More if you count Flatpack and stuff like that.
Brew is my favorite, all-around. Package selection is incredible. Stability is excellent. It's a little slow and I think defaulting to updating the package list damn near every time one invokes the command is a really weird choice, but that's configurable.
My second favorite? Docker :-)
Third would probably be portage (from Gentoo), I guess. Then apt/dpkg.
Worst I've used is easily Macports, and it's not even close—however, I switched years ago because it broke constantly under normal usage, on my machine, so for all I know it's great now—and I've never forgiven RPM-based distros for all the time I lost to RPM hell over the years, and for going so long with worse CLI tools than apt.
Void's seems very nice, but I've not spent enough time with it to feel the rough edges.
And Homebrew does have a progress bar for each app. The bar is for the downloading but other than that, I don't think it need a progress bar for installtion since they are quick to install than using the GUI installation.
Pacman, apt, portage, etc have much more stable interfaces. But the workarounds for my edge cases in Homebrew from a year ago don't work anymore. Even knowing what is an edgecase or not is a problem.
Most of these issues would be fine if the interface changed as slowly and consistently as Linux package managers.
You shouldn't use the system package manager on Ubuntu or Red Hat or whatever the way you're using Brew, either, unless you're exactly matched to your deployment target—same distro, same version, and you don't upgrade locally unless the servers are getting upgraded—and are scripting your local package installations and upgrades with the same script you use to deploy on the server.
Homebrew's response to criticism seems to be to continually narrow the field of users and the scope of their project, and tell users to use something else.
People are only frustrated because they found it to be so helpful.
But I suppose that it had to mature, or something like that.
I find it much faster now, which is quite funny to me because back when Homebrew was new (and a lot less opinionated) it was much faster than MacPorts, especially with the bottles (binary packages) feature.
Today, MacPorts has binary packages, doesn't randomly force incredibly slow updates when I just want to quickly install something or run a package search, has entirely opt-in telemetry through installing a package (mpstats) and still lets me customise packages (through the variants system, which is more powerful than the with --with-feature system Homebrew seems to have abandoned).
The only pain point I've found is upgrading to new macOS releases, though I've often found just reinstalling MacPorts itself will get me going again in a pinch without having to take inventory of my installed ports and reinstall everything from scratch.
I have been much happier with Macports than with Homebrew (which I try every other year to see if it’s improved).
> The only pain point I've found is upgrading to new macOS releases, though I've often found just reinstalling MacPorts itself will get me going again in a pinch without having to take inventory of my installed ports and reinstall everything from scratch.
I used to use the commands suggested on the Macports website (save the list of installed packages to a file; update OS; install Macports; re-install ports). But since a couple of upgrades I have decided to use this as an opportunity to get rid of ports I don’t actually need.
In contrast to how it used to be, Homebrew now seems designed for people that only want popular bleeding edge packages, and nobody else. If I just wanted to install google-chrome, sublime, and skype, I would use the app store. I used to use Homebrew to install more obscure packages that were useful to me, like Arduino, Processing, and some specialized bluetooth tools.
It is especially frustrating because there are good reasons to not want bleeding edge. OSX ages pretty well, and new versions of macOS often remove important features. As long as you have security updates, I think it is reasonable if you run an older version of macOS. For some of us, Catalina and Big Sur were pretty painful, especially if they are a liability for how you make money. Losing total-terminal and total-spaces were a big blow to my workflow, and not at all simple to work around, as well as certain accessibility software.
Homebrew being so aggressive about updating itself compounds many other issues it has. For one thing, major changes are made frequently, and it is very aggressive about pruning packages and only supporting recent version of macOS.
So, I have lost count of the number of times Homebrew has broken itself.
Homebrew will go out of its way to search through its history and tell you a package has been removed, but gives you no easy way to install them. Homebrew could make it fairly easy to revert updates, since so much of it is in a git repo, but it doesn't.
I wanted to install an SNES emulator, and I was using an install of macOS from maybe two years earlier, and Homebrew installed a version that was incompatible with my OS. Since it was a cask, I don't think anything depended on it. I had to actually search through the Homebrew repo history and check out that specific formula, since nobody had a tap for it.
Unless you are near the center of the bell curve, you don't matter. And it is a shame, because I really think that it wouldn't impose a significant cost to support more of us, and substantially improve its UX.
Homebrew used to be a powerful repository of most macOS software. Some of its less used packages could be unreliable, sure, but that was the case regardless of where I got them. Now it is morphing into an App Store. This is part of why I gave up on macOS two years ago and went to Linux full time. I can't rely on Homebrew.
Is it the act of being fastidious regarding everything under '/usr'? If so, count me in.
One of my biggest gripes with the aged Linux install ritual is having to keep the source bundle forever in case I ever decide to uninstall. Why? Because the autoconf makefile is the only rule that cleans up all the bins, docs, and shared files that were sprayed into the OS. Building from source needs an uninstall fix, but no one seems to care. (Or I simply don't understand how w/o keeping the build folder forever... Help?)
export HOMEBREW_NO_AUTO_UPDATE=1It makes sense, but then I don’t do full upgrades and get delayed just like OP. I live with it.
Macports has this appearance of being 'dated', and not the cool kid compared to Homebrew. But it doesn't have an opinion on what version of software you can install. Want postgres 9.4? Go ahead and install it. Want some ancient version of some other library? That's fine.
Dealing with custom port files and repositories isn't quite as easy, I suppose, but that's not really much different to setting up a debian repo in that it's a use case you won't encounter nearly as often as just installing stuff.
I also used nixpkgs at one point, many moons ago. That was also nice but not the most practical on a Macbook with 128GB storage, when you also have Docker, npm/ruby dependencies, and your native Mac software in the mix.
Fortunately Homebrew has lots of helper scripts to upgrade DB’s like Postgres. You probably saw some scroll back with a command to upgrade from 12 to 13 or 13-14 etc. It will even download and install an old version in order to upgrade safely.
I understand the frustration but what is the alternative? Pinning every dependency? The reason so many of your packages were updated was likely because a core dependency was upgraded like OpenSSL.
This can be encapsulated with things like docker, but the "I'll globally, arbitrarily update everything to the bleeding edge" strategy isn't friendly for building and maintaining software.
It's confusing, but we'll get there. You'll need/want:
- nix, the tool/build system.
- nixpkgs, the world's most up-to-date and underfunded package repository.
- nix-darwin, bringing a NixOS experience to Darwin. Not perfect, but pretty damn great.
And optionally,
- home-manager, a nix-based opinionated tool to manage dotfiles and other stuff in your home directory.
And finally, some things to avoid and experimental features to use:
- do not ever use `nix env -i` to install things ala homebrew, apt, etc. This is a trap. You don't want this.
- use nix flakes. Sure, it's experimental, but it's what you _do_ want. Reproducible, version-pinned builds.
- if you use direnv, or are familiar with it, check out nix-direnv, which is like direnv on crack. Instead of managing your packages globally, manage them per workspace or project.
I see "nix-env --install" as a gateway drug to using Nix. It's effortless, and already easy to see benefits from using Nix (like you can easily get the same set of packages on different OSs).
Rather, it's worth explaining why it's bad to use. The footgun I ran into was that I'd caused a messy state by installing something and forgetting I'd installed it.
Maybe nix flakes and home-manager and nix-darwin are really cool.. but they're also much harder to use, and surely overwhelming for someone who just wants a way to install packages. I think it's like telling someone to learn Kubernetes when they're wondering how to serve the website they wrote. -- I think it's easier to appreciate these once you've gotten your feet wet with nix.
My biggest problem is that it's not version-controlled. I don't use home-manager, and (still) haven't looked into Nix flakes.
Instead, I put `export PATH="/path/to/my/repo/result/bin:$PATH"` in my ~/.bashrc, and inside that repo I have a default.nix file:
buildEnv {
name = "my-packages";
paths = [ foo bar baz ... ];
}
Running `nix-build` will update the result/bin symlink to point at the new applications.But yeah I agree, it's fine to use `nix-env -iA <package>` or whatever. It's fine when you're getting started, and it's fine for a slightly more persistent way of trying things out than `nix-shell`.
I've been using `nix env -i` without any issues till now, but I'll explore nix flakes.
In every case they were removing features that were working just fine, and in the process creating work for me. Got fed up, switched to macports (after checking out nix), and so far things are back to the way I like it.
The trick of disabling auto updates doesn't really work when you do want things to be updated. Sometimes there are conflicts and the usual path was to upgrade everything.
Not that it matters: it seems that the usual "upgrade everything" from 2 years ago has changed into "delete every folder and reinstall everything from scratch".
Also, a few years ago, updating everything or reinstalling lots of things from scratch was fast. Now, it requires much more time due to the massive number of dependencies every single package has.
Also, the maintainers have a super weird aversion to everything that is "too simple". I've seen packages rejected because "the build process was too simple and there are no dependencies". The excuse was that "users can build it themselves". This is not for silly stuff random people wrote on weekend, this is for 20 year old tools used in production written in C.
I can't say for certain why or how it got worse for other people, but for me it started when they doubled down on dynamic linking. That's why installing takes 5x the time it used to, takes more disk space, breaks all the time and makes organising your tools a fucking mess.
As for me: I've replaced most of my Brew usage with Docker (for most development tools) or with static binaries compiled weekly using Github Actions (for cli tools like youtube-dl, etc). I'm also using download links straight from language websites (Rust, Ruby, Python, DotNet, Haskell).
wtf? What could be the possible motivation for this? Is their build farm really straining or something?
Can you point me to this example?
> I'm also using download links straight from language websites (Rust, Ruby, Python, DotNet, Haskell).
this sounds downright medieval to me, like why even use macOS for development if the software management tools are so bad that that's what you're doing
I'm a bit wary on relying on it now. It's a shame, because it's a really useful tool (and I actually like the auto-update).
I’ve seen homebrew overwriting system files and thoroughly breaking machines (that’s no longer that easy, but more thanks to Apple).
Haven’t tried many other package managers (Fink, when G3 was bleeding edge), but MacPorts has the feel of an exquisitely well engineered tool.
https://github.com/Homebrew/brew/blob/7d31a70373edae4d8e78d9...
Since then i moved to manage everything that needs to stay frozen by either a versioned formula/cask (python@3.9 and so on) or use brew to install a version manager (asdf,pyenv,pipx) and then use that. Results are much better once I did that
Although versioned casks/formula exists you will still get minor versions - python@3.9 will update from 3.9.0 to 3.9.1 is that ever exists. so while completely protecting you from upgrades it does minimize the the risk
Also, there is really no need to install virtualenv directly from brew. A very bad practice. Of course doesn't change the fact that brew did things that are unrelated to what you asked of it
I've seen countless people trying a new technology/tool, and overselling it as 'amazing' and super easy.
Seeing a post like yours helps to keep the discussion grounded in reality, with tools that looks nice on paper but have practical downsides as well.
Finding your sea legs is rough, and IME people who completely deny this are few and far between. The reward is a pretty impressive lever.
Parts of it are getting easier, and it has an exceptionally smart and helpful community. But it's not smooth and pretty and easy to pick up like Homebrew is. (And that does suck)
I found it much more helpful to find people's own Nix setups and learn from them, by the way. Mine is at https://github.com/Smaug123/nix-dotfiles - like all such things, it's a WIP, and I'm definitely still a noob, but bits of it may be able to help.
I recommend using Nix alongside a couple other systems so you have escape hatches.
- Nix
- pkgsrc or MacPorts ‘just in case’ they're more convenient for some package for any reason
- Homebrew, exclusively to use for Casks (which are really a separate system from the rest of Homebrew)
To get the most out of Nix, you'll need to take some time to really learn it. For managing services like postgres, it's nicest to use Nix-Darwin (a module system for managing services and programs, including automatic startup via LaunchD) but if you want to always keep the same Postgres with Nix-Darwin, you'll have to learn how to pin packages.If you use Nix with Flakes, it'll feel a lot faster (much faster than Homebrew). If you use old-school Nix, it'll be slow if you call some deprecated commands.
It is rough around the edges as some packages are missing if I remember right.
For instance: arkade get kubectl@v1.22.1 yq helm faas-cli
It's not got anywhere near the catalog of brew, and doesn't compile software, or help you find lib-xyz for your Yubikey, but it is really fast and has a growing community behind it.
It works on MacOS, Linux, Windows and arm hosts to determine the correct download URL and pull in a binary.
[1] https://github.com/alexellis/arkade
Contributions are welcome.
Use Docker, probably. Homebrew is for your tools, not your dependencies. Is the system you're deploying to a Mac with Homebrew? Do all your collaborators use Macs with Homebrew? If the answer to either is no, why were you trying to use Homebrew for that in the first place, even if it were otherwise good for that? Would you use Homebrew to install Node modules for your project? Python packages? No? When why are you letting it define which version of PostgreSQL this project depends on?
Because right now https://brew.sh leads with "The Missing Package Manager for macOS", which would lead anyone to think it does the same as a package manager for Linux, and they're _full_ of developer dependency packages.
And for any cli tool that's also mission-critical, it can be run within Docker so I can pin it or keep it bleeding edge more easily.
For the important stuff, performance and ease of installation can take a side seat to stability.
If I had to use a Mac my solutions would be to alway use Docker, a virtual machine, or a remote dev environment of some kind.
Granted I don't work much with compiled languages anymore so I don't need to setup some complicated tool chain, but when I need to do that I usually go for MSYS2 or WSL when it has to be Linux.
apt/dpkg and any other package manager that scatters files all over the filesystem is just an absolute disaster that--if you do a lot of R&D tinkering--eventually renders a computer unusable after a few years. That's what happened to my first WSL instance; no apt command would work anymore because it had broken its own dependencies.
That was your experience. Mine is that after using apt for a lot of R&D tinkering for 3 years, everything runs fine. apt is global. Sometimes that's great and that's what you want. Sometimes it's not. Another way to keep that in mind is to think as apt as "bad at doing cleanup".
The thing is that you have to have a separation between things that you want on your system all the time, and things that you use for one or more projects. For the first, apt is perfect. For the second, usually that's where I use tools like nvm for node versions, languages package managers like npm, and also docker (which I use a lot for development databases).
For a backend JS project, I would install nvm, npm and docker globally, and then for the project I would use node through nvm with a .nvmrc, install packages locally with npm and use a package.json and package-lock.json, and run the development database with docker through a npm command, usually the latest PostgreSQL version. The link between the backend and database would be made with environment variables, because that's also what I use in production.
The difference between the global (apt) scope and the project (the rest) scope might seem like a failure of apt, but I personally see it as the difference between global and local scope in programming: both have their use, we separate them for a reason and we don't put the same things in them.
This is the craziest claim that I've ever heard about package management, I think
I would love to hear a more complete story
Homebrew is one of the slowest package managers I've ever used.
Ports have a long history from the BSD Unices and Macports keeps that ethos. It installs neatly in /opt and doesn't screw around with MacOS except in the approved ways (eg for Java and Python frameworks).
I still use Macports and it's had everything I've needed and when I hit bugs during the Big Sur beta, they were fixed quickly and directly, while still complying with Apple's beta policies.
I've dabbled with Nix, but it's a bit too* prescriptive for me.
I've tried the nix.dev installation + nix-darwin instructions 4 or 5 times but never make it very far.
Seems like I should generally prefer a multi-user install? Does nix-darwin play well with that?
As I supposed to `sudo -i nix-channel --add / update` or not use sudo? Is unstable the generally recommended channel? Do I use sudo with nix-darwin, since it's supposed to be kind of like NixOS / system-wide?
And then I usually give up, count my blessings for homebrew, and resolve to never again waste another 2 days trying to figure out nix.
Rinse and repeat in 1 month.
On my macOS computer, I don't have a multi-user install. Never had issues with it (but I also only just use one user account for everything).
Just tried running the nix-darwin installer, and it sets up some extra users as part of that anyway.
> Am I supposed to `sudo -i nix-channel --add / update` or not use sudo? Is unstable the generally recommended channel? Do I use sudo with nix-darwin, since it's supposed to be kind of like NixOS / system-wide?
Once you've got nix installed, in general you don't want to "sudo nix ...". Unstable is fine; but if things break, it's easy to rollback changes with Nix, so that you can use the versions which worked.
There's no need to start out with wrangling with nix-darwin. Just starting out with "nix-env --install --attr nixpkgs.<whatever>" will be closest to how homebrew is used.
Been running with homebrew for at least a decade since, and I cannot recall any negative encounter other than the hassle of grabbing xcode command line tools when I upgrade a major version of Mac OS, which is a minor detail.
I get the appeal of MacPorts & a dedicated separate package path but it caused all sorts of problems for me v. the integrated approach of homebrew.
O there was another negative now I remember -- had to uninstall brew version of MacVim & install manually. But that not a big issue either & typically, all of the brew packages are CLI only for me.
[1]: <https://rubenerd.com/using-netbsds-pkgsrc-everywhere-i-can/>
[2]: <https://news.ycombinator.com/item?id=27293108>
[3]: <http://www.pkgsrc.org/>
I wasn't able to immediately find any issue tracker for pkgsrc packages, and it seems they're a "mailing list and IRC" type setup, which if true means it definitely isn't for me
https://www.perkin.org.uk/pages/pkgsrc-binary-packages-for-o...
https://github.com/joyent/pkgsrc
Even on a system like that, many times when I interact with package managers like conda, it ends up compiling some huge package from scratch. I consider that a failure.
I instructed you, brew to install something. Not to spend an eternity autoupdating things.
Now, it's unusable.
export HOMEBREW_NO_AUTO_UPDATE=1
in my zshnev so long ago that I forgot about it, and just enjoyed a great product from a great community.Is it a bad default? Sure, probably, spooky-action-at-a-distance is not great. But it's just a default, if you don't like it, change it, one line of shell config is simpler switching distros.
1. Python has built in virtual environment support. python -m venv should do the trick. 2. Use docker for running Postgres, MySQL etc with some directory mounted for data.
EDIT: Personal PC is running NixOS not Windows.
Some other downsides:
- Nix installations can take time. Nix packages can either build from source, or download from a binary cache. If it's not in the cache, it will build from source.
- Nix can take up a significant of storage space.
However, e.g. Nix is amazing at rolling back package installs; and installing a package with nix won't ever break another package installed by nix.
If you like the phrases "pure/immutable", "declarative", "functional programming", etc. then you'll like Nix. -- If those words don't excite you, then you'll not like Nix.
HOMEBREW_NO_INSTALL_UPGRADE
If set, brew install will not automatically upgrade installed but outdated formulae
https://docs.brew.sh/Manpage#HOMEBREW_NO_INSTALL_UPGRADE (that's a fake hyperlink cause they don't put named anchors on their <li> for some reason)updated with an actual hyperlink: https://github.com/Homebrew/brew/blob/3.3.2/docs/Manpage.md?...
I don't want to have to keep updating brew just to keep from having to wait ever-increasing amounts of time when I want to install a new package or upgrade a specific one. I never have these issues with macports, and won't have them with nix.
Macports primarily for system level dep. use this whenever packages available.
Fall back to homebrew when not available on Macports. This includes brew cask which is unique.
This dual setup may requires you to carefully separating the 2 when installing and updating. I do this by installing brew in custom location (not /use/local) which is now the default on ARM. Also some shell functions that selectively control the environment (essentially I use an environment that only sees port to update port, vice versa.)
Lastly, conda for dev environments, mostly for Python stack. But it is also useful for other stuffs (conda is a cross platform package manager and in this sense it is similar to brew which also support Linux.) Obviously selections is not as broad comparing to brew.
On computing facilities, I used to use linuxbrew to install some “system” dependencies that’s missing, including zsh, mosh, tmux, tree, etc. But obviously I cannot install in the recommended path by brew, which means compiles from source. And it is not robust (and they also say this is not a supported pattern.) I now use conda for this and is very robust (conda uses a hack to install precompiled binaries to arbitrary prefix.)
I didn't dig into the process for a user to add their own ports, or share new ports with a team, in order to more fully compare the two packagers, but that ticket stood out to me
Use Homebrew only for tools and not for critical services like databases and use a cloud server or local virtualization like VMware Fusion (which is free these days for personal use) to run services because major distro packages have far more eyes to check for stability issues.
I never understand people trying to run every parts of the development environment through a local machine's third party package managers which would forbid anyone else being able to check your work right then as you're only running it as localhost, not to mention the power can be down at any moment you're not using your machine and you can't even switch machine yourself to work from easily.
And then when deploying, you'll be running it on Linux anyway which would likely bring little consistency issues.
Do yourself a favor, either spend $5/mo for a cloud Linux and run your stuff remotely or run a locally virtualized Linux and stop using third party package managers no one is using to run on production.
And you can happily keep Homebrew and also install Homebrew on Linux to have unified tool sets on your Mac and Linux CLI tools.
Personally, I find that the whole Homebrew "theme" where every command/thing is named after something alcohol/brewing-related (cask, bottle, formulae, tap, keg, etc) is a huge turnoff.
I hate it, but Anaconda might work too, so long as it's not a corporate laptop where you need a license.
- Homebrew is rolling - always was and never claimed otherwise.
- OTOH for key packages (say databases) it has available versioned bottles. for postgresql one have:
- postgresql@10
- postgresql@12
- postgresql@9.4
- postgresql@9.6
- postgresql (points to latest)
- postgresql@11
- postgresql@13
- postgresql@9.5
- Finally, no one is forced to update everything at all.
run `brew outdated` and pick whatever you want updated then `brew update foo`...In short, none of what happened to the OP is due to inherent flaws in homebrew... QED.
why are you being this hostile while being completely wrong?
It is my first choice since a while and if it's not there I go to homebrew
Check [2] https://pkgsrc.se/ before, to see if the availability and the 'freshness' of packages fits your needs.
edit:
[3] http://pkgsrc.joyent.com/install-on-osx/ if you don't want to compile and have binaries instead.
Try:
python -m venv
To fix the very real issue you describe, I would like to see a --isolate option for mission critical packages. All the dependencies would be contained in a separate, package specific directory within /opt or /local. The rest of the dependency management could happen without affecting the isolated package.
- Python already includes the venv module, you don't need to install anything, just run `python -m venv <venv_dir>`
- You should manage multiple versions with pyenv instead of brew. Pyenv can be installed with brew.
not optimal, but sadly necessary.
Here are some arguments why it may be worth it this time :)
EDIT: for me this is a minor issue. i'll continue using `brew` as it does the job quite well
If you forget to include the extensions, you can add them all later.
Also, I'm 100% certain all it did was update the formulae (similar to apt-get update, NOT apt-get upgrade).
I've been using homebrew for years and this is the default behavior, so unless you purposefully set it up to upgrade everything this is PEBKAC.
AFAIK the only time it upgrades everything is when you do a blanket `brew upgrade`. And if you're pinned to something like postgresql@10 it will stay at that major version.
python -m venv /my/directory
I’ve never had any problem with homebrew in over a decade’s usage. But yes, don’t use it for python development tooling: use pyenv and python -m venv and pip for that.brew install pyenv pyenv install 3.9.7 cd ~/myproject pyenv local 3.9.7 python3.9 -m venv --upgrade-deps .venv source ./.venv/bin/activate
You're off to the races. (I think I got that --upgrade-deps flag right.)
Pyenv builds all of my python versions. Pipx installs cli tools in their own env.
Precommit is also great for much more than just pre-commit hooks. It can install tools used for hooks in their own cache, no need to manage venvs yourself.
Just wondering.
My experience has been that very, very rarely is any installation as straightforward as "curl && ./configure && make PREFIX=whatever install", partially due to everyone in the known universe thinking they need some awesome new build system, partially due to unknown dependencies and their versions, partially due to it usually needing some patches because they only build on the author's machine, and all of that is just noise when I just want to have something running
The value of Homebrew to me are the constantly bumped formulae descriptors, definitely, 100% NOT the "brew" frontend for it. So, I've found a nice middle-ground by switching Homebrew into developer mode and neutering its bottle system and using "--build-from-source"
This isn't necessarily to lobby you, as much as "for your consideration" and to raise awareness for others that one need not throw the baby out with the bathwater just because the brew frontend is user-hostle