A collection of computer systems and programming tips that you may find useful.
 
Brought to you by Craic Computing LLC, a bioinformatics consulting company.

Monday, December 8, 2008

Apache on Mac OS X - ~/Documents permissions

I keep all my code in subdirectories under ~/Documents. That works fine - I can build Rails applications, run them under Mongrel etc and they work fine.

But I wanted to run code under Apache2 and when I set things up the way I've done many times on Linux, with a symlink from the Apache document root (/Library/Webserver/Documents) to my code, I was not able to view those pages due to permissions errors.

The issue is that your Documents directory has these permissions:
drwx------@ 17 jones jones 578 Dec 1 09:45 Documents
These mean that only the owner can access the files in that directory. Apache2 runs as user 'www' and even though you might have made the subdirectories world-readable, it is not able to follow the path get there.

You probably don't want to make your entire Documents tree world-readable, so you have two choices.

1: Make Documents executable by everyone, but not readable:
$ chmod a+x Documents
to get these permissions
drwx--x--x@ 17 jones jones 578 Dec 1 09:45 Documents

2: Move your code to your Public directory which by default is world readable and executable.

Debugging problems like this is a real pain. I assume I've screwed up the Apache httpd.conf file and so I'm looking through the countless directives in that. The Apache error logs don't tell you where the problem lies either, unfortunately.


Apache Installations on Mac OS X

I've ended up with several Apache installations on my Mac OS X 10.5 system. This results in multiple httpd.conf files and great confusion if you modify the wrong one for the server that is currently active.

The primary installation that comes with Mac OS X is Apache2.

The executable is found in /usr/sbin
$ /usr/sbin/httpd -v
Server version: Apache/2.2.9 (Unix)
Server built: Sep 18 2008 21:54:05


The config file is found in /etc/apache2/httpd.conf
The document root is found at /Library/WebServer/Documents/inde.html.en

This version is started/stopped from the Mac OS X control Panel -> Sharing -> Web Sharing checkbox

Hopefully this helps you dissect out any problems that you might have with multiple installations.

Wednesday, November 26, 2008

Rails - Drag and Drop Sorting in a Table

Through use of the Prototype and Script.aculo.us libraries, Rails makes it easy to set up drag and drop capability in your pages.

But all the examples I've seen use Lists of elements and I typically use Tables to display sets of data. I was having a hard time getting drag and drop sorting to work but I got there.

My problem was that I was putting my 'container id' into the <table> tag. That doesn't work. You have to have a <tbody> tag pair inside there - which I simply have never bothered with. Put the 'container id' in there and put the 'element id' in the <tr> tag - not the <td> tag.

In this dummy application you have carts and carts have multiple items. The order of each item in the cart is given by the item 'position' field.
class Cart < ActiveRecord::Base
has_many :items, :order => :position
end

class Item < ActiveRecord::Base
belongs_to :cart
acts_as_list :column => :position, :scope => :cart
end

This would go into your cart show page:
<table>
<tbody id="cart_div">
<% @cart.items.each do |item| %>
<tr id="item_<%= item.id %>">
<td><%= item.position %></td>
<td><%= item.name %></td>
</tr>
<% end %>
</tbody>
</table>

Then elsewhere in that page you need to add this block that sets up the JavaScript magic. Note that you need to specify the tag that will get dragged and dropped. The default is 'li' but here we want 'tr'.
<%= sortable_element 'cart_div',
:url => { :action => 'sort', :id => @cart },
:complete => visual_effect(:highlight, 'cart_div'),
:tag => 'tr'
%>

You also need to create a 'sort' action in your carts controller that looks something like this:
  def sort
@cart = Cart.find(params[:id])
@cart.samples.each do |cart|
item.position = params['cart_div'].index(item.id.to_s) + 1
item.save
end
render :nothing => true
end

Note that you don't need to do anything with your routes.rb file, even though 'sort' is not a standard action. I assume that is because it is using a GET and that just gets handled?

Finally, you need to include the javascript libraries in your page layout, but you knew that already.
<%= javascript_include_tag :defaults %>



Monday, November 24, 2008

Installing Rails 2.2 on Mac OS X - MySQL problem

Rails 2.2 is out and you want to install it - but you may run into this issue on Mac OS X.

1: Make sure you have upgraded to rubygems 1.3.1
$ sudo gem update --system

If that barfs try this which does the same thing a different way:
$ sudo gem install rubygems-update
$ sudo update_rubygems


2: Install Rails
This should install just fine
$ sudo gem install rails

3: One important change in 2.2 is that the Mysql database driver is no longer bundled and you have to install yourself. But the obvious command may well fail like this:

$ sudo gem install mysql
Password:
Building native extensions. This could take a while...
ERROR: Error installing mysql:
ERROR: Failed to build gem native extension.
[...]


The issue is that the gem needs more information about your MySQL installation, so do this instead:

$ sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
Building native extensions. This could take a while...
Successfully installed mysql-2.7
1 gem installed


4: That looks good but you may not be out of the woods yet... I got this when I tried a rake db:migrate

$ rake db:migrate
(in /Users/jones/Documents/myapp)
!!! The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again: gem install mysql.
rake aborted!
dlsym(0x1c71570, Init_mysql): symbol not found - /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7/lib/mysql.bundle


After some poking around I found reference to the version of mysql that is installed.

I installed mine as the packaged disk image from mysql.com. For Mac OS X 10.5 you have the choice of these two:
mysql-5.0.67-osx10.5-x86.dmg
mysql-5.0.67-osx10.5-x86_64.dmg


Both work fine on my MacBook but the mysql gem wants the '_x86' version, not the '_x86_64'

Look in /usr/local to see which you have symlinked in:

$ ls -l /usr/local
[...]
lrwxr-xr-x 1 root wheel 24 Nov 24 09:35 mysql -> mysql-5.0.67-osx10.5-x86


Install the correct version, reinstall the gem just to be safe, and try your rake again - it should be fine!

IMPORTANT

If you do have the same issue and install the non _64 version on top of the _64 one then mysql will NOT copy over your data files. To fix this:

1: Shut down MySQL
2: In the new (non _64) version
$ sudo mv data data.bak
$ sudo cp -pr ../mysql-5.0.67-osx10.5-x86_64/data .

3: Start up MySQL

Wednesday, November 19, 2008

Wrapping Scripts with Platypus on Mac OS X

Platypus is a Mac OS X tool, written by Sveinbjorn Thordarson, that lets you create Mac OS X applications that wrap up command line scripts, create installers, etc. It is a great way to package Ruby, Perl, etc. scripts for a broader user audience.

Platypus is easy to figure out if you just have a single script. But I often times develop data analysis pipelines of various sorts where I have one master Ruby script calling a bunch of others.

Wrapping the whole thing up with Platypus can work really well but to do that you need to understand how the tool works.

At first glance you might think that it just calls the target script in its original location, but in fact it copies the script into the folder that embodies the Mac OS X application. So if I have a primary script calling a secondary one then I need to either refer to it by an absolute path, which is not a good idea for portability, or I need to include the secondary script in the Mac application.

Here is an example that shows how you handle this - I'll assume that you have tried Platypus with some simple scripts already.

The primary script (hello.rb) is what the Platypus generated application will execute. This in turn will execute world.rb and echo its output.

hello.rb

#!/usr/bin/ruby
puts "Hello ..."
world = File.join(File.dirname(__FILE__), 'world.rb')
puts `#{world}`


world.rb

#!/usr/bin/ruby
puts "... World"


First of all, specify the path to your Ruby (or whatever) interpreter explicitly. The convention in the Ruby world is to use '#!/usr/bin/env ruby' but doesn't work directly with Platypus. I'm sure you can mess with some of the Platypus options to make it work but I haven't bothered.

The third line in hello.rb specifies where to find the script 'world.rb', namely in the same directory as hello.rb. For Perl coders, this is the same as using FindBin.

Package hello.rb with Platypus, sending output to a Text window and keeping the window open after the script completes, then run the script. You should get something like this:

/Users/jones/Documents/Platypus/hello_world.app/Contents/Resources/script:7: command not found: /Users/jones/Documents/Platypus/hello_world.app/Contents/Resources/world.rb
Hello ...


It has found and run hello.rb but it can't find world.rb. The error message tells us that the script it has run is actually called 'script', not hello.rb, which seems odd.

Platypus copies your script into a new Mac application, which as you should know, is really a directory. 'cd' to the application directory (hello_world.app in my case), then into Contents -> Resources.

Look at the file 'script' and you'll see that is actually 'hello.rb'

To get the result you want you have to add 'world.rb' to the application as a 'Resource' and you do this in the 'Advanced Options' panel in Platypus. Just add the secondary file to this panel, rebuild the application and re-run it.

Hello ...
... World


With more complex applications you can add additional scripts and data files. Test things out by running them from the command line in the platypus generated application directory.

If you want to get around this you can specify an absolute path to the secondary script, or create a symlink to it from within the application directory. But down this path lies madness. A better alternative would be to use an environment variable to show where something lies, such as the PATH variable or something custom. Platypus will let you pass that into the app.

I'm very impressed with Platypus, compared to earlier attempts at doing this, like DropScript. When I get the chance I want to try it in combination with CocoaDialog which allows you to create simple GUIs in your scripts.


Tuesday, October 14, 2008

Memory Leak in Ruby 1.8.6

Just spent way too much time trying to track down a memory leak in a Ruby script that parsed out information from a massive text file. It would just gradually consume all available memory until the swap daemon went nuts.

I can't say that I've had a memory leak that caused me pain before using Ruby, but this one stopped the show.

None of the suggestions for possible causes was of any help, other than a general opinion that garbage collection in Ruby 1.8.6 had some issues.

So I downloaded ruby 1.8.7 (2008-08-11 patchlevel 72) from http://www.ruby-lang.org/en/downloads/, compiled it and reran the code.

Sorted!

1.8.6 is still the default on the systems I work with. If you run into this problem, the first thing to try is an upgrade to 1.8.7.

To help debugging, this line of code will spit out the current usage (Sorry, I forget where I got it from...)

STDERR.puts 'processBlock ' + `pmap #{Process.pid} | tail -1`[10,40].strip



Thursday, October 9, 2008

Tutorial on the Ruby gem aws-sdb - an interface to AWS SimpleDB

Tim Dysinger's aws-sdb is a Ruby interface to the SimpleDB service from Amazon Web Services.

I've written a tutorial
on how to use this interface to access AWS SimpleDB from your Ruby code.

 

Archive of Tips