A Barrel of This • Blog

I've got a barrel of this. What do I do with it?

2010
Sep 30th

Homebrew-Package management for Mac OS X

Unfortunately for me, every once in a while I have to worry about software dependencies. The issue crops up every year or so when there is either a security patch that we (work) need to install or an upgrade we want to attempt. As I get older I’ve become slightly less enthusiastic about upgrading often or at least upgrading quickly. So it was with some trepidation that I removed MacPorts from my MacBook Pro today and decided to give Homebrew a shot.

The good news: It pretty much works for me.
The bad news: It pretty much failed for me within a few hours of installing it.

Failed may be a bit harsh. At work we use a specific version of mysql and that version is compiled with specific options that we require. Homebrew doesn’t make it immediately obvious how you go about requesting a specific version of a package nor how you specify any options for the package when it is built.

I’m not going to bother going over the basics of getting Homebrew up and running as there are already a number of resources for such things. Dr. Google is your friend (or Dr. Bing, or whomever you visit when you are in need). But I will share how to get a Homebrew formula (the recipe for building packages) to do what you want in a few simple steps.

Altering a Homebrew recipe

At first I thought it might be necessary to fork the git repository of homebrew or at least make a fork, branch, or copy of the mysql.rb formula. But, that would have been a lot of overhead for simply altering some build options. Also, the specific set of options I need are probably only relevant to me on this particular project. They certainly would not be the correct options for everyone.

To alter the options one can simply edit the Ruby formula file in brew --prefix/Library/Formula. If you installed Homebrew into /usr/local (which the authors make quite clear that they would very much like you to do) then the path would be: /usr/local/Library/Formula. For example, to edit the mysql build options:

vim `brew --prefix`/Library/Formula/mysql.rb

Look for the array of configure_args. Edit them to your heart’s content.

brew uninstall mysql
brew install mysql

Done! In my case in step two I changed the —with-plugins option to supply the plugins that my mysql install requires.

Alternatively, you could also make a copy of mysql.rb (I actually made a copy of the file myself before editing away). In that case you’d just need to change the class declaration at the top of the file. For example, if you name the file mysql-myCompany.rb then on line 3 you’d change:

class Mysql <Formula 

to

class MysqlMyCompany < Formula 

To ensure your new formula is in place run:

brew info mysql-myCompany

To finish it off you’d need to:

brew uninstall mysql
brew install mysql-myCompany

My sentiment is this: You own the formula directory. It’s on your hard drive, is it not? Do with it as you please.

The drawback of course is that when updating homebrew there may be a conflict on the file or it may just be replaced. I’m hoping since it is just git underneath that the brew update command will give me some way to reconcile the problem. Maybe I’m blindly optimistic. But as I mentioned you can always create your own file if you are concerned.

There also appears to be a HOMEBREW_LIBRARY_PATH environment variable that you could set to temporarily use your own Library and the formula within. Haven’t tried that yet but it is definitely worth a look. Especially if you just want to create your own formula and test it out before embarking on contributing to the de-facto Library.

launchctl is persistent

There were a few nasty issues for me after installing mysql. First, the instructions helpfully provide the command for adding mysql to launchctl so that OS X will start mysql when you boot:

launchctl load -w /Library/LaunchAgents/com.mysql.mysqld.plist

Unfortunately, launchctl will start mysql AND attempt to keep mysql running come hell or high water. It only throttles back its attempts to every 10 seconds. Before you get excited and add mysql to launchctl you want to run the first command in the instruction list:

mysql_install_db

Otherwise mysql will fail to start up and launchctl will dutifully fill your logs with attempts at restarting mysql until you fix the problem. This also comes into play if you’ve adjusted the build options and reinstalled mysql. Again launchctl won’t relent. I would have guessed that launching launchctl and issuing the stop command would have stopped mysql. It does but, then launchctl starts it right back up again. To get out from under launchctl’s, um, ctl you have to unload the plist:

launchctl unload -w ~/Library/LaunchAgents/com.mysql.mysqld.plist

After that I ran:

mysql_install_db --rpm

That’s the “internal use” option that “is used by RPM files during the MySQL installation process.” It might be nice is the mysql formula could run this command for you after a new install. I’d wager that I’m not the only one to perhaps miss a command in the output of an installation. Anyway, it is my own fault for getting in this bind but, those are some tips on how to get out of a similar situation.

Did my options take?

For my install case since I was altering the plugins that mysql compiles and enables I needed to show the list of plugins to be sure they had installed:

mysql> show plugins;
+------------+----------+----------------+---------+---------+
| Name       | Status   | Type           | Library | License |
+------------+----------+----------------+---------+---------+
| binlog     | ACTIVE   | STORAGE ENGINE | NULL    | GPL     |
| partition  | ACTIVE   | STORAGE ENGINE | NULL    | GPL     |
| ARCHIVE    | ACTIVE   | STORAGE ENGINE | NULL    | GPL     |
| BLACKHOLE  | ACTIVE   | STORAGE ENGINE | NULL    | GPL     |
| CSV        | ACTIVE   | STORAGE ENGINE | NULL    | GPL     |
| FEDERATED  | DISABLED | STORAGE ENGINE | NULL    | GPL     |
| MEMORY     | ACTIVE   | STORAGE ENGINE | NULL    | GPL     |
| InnoDB     | ACTIVE   | STORAGE ENGINE | NULL    | GPL     |
| MyISAM     | ACTIVE   | STORAGE ENGINE | NULL    | GPL     |
| MRG_MYISAM | ACTIVE   | STORAGE ENGINE | NULL    | GPL     |
+------------+----------+----------------+---------+---------+
10 rows in set (0.02 sec)

The second plugin, partitioning support, was the one the schema required.

Using what Apple gave you

The creators of Homebrew intend for you to leverage the software already installed by Apple into /usr/bin, /usr/lib/, etc. I have a slight misgiving with this philosophy in that Apple very rarely updates some key components. For example, sqlite3 comes installed by default by Apple. However, the version on my MacBook Pro is 3.6.12. Using MacPorts I was up to version 3.6.23. With no offering from Homebrew I’m left to either install it directly or create my own formula, submit it, and hope that it is accepted by the Homebrew team and that the lack of an existing formula was just an oversight (reasonable possibility given that mysql is there). Still a package that is used by default by every Rails install not being present in the library gives me pause. On the other hand the Formula Cookbook does explain which formula will not be accepted and does list some notable exceptions (libpng, libxml2) since the versions provided with OS X have problematic bugs.

I don’t think the Homebrew philosophy is wrong. To the contrary I feel that Apple is a bit lazy in not having provided something like Homebrew in the first place. Pretty much every Linux distribution offers some sort of package manager. Also, Homebrew is smart enough to point folks in the right direction for packages that are provided by Apple but that nearly everyone is surely going to want to upgrade such as Ruby. Homebrew has a formula for Ruby 1.9.2 but they wisely advise: “Consider using RVM or Cider to manage Ruby environments” and provided links to those two management systems.

What could Homebrew do?

My top feature requests would be: * Provide a migration path from MacPorts and Fink to Homebrew. * A way to accomplish the above might be to just accept a package manifest. Essentially a list of packages to install that already includes all of the dependencies (though dependency checking up front would be an added bonus) and is a complete list that if installed would result in a working system at the end. I’m considering upgrading my laptop and one of the tasks I’m not looking forward to is installing everything I need to do development again.

blog comments powered by Disqus