#!/bin/bash
# Written by Peter over at RimuHosting.com (we provide Linux VPS hosting services)
# Last major update: 2006-06-18
# for a bit of a blurb about this script see http://bliki.rimuhosting.com/space/knowledgebase/linux/miscapplications/ruby+on+rails
# the latest version of this script is typically found at http://downloads.rimuhosting.com/miscproj/rails.sh
# todo:
# require 'mysql' not working?  Try gem install mysql.  Then 
#    cp: /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7/mysql.so /usr/local/lib/ruby/site_ruby/1.8/mysql.so
#

# a function just so we can see on screen what is happening as well as view the install log later on
function echolog() {
   echo $* | tee -a /root/install.log
}

# download a file and cd into there.  With a bit of error handling
function download() {
local name=$1
local version=$2
local url=$3
mkdir -p /usr/local/src
cd /usr/local/src
if [ -d /usr/local/src/$name-$version ]; then
    echolog "$name directory already exists, skipping the download"
    cd /usr/local/src/$name-$version
    return 0
fi
echolog "Grabbing $name from $url"
wget -qO - $url | tar xz
if [ $? -ne 0 ]; then
    echolog "failed getting $url" >&2
    return 1
fi
cd /usr/local/src/$name-$version
}

function installrails() {

function installprerequisites() {
if [ -e /etc/redhat-release ] ; then
# Getting errors like: custom_require.rb:21:in `require__': No such file to load -- zlib (LoadError)
# Then you need zlib devel _before_ compiling ruby
apt-get -y install zlib-devel
apt-get -y install readline-devel readline
apt-get -y install mysql-devel
apt-get -y install ImageMagick-devel ImageMagick
else 
apt-get install -y zlib1g-dev
apt-get install -y 'g++-3.4'
apt-get install -y libmysqlclient14-dev
apt-get -y install libmagick++6-dev libmagick++6
apt-get -y install libreadline5-dev
fi
if [ -e /etc/issue ] && grep -qai 'Ubuntu 6' /etc/issue ; then
    # note ubuntu comes with 1.8.4 so no ruby compile needs to be done
    # else you will get gem spitting out extconf.rb:1:in `require': no such file to load -- mkmf (LoadError)
    apt-get -y install ruby1.8-dev
    apt-get -y install libmagick9 libmagick9-dev
    # /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:21:in `require__': no such file to load -- rdoc/rdoc (LoadError)
    apt-get -y install rdoc1.8
    apt-get -y install make
    apt-get -y install libmagick9-dev libmagick9
fi
if [ -e /usr/bin/irb1.8 -a ! -e /usr/bin/irb ] ; then
    ln -sf /usr/bin/irb1.8 /usr/bin/irb
fi
 # else ./configure may fail with the script not finding cpp or a c++ compiler
if [ ! -e /usr/bin/g++ -a -e /usr/bin/gcc-3.4 ]; then
    ln -sf /usr/bin/gcc-3.4 /usr/bin/gcc; ln -sf /usr/bin/g++-3.4 /usr/bin/g++
fi
}
installprerequisites
if [ $? -ne 0 ]; then echolog "failed prerequisites" >&2; return 1; fi

# debian is -dev, rh is -devel
function installruby() {
echolog "checking ruby is latest version"
# try to scrape the version off the ruby home page
VERSION=$(wget -qO - http://www.ruby-lang.org/en/20020102.html| grep "The stable release" | sed 's/.*tar.gz">ruby-//g' | sed 's/<\/a>.*//g')

# correct as at 2006-06-18
if [ -z "$VERSION" -o $? -ne 0 ]; then
    VERSION=1.8.4
fi
# check if we have ruby 1.8 already and then exit
if [ -e /usr/bin/ruby ] && /usr/bin/ruby --version | grep -qai $VERSION ; then
    echolog "/usr/bin/ruby already version $VERSION, skipping install"
    return 0
elif [ -e /usr/bin/ruby ]; then 
    # if we have an old version of ruby then move it out of the way and clear out the devel libraries so they do not conflict
    mv /usr/bin/ruby /usr/bin/ruby.not$VERSION
    if [ -e /etc/redhat-release ] ; then
        apt-get -y remove ruby
        apt-get -y remove ruby-devel
    else 
        apt-get -y remove ruby
    fi
fi

if [ -e /usr/local/bin/ruby ] && /usr/local/bin/ruby --version | grep -qai $VERSION ; then
    echolog "/usr/local/bin/ruby already version $VERSION, skipping install"
    return 0
fi

echolog Installing Ruby VERSION=$VERSION

download ruby $VERSION ftp://ftp.ruby-lang.org/pub/ruby/ruby-$VERSION.tar.gz
if [ $? -ne 0 ]; then echolog "failed downloading ruby" >&2; return 1; fi
./configure && make && make test && make install
if [ $? -ne 0 ]; then
    echolog "Ruby make install failed">&2
    return 1
fi

# so there'll be a /usr/bin/ruby to use
if [ -e /usr/local/bin/ruby -a ! -e /usr/bin/ruby ]; then
    ln -sf /usr/local/bin/ruby /usr/bin/ruby
fi
# doing this voodo to prevent errors like:
# /usr/local/lib/ruby/1.8/irb/completion.rb:10:in `require’: no such file to load—readline (LoadError)
cd /usr/local/src/ruby-$VERSION/ext/readline
if [ $? -ne 0 ]; then echolog "no /usr/local/src/ruby-$VERSION/ext/readline dir">&2;return 1;fi
ruby extconf.rb
if [ $? -ne 0 ]; then echolog "readline extconf.rb failed">&2;return 1;fi
make clean && make install
if [ $? -ne 0 ]; then echolog "readline make failed">&2;return 1;fi

if ! ruby --version | grep -qai $VERSION ; then
    echolog "$(which ruby) version is not as expected.  Expected $VERSION, got: $(ruby --version)" >&2
    return 1
fi
}
installruby
if [ $? -ne 0 ]; then echolog "failed installing ruby" >&2; return 1; fi

# gems is an app kind of like apt or up2date or yum which lets you gem install modulename for ruby
function installgems() {
###########################################

# the rubyforge download pages confound my screen
# scraping ability to get the latest version.  so you
# will need to manually check this if you want the 
# latest version
gemsversion=0.8.11
echolog "installing rubygems"
download rubygems $gemsversion http://rubyforge.org/frs/download.php/5207/rubygems-$gemsversion.tgz || return 1
if [ -e builtok ] ; then echolog "ruby gems already installed, skipping"; return 0; fi
ruby setup.rb
if [ $? -ne 0 ]; then
    echolog "gems setup failed">&2
    return 1
fi
touch builtok
}
installgems
if [ $? -ne 0 ]; then echolog "failed installing gems" >&2; return 1; fi

# this function installs commonly requested 'gems'
function installgems() {
###########################################
echolog "installing gems rails fcgi"

gem install -y rails
if [ $? -ne 0 ]; then
    echolog "rails gem install failed">&2
    return 1
fi
if [ ! -e /usr/local/bin/mongrel_rails ]; then
    echo "If prompted select the latest mongrelversion.  Typically item 1 on the list.  Do not choose the mswin ones."
    gem install -y mongrel
    if [ $? -ne 0 ]; then
    echolog "mongrelgem install failed">&2
    return 1
    fi
fi
if ! echo "require 'rubygems'; require_gem 'mysql'" | irb | grep -qai true; then
	echo "You probably want to choose the 'mysql 2.7 (ruby)' option.  Don't choose the mswin options."
	gem install -y mysql
	if [ $? -ne 0 ]; then
		if [ -e /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7/extconf.rb ]; then
			cd /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7
			# the regular gem install mysql should work, but if not then you may need to fall back on this
			ruby extconf.rb --with-mysql-config
			if [ $? -ne 0 ]; then echolog "mysql gem install failed (0) ">&2; return 1; fi
			make install
			if [ $? -ne 0 ]; then echolog "mysql gem install failed (1) ">&2; return 1; fi
		else 
			echolog "mysql gem install failed">&2
			return 1
		fi
	fi
fi
# using irb (interactive ruby) we can check that the module we thought was installed is actually there
if ! echo "require 'rubygems'; require_gem 'mysql'" | irb | grep -qai true; then
    echolog "myql gem install failed"
fi
if ! echo "require 'rubygems';require_gem 'rmagick'" | irb | grep -qai true; then
	gem install rmagick
	if [ $? -ne 0 ]; then
	    echolog "rmagick gem install failed">&2
	    return 1
	fi
fi
}
installgems
if [ $? -ne 0 ]; then echolog "failed installing gems" >&2; return 1; fi

# the setup for fastcgi for rhel4 and debian is different enough that we'll just use different functions for each
function debianfastcgi() {
    function debinstallpcre() {
    echolog "installing pcre"
    pcreversion=5.0
    download pcre $pcreversion ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-$pcreversion.tar.gz 
    if [ $? -ne 0 ]; then echolog "pcre download failed" >&2; return 1; fi
    if [ -e builtok ]; then
    echolog "Looks like we'd already built it, skipping this step"
    return 0
    fi
    ./configure  && make && make test && make install
    if [ $? -ne 0 ]; then echolog "pcre install failed" >&2; return 1; fi
    touch builtok
    }
    debinstallpcre
    if [ $? -ne 0 ]; then echolog "debinstallpcre failed" >&2; return 1; fi
    
    
    function debinstallfcgi() {
    echolog "installing fcgi"
    fcgiversion=2.4.0
    download fcgi  $fcgiversion http://www.fastcgi.com/dist/fcgi-$fcgiversion.tar.gz || return 1
    if [ $? -ne 0 ]; then echolog "download fcgi failed" >&2; return 1; fi
    if [ -e builtok ]; then
    echolog "Looks like we'd already built fcgi, skipping this step"
    return 0
    fi
    ./configure && make && make install
    if [ $? -ne 0 ]; then echolog "fcgi compile" >&2; return 1; fi
    cd /etc/apache2/mods-enabled
    ln -s ../mods-available/fcgid.* .
    ln -s ../mods-available/rewrite.* .
    touch builtok
    }
    debinstallfcgi
    if [ $? -ne 0 ]; then echolog "debinstallfcgi failed" >&2; return 1; fi
    
    function debinstallrubyfcgi() {
    echolog "installing ruby fcgi"
    echolog "require 'fcgi'"| irb | grep -q true
    if [ $? -eq 0 ]; then echolog "rubyfcgi already working, skipping this step" >&2; return 0; fi
    rubyfcgiversion=0.8.6
    download ruby-fcgi $rubyfcgiversion http://sugi.nemui.org/pub/ruby/fcgi/ruby-fcgi-$rubyfcgiversion.tar.gz
    if [ $? -ne 0 ]; then echolog "installrubyfcgi download failed" >&2; return 1; fi
    ruby install.rb config
    if [ $? -ne 0 ]; then echolog "installrubyfcgi install config failed" >&2; return 1; fi
    ruby install.rb setup
    ruby install.rb install
    if [ $? -ne 0 ]; then echolog "installrubyfcgi install failed" >&2; return 1; fi
    echolog "require 'fcgi'"| irb | grep -q true
    if [ $? -ne 0 ]; then echolog "installrubyfcgi require fcgi failed" >&2; return 1; fi
    
    }
    debinstallrubyfcgi
    if [ $? -ne 0 ]; then echolog "debinstallrubyfcgi failed" >&2; return 1; fi
}

function redhatfastcgi() {
    function installfcgi() {
        fcgiversion=2.4.0
        echolog "installing fcgi"
        download fcgi  $fcgiversion http://www.fastcgi.com/dist/fcgi-$fcgiversion.tar.gz || return 1
        if [ -e builtok ] ; then echolog "fcgi already installed, skipping"; return 0; fi
        ./configure && make && make install
        if [ $? -ne 0 ]; then 
        echolog "fgci compile failed">&2
        return 1
        fi
        touch builtok
    }
    installfcgi
    if [ $? -ne 0 ]; then echolog "failed installing fcgi" >&2; return 1; fi
    
    function installmodfastcgi() {
        if [ -e /etc/debian_version ]; then
            echolog "Skipping fcgi for Debian" 
            return 0
        fi
    
        ###########################################
        modfastcgiversion=2.4.2
        echolog "installing mod_fcgi"
        download mod_fastcgi  $modfastcgiversion http://www.fastcgi.com/dist/mod_fastcgi-$modfastcgiversion.tar.gz || return 1
        if [ -e builtok ] ; then echolog "ruby gems already installed, skipping"; return 0; fi
        /bin/cp -f Makefile.AP2 Makefile
        if [ -e /etc/debian_version ]; then
        apt-get -y install apache2-threaded-dev
        make top_dir=/etc/apache2 && make top_dir=/etc/apache2 install
        elif [ ! -e /etc/redhat-release ]; then
        echolog "Don't recognise this distro.  Can't build mod_fastcgi" >&2
        return 1
        else 
        apt-get -y install httpd-devel
        make top_dir=/etc/httpd && make top_dir=/etc/httpd install
        fi
        if [ $? -ne 0 ]; then
        echolog "mod_fastcgi install failed" >&2
        return 1
        fi
        if ! grep -qai fastcgi /etc/httpd/conf/httpd ; then
        echo 'LoadModule fastcgi_module modules/mod_fastcgi.so
        FastCgiConfig -minProcesses 1 -maxProcesses 2 -processSlack 1
        AddHandler fastcgi-script .fcgi
        # to avoid Permission denied: FastCGI: failed to connect to (dynamic) server
        FastCgiIpcDir /tmp
        ' >> /etc/httpd/conf/httpd.conf
        mkdir -p /tmp/dynamic
        chmod o+rwx /tmp/dynamic
        fi
        /etc/init.d/httpd restart
        if [ $? -ne 0 ]; then echolog "failed restarting httpd" >&2; return 1; fi
        touch builtok
    }
    installmodfastcgi
    if [ $? -ne 0 ]; then echolog "failed installing mod_fastcgi" >&2; return 1; fi

    function installfcgigem() {
    gem install -y fcgi
    if [ $? -ne 0 ]; then
        echolog "fcgi gem install failed">&2
        return 1
    fi
    # not sure why the .rb and .so are not put where ruby can find them, do it manually
    if [ ! -e /usr/local/lib/ruby/1.8/fcgi.so ]; then
        if [ ! -e /usr/local/lib/ruby/gems/1.8/gems/fcgi-0.8.6.1/fcgi.so ] ; then
        echolog "could not find /usr/local/lib/ruby/gems/1.8/gems/fcgi-0.8.6.1/fcgi.so"
        return 1
        fi
        /bin/cp -f /usr/local/lib/ruby/gems/1.8/gems/fcgi-0.8.6.1/fcgi.so /usr/local/lib/ruby/gems/1.8/gems/fcgi-0.8.6.1/fcgi.rb /usr/local/lib/ruby/1.8/ 
    fi
    }
    installfcgigem
    if [ $? -ne 0 ]; then echolog "failed installing fcgi gem" >&2; return 1; fi
}
if [ -e /etc/debian_version ]; then
    debianfastcgi 
    if [ $? -ne 0 ]; then echolog "fcgi setup failed" >&2; return 1; fi
else 
    redhatfastcgi
    if [ $? -ne 0 ]; then echolog "fcgi setup failed" >&2; return 1; fi
fi


# lighttpd is a standalone web server often used/requested by the rails community
function installlighthttpd() {
echolog "installing lighttpd"
lighttpd 2>&1| grep -q "No configura" 
if [ $? -eq 0 ]; then echolog "looks like it is already working" >&2; return 0; fi
version=1.4.11
download lighttpd $version http://www.lighttpd.net/download/lighttpd-$version.tar.gz 
if [ $? -ne 0 ]; then echolog "download lighttpd failed" >&2; return 1; fi
./configure  && make && make install
if [ $? -ne 0 ]; then echolog "download compile failed" >&2; return 1; fi
lighttpd 2>&1| grep -q "No configura" 
if [ $? -ne 0 ]; then echolog "lighttpd startup failed" >&2; return 1; fi
}
installlighthttpd
if [ $? -ne 0 ]; then echolog "lighttpd install failed" >&2; return 1; fi

# create a test project so we can have something to display
function createtestrailsproj() {
echolog "creating a test rails project in /var/www/test"
cd /var/www
rails test
if [ $? -ne 0 ]; then echolog "failed doing rails test" >&2; return 1; fi
#railsdir=$(find /usr/lib/ruby/gems/1.8 -type d | grep rails | head -n 1)
#if [ -z "$railsdir" ]; then echolog "could not find the rails dir under /usr/lib/ruby/gems/1.8" >&2; return 1; fi
#echo railsdir=$railsdir
#replace "server.port = 3000" "server.port = 80" -- $railsdir/configs/lighttpd.conf
#if [ $? -ne 0 ]; then echolog "expected rails config setting not found" >&2; return 1; fi
cd /var/www/test
echolog "press ctrl-c after this has started up"
ruby script/server
}
createtestrailsproj
if [ $? -ne 0 ]; then echolog "createtestrailsproj failed" >&2; return 1; fi

function testapachefcgi() {
    echolog "Testing that apache works with fastcgi"
    ###########################################
    # create a  'hello world' fcgi test
    if [ -e /etc/debian_version ]; then
        CGIBINDIR=/usr/lib/cgi-bin
        /etc/init.d/apache2 restart
    else 
        CGIBINDIR=/var/www/cgi-bin
        /etc/init.d/httpd restart
    fi
    if [ ! -e $CGIBINDIR/test.fcgi ] ; then
    echo "#"'!'"/usr/bin/ruby
require 'cgi'
require 'fcgi'
FCGI.each_cgi{|cgi| cgi.out{'<HTML>hello, world.</HTML>'}}
" > $CGIBINDIR/test.fcgi
    chmod +x $CGIBINDIR/test.fcgi
    fi
    sleep 3
    # grab the server IP
    ip=$(ifconfig | grep --after-context=1 "eth0 " | grep inet | cut -d: -f2 | cut -f1 -d' ')
    if wget -O - http://$ip/cgi-bin/test.fcgi 2>/dev/null| grep -qai hello ; then 
        echolog "Looks like http://$ip/cgi-bin/test.fcgi is loading"; 
    else 
        echolog "apache fcgi page http://$ip/cgi-bin/test.fcgi does not appear to load corectly" >&2 
        return 1
    fi
}
testapachefcgi
if [ $? -ne 0 ]; then echolog "test apache cgi failed" >&2; return 1; fi

# automatically tests that lighttpd is working ok.  Sets itself up on port 3000
function testlighttpd() {
echolog "setting up an /etc/init.d/lighttpd script that will start up lighttpd pointing at the project in /var/www/test"
echo '#!/bin/bash
#
# chkconfig: 345 94 16
# description: Startup script for Lighttpd
BASEDIR=/var/www/test
case "$1" in
    start)
    echo "starting up lighttpd in $BASEDIR"
    cd $BASEDIR
    ./script/server -d lighttpd 2>&1 >> /var/log/messages &
    ;;
    stop)
    echo "stopping lighttpd"
    pid="$(pidof lighttpd) $(ps auxf | grep $BASEDIR | awk '"'"'{print $2}'"'"')"
    if [ -z "$pid" ]; then 
        echo "lighttpd not running"; 
    else 
        kill -9 $pid
    fi
    ;;
     restart)
        stop
        sleep 3
        start
        ;;
esac
' > /etc/init.d/lighttpd
chmod +x /etc/init.d/lighttpd
#if [ -e /etc/debian_version ]; then
#update-rc.d  rails start 99 3 .
#else 
#chkconfig --level 35 lighttpd on
#fi
/etc/init.d/lighttpd start
ip=$(ifconfig | grep --after-context=1 "eth0 " | grep inet | cut -d: -f2 | cut -f1 -d' ')
sleep 5
wget -O - http://$ip:3000 2>&1 | grep -q "Welcome ab"
if [ $? -ne 0 ]; then 
    echolog "Test load of http://$ip:3000 indicates rails or lighttpd is not working.  failed." >&2; 
    return 1; 
else 
    echolog "Test load of http://$ip:3000 indicates rails andlighttpd is working ok" >&2; 
fi
/etc/init.d/lighttpd stop
echolog "To check lighttpd, run /etc/init.d/ligttpd start then go to http://$ip:3000/ check it works"
}
testlighttpd
if [ $? -ne 0 ]; then echolog "testlighttpd failed" >&2; return 1; fi

# automatically tests that mongrel is working ok.  Sets itself up on port 3000
function testmongrel() {
echolog "setting up an /etc/init.d/mongrel script that will start up lighttpd pointing at the project in /var/www/test"
echo '#!/bin/bash
#
# chkconfig: 345 94 16
# description: Startup script for mongrel
BASEDIR=/var/www/test
case "$1" in
    start)
    echo "starting up mongrel in $BASEDIR"
    cd $BASEDIR
    mongrel_rails start -d 2>&1 >> /var/log/messages &
    ;;
    stop)
    echo "stopping mongrel"
    cd $BASEDIR
    mongrel_rails stop
    ;;
     restart)
        stop
        sleep 3
        start
        ;;
esac
' > /etc/init.d/mongrel
chmod +x /etc/init.d/mongrel
#if [ -e /etc/debian_version ]; then
#update-rc.d  rails start 99 3 .
#else 
#chkconfig --level 35 lighttpd on
#fi
/etc/init.d/mongrel start
ip=$(ifconfig | grep --after-context=1 "eth0 " | grep inet | cut -d: -f2 | cut -f1 -d' ')
sleep 5
wget -O - http://$ip:3000 2>&1 | grep -q "Welcome ab"
if [ $? -ne 0 ]; then 
    echolog "Test load of http://$ip:3000 indicates rails or mongrel is not working.  failed." >&2; 
    return 1; 
fi
echolog "Looks like http://$ip:3000 is loading OK with Mongrel" >&2; 

echolog "To check mongrel, run /etc/init.d/mongrel start then go to http://$ip:3000/ and check it works"
/etc/init.d/mongrel stop
}
testmongrel

echolog "All Done!"
}
installrails