Lost in Code.

Homebrew.

I wanted to install the Ultraviolet gem, which gives you the ability to syntax-highlight code using Textmate syntax files through the Textpow gem. However textpow in turn depends on Oniguruma (a regex engine that happens to be more efficient than Ruby's built-in version). However, if you install Onigurama you will probably get a bunch of compilation errors and something about not being able to find oniguruma.h. This is because installing the gem only installs the Ruby bindings, but that assumes you already have the Oniguruma header files installed.

So I course need to do that, and I'm faced with the choice: do I a) compile it from source or b) use a package manager like MacPorts or Fink?

On Linux, of course, this is a no-brainer: apt-get install and you're done.

On Mac, neither option is really great. You can compile from source, but if the library has dependencies, you have to install those too, and then what if you want to uninstall it at some point? Good luck with that.

Okay then, what about MacPorts or Fink? Well, the problem with MacPorts is that it insists on installing everything from scratch. If you already have, say, Perl on your system (and you do), well, tough cookies, because it's going to install its own. I remember I tried to install Ghostscript one time and ended up with 15 different other packages. This gets to be unbelievably annoying. Fink is better, but they don't have every package that Debian does (naturally), and anyway, trying to shoehorn a Debian-like package management system into the Mac OS environment just seems kinda weird to me, like trying to mix oil and water.

Enter Homebrew

Homebrew appealed to me because it's so incredibly simple and flexible. Engine Yard has a good writeup here, but basically it's like MacPorts in that nobody hosts any packages -- when you install Homebrew you just install a collection of Ruby files ("formulae"). When you install a package, Homebrew finds its formula and executes the instructions therein, downloading the source and compiling it according to the formula. Where does Homebrew get the source? If you scan through some of the formulae, you'll notice that most of them come from tarballs at public URLs. However, the cool thing is that Homebrew also lets you download source from a git, svn, hg, or other repository. Evidently, this means the packages where this applies, Homebrew lets you upgrade simply by hitting the repo again.

I think the biggest thing I like about Homebrew, though, is this:

[It] doesn’t dupe stuff that comes with OS X or stuff that is provided by RubyGems, CPAN or PyPi.

Hal-le-lu-jah. I thought I would never see the end of that.

So, I'm sure that Homebrew is not perfect since it is still a maturing project, but it seems like a worthy alternative to the madness that is MacPorts or Fink.

Installing Homebrew

Normally I'd be able to follow the instructions in the wiki, but there are a few extra things that I had to do. First, Homebrew places everything in /usr/local. That's not a big deal if you don't have anything already there, but I have a few things that are, such as Ruby and MySQL. Second, Homebrew recommends you do not use sudo to manage packages. The reasoning is that you probably use it without thinking about it, and you don't need root access to install programs anyway, so why bother? I saw someone say the same thing the other day, and it's probably true. sudo was designed for multiuser setups; if you're the only person that uses your computer then it's probably not doing anything to increase safety.

Even with all that it was incredibly easy to install Homebrew. So here's a little walkthrough of what I did.

Getting ready

First we remove MacPorts:

$ sudo port -f uninstall installed
$ sudo rm -rf \
  /opt/local \
  /Applications/DarwinPorts \
  /Applications/MacPorts \
  /Library/LaunchDaemons/org.macports.* \
  /Library/Receipts/DarwinPorts*.pkg \
  /Library/Receipts/MacPorts*.pkg \
  /Library/StartupItems/DarwinPortsStartup \
  /Library/Tcl/darwinports1.0 \
  /Library/Tcl/macports1.0 \
  ~/.macports

Then Fink:

$ sudo rm -rf /sw

As for the stuff in /usr/local, we can just move it out of the way:

$ cd /usr
$ sudo mv local local.old

Moving /usr/local caused a few problems so let's deal with them now. The immediate problem is that upon opening a new bash session I get an error since ~/.bash_profile is failing to load (it depended on the GNU version of ls which I'd also had installed to /usr/local). So let's get that out of the way:

$ mv ~/.bash_profile ~/.bash_profile.old

Re-creating /usr/local doesn't matter since the Homebrew installation script will do that for us.

Fixing RubyGems

I am back to a stock Ruby installation since my custom Ruby was previously in /usr/local. So, I need to upgrade RubyGems, which is woefully out of date:

$ which gem
/usr/bin/gem
$ gem -v
1.0.1

Yikes.

$ sudo gem update --system
$ gem -v
1.3.6

Much better ;)

I also want RubyGems to install any executables that may come with gems to /Library/Ruby/Gems/1.8/bin instead of /usr/bin. We can do this by placing gem: -n/Library/Ruby/Gems/1.8/bin in our ~/.gemrc file (it's just a hash represented in a YAML file; gem is the key in this case). Then, we need to make sure to add /Library/Ruby/Gems/1.8/bin to our PATH.

Homebrew time

I think that's all. Let's install Homebrew! To do that, simply copy the recommended script, paste it into a file, and run it (remember though: not as root!).

Okay, let's try out some packages:

$ brew install readline
$ brew install git
$ brew install wget

Impressive! I notice that I keep getting a warning about XCode needing to be upgraded to 3.1.4, but it doesn't seem to matter, so I don't worry about it.

Here's one that was pretty painful with MacPorts:

$ brew install imagemagick

Oh man. It caught the dependencies (libjpeg, libgd, libwmf, libtiff, and jasper) automatically without installing a crapload of other things too. I love this thing already.

Fixing MySQL

I realize that MySQL had been in its own directory before, /usr/local/mysql. So I find I can simply move that over to the new /usr/local:

$ mv /usr/local.old/mysql /usr/local

The mysql client program will complain because it can't read or write to the database so we need to do:

$ chown -R mysql:mysql /usr/local/mysql

Installing coreutils

One of the essential things I needed immediately was GNU coreutils (because I'm used to GNU ls options). So I simply reinstalled it:

$ brew install coreutils

However, it told me to then run brew install coreutils --aliases > ~/.bashrc. I found that didn't work, so if you install this too, DON'T DO THAT!! Besides, what this will do is add lines like

alias ls="/usr/local/bin/gls"

which I put in ~/.bash_profile, but it didn't work for some reason. So I decided to install symlinks instead. Because I don't want to muddy up /usr/local/bin this time around, I opted to install them to ~/.bin, and then add ~/.bin to my PATH. Then I ran:

for command in base64 basename cat chcon chgrp chmod chown chroot cksum comm \
cp csplit cut date dd df dir dircolors dirname du echo env expand expr factor \
false fmt fold groups head hostid id install join kill link ln logname ls \
md5sum mkdir mkfifo mknod mktemp mv nice nl nohup od paste pathchk pinky pr \
printenv printf ptx pwd readlink rm rmdir runcon seq sha1sum sha224sum \
sha256sum sha384sum sha512sum shred shuf sleep sort split stat stty sum sync \
tac tail tee test touch tr true tsort tty uname unexpand uniq unlink uptime \
users vdir wc who whoami yes "["; do
  ln -s "/usr/local/bin/g$command" "$command"
done

Back to it

If you recall we were trying to install the Oniguruma gem. First let's try installing Oniguruma proper. Do we have it?

$ brew search oniguruma
oniguruma

Yes indeedy. Let's do it:

$ brew install oniguruma
==> Downloading http://www.geocities.jp/kosako3/oniguruma/archive/onig-5.9.1.tar.gz
######################################################################### 100.0%
==> ./configure --prefix=/usr/local/Cellar/oniguruma/5.9.1 --disable-debug --disable-dependency-tracking
==> make install
/usr/local/Cellar/oniguruma/5.9.1: 9 files, 800K, built in 25 seconds

Lovely! Now the moment of truth:

$ gem install oniguruma
Building native extensions.  This could take a while...
Successfully installed oniguruma-1.1.0
1 gem installed

And that, my friends, is why you should use Homebrew.

Resources