Linux Mint Is Weird

9:12 PM / Comments (0) / by Nick

I have a MacBook Pro. I bought it back in 2007 when I was living in Australia. It's awesome. I love it, especially the keyboard. Unfortunately, Mac OS X has pissed me off way too many times. So I jumped ship to Linux Mint 7.

Out of the box, Mint 7 supports my Mac's Atheros wifi card and ATI video card. That's something that not even Ubuntu managed to do. Needless to say, I was impressed.

After installing and configuring most of Mint 7, things were looking pretty good. As some of you know, I customize KDE heavily. Shortcuts, panels, virtual desktops, colour schemes, etc. Once all of that's configured as I like it, I don't touch'em: they're perfect (for me).

Mint 7 ships with KDE 4 though, which uses Plasma. Trying to get Plasma configured just right is like trying to fine-tune a space ship: it sounds like fun, but it just Ain't Gonna Happen (tm).

While trying to configure Plasma, I ran sudo aptitude safe-upgrade, and went to bed. I awoke to hell. Well, desktop hell. None of my panels were showing, the Plasma "cashew" was missing, and right-clicking on the desktop did nothing. Fark!

To make a long story short, Steely in #LinuxMint.com on irc.spotchat.org saved me. He corrected my sources.list , and after running mintupdate, life was peachy!

Apparently, one is not supposed to use aptitude's safe-upgrade tool, because it'll install packages that Linux Mint doesn't want you to.

How/why/what/?!?

According to Steely:
mint will fix packages or omit items until they get what they consider a stable base
mint uses updates levels 1 to 5 and mintupdate is set to use levels 1 to 3 by default, 4 and 5
has kernel and driver and other package updates
if you use mintupdate you will rarely have problems but if you use the terminal it ignores
levels and can introduce packages that conflict with mint's patches / fixes

So there you have it. When running Linux Mint, use mintUpdate, not aptitude, to perform upgrades.

In case anyone else is plagued by this problem, the solution is to comment out this line in /etc/apt/sources.list :
deb http://ppa.launchpad.net/kubuntu-ppa/ppa/ubuntu jaunty main
and uncomment this line:
deb http://archive.ubuntu.com/ubuntu/ jaunty-backports main restricted universe multiverse
Next, use mintUpdate to upgrade the rest of your packages, reboot, and pray to whichever god(s) you believe in.

Idiosynchracy With Apache Rewrites

11:04 AM / Comments (2) / by Nick

Did you know that it's not possible to apply an Apache rewrite condition to multiple rewrite rules? I thought this would work, but requests from every IP address were being redirected:
RewriteCond %{REMOTE_ADDR} ^10\.0\.10\.10$
RewriteRule ^uploads/(.*)$ /wp-content/uploads/$1
RewriteRule (.*) http://deadorange.com/blog$1 [L,R=301]

It turns out that RewriteCond directives only apply to the following RewriteRule. So my rewrite directives above were equivalent to:
If the request came from 10.0.10.10, rewrite /uploads/.* to /wp-content/uploads/.* .
Next, redirect everyone to http://deadorange.com/blog$1 .

Unfortunately, the only solution is to repeat the condition:
RewriteCond %{REMOTE_ADDR} ^10\.0\.10\.10$
RewriteRule ^uploads/(.*)$ /wp-content/uploads/$1
RewriteCond %{REMOTE_ADDR} ^10\.0\.10\.10$
RewriteRule (.*) http://deadorange.com/blog$1 [L,R=301]

That isn't very DRY, but if it's the only way, we have to live with it!

Importing large WordPress blogs

10:26 AM / Comments (1) / by Nick

I just finished importing a WordPress blog with >1500 posts into a different WordPress blog. Importing the posts succeeded, but the last few steps at the end failed, like recalculating how many posts are in each category. This happened because the page always timed out; the import took more than 10 minutes.

If you find yourself with this problem, the fix is easy:
  1. First, comment out the following line in wp-admin/import/wordpress.php . In WordPress 2.8.4, it's line 367.
    set_time_limit( 60 );

  2. Configure your web server to allow PHP scripts to execute for a long time. In Apache, you do that with the "Timeout" directive:
    Timeout 6000
    This can be put within a specific virtual host, or configured globally.

  3. Increase PHP's max execution time. This is done with the "max_execution_time" setting in the appropriate php.ini :
    max_execution_time = 600    ; Maximum execution time of each script, in seconds
    or within your web server's configuration, if that's allowed. For example, within Apache, you include this globally, or within a virtual host:
    <IfModule mod_php5.c>
    php_value max_execution_time 6000
    </IfModule>

Hashes and Frozen Keys

4:07 PM / Comments (2) / by Nick

The hash class freezes keys that are strings:

This can be a problem if you want to use those keys later on...more specifically, if you want to extract and edit those strings:

Unfortunately, those strings will have to be duped or cloned:

Sinatra and Passenger/mod_rails

4:24 PM / Comments (0) / by Nick

If you want Apache to serve up a Sinatra app, your best bet is to use Passenger (AKA mod_rails).

All your app needs is the usual Rackup config file (config.ru) in the app's root directory, and the directory public/ .

There's one caveat, though: if you have a file named environment.rb , do not put it in config/ .

If mod_rails finds config/environment.rb , it'll think your app runs on Rails:

Ruby in Etch

10:24 PM / Comments (0) / by Nick

As some of you may know, Ruby and Debian's ways of packaging software go together like Darwin and religious zealots...as in, they don't. So how should you install Ruby when using Debian Stable? How do you stay up-to-date with new versions of Ruby and gems?

By using Backports, and not worrying so much.

First, setup your box to be able to install backports of packages. Next, uninstall any Ruby-related packages. Yeah, that's right. Do you know why? Because, if you're running Etch, you're using Ruby 1.8.5! Egad! That's almost medieval. Make sure to uninstall irb and rdoc, too.

Now it's time to install shinier versions...1.8.7, to be exact:
$ sudo aptitude install -t etch-backports libruby1.8 ruby1.8 rdoc1.8 irb1.8
All of that should be on one line.

There you have it. Now you've got Ruby 1.8.7 on Debian Stable (AKA "Etch"). Ruby's not complete without RubyGems, though. Download the latest version to /usr/src/ , and extract it:
$ cd /usr/src/
$ wget http://rubyforge.org/frs/download.php/45905/rubygems-1.3.1.tgz
$ tar zxf rubygems-1.3.1.tgz
Then run the setup utility:
$ cd rubygems-1.3.1/
$ sudo ruby setup.rb

Let's do one last thing to make life easier. The RubyGems setup script installed the "gem" command as /usr/bin/gem1.8 . I don't want to have to type that "1.8" every time.
$ cd /usr/local/bin/
$ sudo ln -v -s /usr/bin/gem1.8 gem

There. Now we can run "gem" like the rest of the world.

Easy? Yar.

Default stegosaurses

7:10 PM / Comments (0) / by Nick

Ever heard of Jonathan Viney's active_record_defaults plugin? It's fantastic. In a nutshell, it enables you to specify default values for model attributes. If an attribute isn't set when initialising a new instance, the attribute's set to whatever the default value is.

For example, let's rebuild that Stegosaurus class from a previous post:
class Stegosaurus < ActiveRecord::Base
attr_accessible :tail_spikes, :back_plates

validates_numericality_of :tail_spikes,
:only_integer => true,
:greater_than_or_equal_to => 0

validates_numericality_of :back_plates,
:only_integer => true,
:greater_than_or_equal_to => 0
end

With that, if we created a new Stegosaurus and didn't specify any attributes, not only would it have no tail spikes or back plates, but the model instance wouldn't be valid.

To fix that, all we need to do is add two lines:
class Stegosaurus < ActiveRecord::Base
attr_accessible :tail_spikes, :back_plates

default :tail_spikes => 4
default :back_plates => 6

validates_numericality_of :tail_spikes,
:only_integer => true,
:greater_than_or_equal_to => 0

validates_numericality_of :back_plates,
:only_integer => true,
:greater_than_or_equal_to => 0
end

And voila, new Stegosaurus objects will automatically have 4 tail spikes and 6 back plates:
>> s = Stegosaurus.new
=> #<Stegosaurus tail_spikes: 4, back_plates: 6>
>>
?> s.tail_spikes
=> 4
>> s.back_plates
=> 6

However, if used improperly, this can lead to several hours of pounding your head on your desk. Note that that the default values we used above, 4 and 6, are immutable objects. You can't change them. You can perform operations on them, such as addition (4 + 1), but that never changes the object.

Say we want our Stegosaurus class to have an array specifying its diet that defaults to "fern" and "cycad":
class Stegosaurus < ActiveRecord::Base
attr_accessible :tail_spikes, :back_plates, :diet

default :tail_spikes => 4
default :back_plates => 6
default :diet => %w(fern cycad)

validates_numericality_of :tail_spikes,
:only_integer => true,
:greater_than_or_equal_to => 0

validates_numericality_of :back_plates,
:only_integer => true,
:greater_than_or_equal_to => 0
end

That looks right. But watch this:
=> charles = Stegosaurus.new
=> #<Stegosaurus tail_spikes: 4, back_plates: 6, diet: ["fern", "cycad"]>
>>
?> arnold = Stegosaurus.new
=> #<Stegosaurus tail_spikes: 4, back_plates: 6, diet: ["fern", "cycad"]>
>>
?> charles.diet << 'moss'
=> ["fern", "cycad", "moss"]
>>
?> arnold.diet
=> ["fern", "cycad", "moss"]
We didn't mean to do that...Arnold doesn't want to eat moss!

At the moment, when the Stegosaurus class is initialised, it creates one Array for the default "diet" attribute of all future Stegosaurus objects. In other words, Charles' and Arnolds' "diet" attributes were references to the same object:
>> charles.diet.object_id
=> 19103090
>>
?> arnold.diet.object_id
=> 19103090

How do we fix that? We tell the Stegosaurus class to create a new Array for each model instance. Simply change this:
default :diet => %w(fern cycad)
to this:
default :diet => Proc.new { %w(fern cycad) }

Now each time we create a new Stegosaurus, that Proc will fire, and create a new "diet" Array:
=> charles = Stegosaurus.new
=> #<Stegosaurus tail_spikes: 4, back_plates: 6, diet: ["fern", "cycad"]>
>>
?> arnold = Stegosaurus.new
=> #<Stegosaurus tail_spikes: 4, back_plates: 6, diet: ["fern", "cycad"]>
>>
?> charles.diet << 'moss'
=> ["fern", "cycad", "moss"]
>>
?> arnold.diet
=> ["fern", "cycad"]

I highly recommend giving active_record_defaults a try. It's very handy, and very easy to use.

And by the way, yes, I was bitten by this problem. Why else would I be writing about it! Can you guess how I discovered it, though? ... My tests picked it up!