Before Bundler came to save us all from dependency hell, it was pretty common to check in specific versions of plugins and gems into a Rails app’s vendor directory. Unfortunately, due to our flawed nature as mortal developers, the temptation to make that one little change directly in the vendor’d code sometimes proved to be too great to master.

The result: forked and frozen code whose change history is deeply integrated into the entire project’s history, making upgrading nearly impossible.

But with Bundler and its integration with git there’s little reason for this. Your app can depend on your own private version of the gem. If you’re a good open source citizen, having a separate gem will make it easily to contribute your changes back.

Checkout this Gist for how to extract a plugin (in this case active_shipping) and preserve its changes. [One of these days I just need to move my blog over to GitHub and be done with it… but I digress…]

If your codebase is like mine was, the first commit included both the initial plugin import and a bunch of changes. If that’s the case, you’ll probably have some conflicts to resolve. But if you’re hear, hopefully you know how to do that.

Also, you might take the chance to rewrite your history to remove references to project specific things in comments so that when you push changes to the public gem the authors don’t have to pick through the accumulated history of years of your project’s secret-garden-development. Again, that’s something left to other tutorials.

Anyway, the most amazing part to me was git-filter-branch, which I learned about in this Stack Overflow question. A word of warning though: this tool can have some sharp edges. I think Patrick Thomson said it best: “filter-branch really should be renamed to nuclear-chainsaw considering how dangerous and powerful it is.

Advertisements

Ever had one of those problems that makes you feel like a complete idiot? You tinker and tinker and it’s still there. You recreate an entire configuration file from scratch trying to figure out the exact point where everything goes haywire.

Sorry, I should rephrase that first sentence: the solution makes you feel like an idiot.

Often the culprit is a misspelled variable or filename (which looked right every one of the last hundred times you looked at it!). The worst is when you realize you’ve been looking at cached content the whole time or the system has been running a stale version of your code for some reason.

Facepalm.

We prideful IT-types usually move onto the next problem grumbling excuses and muttering curses, but not me! Not this time! I will help my fellow human beings who are desperately Googling for a solution!

So here’s what happened to me recently. I’ve been hacking on Github’s wonderful Gollum git-based wiki. As it is, Gollum is setup to run using a `bin/gollum` script. Nice for someone poking around with the project, but I wanted something that worked nicely with Capistrano and Passenger.

I extracted what I thought was a reasonable config.ru from the bin/gollum script:


require 'rubygems'
require 'bundler'
Bundler.require(:default, ENV['RACK_ENV'].to_sym)

options = {}
wiki_options = {}

require 'gollum/frontend/app'
Precious::App.set(:gollum_path, "wiki_data.git")
Precious::App.set(:wiki_options, wiki_options)

Precious::App.run! # <- SPOILER ALERT: this is what's wrong

What happened when I started this up? The damnedest thing: Passenger was trying to spin up WEBrick!


[Mon Mar 14 07:16:00 2011] [notice] Apache/2.2.16 (Ubuntu) Phusion_Passenger/3.0.5 configured -- resuming normal operations
[2011-03-14 07:16:07] INFO  WEBrick 1.3.1
[2011-03-14 07:16:07] INFO  ruby 1.9.2 (2011-02-18) [x86_64-linux]
[2011-03-14 07:16:07] INFO  WEBrick::HTTPServer#start: pid=30305 port=4567

What’s going on here? Is it a problem with Passenger? Apache (also tried Nginx)? Rack? Sinatra? Gollum? So many components!

Well, of course it’s my fault. You see, here’s the documentation for `Sinatra::Base.run!` (`Sinatra::Base` is, of course, the superclass of `Precious::App`, Gollum’s default frontend):

Run the Sinatra app as a self-hosted server using Thin, Mongrel or WEBrick (in that order)

So, it turns out `run!` is not just a convenience method for Rack::Builder#run… It actually tries to spin up a self-hosted server. Which is how I ended up in the bizarre situation of Passenger trying to start another server on port 4567.

Duh.

For reference, here’s the working config.ru:


require 'rubygems'
require 'bundler'
Bundler.require(:default, ENV['RACK_ENV'].to_sym)

require 'gollum/frontend/app'
Precious::App.set(:gollum_path, "wiki_data.git")
Precious::App.set(:wiki_options, {})

run Precious::App