top | item 43765011

Sapphire: Rust based package manager for macOS

443 points| adamnemecek | 10 months ago |github.com

290 comments

order
[+] alexykn|10 months ago|reply
Hey, so I built this thing, most of it at so far at least. And yeah, right now it isn't doing many things better than Homebrew.

Setting of relative paths for bottle installs is still not perfect, well it works for every bottle I have tested except rust. Getting bottles working 100% is very doable though imo.

Build from source formulae is still pretty f*ed + I do not know if it is really feasible given that the json API lacks information there and a full on Ruby -> Rust transpiler is way out of scope. Will probably settle for automatic build system detection based on archive structure there. + Maybe do my own version of the .rb scripts but in a more general machine readable format, not .rs lol

Casks seem to work but I have only tested some .dmg -> .app ones and .pkg installers so far though. As with bottles 100% doable.

Given that almost all formulae are available as bottles for modern ARM mac this could become a fully featured package manager. Actually didn't think so many people would look at it, started building it for myself because Homebrew just isn't cutting it for what I want.

Started working on a declarative package + system manager for mac because I feel ansible is overkill for one machine and not really made for that and nix-darwin worms itself into the system so deep. Wrapping Brew commands was abysmally slow though so I started working on this and by now I am deep enough in I won't stop xD

Anyway I am grateful for every bug report, Issue and well meaning pull request.

[+] godelski|10 months ago|reply
This is awesome!

Is there uv support?[0]

One of my biggest gripes about brew is how they manage dependencies. The devs have a conflicting philosophy that creates bloat. Package maintainers must define settings, settings should always use the latest Python version. It makes no sense. Maintainers won't update unless things break so you got a bunch of Python versions running around. And it won't use system Python!

Uv seems to provide an elegant solution for this. You can build a venv for each package and rust version will only have the specified deps. Since uv finds all your Python instances (and packages) and soft links them you have way less bloat and venvs become really useful. You can also use run and other tools to handle executables

Plus is also rust so good synergy ;)

[0] https://astral.sh/blog/uv

[+] samhclark|10 months ago|reply
You mentioned a declarative package manager for Mac. I've really liked using Homebrew Bundle [1] over the last couple years. It's about the level of declarative that I've wanted and has made it really easy to bootstrap new laptop or VM (since it also works on Linux). The format for a Brewfile was pretty easy to figure out.

The way I ended up using it was that `brew install` would temporarily install something, without adding it to my Brewfile. And a little `brew add` wrapper would add the package to my Brewfile to keep it on the system permanently. That part with the wrapper could have used some love and would be a nice fit for a new brew-compatible frontend IMO. Maybe you could expand on that for Sapphire, if that also scratches your declarative itch?

[1] https://docs.brew.sh/Brew-Bundle-and-Brewfile

[+] jrochkind1|10 months ago|reply
What makes you interested in a rust implementation of brew?

I'm guessing it's that you hoping that it is eventually more performant -- are there specific areas of current brew you have identified as performance bottlenecks likely to eventually benefit from a rust implementation?

Or any more info to share about assumptions/hopes that motivated this or any other motivations?

[+] Scramblejams|10 months ago|reply
Cool project, good luck with it!

If I may surface one use case: Several years ago I had to manage a bunch of Macs for CI jobs. The build process (Unreal's UAT) didn't support running more than one build process at a time, and Docker was really slow, so I'd hoped to use different user accounts to bypass that and get some parallelization gains. Homebrew made that very difficult with its penchant for system-wide installs. So a feature request: I'd love to see a competitive package manager that limits itself to operating somewhere (overridable) in the user's home directory.

[+] 3np|10 months ago|reply
> probably settle for automatic build system detection based on archive structure there

Please add knobs for the end user to manually configure this per package and global default before adding autodetection. As a user to is very frustrating to have to patch the package manager to override some well-intentioned automagic which didn't consider my setup or dig through sources to uncover some undocumented assumption. yarn is a cautionary example.

[+] miki123211|10 months ago|reply
> Build from source formulae is still pretty f*ed + I do not know if it is really feasible given that the json API lacks information there and a full on Ruby -> Rust transpiler is way out of scope. Will probably settle for automatic build system detection based on archive structure there. + Maybe do my own version of the .rb scripts but in a more general machine readable format, not .rs lol

Last I checked (which was about a year ago), Homebrew had ~7000 formulas (not including casks).

I think it would be feasible to transcribe most of them to your format of choice with AI, run the build in a loop and ask the LLM to fix errors, and reserve manual intervention for the few cases that the LLM can't fix.

[+] stevage|10 months ago|reply
Does the "casks" and "bottles" language imply that it's intended be compatible with Homebrew? That isn't made explicit in the description.
[+] AlphaSite|10 months ago|reply
Can you just shell out to homebrew for unsupported cases? I don’t imagine the overhead of ruby will be that high compared to compiling the code.
[+] internet2000|10 months ago|reply
Good luck. Homebrew hasn't cut it since they started disallowing custom compile flags, and making the user jump through hoops if they want anything slightly different.
[+] woodruffw|10 months ago|reply
With my Homebrew hat on, but not speaking for others: I think this is pretty cool, and demonstrates something that we've discussed indirectly for years.

At its core, there are really two parts to Homebrew:

1. There's the client side, i.e. `brew`, which 99.9% of users stick to happy paths (bottle installs, supported platforms) within. These users could be supported with relative ease by a small native-code installer, since the majority of the work done by the installer in the happy path is fetching bottles, exploding them, and doing a bit of relocation.

2. There's literally everything else, i.e. all of the developer, repository, and CI/CD machinery that keeps homebrew-core humming. This is the largely invisible infrastructure that makes `brew install` work smoothly, and it's very hard to RIIR (in a large part because it's tied heavily to the formula DSL, which is arbitrary Ruby).

(1) is a nice experimental space, because Homebrew does (IMO) a decent job of isolating the client-facing side from the complexity of (2). However, (2) is where the meat-and-potatoes of packaging happens, and where Homebrew's differentiators really lie (specifically, in how easy it is to contribute new packages and bump existing ones).

Edit: Another noteworthy aspect here around performance: I mentioned this in another comment[1], but parallel downloads of things like bottles and DMGs is not an architectural limitation of Homebrew itself, but instead a conscious decision to trade some install speed for courtesy towards the services we fetch from (including GitHub itself). Smaller projects can sidestep this because they're not directing nearly the same degree of volume; I think this project will discover if/when its volumes grow that it will need to serialize downloads to avoid being throttled or outright limited.

[1]: https://news.ycombinator.com/item?id=43765605

[+] chrisweekly|10 months ago|reply
> "it's very hard to RIIR"

RIIR - "Rewrite It In Rust" (maybe obvious in context? sharing in case not)

[+] xiphias2|10 months ago|reply
It's not _just_ the infrastructure that is awesome for homebrew. The help I got from the team, answering in real-time when I didn't know how to get through the CI bugs is amazing. It's the boring maintainence work that makes it so special for me.

I also feel that there could be a lot of automation in the backend part, catching bugs early (maybe even on local machine before CI run) for example.

[+] fastball|10 months ago|reply
Yeah, to me the language (ruby) has nothing to do with the success of Homebrew, it is entirely about the DX around backend packaging. The main reason I switched from MacPorts to Homebrew back in the day is because when a new version of [insert software here] was released, I could expect the brew package to be updated within days. MacPorts always lagged significantly behind, and oftentimes didn't have certain packages at all.
[+] IshKebab|10 months ago|reply
> but parallel downloads of things like bottles and DMGs is not an architectural limitation of Homebrew itself, but instead a conscious decision to trade some install speed for courtesy towards the services we fetch from

That doesn't make sense. As you say you're directing a huge volume of traffic so it makes no difference exactly when a user downloads a byte. It all gets smeared out. Only the total amount of data matters and that is unaffected by parallelism.

[+] mort96|10 months ago|reply
This looks like a fun little project, nice work!

I'm not a big fan of keeping the Homebrew terminology though. I never know what a formula, keg, cask, cellar, tap or bottle is. Why not keep to the standard terms of package and repository etc? I don't know beer brewing terminology or how beer brewing is analogous to package management, and I honestly wish that it wasn't something which my tools expect me to learn.

[+] larusso|10 months ago|reply
I was a macports user but had to switch to homebrew because most new projects went there and it was generally easier to write Formulars etc. But I never really liked the project. I think writing a new package manager on top of brew infrastructure won‘t create a better setup. I don‘t know if all casks and Formulars only use the DSL stanzas or if still some use custom ruby functions and helpers. Because otherwise this new tool might need to eval ruby scripts for backwards compatibility.
[+] ARandomerDude|10 months ago|reply
Suggestion: create a Goals/Motivation/Rationale section in the README. What are the problems with Homebrew you're trying to solve? Why should a prospective user install and try this tool instead of staying with Homebrew?
[+] selkin|10 months ago|reply
Homebrew sure has room for improvement, as most software does, and I appreciate every effort to replace and renew what we have with something better. But my own grievances with Homebrew isn't with the codebase itself.

What discourages me from using Homebrew is the intent and the mindset of its developers and packagers, who, I think, see their goal building an "unstable" distribution, as Debian defines it: "[a distribution that] is run by developers and those who like to live on the edge".

I am not blaming the Homebrew developers for building a Sid rather than Bookworm. Some people want just that. Heck, I used to run Debian Sid myself, but have lost my patience for maintaining my own computers since: I am kept busy enough by fixing the software I write, I don't want to spend more time fixing software I did not.

[+] frollogaston|10 months ago|reply
I mainly disagree with the Homebrew stance on sudo/root. They claim it's better to install everything under a user dir, but 10% of the time that doesn't work for whatever reason, and tons of users have screwed up their permissions trying to fix it. No other package manager has this issue.
[+] jamesgeck0|10 months ago|reply
If I understand correctly, running a Debian-style stable repo would essentially require forking all distributed software and backporting security fixes to them.

With many macOS users coming from a different communities than Debian users, I really wonder how well that would go over with the folks whose software was being distributed.

[+] kccqzy|10 months ago|reply
There are rolling distros on Linux that are remarkably stable. My current Linux distribution openSUSE Tumbleweed is one. And on macOS you already have an immutable system partition that provides a stable base to build on top of, so I fail to see the value proposition of a package manager on macOS that's deliberately slow.
[+] mrbonner|10 months ago|reply
I used to be a big fan of Homebrew but switch to Nix about 2 years ago. For the most part, it works great with home manager for me. Many tools can be installed with breeze just like breeze albeit a bit quicker. The critical thing for me is that Nix doesn't polute my Mac environment like Brew does. But, I admit that this is just for tools. For dev environment I usually just fall back to the language specific methods like cargo, uv or npm.
[+] KingMob|10 months ago|reply
Funny, I gave up on nix-darwin recently after a year, and went back to homebrew.

Trying to manage nix was more work than I wanted to do.

[+] nicce|10 months ago|reply
Some GUI-based applications tend to require too much hassle with Nix so I personally install those with brew. But I still use home manager on top of everything.
[+] alexykn|10 months ago|reply
Anyway, please do not expect progress to be too rapid. I have a full time job and do most work on this on weekends. I fully intend to make it a stable, "finished" (as much as this is possible in software) thing, it will take a while though. If anyone want's to help out I do open the bugs I find as Issues to keep track and give people an idea of things that do not work. Good Night!
[+] whywhywhywhy|10 months ago|reply
Consider rebranding to a 4 letter name or even better a 3 letter one.

I know it sounds dumb but uv was smart to go shorter than pip and sapphire feels heavier than brew no matter what it does after typing that.

[+] fastball|10 months ago|reply
The name of the project doesn't need to be the same as the CLI, e.g. Homebrew -> brew.

This could be Sapphire -> sap

[+] alexykn|10 months ago|reply
I know, probably will, also feel typing out sapphire for the command all the time is annoying + sapp would be weird. For me technical implementation comes first though. I'll do that when something comes to mind
[+] jdeaton|10 months ago|reply
Yeah i vote it should be rebranded “why”
[+] TriangleEdge|10 months ago|reply
In my experience, rewriting software doesn't work. You should replace the components iteratively in Homebrew itself if you want your ideas to succeed. I doubt your software will see any major adoption just because you wrote it in some other language. The word Homebrew is culturally significant in hacker groups as well and sapphire is not.
[+] hnarayanan|10 months ago|reply
I’m really happy with my MacPorts.
[+] cantrecallmypwd|10 months ago|reply
This isn't a HB replacement, it's just using HB binaries. It doesn't replace HB at all. HB and this aren't full package managers when they don't officially or technically support building from source or working independently of another project's infrastructure.

A decent full package manager would support a simple, shell-like DSL like say Alpine or Arch, concurrent and parallel phases (such as downloads/builds/installs), multiple versions, reproducible builds, building from source, build acceleration, security auditing, patch management, and package cryptographic signatures (not hashes or signing of hashes).

Nix is theoretically amazing but the barrier-to-entry and gotchas for popular use make it self-limiting. Simplicity in particular areas is a price that is often paid for popularity.

[+] maartn|10 months ago|reply
Please give it an easier command name than ‘sapphire’ if you want to win people over to use it. Double in size and three times as hard to remember (or type) than ‘brew’. Even cli peeps are still just people
[+] hk1337|10 months ago|reply
I wish homebrew was a little more friendly to installing in a directory other than what the installer sets. I used to have a lot of permissions issues back when /usr/local was the only directory and none since I started installing it in ~/.brew
[+] rewgs|10 months ago|reply
Really glad to see that someone has started on a Mac package manager written in Rust.

A couple purely superficial suggestions (echoing some other comments here):

- Lose the Brew terminology, especially if the name of the project isn't a synonym of "brew." - Change the name in general. "Sapphire" makes me think of "Ruby." IMO the obvious name is MacPac :p

[+] commandersaki|10 months ago|reply
If this provided support for multi-user setup without the user switching gymnastics of homebrew, then I'd be interested.
[+] benatkin|10 months ago|reply
FWIW the author of Homebrew is also working on a next generation package manager in rust: https://pkgx.dev/ (beware facebook tracking and infinite AI slop)
[+] woodruffw|10 months ago|reply
Creator, not current maintainer. Homebrew is currently maintained by over a dozen people, myself included.
[+] joshuaturner|10 months ago|reply
Oof. Those AI images really harm the credibility of the package manager.
[+] no_wizard|10 months ago|reply
What’s the deal with the cautious warnings? Is homebrew being replaced by software developed using a “vibing coding” or what have you?