Setting up rubygems without root access

Recently we had to install our rails app on a box, but we didn't have root access. The machine had ruby 1.8.6 and rubygems 0.9.6 (ouch). We can live with Ruby 1.8.6; but to run modern rails, we needed modern rubygems.

The rubygems install page has a helpful section on how to install locally without root access. Note: be sure to add export GEM_HOME=~/rubygems/gems to your .bashrc or your .bash_profile or else the next time you log in, your system gets confused again.

$ mkdir rubygems
$ cd rubygems-a.b.c
$ export GEM_HOME=~/rubygems/gems
$ ruby setup.rb --prefix=~/rubygems

Unfortunately, this didn't go as smoothly as I hoped. The result:

" `gem_original_require': no such file to load -- rubygems/exceptions"

and many other similar error messages.

The issue was that since the server installation already had an old version of rubygems installed, my local gem script was calling up the old rubygems files, but using my new GEM_HOME. A big mess.

What needs to happen is that your new gem executable needs to load your new rubygems files, and work with your new GEM_HOME. There may be a better way to do this, but I have found a workable solution for my case. It involves messing with the executable files that rubygems installs.

If you take a look at your gem executable, you'll see it is just a text file, a ruby program that executes itself.

$ cat  ~/rubygems/bin/gem

#!/usr/local/bin/ruby
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++

require 'rubygems'
require 'rubygems/gem_runner'
require 'rubygems/exceptions'

...

If you are familiar with shell scripts, you'll know that the first line (the shebang) specifies the binary to use to process the file. In this case, its #!/usr/local/bin/ruby. In general this is great. Ruby loads up the file and runs the script and magic happens. But what if the require 'rubygems' line is loading up the wrong rubygems?

We need to tell ruby where to find our custom rubygems libraries. Luckily, ruby has an option for this, -I path/to/lib. So, all we need to do is open up our gem executable and modify the shebang line to include this option.

$ vim  ~/rubygems/bin/gem

#!/usr/local/bin/ruby -I ~/rubygems/lib
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++

require 'rubygems'
require 'rubygems/gem_runner'
require 'rubygems/exceptions'

This tells the ruby interpreter to start the process with our custom path in the include path. If we have a newer version of the rubygems library there, they get required instead of the old versions. I can now install gems locally into my GEM_HOME without needing root access like so:

$ gem install mongrel

But that's not all. mongrel also installs its own executable, and when you try to run it, it will require rubygems. And yes, you guessed it, it will find the old version of rubygems and get completely confused. So again, we need to go into the executable file ~/rubygems/gems/bin/mongrel_rails and modify the shebang line.

As far as I can tell, you would need to do this for each and every gem that installs its own executable.

Update: after further consideration, using the $LOAD_PATH environment variable would probably be more robust, but my app is already installed. Perhaps you will let me know how it goes with $LOAD_PATH

Posted by Adeh Tue, 20 Jul 2010 03:52:00 GMT


installing mysql gem on MacOS X Leopard

Using Rails 2.1.1, I get this warning about the mysql libraries associated with Rails:

The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again: gem install mysql.

As many have noted, the suggestion of `gem install mysql` doesn't seem to work well on the vanilla Leopard install with the standard MySQL pre-compiled binary. I followed lots of good advice from wonko, jlaine, hivelogic, and Seth Willits, but finally none of it worked.

Using the command from wonko:

sudo env ARCHFLAGS="-arch i386" gem install mysql -- \
  --with-mysql-dir=/usr/local/mysql --with-mysql-lib=/usr/local/mysql/lib \
  --with-mysql-include=/usr/local/mysql/include

got me the ulong compile error mentioned by jlaine,. Unfortunately, jlaine's instructions didn't work for me, the manual install step doesn't seem to really install anything. I realized I had to take it step further by modifying the source of he gem itself.

In order to fix the compile error in mysql.c, it helps to understand how the gem install command works. First, gem goes online to find the correct file, then downloads the packaged .gem file to your local gem cache. Then, gem unpacks the .gem and runs extconf.rb and make/make install. From reading extconf.rb, one can see that the mysql gem uses a file called mysql.c.in as a template to build a properly configured mysql.c, which then gets compiled into the C library that we will use.

$cd /Library/Ruby/Gems/1.8/cache
$sudo gem unpack mysql-2.7.gem
$cd mysql-2.7

This gives you the source of the gem. Open mysql.c.in to add the single line we need.

#define ulong unsigned long // quick fix so that it compiles on my machine

Then we need to repack the gem, copy it to the cache folder, and install our customized version using the command above.

$sudo gem build mysql.gemspec
$sudo mv mysql-2.7.gem ../mysql-2.7-CUSTOM.gem
$sudo env ARCHFLAGS="-arch i386" gem install mysql-2.7-CUSTOM.gem -- \
  --with-mysql-dir=/usr/local/mysql --with-mysql-lib=/usr/local/mysql/lib \
  --with-mysql-include=/usr/local/mysql/include

All this for one line of code...but finally:

$ gem list mysql

*** LOCAL GEMS ***

mysql (2.7)

Thankfully, most of the time we don't need to go through all this just to instal a library. This sort of thing happens rarely. But its great to know that as long as you have your command line, a good compiler, and some detective skills, you can fix many problems on your own!

Posted by Adeh Fri, 12 Sep 2008 21:07:00 GMT


kudelabs public code repository

We have started a new code repository at http://github.com/kudelabs. We will be using this to host our own plugins, utility files, and example code that we wish to make public. Hopefully, something here is of use to others in the community. If you find ways to improve upon our code, we will be happy incorporate your ideas as well. We'll be posting new code when it is ready, you can use github's "follow" feature to learn about new items.

So far I am impressed with github's features, there really isn't anything quite like it. I look forward to interacting with more developers through the site.

Posted by Adeh Tue, 02 Sep 2008 22:41:00 GMT


Rake task to help manage svn rename

I recently had to rename several views+controllers in a project. This is a very wearisome task since its not just a directory or a file; but directories, files, tests, fixtures, and other files that get generated by the Rails generator helpers. I searched for a little piece of code to help manage this, but didn't find anything. That may be due to the fact that earlier versions of rake did not work with arguments very well. Here is my little rake task, you can put it into a file in your lib/tasks directory and run it using:
$rake svn:rename[old_name,new_name] # notice no spaces
And here is the code:
namespace :svn do
  FILES_TO_RENAME = [ "app/views/%s",
                      "app/controllers/%s_controller.rb", 
                      "app/models/%s.rb", 
                      "test/unit/%s_test.rb", 
                      "test/functional/%s_controller_test.rb", 
                      "test/fixtures/%s.yml"]
  task :rename, :from, :to do |t, args|
    FILES_TO_RENAME.each do |s|
      from_f = s % args.from
      to_f = s % args.to
      if File.exists?(File.expand_path(from_f))
        puts "Renaming #{from_f} -> #{to_f}"
        puts %x[svn mv #{from_f} #{to_f}]
      else
        puts "Skipping #{from_f}. File not found."
      end  
    end
  end
  
end
Please leave comments if you see a way to improve this. Feel free to modify it to your needs and tell me about it.

Posted by Adeh Fri, 13 Jun 2008 21:48:00 GMT


Rubob (Ruby Object Browser) 0.0.3 released

After literally a year of not finding time for finishing touches, I decided to finally just release what I have. It works fine, after all.

Rubob is based on a little tool I wrote together with Matthias Hopf in 1997 or so to play with the Java Reflection API. When I started working with Ruby almost a decade later, I realized how much easier it would be in Ruby, so I rewrote it. And then it sat there...

So what does it do?

Rubob generates a hyperlinked Web-view of your program while it runs. It can very easily be added to any existing application (one line of code).

With Rubob, every object in the system has a corresponding URL. When you access that URL, Rubob generates a Web page that contains a human readable version of the object. All instance variables are hyperlinked to the URL for their value; so you can click your way through from object to object to explore the state of your program while it's running.

Certain classes, such as Array and Hash, have a custom representation that makes their content easier to explore.

You can add your own custom representation of objects using a simple API that I'll explain when I have some time.

Here is the code.

Enjoy!

Posted by Uli Tue, 29 Apr 2008 21:49:00 GMT