Sep 26, 2011

Running Rails 3.1.1 on Heroku

Heroku officially supports rails 3.1.1 on their Cedar stack now, unfortunately, you may still fail on deploy. The trouble maker is the assets:precompile rake task in rails 3.1. Heroku runs 'rake assets:precompile' for you when deploy, at a time many application dependencies, e.g. database server, redis, are NOT ready, so if there's any database/redis/any-other-not-ready-dependency use in your rails initialization process, assets:precompile will fail.

The tricky thing is, even you know the underlying theory, it's hard to find the exact place caused the problem, because heroku deployment do not use '--trace' flag when running precompile task, the limited error output is almost useless; and rails initialization process walks through so many files it's stupid to check them one by one.

For example, this is the error I got today when I deploy to heroku:

rake aborted!
bad URI(is not URI?):

Can you spot the broken code with so few information? I can't ... Fortunately, we can ask rake to give detail error stack without passing it '--trace' option, by adding this line in your Rakefile:

Rake.application.options.trace = true if %w(staging production).include?(Rails.env)

Then another problem pops up, I now found the broken code, how to fix it? Since the broken code uses something that is not ready when assets:precompile task running, an easy way would be:

# in Rakefile
if %w(staging production).include? Rails.env
$heroku_deploying = true if File.basename($0) == 'rake' && ARGV.include?('assets:precompile')
end

# in some initializers:
# reference to UsersController will trigger operation on database
provider :identity, :fields => [:name, :email, :nickname], :on_failed_registration => UsersController.action(:new) unless $heroku_deploying

With this duct tape kind fix, you may have $heroku_deploying scattered in your code .. it's ugly but works. Let me know if you have better idea :-)

Jun 17, 2011

[ANN] Rubytest.vim 1.1.0 Released!

There're two major changes in this release:

* Remember last run: <leader>l to run last run test (thanks John Weir!)
* Default support to rspec2. You need to customize g:rubytest_cmd_spec to work with rspec 1.*

Download [1][2] and copy/overwrite to install/upgrade!

May 30, 2011

Jan 26, 2011

Angry Terminal

Last night I got the idea that using different colors in shell prompt to tell the user about the result of last command executed, e.g. red for failed execution and green for success.

It's really easy to do that in the ultimate shell, all I need is a function and a prompt using it:

function prompt_base_color() {
if [[ $? == "0" ]]; then
echo $PR_GREEN
else
echo "$PR_RED"
fi
}

PROMPT='$PR_SET_CHARSET$PR_STITLE${(e)PR_TITLEBAR}$(prompt_base_color)%D{%H:%M} $PR_GREEN%~ $PR_RED$(git_prompt_info)$PR_NO_COLOUR'
It make your terminal look like this:



Then I realized I can go one step further to help terminal express her feeling, I always feel she is angry with me.

So I changed the function a bit, like this:

function prompt_base_color() {
if [[ $? == "0" ]]; then
echo $PR_GREEN
else
txt=`cat ~/.zsh/my_ass.txt`
echo "$txt\n$PR_RED"
fi
}
And put the feeling in a file by `cowsay My ASS > ~/.zsh/my_ass.txt`.

Now Miss Terminal can tell me what she thinks when I do something wrong!

Nov 26, 2010

QorCMS preview

Qor is the admin tool we build for rails. It's not public released yet but already used by some of our clients. It's like the Django one but only better!

Qor Enterprise CMS Demo from Felix Sun on Vimeo.

Nov 4, 2010

Compiling Google mod_pagespeed on Archlinux

Google released its awesome apache module mod_pagespeed recently. Unfortunately only .deb/.rpm packages are provided officially. For arch user, we have to compile it by ourselves.

Based on google's howto, we need depot_tools to compile mod_pagespeed. There is an aur package depot_tools-svn, but seems not work now because arch switched to python 3.

So I downloaded depot_tools myself and put it in my ~/scripts/depot_tools.

mkdir -p ~/scripts
cd ~/scripts
svn co http://src.chromium.org/svn/trunk/tools/depot_tools


To make depot_tools work, you need to switch to python2:

sudo rm /usr/bin/python
sudo ln -s /usr/bin/python2 /usr/bin/python
sudo rm /usr/bin/python-config
sudo ln -s /usr/bin/python2-config /usr/bin/python-config


Next step we download mod_pagespeed source code use depot_tools:

mkdir ~/mod_pagespeed # any directory is fine
cd ~/mod_pagespeed
gclient config http://modpagespeed.googlecode.com/svn/trunk/src
gclient sync --force # this will download all source code


You're ready to compile now.

cd ~/mod_pagespeed/src
make BUILDTYPE=Release # BUILDTYPE defaults to 'Debug'


I got an error when I compile it on my box:

In file included from /usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.1/../../../../include/c++/4.5.1/utility:71:0,
from /usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.1/../../../../include/c++/4.5.1/algorithm:61,
from ./net/instaweb/util/fetcher_test.h:24,
from ./net/instaweb/util/cache_fetcher_test.h:27,
from net/instaweb/util/cache_fetcher_test.cc:19:
...
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.1/../../../../include/c++/4.5.1/bits/stl_map.h:87:5: instantiated from here
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.1/../../../../include/c++/4.5.1/bits/stl_pair.h:77:11: error: ?std::pair<_t1,>::second? has incomplete type
./net/instaweb/util/public/cache_interface.h:28:7: error: forward declaration of ?struct net_instaweb::SharedString?


After digging a while, I made this patch to fix the error:

Index: net/instaweb/util/public/cache_interface.h
===================================================================
--- net/instaweb/util/public/cache_interface.h (revision 137)
+++ net/instaweb/util/public/cache_interface.h (working copy)
@@ -21,6 +21,7 @@

#include <string>
#include "net/instaweb/util/public/string_util.h"
+#include "net/instaweb/util/public/shared_string.h"

namespace net_instaweb {


ps: I also deployed mod_pagespeed to our centos staging server, the whole process is very smooth. The result is also very impressive: gzip, cache-control, inline assets, etc. etc. all suddenly work like a charm. The only problem is with extend_cache filter: it modified asset name correctly, but when brower send request to those assets, the server reponds with 404 error. I have to disable rewrite_javascript and extend_cache filter to make our sites work correctly:

ModPagespeedDisableFilters rewrite_javascript
ModPagespeedDisableFilters extend_cache

Oct 26, 2010

On Vim again

There's only 10 kinds of people, those who use Vim, and those who use Emacs.

Two months ago I don't know whether I'm wrong on choosing Vim as my editor, now I know I made a right decision, one of those few right decisions in my life.

Emacs can do everything, except editing texts, everyone knows it. But I didn't expect that I can't simply *copy a line* before I learned to use it. I can copy a line by press y twice in Vim by one finger while the other hand is filling my mouth with cookies; I need to move the cursor to the beginning of a line, press C-S-e, then press M-w to copy the damn line.

Of course I can write a macro and map the copy-line macro to my favorite keys. Yes, I can also write a text editor myself. Those two doesn't have much differences, no?

Be serious: I really wrote a macro to do that, the problem is when I tried to map it to some key I failed - there's no reasonable key combination left for me to use. C-y? that's for yank, C-c? that's a common prefix, etc. etc. I don't want to match copy-line to something like C-c C-t C-y, that just won't save my time and stupid.

Luckily Emacs do leave some key combination possibilities for me, so I can quick access find file/buffer functions. I'd say ido is really awesome, that's what I miss when I switch back to Vim. Vim lacks a decent file navigator. FuzzyFinder is cool, but it's turtle slow on large project.

I also miss ruby-test-mode, which can do exactly the same thing but faster than my little rubytest.vim.

Emacs follows totally different philosophy than Vim: Emacs included everything in itself, while Vim leave everything but editing to others. An example is Tramp. Tramp is really cool because you can prefix the file name with 'su::/' or 'su:root@hostfoo' when you want to edit a file you have no privileges or on a remote server, it's not convenient to do the same thing in Vim. But I found myself more like to open a terminal and sudo vim /etc/hosts. (btw. emacs in console sucks.) I believe Emacs fits certain people, people who like to do everything in one place.

Sometimes I think Emacs is for people who're using poor window manager. Because if you're using something like Gnom's default metacity, it's hard to create a new console, do something there while reading stuff in your text editor, then switch back to your editor. In short, most window managers doesn't allow you to manipulate layout between your editor and task windows easily. But if you're using tiling window manager like XMonad, I think Vim is the best fit because you can always do something in a new window easily while looking at your editor.

Emacs is cool. I just like Vim more.